more locked IO performance tests.
[vamsas.git] / src / org / vamsas / client / simpleclient / FileWatcher.java
index f486360..e2a3ad0 100644 (file)
@@ -5,48 +5,141 @@ package org.vamsas.client.simpleclient;
 
 import java.io.File;
 
+
 /**
- * @author jim
- * Watches a particular file for its creation, deletion, or modification.
+ * @author jim Watches a particular file for its creation, deletion, or
+ *         modification.
  */
 public class FileWatcher {
-  private File subject=null;
-  private long lastStat;
-  boolean exists=false;
+
+  private File subject = null;
+
+  private long lastStat[];
+  boolean waslocked=false;
+  boolean exists = false;
   /**
-   * Make a watcher for a particular file.
-   * If the file doesn't exist, the watcher will watch
-   * for its creation (and indicate a change of state)
-   * @param subject
+   * transient lock on subject - can be passed back to calling class
+   * to preserve new state of file for immediate reading.
+   */
+  private Lock subjectLock = null;
+  
+  private void clearLock() {
+    if (subjectLock!=null)
+      subjectLock.release();
+    subjectLock=null;
+  }
+  
+  private boolean checkLock() {
+    if (subject!=null && subject.exists()) {
+      if (subjectLock!=null) {
+        subjectLock.release();
+      }
+      subjectLock = new Lock(subject);
+      if (subjectLock.isLocked()) {
+        // subjectLock.release();
+        return false;
+      }
+      clearLock();
+      return true;
+    }
+    return false;
+  }
+  
+  private long[] getStat(File subject) {
+    return new long[] { subject.lastModified(), subject.length() };
+  }
+  private boolean compStat(long[] stat, long[] newstat) {
+    if (stat[0]!=newstat[0] || stat[1]!=newstat[1])
+      return false;
+    return true;
+  }
+  /**
+   * Detect changes in file state and release of any
+   * lock in place during change.
+   * @return true if file state has changed. Leaves lock in subjectLock (ready to be passed to caller)
    */
   private boolean check() {
-    if (subject!=null) {
+    if (subject != null) {
       if (!subject.exists()) {
         if (exists) {
-        exists=false;
-        return true;
-      } 
-      return false;
-    } else {
-      long newStat=subject.lastModified();
-      if (exists && lastStat==newStat) {
+          if (!waslocked) {
+            // !checkLock()) {
+          
+            exists = false;
+            // waslocked=false;
+            return true;
+          }
+        }
+        // locked - state change registered after lock is released
         return false;
+      } else {
+        long[] newStat = getStat(subject); // subject.lastModified();
+        if (!checkLock()) {
+          // file is free to access, return state change
+          if (!exists || !compStat(lastStat, newStat)) {
+            waslocked=false;
+            exists=true;
+            lastStat=newStat;
+            return true;
+          }
+          // no change
+          return false;
+        } else {
+          waslocked=true;
+          return false;
+        }
       }
-      lastStat=newStat;
-      exists=true;
-      return true;
     }
-  }
     return false;
   }
+  /**
+   * updates internal record of file state when caller has intentionally
+   * modified subject. (ignores locked-state of subject)
+   */
+  public void setState() {
+    if (subject!=null) {
+      if (exists = subject.exists()) {
+        lastStat = getStat(subject);
+        waslocked = false;
+      }
+    }
+  }
   
+  /**
+   * Make a watcher for a particular file. If the file doesn't exist, the
+   * watcher will watch for its creation (and indicate a change of state) 
+   * For locked files, the removal of a lock constitutes a change of 
+   * state if the file was modified.
+   * 
+   * @param subject
+   */
   
   public FileWatcher(File subject) {
     // TODO Auto-generated constructor stub
     this.subject = subject;
-    check();
+    setState();
   }
+  /**
+   * Test for change in file state. Only indicates a change 
+   * after any lock on a file has been released.
+   * @return true if file has been modified.
+   */
   public boolean hasChanged() {
-    return check();
+    boolean res = check();
+    clearLock();
+    return res;
+  }
+  /**
+   * passes lock back to caller if hasChanged returned true.
+   * @return
+   */
+  public Lock getChangedState() {
+    boolean res = check();
+    if (res)
+      return subjectLock;
+    else {
+      clearLock();
+      return null;
+    }
   }
 }