]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRUObject.java
Merge commit '25b6c25959c1fb3c60bb41cd0e1f0808e7fc3769'
[simantics/platform.git] / bundles / org.simantics.acorn / src / org / simantics / acorn / lru / LRUObject.java
1 package org.simantics.acorn.lru;
2
3 import java.io.IOException;
4 import java.nio.file.Path;
5 import java.util.concurrent.Semaphore;
6 import java.util.concurrent.TimeUnit;
7
8 import org.simantics.acorn.FileIO;
9 import org.simantics.acorn.Persistable;
10 import org.simantics.utils.datastructures.Pair;
11
12 public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapValue>> implements Persistable {
13         
14         public static boolean VERIFY = true;
15         
16         // Final stuff
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;
21         
22         // Mutable stuff
23         protected long accessTime = AccessTime.getInstance().getAccessTime();
24         private int offset;
25         private int length;
26         private boolean resident = true;
27         private boolean dirty = true;
28         private boolean forceResident = false;
29         
30         // DEBUG
31 //      private boolean isForceResidentSetAfterLastGet = false;
32         
33         private Path readDirectory;
34
35         private Thread mutexOwner;
36
37         // for loading
38         public LRUObject(LRU<MapKey, MapValue> LRU, MapKey key, Path readDirectory, String fileName, int offset, int length, boolean dirty, boolean resident) {
39                 this.LRU = LRU;
40                 this.key = key;
41                 this.fileName = fileName;
42                 this.offset = offset;
43                 this.length = length;
44                 this.readDirectory = readDirectory;
45                 this.dirty = dirty;
46                 this.resident = resident;
47         }
48
49         // for creating
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);
52         }
53
54         /*
55          * Public interface
56          */
57         public MapKey getKey() {
58                 // This can be called without mutex
59                 return key;
60         }
61         
62         public void acquireMutex() {
63                 
64                 try {
65
66                         while(!mutex.tryAcquire(3, TimeUnit.SECONDS)) {
67                                 System.err.println("Mutex is taking a long time to acquire - owner is " + mutexOwner);
68                         }
69                         
70                         if(VERIFY)
71                                 mutexOwner = Thread.currentThread();
72
73                 } catch (InterruptedException e) {
74                         throw new IllegalStateException(e);
75                 }
76         }
77         
78         public boolean tryAcquireMutex() {
79                 return mutex.tryAcquire();
80         }
81         
82         public void releaseMutex() {
83                 mutex.release();
84         }
85
86         @Override
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);
95         }
96         
97         public int makeResident() {
98                 if(VERIFY) verifyAccess();
99                 return LRU.makeResident(this, false);
100         }
101
102         public int makeResident(boolean keepResident) {
103                 if(VERIFY) verifyAccess();
104                 return LRU.makeResident(this, true);
105         }
106
107         /*
108          * Package implementation details
109          */
110
111         abstract void release();
112         abstract String getExtension();
113         
114         String getStateKey() {
115                 String result = getKey().toString() + "#" + getDirectory().getFileName() + "#" + getOffset() + "#" + getLength(); 
116                 if(offset == -1)
117                     throw new IllegalStateException(result);
118                 return result; 
119         }
120
121         long getLastAccessTime() {
122                 if(VERIFY) verifyAccess();
123                 return accessTime;
124         }
125         
126         void accessed() {
127                 if(VERIFY) verifyAccess();
128                 accessTime = AccessTime.getInstance().getAccessTime();
129         }
130         
131         boolean persist() {
132                 if(VERIFY) verifyAccess();
133                 if(LRU.persist(this)) {
134                         readDirectory = LRU.getDirectory();
135                         return true;
136                 } else {
137                         return false;
138                 }
139         }
140         
141         void setForceResident(boolean value) {
142         if(VERIFY) verifyAccess();
143         forceResident = value;
144 //        isForceResidentSetAfterLastGet = true;
145         }
146         
147         boolean canBePersisted() {
148                 if(VERIFY) verifyAccess();
149 //              isForceResidentSetAfterLastGet = false;
150                 return !forceResident;
151         }
152         
153         boolean isDirty() {
154                 if(VERIFY) verifyAccess();
155                 return dirty;
156         }
157         
158         boolean isResident() {
159                 if(VERIFY) verifyAccess();
160                 return resident;
161         }
162         
163         String getFileName() {
164                 if(VERIFY) verifyAccess();
165                 return fileName;
166         }
167
168         void setResident(boolean value) {
169                 if(VERIFY) verifyAccess();
170                 resident = value;
171         }
172         
173         void setDirty(boolean value) {
174                 if(VERIFY) verifyAccess();
175                 dirty = value;
176         }
177         
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());
184         }
185         
186         /*
187          * Protected implementation details
188          */
189
190         abstract protected boolean overwrite();
191         
192         abstract protected Pair<byte[],Integer> toBytes();
193         
194         protected void setDirty() {
195                 if(VERIFY) verifyAccess();
196                 dirty = true;
197         }
198         
199         protected void verifyAccess() {
200                 assert(mutex.availablePermits() == 0);
201         }
202
203         protected synchronized void cancelForceResident() {
204                 setForceResident(false);
205         }
206         
207         /*
208          * Private implementation details
209          */
210         
211         private int getOffset() {
212                 if(VERIFY) verifyAccess();
213                 return offset;
214         }
215         
216         private int getLength() {
217                 if(VERIFY) verifyAccess();
218                 return length;
219         }
220         
221         private void setPosition(int offset, int length) {
222                 if(VERIFY) verifyAccess();
223                 if(offset == -1)
224                     throw new IllegalStateException();
225                 this.offset = offset;
226                 this.length = length;
227                 if(overwrite() && offset > 0)
228                         throw new IllegalStateException();
229         }
230         
231         private Path getDirectory() {
232                 if(VERIFY) verifyAccess();
233                 return readDirectory;
234         }
235         
236 }