Skip to content

Commit 7d99508

Browse files
brahmareddybattulaccpds
authored andcommitted
HDFS-8693. refreshNamenodes does not support adding a new standby to a running DN. Contributed by Ajith S.
(cherry picked from commit 880b9d2) (cherry picked from commit d03115d) Change-Id: Ice8961ae8fbfe08a217818eee7f96e702c5bc4d4 (cherry picked from commit a5a0ce3)
1 parent c6d687f commit 7d99508

File tree

2 files changed

+93
-8
lines changed

2 files changed

+93
-8
lines changed

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/BPOfferService.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,25 @@ void refreshNNList(ArrayList<InetSocketAddress> addrs,
148148
}
149149
Set<InetSocketAddress> newAddrs = Sets.newHashSet(addrs);
150150

151-
if (!Sets.symmetricDifference(oldAddrs, newAddrs).isEmpty()) {
152-
// Keep things simple for now -- we can implement this at a later date.
153-
throw new IOException(
154-
"HA does not currently support adding a new standby to a running DN. " +
155-
"Please do a rolling restart of DNs to reconfigure the list of NNs.");
151+
// Process added NNs
152+
Set<InetSocketAddress> addedNNs = Sets.difference(newAddrs, oldAddrs);
153+
for (InetSocketAddress addedNN : addedNNs) {
154+
BPServiceActor actor = new BPServiceActor(addedNN,
155+
lifelineAddrs.get(addrs.indexOf(addedNN)), this);
156+
actor.start();
157+
bpServices.add(actor);
158+
}
159+
160+
// Process removed NNs
161+
Set<InetSocketAddress> removedNNs = Sets.difference(oldAddrs, newAddrs);
162+
for (InetSocketAddress removedNN : removedNNs) {
163+
for (BPServiceActor actor : bpServices) {
164+
if (actor.getNNSocketAddress().equals(removedNN)) {
165+
actor.stop();
166+
shutdownActor(actor);
167+
break;
168+
}
169+
}
156170
}
157171
}
158172

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/datanode/TestBPOfferService.java

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.io.File;
2929
import java.io.IOException;
3030
import java.net.InetSocketAddress;
31+
import java.util.ArrayList;
3132
import java.util.Collections;
3233
import java.util.List;
3334
import java.util.Map;
@@ -99,10 +100,10 @@ public class TestBPOfferService {
99100
private DatanodeProtocolClientSideTranslatorPB mockNN1;
100101
private DatanodeProtocolClientSideTranslatorPB mockNN2;
101102
private final NNHAStatusHeartbeat[] mockHaStatuses =
102-
new NNHAStatusHeartbeat[2];
103+
new NNHAStatusHeartbeat[3];
103104
private final DatanodeCommand[][] datanodeCommands =
104-
new DatanodeCommand[2][0];
105-
private final int[] heartbeatCounts = new int[2];
105+
new DatanodeCommand[3][0];
106+
private final int[] heartbeatCounts = new int[3];
106107
private DataNode mockDn;
107108
private FsDatasetSpi<?> mockFSDataset;
108109

@@ -864,4 +865,74 @@ public void testNNHAStateUpdateFromVersionRequest() throws Exception {
864865
assertNotNull(bpos.getActiveNN());
865866

866867
}
868+
869+
@Test
870+
public void testRefreshNameNodes() throws Exception {
871+
872+
BPOfferService bpos = setupBPOSForNNs(mockDn, mockNN1, mockNN2);
873+
874+
bpos.start();
875+
try {
876+
waitForBothActors(bpos);
877+
878+
// The DN should have register to both NNs.
879+
Mockito.verify(mockNN1)
880+
.registerDatanode(Mockito.any(DatanodeRegistration.class));
881+
Mockito.verify(mockNN2)
882+
.registerDatanode(Mockito.any(DatanodeRegistration.class));
883+
884+
// Should get block reports from both NNs
885+
waitForBlockReport(mockNN1);
886+
waitForBlockReport(mockNN2);
887+
888+
// When we receive a block, it should report it to both NNs
889+
bpos.notifyNamenodeReceivedBlock(FAKE_BLOCK, null, "", false);
890+
891+
ReceivedDeletedBlockInfo[] ret = waitForBlockReceived(FAKE_BLOCK,
892+
mockNN1);
893+
assertEquals(1, ret.length);
894+
assertEquals(FAKE_BLOCK.getLocalBlock(), ret[0].getBlock());
895+
896+
ret = waitForBlockReceived(FAKE_BLOCK, mockNN2);
897+
assertEquals(1, ret.length);
898+
assertEquals(FAKE_BLOCK.getLocalBlock(), ret[0].getBlock());
899+
900+
// add new standby
901+
DatanodeProtocolClientSideTranslatorPB mockNN3 = setupNNMock(2);
902+
Mockito.doReturn(mockNN3).when(mockDn)
903+
.connectToNN(Mockito.eq(new InetSocketAddress(2)));
904+
905+
ArrayList<InetSocketAddress> addrs = new ArrayList<>();
906+
ArrayList<InetSocketAddress> lifelineAddrs = new ArrayList<>(
907+
addrs.size());
908+
// mockNN1
909+
addrs.add(new InetSocketAddress(0));
910+
lifelineAddrs.add(null);
911+
// mockNN3
912+
addrs.add(new InetSocketAddress(2));
913+
lifelineAddrs.add(null);
914+
915+
bpos.refreshNNList(addrs, lifelineAddrs);
916+
917+
assertEquals(2, bpos.getBPServiceActors().size());
918+
// wait for handshake to run
919+
Thread.sleep(1000);
920+
921+
// verify new NN registered
922+
Mockito.verify(mockNN3)
923+
.registerDatanode(Mockito.any(DatanodeRegistration.class));
924+
925+
// When we receive a block, it should report it to both NNs
926+
bpos.notifyNamenodeReceivedBlock(FAKE_BLOCK, null, "", false);
927+
928+
// veridfy new NN recieved block report
929+
ret = waitForBlockReceived(FAKE_BLOCK, mockNN3);
930+
assertEquals(1, ret.length);
931+
assertEquals(FAKE_BLOCK.getLocalBlock(), ret[0].getBlock());
932+
933+
} finally {
934+
bpos.stop();
935+
bpos.join();
936+
}
937+
}
867938
}

0 commit comments

Comments
 (0)