]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.acorn/src/org/simantics/acorn/lru/LRUObject.java
Merge "Upgrade pdfbox to 2.0.3 and fastutil to 7.0.13."
[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.acorn.exception.AcornAccessVerificationException;
11 import org.simantics.acorn.exception.IllegalAcornStateException;
12 import org.simantics.utils.datastructures.Pair;
13
14 public abstract class LRUObject<MapKey, MapValue extends LRUObject<MapKey, MapValue>> implements Persistable {
15         
16         public static boolean VERIFY = true;
17         
18         // Final stuff
19         final protected LRU<MapKey, MapValue> LRU;
20         final private Semaphore mutex = new Semaphore(1);
21         final private MapKey key;
22         final private String fileName;
23         
24         // Mutable stuff
25         protected long accessTime = AccessTime.getInstance().getAccessTime();
26         private int offset;
27         private int length;
28         private boolean resident = true;
29         private boolean dirty = true;
30         private boolean forceResident = false;
31         
32         // DEBUG
33 //      private boolean isForceResidentSetAfterLastGet = false;
34         
35         private Path readDirectory;
36
37         private Thread mutexOwner;
38
39         // for loading
40         public LRUObject(LRU<MapKey, MapValue> LRU, MapKey key, Path readDirectory, String fileName, int offset, int length, boolean dirty, boolean resident) {
41                 this.LRU = LRU;
42                 this.key = key;
43                 this.fileName = fileName;
44                 this.offset = offset;
45                 this.length = length;
46                 this.readDirectory = readDirectory;
47                 this.dirty = dirty;
48                 this.resident = resident;
49         }
50
51         // for creating
52         public LRUObject(LRU<MapKey, MapValue> LRU, MapKey key, Path readDirectory, String fileName, boolean dirty, boolean resident) {
53                 this(LRU, key, readDirectory, fileName, -1, -1, dirty, resident);
54         }
55
56         /*
57          * Public interface
58          */
59         public MapKey getKey() {
60                 // This can be called without mutex
61                 return key;
62         }
63         
64         public void acquireMutex() throws IllegalAcornStateException {
65                 try {
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 IllegalAcornStateException(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) {
89                     try {
90                 verifyAccess();
91             } catch (AcornAccessVerificationException e) {
92                 throw new IOException("Exception occured during toFile for file " + fileName, e);
93             }
94                 }
95         try {
96             Pair<byte[], Integer> pair = toBytes();
97             byte[] data = pair.first;
98             int length = pair.second;
99             FileIO fio = FileIO.get(bytes);
100             int offset = fio.saveBytes(data, length, overwrite());
101             setPosition(offset, length);
102         } catch (AcornAccessVerificationException | IllegalAcornStateException e) {
103             throw new IOException("Exception occured during toFile for file " + fileName, e);
104         }
105     }
106         
107         public int makeResident() throws AcornAccessVerificationException, IllegalAcornStateException {
108                 if(VERIFY) verifyAccess();
109                 return LRU.makeResident(this, false);
110         }
111
112         public int makeResident(boolean keepResident) throws AcornAccessVerificationException, IllegalAcornStateException {
113                 if(VERIFY) verifyAccess();
114                 return LRU.makeResident(this, true);
115         }
116
117         /*
118          * Package implementation details
119          */
120
121         abstract void release();
122         abstract String getExtension();
123         
124         String getStateKey() throws IllegalAcornStateException, AcornAccessVerificationException {
125                 String result = getKey().toString() + "#" + getDirectory().getFileName() + "#" + getOffset() + "#" + getLength(); 
126                 if(offset == -1)
127                     throw new IllegalAcornStateException(result);
128                 return result; 
129         }
130
131         long getLastAccessTime() throws AcornAccessVerificationException {
132                 if(VERIFY) verifyAccess();
133                 return accessTime;
134         }
135         
136         void accessed() throws AcornAccessVerificationException {
137                 if(VERIFY) verifyAccess();
138                 accessTime = AccessTime.getInstance().getAccessTime();
139         }
140         
141         boolean persist() throws AcornAccessVerificationException {
142                 if(VERIFY) verifyAccess();
143                 if(LRU.persist(this)) {
144                         readDirectory = LRU.getDirectory();
145                         return true;
146                 } else {
147                         return false;
148                 }
149         }
150         
151         void setForceResident(boolean value) throws AcornAccessVerificationException {
152         if(VERIFY) verifyAccess();
153         forceResident = value;
154 //        isForceResidentSetAfterLastGet = true;
155         }
156         
157         boolean canBePersisted() throws AcornAccessVerificationException {
158                 if(VERIFY) verifyAccess();
159 //              isForceResidentSetAfterLastGet = false;
160                 return !forceResident;
161         }
162         
163         boolean isDirty() throws AcornAccessVerificationException {
164                 if(VERIFY) verifyAccess();
165                 return dirty;
166         }
167         
168         boolean isResident() throws AcornAccessVerificationException {
169                 if(VERIFY) verifyAccess();
170                 return resident;
171         }
172         
173         String getFileName() throws AcornAccessVerificationException {
174                 if(VERIFY) verifyAccess();
175                 return fileName;
176         }
177
178         void setResident(boolean value) throws AcornAccessVerificationException {
179                 if(VERIFY) verifyAccess();
180                 resident = value;
181         }
182         
183         void setDirty(boolean value) throws AcornAccessVerificationException {
184                 if(VERIFY) verifyAccess();
185                 dirty = value;
186         }
187         
188         byte[] readFile() throws IOException, AcornAccessVerificationException {
189                 if(VERIFY) verifyAccess();
190                 Path dir = getDirectory();
191                 Path f = dir.resolve(getFileName());
192                 FileIO fio = FileIO.get(f);
193                 return fio.readBytes(getOffset(), getLength());
194         }
195         
196         /*
197          * Protected implementation details
198          */
199
200         abstract protected boolean overwrite();
201         
202         abstract protected Pair<byte[],Integer> toBytes() throws IllegalAcornStateException;
203         
204         protected void setDirty() throws AcornAccessVerificationException {
205                 if(VERIFY) verifyAccess();
206                 dirty = true;
207         }
208         
209         protected void verifyAccess() throws AcornAccessVerificationException {
210         if (mutex.availablePermits() != 0)
211             throw new AcornAccessVerificationException("fileName=" + fileName + " mutex has " + mutex.availablePermits() + " available permits, should be 0! Current mutexOwner is " + mutexOwner);
212         }
213
214         protected synchronized void cancelForceResident() throws AcornAccessVerificationException {
215                 setForceResident(false);
216         }
217         
218         /*
219          * Private implementation details
220          */
221         
222         private int getOffset() throws AcornAccessVerificationException {
223                 if(VERIFY) verifyAccess();
224                 return offset;
225         }
226         
227         private int getLength() throws AcornAccessVerificationException {
228                 if(VERIFY) verifyAccess();
229                 return length;
230         }
231         
232         private void setPosition(int offset, int length) throws AcornAccessVerificationException, IllegalAcornStateException {
233                 if(VERIFY) verifyAccess();
234                 if(offset == -1)
235                     throw new IllegalAcornStateException("offset == -1 for " + fileName + " in " + readDirectory.toAbsolutePath() + ", dirty=" + dirty + ", resident=" + resident + ", forceResident=" + forceResident);
236                 this.offset = offset;
237                 this.length = length;
238                 if(overwrite() && offset > 0)
239                     throw new IllegalAcornStateException("overwrite() == true &&  offset > 0 for " + fileName + " in " + readDirectory.toAbsolutePath() + ", dirty=" + dirty + ", resident=" + resident + ", forceResident=" + forceResident);
240         }
241         
242         private Path getDirectory() throws AcornAccessVerificationException {
243                 if(VERIFY) verifyAccess();
244                 return readDirectory;
245         }
246         
247 }