|
@@ -36,6 +36,8 @@ import java.util.SortedSet;
|
|
|
import java.util.TreeSet;
|
|
|
import java.util.concurrent.BlockingQueue;
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
@@ -69,6 +71,7 @@ import org.apache.hadoop.hdfs.server.protocol.VolumeFailureSummary;
|
|
|
import org.apache.hadoop.io.IOUtils;
|
|
|
import org.apache.hadoop.ipc.RemoteException;
|
|
|
import org.apache.hadoop.net.NetUtils;
|
|
|
+import org.apache.hadoop.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
|
import org.apache.hadoop.util.Preconditions;
|
|
|
import org.apache.hadoop.util.Time;
|
|
|
import org.apache.hadoop.util.VersionInfo;
|
|
@@ -98,6 +101,8 @@ class BPServiceActor implements Runnable {
|
|
|
|
|
|
volatile long lastCacheReport = 0;
|
|
|
private final Scheduler scheduler;
|
|
|
+ private final Object sendIBRLock;
|
|
|
+ private final ExecutorService ibrExecutorService;
|
|
|
|
|
|
Thread bpThread;
|
|
|
DatanodeProtocolClientSideTranslatorPB bpNamenode;
|
|
@@ -153,6 +158,10 @@ class BPServiceActor implements Runnable {
|
|
|
}
|
|
|
commandProcessingThread = new CommandProcessingThread(this);
|
|
|
commandProcessingThread.start();
|
|
|
+ sendIBRLock = new Object();
|
|
|
+ ibrExecutorService = Executors.newSingleThreadExecutor(
|
|
|
+ new ThreadFactoryBuilder().setDaemon(true)
|
|
|
+ .setNameFormat("ibr-executor-%d").build());
|
|
|
}
|
|
|
|
|
|
public DatanodeRegistration getBpRegistration() {
|
|
@@ -372,8 +381,10 @@ class BPServiceActor implements Runnable {
|
|
|
// we have a chance that we will miss the delHint information
|
|
|
// or we will report an RBW replica after the BlockReport already reports
|
|
|
// a FINALIZED one.
|
|
|
- ibrManager.sendIBRs(bpNamenode, bpRegistration,
|
|
|
- bpos.getBlockPoolId(), getRpcMetricSuffix());
|
|
|
+ synchronized (sendIBRLock) {
|
|
|
+ ibrManager.sendIBRs(bpNamenode, bpRegistration,
|
|
|
+ bpos.getBlockPoolId(), getRpcMetricSuffix());
|
|
|
+ }
|
|
|
|
|
|
long brCreateStartTime = monotonicNow();
|
|
|
Map<DatanodeStorage, BlockListAsLongs> perVolumeBlockLists =
|
|
@@ -604,6 +615,9 @@ class BPServiceActor implements Runnable {
|
|
|
if (commandProcessingThread != null) {
|
|
|
commandProcessingThread.interrupt();
|
|
|
}
|
|
|
+ if (ibrExecutorService != null && !ibrExecutorService.isShutdown()) {
|
|
|
+ ibrExecutorService.shutdownNow();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//This must be called only by blockPoolManager
|
|
@@ -618,13 +632,18 @@ class BPServiceActor implements Runnable {
|
|
|
} catch (InterruptedException ie) { }
|
|
|
}
|
|
|
|
|
|
- //Cleanup method to be called by current thread before exiting.
|
|
|
+ // Cleanup method to be called by current thread before exiting.
|
|
|
+ // Any Thread / ExecutorService started by BPServiceActor can be shutdown
|
|
|
+ // here.
|
|
|
private synchronized void cleanUp() {
|
|
|
|
|
|
shouldServiceRun = false;
|
|
|
IOUtils.cleanupWithLogger(null, bpNamenode);
|
|
|
IOUtils.cleanupWithLogger(null, lifelineSender);
|
|
|
bpos.shutdownActor(this);
|
|
|
+ if (!ibrExecutorService.isShutdown()) {
|
|
|
+ ibrExecutorService.shutdownNow();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private void handleRollingUpgradeStatus(HeartbeatResponse resp) throws IOException {
|
|
@@ -710,11 +729,6 @@ class BPServiceActor implements Runnable {
|
|
|
commandProcessingThread.enqueue(resp.getCommands());
|
|
|
}
|
|
|
}
|
|
|
- if (!dn.areIBRDisabledForTests() &&
|
|
|
- (ibrManager.sendImmediately()|| sendHeartbeat)) {
|
|
|
- ibrManager.sendIBRs(bpNamenode, bpRegistration,
|
|
|
- bpos.getBlockPoolId(), getRpcMetricSuffix());
|
|
|
- }
|
|
|
|
|
|
List<DatanodeCommand> cmds = null;
|
|
|
boolean forceFullBr =
|
|
@@ -878,6 +892,10 @@ class BPServiceActor implements Runnable {
|
|
|
initialRegistrationComplete.countDown();
|
|
|
}
|
|
|
|
|
|
+ // IBR tasks to be handled separately from offerService() in order to
|
|
|
+ // improve performance of offerService(), which can now focus only on
|
|
|
+ // FBR and heartbeat.
|
|
|
+ ibrExecutorService.submit(new IBRTaskHandler());
|
|
|
while (shouldRun()) {
|
|
|
try {
|
|
|
offerService();
|
|
@@ -1108,6 +1126,34 @@ class BPServiceActor implements Runnable {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ class IBRTaskHandler implements Runnable {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ LOG.info("Starting IBR Task Handler.");
|
|
|
+ while (shouldRun()) {
|
|
|
+ try {
|
|
|
+ final long startTime = scheduler.monotonicNow();
|
|
|
+ final boolean sendHeartbeat = scheduler.isHeartbeatDue(startTime);
|
|
|
+ if (!dn.areIBRDisabledForTests() &&
|
|
|
+ (ibrManager.sendImmediately() || sendHeartbeat)) {
|
|
|
+ synchronized (sendIBRLock) {
|
|
|
+ ibrManager.sendIBRs(bpNamenode, bpRegistration,
|
|
|
+ bpos.getBlockPoolId(), getRpcMetricSuffix());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // There is no work to do; sleep until heartbeat timer elapses,
|
|
|
+ // or work arrives, and then iterate again.
|
|
|
+ ibrManager.waitTillNextIBR(scheduler.getHeartbeatWaitTime());
|
|
|
+ } catch (Throwable t) {
|
|
|
+ LOG.error("Exception in IBRTaskHandler.", t);
|
|
|
+ sleepAndLogInterrupts(5000, "offering IBR service");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Utility class that wraps the timestamp computations for scheduling
|
|
|
* heartbeats and block reports.
|