]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRUObject.java
Sharing org.simantics.acorn for everyone to use
[simantics/platform.git] / bundles / org.simantics.acorn / src / org / simantics / acorn / lru / LRUObject.java
diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRUObject.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRUObject.java
new file mode 100644 (file)
index 0000000..1079bf5
--- /dev/null
@@ -0,0 +1,236 @@
+package org.simantics.acorn.lru;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.simantics.acorn.FileIO;
+import org.simantics.acorn.Persistable;
+import org.simantics.utils.datastructures.Pair;
+
+public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapValue>> implements Persistable {
+       
+       public static boolean VERIFY = true;
+       
+       // Final stuff
+       final protected LRU<MapKey, MapValue> LRU;
+       final private Semaphore mutex = new Semaphore(1);
+       final private MapKey key;
+       final private String fileName;
+       
+       // Mutable stuff
+       protected long accessTime = AccessTime.getInstance().getAccessTime();
+       private int offset;
+       private int length;
+       private boolean resident = true;
+       private boolean dirty = true;
+       private boolean forceResident = false;
+       
+       // DEBUG
+//     private boolean isForceResidentSetAfterLastGet = false;
+       
+       private Path readDirectory;
+
+       private Thread mutexOwner;
+
+       // for loading
+       public LRUObject(LRU<MapKey, MapValue> LRU, MapKey key, Path readDirectory, String fileName, int offset, int length, boolean dirty, boolean resident) {
+               this.LRU = LRU;
+               this.key = key;
+               this.fileName = fileName;
+               this.offset = offset;
+               this.length = length;
+               this.readDirectory = readDirectory;
+               this.dirty = dirty;
+               this.resident = resident;
+       }
+
+       // for creating
+       public LRUObject(LRU<MapKey, MapValue> LRU, MapKey key, Path readDirectory, String fileName, boolean dirty, boolean resident) {
+               this(LRU, key, readDirectory, fileName, -1, -1, dirty, resident);
+       }
+
+       /*
+        * Public interface
+        */
+       public MapKey getKey() {
+               // This can be called without mutex
+               return key;
+       }
+       
+       public void acquireMutex() {
+               
+               try {
+
+                       while(!mutex.tryAcquire(3, TimeUnit.SECONDS)) {
+                               System.err.println("Mutex is taking a long time to acquire - owner is " + mutexOwner);
+                       }
+                       
+                       if(VERIFY)
+                               mutexOwner = Thread.currentThread();
+
+               } catch (InterruptedException e) {
+                       throw new IllegalStateException(e);
+               }
+       }
+       
+       public boolean tryAcquireMutex() {
+               return mutex.tryAcquire();
+       }
+       
+       public void releaseMutex() {
+               mutex.release();
+       }
+
+       @Override
+       public void toFile(Path bytes) throws IOException {
+               if(VERIFY) verifyAccess();
+               Pair<byte[],Integer> pair = toBytes();
+               byte[] data = pair.first;
+               int length = pair.second;
+               FileIO fio = FileIO.get(bytes);
+               int offset = fio.saveBytes(data, length, overwrite());
+               setPosition(offset, length);
+       }
+       
+       public int makeResident() {
+               if(VERIFY) verifyAccess();
+               return LRU.makeResident(this, false);
+       }
+
+       public int makeResident(boolean keepResident) {
+               if(VERIFY) verifyAccess();
+               return LRU.makeResident(this, true);
+       }
+
+       /*
+        * Package implementation details
+        */
+
+       abstract void release();
+       abstract String getExtension();
+       
+       String getStateKey() {
+               String result = getKey().toString() + "#" + getDirectory().getFileName() + "#" + getOffset() + "#" + getLength(); 
+               if(offset == -1)
+                   throw new IllegalStateException(result);
+               return result; 
+       }
+
+       long getLastAccessTime() {
+               if(VERIFY) verifyAccess();
+               return accessTime;
+       }
+       
+       void accessed() {
+               if(VERIFY) verifyAccess();
+               accessTime = AccessTime.getInstance().getAccessTime();
+       }
+       
+       boolean persist() {
+               if(VERIFY) verifyAccess();
+               if(LRU.persist(this)) {
+                       readDirectory = LRU.getDirectory();
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+       
+       void setForceResident(boolean value) {
+        if(VERIFY) verifyAccess();
+        forceResident = value;
+//        isForceResidentSetAfterLastGet = true;
+       }
+       
+       boolean canBePersisted() {
+               if(VERIFY) verifyAccess();
+//             isForceResidentSetAfterLastGet = false;
+               return !forceResident;
+       }
+       
+       boolean isDirty() {
+               if(VERIFY) verifyAccess();
+               return dirty;
+       }
+       
+       boolean isResident() {
+               if(VERIFY) verifyAccess();
+               return resident;
+       }
+       
+       String getFileName() {
+               if(VERIFY) verifyAccess();
+               return fileName;
+       }
+
+       void setResident(boolean value) {
+               if(VERIFY) verifyAccess();
+               resident = value;
+       }
+       
+       void setDirty(boolean value) {
+               if(VERIFY) verifyAccess();
+               dirty = value;
+       }
+       
+       byte[] readFile() throws IOException {
+               if(VERIFY) verifyAccess();
+               Path dir = getDirectory();
+               Path f = dir.resolve(getFileName());
+               FileIO fio = FileIO.get(f);
+               return fio.readBytes(getOffset(), getLength());
+       }
+       
+       /*
+        * Protected implementation details
+        */
+
+       abstract protected boolean overwrite();
+       
+       abstract protected Pair<byte[],Integer> toBytes();
+       
+       protected void setDirty() {
+               if(VERIFY) verifyAccess();
+               dirty = true;
+       }
+       
+       protected void verifyAccess() {
+               assert(mutex.availablePermits() == 0);
+       }
+
+       protected synchronized void cancelForceResident() {
+               setForceResident(false);
+       }
+       
+       /*
+        * Private implementation details
+        */
+       
+       private int getOffset() {
+               if(VERIFY) verifyAccess();
+               return offset;
+       }
+       
+       private int getLength() {
+               if(VERIFY) verifyAccess();
+               return length;
+       }
+       
+       private void setPosition(int offset, int length) {
+               if(VERIFY) verifyAccess();
+               if(offset == -1)
+                   throw new IllegalStateException();
+               this.offset = offset;
+               this.length = length;
+               if(overwrite() && offset > 0)
+                       throw new IllegalStateException();
+       }
+       
+       private Path getDirectory() {
+               if(VERIFY) verifyAccess();
+               return readDirectory;
+       }
+       
+}
\ No newline at end of file