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