]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Improved tracking and disposal robustness of DirectorySizeTracker 13/1113/1
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Mon, 16 Oct 2017 19:54:33 +0000 (22:54 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Mon, 16 Oct 2017 19:54:33 +0000 (22:54 +0300)
refs #7551

Change-Id: I2844c5d53a365d2f69aee169772e97e09dbda815

bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/file/DirectorySizeTracker.java

index 6050f4dc947f5c88bb4465ec5455b451033724a8..4746afc89df044097c7cac450ebb3dfbffea2c9b 100644 (file)
@@ -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<Path> 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"));