Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
84b56f8
HDDS-5916: DNs in pipeline raft group get stuck in infinite leader el…
Mar 11, 2022
cb4adb9
fix rat and checkstyle errors
Mar 14, 2022
e51aa4b
fix findbugs errors
Mar 15, 2022
50ded1c
solve a edge case bug
Mar 30, 2022
5c9addf
fix test
Mar 31, 2022
a7e47b7
fix check style error
Mar 31, 2022
71f1b28
address PR comments
Apr 1, 2022
d7dbf36
address PR comments
Apr 1, 2022
9452d81
resolve conflicts
May 7, 2022
b89eed1
fix checkstyle error
May 7, 2022
e346e8b
trigger new CI check
adoroszlai May 9, 2022
878f989
Avoid new static import for easier merge from master
adoroszlai May 18, 2022
b807db6
Merge remote-tracking branch 'origin/master' into HDDS-5916-support-d…
adoroszlai May 18, 2022
424c788
address PR comments
May 20, 2022
e6156e6
fix compilation error
May 20, 2022
f94bb3d
Test read/write after restart
adoroszlai May 23, 2022
c7993ae
Remove ozone-dn-restart env
adoroszlai May 23, 2022
52d20d2
Fix smoketest path
adoroszlai May 23, 2022
aa2fb97
Default values for variables
adoroszlai May 23, 2022
627a568
Skip chunk generator/validator in kubernetes
adoroszlai May 23, 2022
4404106
merge ozone and ozne-dn-restart environment
May 30, 2022
8bbca39
delete unecessary dn env setting
May 30, 2022
aeeee27
trun two logs from debug to info
May 31, 2022
db20d84
make block allocation more reliable when there are pipelines are in a…
Jun 1, 2022
62c46eb
address PR comments
Jun 1, 2022
1a81703
fix checkstyle error
Jun 2, 2022
2c5f812
fix a comment
Jun 11, 2022
27f2d76
add more unit test
Jun 16, 2022
7941838
resovle conflict
Jun 16, 2022
7ce0077
fix test failure
Jun 17, 2022
e742158
working
Jun 17, 2022
d8f4822
cleanup
Jun 17, 2022
801e856
Merge remote-tracking branch 'origin/master' into HDDS-5916-support-d…
adoroszlai Jun 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import org.apache.hadoop.hdds.StringUtils;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeDetails.Port;
import org.apache.hadoop.hdds.ratis.conf.RatisClientConfig;
Expand All @@ -38,6 +39,7 @@
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.security.x509.SecurityConfig;

