DirectoryScanner
DirectoryScanner的主要任務是定期掃描磁盤上的數據塊,檢查磁盤上的數據塊信息是否與FsDatasetImpl中保存的數據塊信息一致,如果不一致則對FsDatasetImpl中的信息進行更新。
注:DirectoryScanner只檢查內存和磁盤上FINALIZED狀態的數據塊是否一致。
public class DirectoryScanner implements Runnable {
...
// 異步收集磁盤數據塊信息的線程池
private final ExecutorService reportCompileThreadPool;
// master線程,定期調用DirectoryScanner.run方法
private final ScheduledExecutorService masterThread;
// 數據塊信息與內存元數據的差異,掃描過程中更新,掃描結束後把diffs更新到FsDatasetImpl
final ScanInfoPerBlockPool diffs = new ScanInfoPerBlockPool();
...
DirectoryScanner(DataNode datanode, FsDatasetSpi<?> dataset, Configuration conf) {
...
reportCompileThreadPool = Executors.newFixedThreadPool(threads,
new Daemon.DaemonFactory());
//初始化master線程
masterThread = new ScheduledThreadPoolExecutor(1,
new Daemon.DaemonFactory());
}
void start() {
...
// 定期執行DirectoryScanner的run方法
masterThread.scheduleAtFixedRate(this, offset, scanPeriodMsecs,
TimeUnit.MILLISECONDS);
}
@Override
public void run() {
try {
if (!shouldRun) {
//shutdown has been activated
LOG.warn("this cycle terminating immediately because 'shouldRun' has been deactivated");
return;
}
//We're are okay to run - do it
reconcile();
} catch (Exception e) {
//Log and continue - allows Executor to run again next cycle
LOG.error("Exception during DirectoryScanner execution - will continue next cycle", e);
} catch (Error er) {
//Non-recoverable error - re-throw after logging the problem
LOG.error("System Error during DirectoryScanner execution - permanently terminating periodic scanner", er);
throw er;
}
}
void reconcile() throws IOException {
// 調用scan蒐集磁盤數據塊與內存數據塊的差異信息
scan();
for (Entry<String, LinkedList<ScanInfo>> entry : diffs.entrySet()) {
String bpid = entry.getKey();
LinkedList<ScanInfo> diff = entry.getValue();
for (ScanInfo info : diff) {
// 與FsDatasetImpl完成同步
dataset.checkAndUpdate(bpid, info.getBlockId(), info.getBlockFile(),
info.getMetaFile(), info.getVolume());
}
}
if (!retainDiffs) clear();
}
}
DirectoryScanner對象會定期在master線程上出發掃描任務,這個任務由reconcile()方法完成。