1 package org.simantics.acorn.lru;
3 import java.io.IOException;
4 import java.nio.file.Path;
5 import java.util.concurrent.Semaphore;
6 import java.util.concurrent.TimeUnit;
8 import org.simantics.acorn.FileIO;
9 import org.simantics.acorn.Persistable;
10 import org.simantics.utils.datastructures.Pair;
12 public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapValue>> implements Persistable {
14 public static boolean VERIFY = true;
17 final protected LRU<MapKey, MapValue> LRU;
18 final private Semaphore mutex = new Semaphore(1);
19 final private MapKey key;
20 final private String fileName;
23 protected long accessTime = AccessTime.getInstance().getAccessTime();
26 private boolean resident = true;
27 private boolean dirty = true;
28 private boolean forceResident = false;
31 // private boolean isForceResidentSetAfterLastGet = false;
33 private Path readDirectory;
35 private Thread mutexOwner;
38 public LRUObject(LRU<MapKey, MapValue> LRU, MapKey key, Path readDirectory, String fileName, int offset, int length, boolean dirty, boolean resident) {
41 this.fileName = fileName;
44 this.readDirectory = readDirectory;
46 this.resident = resident;
50 public LRUObject(LRU<MapKey, MapValue> LRU, MapKey key, Path readDirectory, String fileName, boolean dirty, boolean resident) {
51 this(LRU, key, readDirectory, fileName, -1, -1, dirty, resident);
57 public MapKey getKey() {
58 // This can be called without mutex
62 public void acquireMutex() {
66 while(!mutex.tryAcquire(3, TimeUnit.SECONDS)) {
67 System.err.println("Mutex is taking a long time to acquire - owner is " + mutexOwner);
71 mutexOwner = Thread.currentThread();
73 } catch (InterruptedException e) {
74 throw new IllegalStateException(e);
78 public boolean tryAcquireMutex() {
79 return mutex.tryAcquire();
82 public void releaseMutex() {
87 public void toFile(Path bytes) throws IOException {
88 if(VERIFY) verifyAccess();
89 Pair<byte[],Integer> pair = toBytes();
90 byte[] data = pair.first;
91 int length = pair.second;
92 FileIO fio = FileIO.get(bytes);
93 int offset = fio.saveBytes(data, length, overwrite());
94 setPosition(offset, length);
97 public int makeResident() {
98 if(VERIFY) verifyAccess();
99 return LRU.makeResident(this, false);
102 public int makeResident(boolean keepResident) {
103 if(VERIFY) verifyAccess();
104 return LRU.makeResident(this, true);
108 * Package implementation details
111 abstract void release();
112 abstract String getExtension();
114 String getStateKey() {
115 String result = getKey().toString() + "#" + getDirectory().getFileName() + "#" + getOffset() + "#" + getLength();
117 throw new IllegalStateException(result);
121 long getLastAccessTime() {
122 if(VERIFY) verifyAccess();
127 if(VERIFY) verifyAccess();
128 accessTime = AccessTime.getInstance().getAccessTime();
132 if(VERIFY) verifyAccess();
133 if(LRU.persist(this)) {
134 readDirectory = LRU.getDirectory();
141 void setForceResident(boolean value) {
142 if(VERIFY) verifyAccess();
143 forceResident = value;
144 // isForceResidentSetAfterLastGet = true;
147 boolean canBePersisted() {
148 if(VERIFY) verifyAccess();
149 // isForceResidentSetAfterLastGet = false;
150 return !forceResident;
154 if(VERIFY) verifyAccess();
158 boolean isResident() {
159 if(VERIFY) verifyAccess();
163 String getFileName() {
164 if(VERIFY) verifyAccess();
168 void setResident(boolean value) {
169 if(VERIFY) verifyAccess();
173 void setDirty(boolean value) {
174 if(VERIFY) verifyAccess();
178 byte[] readFile() throws IOException {
179 if(VERIFY) verifyAccess();
180 Path dir = getDirectory();
181 Path f = dir.resolve(getFileName());
182 FileIO fio = FileIO.get(f);
183 return fio.readBytes(getOffset(), getLength());
187 * Protected implementation details
190 abstract protected boolean overwrite();
192 abstract protected Pair<byte[],Integer> toBytes();
194 protected void setDirty() {
195 if(VERIFY) verifyAccess();
199 protected void verifyAccess() {
200 assert(mutex.availablePermits() == 0);
203 protected synchronized void cancelForceResident() {
204 setForceResident(false);
208 * Private implementation details
211 private int getOffset() {
212 if(VERIFY) verifyAccess();
216 private int getLength() {
217 if(VERIFY) verifyAccess();
221 private void setPosition(int offset, int length) {
222 if(VERIFY) verifyAccess();
224 throw new IllegalStateException();
225 this.offset = offset;
226 this.length = length;
227 if(overwrite() && offset > 0)
228 throw new IllegalStateException();
231 private Path getDirectory() {
232 if(VERIFY) verifyAccess();
233 return readDirectory;