import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.ratis.RaftConfigKeys;
import org.apache.ratis.client.RaftClient;
import org.apache.ratis.client.RaftClientConfigKeys;
Expand All @@ -64,6 +66,8 @@ public final class RatisHelper {

private static final Logger LOG = LoggerFactory.getLogger(RatisHelper.class);

private static final OzoneConfiguration CONF = new OzoneConfiguration();

// Prefix for Ratis Server GRPC and Ratis client conf.
public static final String HDDS_DATANODE_RATIS_PREFIX_KEY = "hdds.ratis";

Expand Down Expand Up @@ -96,7 +100,13 @@ public static UUID toDatanodeId(RaftProtos.RaftPeerProto peerId) {
}

private static String toRaftPeerAddress(DatanodeDetails id, Port.Name port) {
return id.getIpAddress() + ":" + id.getPort(port).getValue();
if (datanodeUseHostName()) {
LOG.debug("Datanode is using hostname for raft peer address");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well print the actual value calculated in the debug log.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

return id.getHostName() + ":" + id.getPort(port).getValue();
} else {
LOG.debug("Datanode is using IP for raft peer address");
return id.getIpAddress() + ":" + id.getPort(port).getValue();
}
}

public static RaftPeerId toRaftPeerId(DatanodeDetails id) {
Expand Down Expand Up @@ -323,6 +333,12 @@ public static Long getMinReplicatedIndex(
.min(Long::compareTo).orElse(null);
}

private static boolean datanodeUseHostName() {
return CONF.getBoolean(
DFSConfigKeys.DFS_DATANODE_USE_DN_HOSTNAME,
DFSConfigKeys.DFS_DATANODE_USE_DN_HOSTNAME_DEFAULT);
Comment thread
adoroszlai marked this conversation as resolved.
}

private static <U> Class<? extends U> getClass(String name,
Class<U> xface) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private void persistContainerDatanodeDetails() {
File idPath = new File(dataNodeIDPath);
DatanodeDetails datanodeDetails = this.context.getParent()
.getDatanodeDetails();
if (datanodeDetails != null && !idPath.exists()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation for dropping this check?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because when the datanode got restarted in k8s, the IP will be changed. So the original info in this file is not accurate any more. This will make sure we update with the latest info.

And when we are not using k8s, I think it is not harmful to always update this file whenever the node restarts.

if (datanodeDetails != null) {
try {
ContainerUtils.writeDatanodeDetailsTo(datanodeDetails, idPath);
} catch (IOException ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import org.apache.hadoop.hdds.scm.net.NodeImpl;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.util.Time;

Expand Down Expand Up @@ -58,10 +61,29 @@ public class EventQueue implements EventPublisher, AutoCloseable {

private boolean isRunning = true;

private static final Gson TRACING_SERIALIZER = new GsonBuilder().create();
private static final Gson TRACING_SERIALIZER = new GsonBuilder()
.setExclusionStrategies(new DatanodeDetailsGsonExclusionStrategy())
.create();

private boolean isSilent = false;

// The field parent in DatanodeDetails class has the circular reference
// which will result in Gson infinite recursive parsing. We need to exclude
// this field when generating json string for DatanodeDetails object
static class DatanodeDetailsGsonExclusionStrategy

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change can be merged as a quick PR and not wait on this PR.

implements ExclusionStrategy {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass() == NodeImpl.class
&& f.getName().equals("parent");
}

@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
}

/**
* Add new handler to the event queue.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ public final class SCMEvents {
public static final TypedEvent<DatanodeDetails> NEW_NODE =
new TypedEvent<>(DatanodeDetails.class, "New_Node");

/**
* This event will be triggered whenever a datanode is registered with
* SCM with a different Ip or host name.
*/
public static final TypedEvent<DatanodeDetails> NODE_IP_OR_HOSTNAME_UPDATE =
new TypedEvent<>(DatanodeDetails.class, "Node_Ip_Or_Hostname_Update");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of "IP or hostname" I think we can simply say "address", here and elsewhere, too (e.g. in NodeIpOrHostnameUpdateHandler).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure.


/**
* This event will be triggered whenever a datanode is moved from healthy to
* stale state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ enum ServiceStatus {
enum Event {
PRE_CHECK_COMPLETED,
NEW_NODE_HANDLER_TRIGGERED,
NODE_IP_OR_HOSTNAME_UPDATE_HANDLER_TRIGGERED,
UNHEALTHY_TO_HEALTHY_NODE_HANDLER_TRIGGERED
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public NewNodeHandler(PipelineManager pipelineManager,
public void onMessage(DatanodeDetails datanodeDetails,
EventPublisher publisher) {
try {
pipelineManager.closeStalePipelines(datanodeDetails);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is closeStalePipelines necessary here? Since when SCM processes the register command, it should be able to distinguish the new node / updated node, and here should be only responsible for the new node case

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. This is necessary. I believe in my testing, if a datanode is dead for a long time, SCM will remove it from the registration list. When the node comes up with a different IP, it first registers with SCM, and SCM treat it as a new node. But the old pipeline with the old IPs may still be there.

Another way to achieve this is to delete the pipelines if SCM is going to remove the dead nodes. But I am not that familiar with this part of the code. I may need to have a further look.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to your implementation, when the node comes up with a different IP, it will register first with SCM, SCM node manager will get it as long as its UUID is not changed through isNodeRegistered. Since it triggers the event of address updated event and in which it will close state pipelines and update node info, also creating new pipelines.
For the New node case, I think we do not need this close action.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry. I think I misstated my case. You are right. When a datanode is dead for a long time, SCM actually won't remove it from its registration list. So when this node with the same uuid comes up again with different IP, it will fall to update address condition, instead of registering new node.

However, there is another case. If the SCM also restarts, then it will lose all its in memory node registration map, but it still have all the old pipelines since pipelines are read from persistent. So in this case, if the datanode changes its IP, and come to register with SCM, SCM will treat it as a new node instead of a known node with different IP. So in this case, we still need to close all the stale pipelines which has the old IPs for this datanode.

Please let me know if my above statement makes sense to you. Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, thx for the explanation.

serviceManager.notifyEventTriggered(Event.NEW_NODE_HANDLER_TRIGGERED);

if (datanodeDetails.getPersistedOpState()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.hadoop.hdds.scm.node;

import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
import org.apache.hadoop.hdds.scm.ha.SCMService;
import org.apache.hadoop.hdds.scm.ha.SCMServiceManager;
import org.apache.hadoop.hdds.scm.node.states.NodeNotFoundException;
import org.apache.hadoop.hdds.scm.pipeline.PipelineManager;
import org.apache.hadoop.hdds.server.events.EventHandler;
import org.apache.hadoop.hdds.server.events.EventPublisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Handles datanode ip or hostname change event.
*/
public class NodeIpOrHostnameUpdateHandler
implements EventHandler<DatanodeDetails> {
private static final Logger LOG =
LoggerFactory.getLogger(NodeIpOrHostnameUpdateHandler.class);

private final PipelineManager pipelineManager;
private final NodeDecommissionManager decommissionManager;
private final SCMServiceManager serviceManager;

public NodeIpOrHostnameUpdateHandler(PipelineManager pipelineManager,
NodeDecommissionManager decommissionManager,
SCMServiceManager serviceManager) {
this.pipelineManager = pipelineManager;
this.decommissionManager = decommissionManager;
this.serviceManager = serviceManager;
}

@Override
public void onMessage(DatanodeDetails datanodeDetails,
EventPublisher publisher) {
try {
pipelineManager.closeStalePipelines(datanodeDetails);
serviceManager.notifyEventTriggered(SCMService.Event
.NODE_IP_OR_HOSTNAME_UPDATE_HANDLER_TRIGGERED);

if (datanodeDetails.getPersistedOpState()
!= HddsProtos.NodeOperationalState.IN_SERVICE) {
decommissionManager.continueAdminForNode(datanodeDetails);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to depend on the guarantees of continueAdminForNode (need to update javadoc for continueAdminForNode) and always call that method here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continueAdminForNode implements the logic for when the dn should be monitored. Let's not replicate it.

  public synchronized void continueAdminForNode(DatanodeDetails dn)
      throws NodeNotFoundException {
    if (!scmContext.isLeader()) {
      LOG.info("follower SCM ignored continue admin for datanode {}", dn);
      return;
    }
    NodeOperationalState opState = getNodeStatus(dn).getOperationalState();
    if (opState == NodeOperationalState.DECOMMISSIONING
        || opState == NodeOperationalState.ENTERING_MAINTENANCE
        || opState == NodeOperationalState.IN_MAINTENANCE) {
      LOG.info("Continue admin for datanode {}", dn);
      monitor.startMonitoring(dn);
    }
  }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

}
} catch (NodeNotFoundException e) {
// Should not happen, as the node has just registered to call this event
// handler.
LOG.warn(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log as an error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

"NodeNotFound when updating the node Ip or host name to the " +
"decommissionManager",
e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,28 @@ public void updateLastKnownLayoutVersion(DatanodeDetails datanodeDetails,
.updateLastKnownLayoutVersion(layoutInfo);
}

/**
* Update node.
*
* @param datanodeDetails the datanode details
* @param layoutInfo the layoutInfo
* @throws NodeNotFoundException the node not found exception
*/
public void updateNode(DatanodeDetails datanodeDetails,
LayoutVersionProto layoutInfo)
throws NodeNotFoundException {
DatanodeInfo datanodeInfo =
nodeStateMap.getNodeInfo(datanodeDetails.getUuid());
NodeStatus newNodeStatus = newNodeStatus(datanodeDetails, layoutInfo);
LOG.info("updating node {} from {} to {} with status {}",
datanodeDetails.getUuidString(),
datanodeInfo,
datanodeDetails,
newNodeStatus);
nodeStateMap.updateNode(datanodeDetails, newNodeStatus, layoutInfo);
updateLastKnownLayoutVersion(datanodeDetails, layoutInfo);
}

/**
* Returns the current state of the node.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,33 +359,34 @@ public RegisteredCommand register(
.build();
}

InetAddress dnAddress = Server.getRemoteIp();
if (dnAddress != null) {
// Mostly called inside an RPC, update ip
datanodeDetails.setHostName(dnAddress.getHostName());
datanodeDetails.setIpAddress(dnAddress.getHostAddress());
}

String dnsName;
String networkLocation;
datanodeDetails.setNetworkName(datanodeDetails.getUuidString());
if (useHostname) {
dnsName = datanodeDetails.getHostName();
} else {
dnsName = datanodeDetails.getIpAddress();
}
networkLocation = nodeResolve(dnsName);
if (networkLocation != null) {
datanodeDetails.setNetworkLocation(networkLocation);
}

if (!isNodeRegistered(datanodeDetails)) {
InetAddress dnAddress = Server.getRemoteIp();
if (dnAddress != null) {
// Mostly called inside an RPC, update ip and peer hostname
datanodeDetails.setHostName(dnAddress.getHostName());

@sokui sokui Jun 16, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I delete this line, because these days, when I tested it, I found sometimes dnAddress.getHostName() returns IP instead of hostName, which makes the datanode restarting not work. Please let me know if it is OK to delete this line. @GeorgeJahad @adoroszlai

@GeorgeJahad GeorgeJahad Jun 20, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sokui @adoroszlai I'm nervous about removing the call to setHostName().

I just took around and it seems to get used in many places. I've included some below:

Why does restart not work when it returns the IP string instead of the host string?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @GeorgeJahad ,

To not change the old code path, I added the if condition: when useHostname is true, we will not setHostname, but when it is false (old code), we keep the old logic which set the hostname. There are two things I want to explain:

  1. When datanode fist register with scm, the datanodeDetails already contains hostName. Here the code we are talking about is just to reset the datanodeDetails.hostName. So the code you listed above won't return null if we remove this line of code datanodeDetails.setHostName(dnAddress.getHostName());.

  2. Why it doesn't work when we reset datanodeDetails.hostName when useHostname is true? this is because in k8s, when datanode first registered with scm, dnAddress.getHostName() may return IP instead of hostName (maybe because of k8s DNS lookup service delay, I am not exactly sure). this will result in the IP instead of hostName is used in datanode Ratis communication for Pipelines. When datanode gets restarted with different IP, then the Ratis communication with old IP throws the HostNotFoundException. But if we remove this line, then we are sure that the datanodeDetails.hostName always contains the hostname instead of the IP. So it won't have the Ratis communication problem.

This is the whole story. That's why now I keep the old code path same, but if useHostname is true, we won't do datanodeDetails.setHostName(dnAddress.getHostName()); in the register process. Please let me know if it makes sense to you.

@GeorgeJahad GeorgeJahad Jun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When datanode fist register with scm, the datanodeDetails already contains hostName. Here the code we are talking about is just to reset the datanodeDetails.hostName.

If you are sure this is true, then I'm fine with the change.

To not change the old code path, I added the if condition: when useHostname is true, we will not setHostname, but when it is false (old code),

I'm confused about this statement. The old code path is when "(!isNodeRegistered(datanodeDetails))" is true, isn't it? not when "(!useHostname)" is true? what am I missing?

@adoroszlai adoroszlai Jun 21, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old codepath means current master, before this PR (or when DFS_DATANODE_USE_DN_HOSTNAME is not enabled).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion. The old path is the current master. So I made the following change:

from

if (dnAddress != null) {
        // Mostly called inside an RPC, update ip and peer hostname
        datanodeDetails.setHostName(dnAddress.getHostName());
        ...
}

To

if (dnAddress != null) {
        // Mostly called inside an RPC, update ip and peer hostname
        if (!useHostname) {
            datanodeDetails.setHostName(dnAddress.getHostName());
        }
        ...
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I was saying is that even we delete this line datanodeDetails.setHostName(dnAddress.getHostName());, it should be still fine because when datanode register with scm, the datanodeDetails already have the hostName info. But to be conservative, I just use the above logic to make sure when DFS_DATANODE_USE_DN_HOSTNAME is not enabled, the code is the exactly same as before.

datanodeDetails.setIpAddress(dnAddress.getHostAddress());
}
try {
String dnsName;
String networkLocation;
datanodeDetails.setNetworkName(datanodeDetails.getUuidString());
if (useHostname) {
dnsName = datanodeDetails.getHostName();
} else {
dnsName = datanodeDetails.getIpAddress();
}
networkLocation = nodeResolve(dnsName);
if (networkLocation != null) {
datanodeDetails.setNetworkLocation(networkLocation);
}

clusterMap.add(datanodeDetails);
nodeStateManager.addNode(datanodeDetails, layoutInfo);
// Check that datanode in nodeStateManager has topology parent set
DatanodeDetails dn = nodeStateManager.getNode(datanodeDetails);
Preconditions.checkState(dn.getParent() != null);
addEntryTodnsToUuidMap(dnsName, datanodeDetails.getUuidString());
addEntryToDnsToUuidMap(dnsName, datanodeDetails.getUuidString());
// Updating Node Report, as registration is successful
processNodeReport(datanodeDetails, nodeReport);
LOG.info("Registered Data node : {}", datanodeDetails);
Expand All @@ -399,6 +400,44 @@ public RegisteredCommand register(
LOG.error("Cannot find datanode {} from nodeStateManager",
datanodeDetails.toString());
}
} else {
// Update datanode if it is registered but the ip or hostname changes
try {
final DatanodeInfo datanodeInfo =
nodeStateManager.getNode(datanodeDetails);
if (!datanodeInfo.getIpAddress().equals(datanodeDetails.getIpAddress())
|| !datanodeInfo.getHostName()
.equals(datanodeDetails.getHostName())) {
LOG.info("Updating data node {} from {} to {}",
datanodeDetails.getUuidString(),
datanodeInfo,
datanodeDetails);
if (clusterMap.contains(datanodeInfo)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to implement clusterMap.update(datanodeDetails). This would keep the locking and concurrency issues in check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

clusterMap.remove(datanodeInfo);
}
clusterMap.add(datanodeDetails);

String oldDnsName;
if (useHostname) {
oldDnsName = datanodeInfo.getHostName();
} else {
oldDnsName = datanodeInfo.getIpAddress();
}
removeEntryFromDnsToUuidMap(oldDnsName);
addEntryToDnsToUuidMap(dnsName, datanodeDetails.getUuidString());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here better to implement a new method updateEntryInDnsToUuisMap(oldDnsName, dnsName, datanodeDetails.getUuidString)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


nodeStateManager.updateNode(datanodeDetails, layoutInfo);
DatanodeDetails dn = nodeStateManager.getNode(datanodeDetails);
Preconditions.checkState(dn.getParent() != null);
processNodeReport(datanodeDetails, nodeReport);
LOG.info("Updated Datanode to: {}", dn);
scmNodeEventPublisher
.fireEvent(SCMEvents.NODE_IP_OR_HOSTNAME_UPDATE, dn);
}
} catch (NodeNotFoundException e) {
LOG.error("Cannot find datanode {} from nodeStateManager",
datanodeDetails);
}
}

return RegisteredCommand.newBuilder().setErrorCode(ErrorCode.success)
Expand All @@ -415,11 +454,9 @@ public RegisteredCommand register(
* @param dnsName String representing the hostname or IP of the node
* @param uuid String representing the UUID of the registered node.
*/
@SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION",
justification = "The method is synchronized and this is the only place " +
"dnsToUuidMap is modified")
private synchronized void addEntryTodnsToUuidMap(
String dnsName, String uuid) {
@SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION")
private synchronized void addEntryToDnsToUuidMap(
String dnsName, String uuid) {
Set<String> dnList = dnsToUuidMap.get(dnsName);
if (dnList == null) {
dnList = ConcurrentHashMap.newKeySet();
Expand All @@ -428,6 +465,19 @@ private synchronized void addEntryTodnsToUuidMap(
dnList.add(uuid);
}

private synchronized void removeEntryFromDnsToUuidMap(String dnsName) {
if (!dnsToUuidMap.containsKey(dnsName)) {
return;
}
Set<String> dnSet = dnsToUuidMap.get(dnsName);
if (dnSet.contains(dnsName)) {
dnSet.remove(dnsName);
}
if (dnSet.isEmpty()) {
dnsToUuidMap.remove(dnsName);
}
}

/**
* Send heartbeat to indicate the datanode is alive and doing well.
*
Expand Down
Loading