From: Tuukka Lehtonen Date: Mon, 16 Oct 2017 19:54:33 +0000 (+0300) Subject: Improved tracking and disposal robustness of DirectorySizeTracker X-Git-Tag: v1.31.0~118 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=6c1351a1fed0c714a6f0b3fa2606c708381ecefc;p=simantics%2Fplatform.git Improved tracking and disposal robustness of DirectorySizeTracker refs #7551 Change-Id: I2844c5d53a365d2f69aee169772e97e09dbda815 --- diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/file/DirectorySizeTracker.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/file/DirectorySizeTracker.java index 6050f4dc9..4746afc89 100644 --- a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/file/DirectorySizeTracker.java +++ b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/file/DirectorySizeTracker.java @@ -18,6 +18,7 @@ import static java.nio.file.StandardWatchEventKinds.OVERFLOW; import java.io.Closeable; import java.io.IOException; +import java.nio.file.AccessDeniedException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; @@ -61,7 +62,7 @@ public class DirectorySizeTracker implements Runnable, Closeable { private static final Kind[] ALL_EVENTS = { ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY }; - private static AtomicInteger threadCounter = new AtomicInteger(); + private static AtomicInteger threadCounter = new AtomicInteger(1); private LongConsumer consumer; private Kind[] events; @@ -86,7 +87,7 @@ public class DirectorySizeTracker implements Runnable, Closeable { public static DirectorySizeTracker startTracker(LongConsumer sizeChangeListener) throws IOException { DirectorySizeTracker watcher = new DirectorySizeTracker(sizeChangeListener, ALL_EVENTS); - watcher.thread = new Thread(watcher, DirectorySizeTracker.class.getSimpleName() + threadCounter.get()); + watcher.thread = new Thread(watcher, DirectorySizeTracker.class.getSimpleName() + "-" + threadCounter.get()); watcher.thread.start(); return watcher; } @@ -275,6 +276,18 @@ public class DirectorySizeTracker implements Runnable, Closeable { Path dir = trackedDirs.getRight(key); if (dir == null) { LOGGER.error("WatchKey not registered: " + key); + for (WatchEvent event : key.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + // TBD - provide example of how OVERFLOW event is handled + if (kind == OVERFLOW) + continue; + // Context for directory entry event is the file name of entry + WatchEvent evt = cast(event); + Path name = evt.context(); + LOGGER.error(String.format("MISSED EVENT: %s: %s", event.kind().name(), name)); + } + boolean valid = key.reset(); + LOGGER.error("RESET KEY RETURNED: " + valid); continue; } @@ -317,6 +330,8 @@ public class DirectorySizeTracker implements Runnable, Closeable { if (!entrySizes.containsKey(child)) { untrack(child); } + } catch (AccessDeniedException e) { + // Ignore. This can happen e.g. with temporary locked Lucene index files. } catch (IOException ioe) { LOGGER.error("Failed to read attribute for path " + child, ioe); } @@ -354,10 +369,23 @@ public class DirectorySizeTracker implements Runnable, Closeable { while (running) processEvents(); } finally { + // It seems that for some reason cancelling all watch keys + // helps the watcher close itself. Otherwise closing the + // watch service seemed to get stuck easily. + cancelWatchKeys(); FileUtils.uncheckedClose(watcher); } } + private void cancelWatchKeys() { + synchronized (lock) { + for (WatchKey key : trackedDirs.getLeftSet()) { + key.cancel(); + key.pollEvents(); + } + } + } + /** * @return total size of the tracked directories in bytes */ @@ -366,9 +394,8 @@ public class DirectorySizeTracker implements Runnable, Closeable { } // public static void main(String[] args) { -// try { -// DirectorySizeTracker tracker = DirectorySizeTracker.startTracker(null); -// tracker.track(Paths.get("d:/track-test")); +// try (DirectorySizeTracker tracker = DirectorySizeTracker.startTracker(null)) { +// tracker.track(Paths.get("d:/temp dir")); // LOGGER.info("AFTER TRACK: Total size from " + tracker.entrySizes.size() + " files and " + tracker.trackedDirs.size() + " directories is " + tracker.getTotalSize()); // Thread.sleep(2000); // //tracker.untrack(Paths.get("d:/track-test"));