-
Notifications
You must be signed in to change notification settings - Fork 9.2k
HDFS-17072. DFSAdmin: add a triggerDirectoryScanner command. #5825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a84d68c
1a82e66
b193a44
0904fcb
7b82a77
b45def5
5fcfe4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,8 @@ public class DirectoryScanner implements Runnable { | |
| private final long scanPeriodMsecs; | ||
| private final long throttleLimitMsPerSec; | ||
| private final AtomicBoolean shouldRun = new AtomicBoolean(); | ||
| // Method reconcile is executing currently. | ||
| private final AtomicBoolean reconcileRunning = new AtomicBoolean(); | ||
|
|
||
| private boolean retainDiffs = false; | ||
|
|
||
|
|
@@ -362,6 +364,7 @@ public DirectoryScanner(FsDatasetSpi<?> dataset, Configuration conf) { | |
| @VisibleForTesting | ||
| public void start() { | ||
| shouldRun.set(true); | ||
| reconcileRunning.set(false); | ||
| long firstScanTime = ThreadLocalRandom.current().nextLong(scanPeriodMsecs); | ||
|
|
||
| LOG.info( | ||
|
|
@@ -404,6 +407,11 @@ public void run() { | |
| "This cycle terminating immediately because 'shouldRun' has been deactivated"); | ||
| return; | ||
| } | ||
| if (reconcileRunning.get()) { | ||
| // Method reconcile is executing. | ||
| LOG.warn("This cycle terminating immediately because reconcile is being executed."); | ||
| return; | ||
| } | ||
| try { | ||
| reconcile(); | ||
| dataset.setLastDirScannerFinishTime(System.currentTimeMillis()); | ||
|
|
@@ -412,11 +420,13 @@ public void run() { | |
| LOG.error( | ||
| "Exception during DirectoryScanner execution - will continue next cycle", | ||
| e); | ||
| reconcileRunning.set(false); | ||
| } catch (Error er) { | ||
| // Non-recoverable error - re-throw after logging the problem | ||
| LOG.error( | ||
| "System Error during DirectoryScanner execution - permanently terminating periodic scanner", | ||
| er); | ||
| reconcileRunning.set(false); | ||
| throw er; | ||
| } | ||
| } | ||
|
|
@@ -432,6 +442,9 @@ void shutdown() { | |
| if (!shouldRun.getAndSet(false)) { | ||
| LOG.warn("Shutdown has been called, but periodic scanner not started"); | ||
| } | ||
| if (reconcileRunning.getAndSet(false)) { | ||
| LOG.warn("Shutdown has been called when directory scanner is running."); | ||
| } | ||
| if (masterThread != null) { | ||
| masterThread.shutdown(); | ||
| } | ||
|
|
@@ -463,8 +476,10 @@ void shutdown() { | |
| * Reconcile differences between disk and in-memory blocks | ||
| */ | ||
| @VisibleForTesting | ||
| public void reconcile() throws IOException { | ||
| public synchronized void reconcile() throws IOException { | ||
| reconcileRunning.set(true); | ||
| LOG.debug("reconcile start DirectoryScanning"); | ||
| DataNodeFaultInjector.get().throwIOExceptionWhenReconcile(); | ||
| scan(); | ||
|
|
||
| // HDFS-14476: run checkAndUpdate with batch to avoid holding the lock too | ||
|
|
@@ -488,6 +503,7 @@ public void reconcile() throws IOException { | |
| if (!retainDiffs) { | ||
| clear(); | ||
| } | ||
| reconcileRunning.set(false); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -777,4 +793,29 @@ private void accumulateTimeWaiting() { | |
| perfTimer.reset().start(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Trigger an instant run of directory scanner if it's not running currently. | ||
| * @return | ||
| */ | ||
| public String triggerDirectoryScanner() throws IOException { | ||
| if (reconcileRunning.get()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just as mentioned above. |
||
| return "Trigger DirectoryScanner failed, because it's running. Please try again later."; | ||
| } | ||
| try { | ||
| reconcile(); | ||
| dataset.setLastDirScannerFinishTime(System.currentTimeMillis()); | ||
| } catch (Exception e) { | ||
| // Log and reset reconcileRunning. | ||
| LOG.error( | ||
| "Exception during trigger DirectoryScanner execution, " + | ||
| "Try again later.", e); | ||
| reconcileRunning.set(false); | ||
| throw e; | ||
| } catch (Throwable e) { | ||
| reconcileRunning.set(false); | ||
| throw e; | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's safer to capture the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice suggestions. Have fixed it. Thanks~ |
||
| return "Trigger DirectoryScanner successfully."; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the
reconcileRunningvariable in this way cannot prevent two threads from executingreconcile()at the same time. When this thread is running after line410 and before line416, another thread may setreconcileRunningto true.