Uses 11335K of libraries. Click here for Pure Java version (4680L/31K).
1 | !include once #1027304 // Eclipse Collections |
2 | |
3 | // read-only, so far. not thread-safe |
4 | final sclass BufferedDiskIntMemory implements IIntMemory, AutoCloseable { |
5 | File file; |
6 | long size; // file size in ints |
7 | RandomAccessFile raf; |
8 | bool bigEndian = true; |
9 | bool writable = true; |
10 | bool debug, verboseEvictions; |
11 | long cacheSize = 128*1024*1024; // in bytes |
12 | |
13 | // pageSize is in ints |
14 | // page indices are ints interpreted as unsigned |
15 | int pageShift, pageSize, maxCachedPages; |
16 | new IntObjectHashMap<CacheEntry> cache; |
17 | CacheEntry newestCacheEntry, oldestCacheEntry; |
18 | |
19 | // stats |
20 | int pageLoads, evictions; |
21 | |
22 | static int defaultPageSize = 4096; // in bytes |
23 | |
24 | sclass CacheEntry { |
25 | int page; |
26 | bool dirty; |
27 | int[] data; |
28 | CacheEntry newer, older; // MRU list |
29 | |
30 | toString { ret "Page " + page; } |
31 | } |
32 | |
33 | *() { |
34 | setPageSize(4096); |
35 | } |
36 | |
37 | void setPageSize(int pageSizeInBytes) { |
38 | clearCache(); |
39 | pageShift = 31-Int.numberOfLeadingZeros(pageSizeInBytes >> 2); |
40 | pageSize = 1 << pageShift; |
41 | updateMaxCachedPages(); |
42 | } |
43 | |
44 | void setMaxCachedBytes(long bytes) { |
45 | cacheSize = bytes; |
46 | updateMaxCachedPages(); |
47 | } |
48 | |
49 | // internal |
50 | void updateMaxCachedPages { |
51 | maxCachedPages = (int) (cacheSize >> (pageShift+2)); |
52 | } |
53 | |
54 | long maxCachedBytes() { |
55 | ret ((long) maxCachedPages) << (pageShift+2); |
56 | } |
57 | |
58 | long cachedBytes() { |
59 | ret ((long) cache.size()) << (pageShift+2); |
60 | } |
61 | |
62 | void clearCache { |
63 | flush(); |
64 | cache = new IntObjectHashMap; |
65 | newestCacheEntry = oldestCacheEntry = null; |
66 | } |
67 | |
68 | |
69 | *(File *file) { |
70 | this(file, false); |
71 | } |
72 | |
73 | *(File *file, bool *writable) { |
74 | this(); |
75 | size = fileSize(file)/4; |
76 | if (size > 0xFFFFFFFFL) fail("File too big"); |
77 | raf = newRandomAccessFile(file, writable ? "rw" : "r"); |
78 | } |
79 | |
80 | public void close { |
81 | flush(); |
82 | dispose raf; |
83 | } |
84 | |
85 | void flush { |
86 | for (CacheEntry e: cache.values()) |
87 | flushPage(e); |
88 | } |
89 | |
90 | public int get(int idx) { |
91 | rangeCheck(uintToLong(idx), size); |
92 | ret loadCell(idx).data[idx & (pageSize-1)]; |
93 | } |
94 | |
95 | CacheEntry loadCell(int idx) { |
96 | int page = toInt(uintToLong(idx) >> pageShift); |
97 | CacheEntry e = cache.get(page); |
98 | if (e == null) { |
99 | if (debug) print("Accessing unloaded cell " + intToHex(idx)); |
100 | e = loadPage(page); |
101 | } else |
102 | touchPage(e); |
103 | ret e; |
104 | } |
105 | |
106 | void touchPage(CacheEntry e) { |
107 | if (e == newestCacheEntry) ret; |
108 | if (debug) print("Touching page " + e.page + ". Older=" + e.older + ", newer=" + e.newer + ". Oldest=" + oldestCacheEntry + ", newest=" + newestCacheEntry); |
109 | |
110 | // Take out of list |
111 | removeFromLinkedList(e); |
112 | |
113 | // re-insert at top |
114 | e.newer = null; // nobody newer than us |
115 | e.older = newestCacheEntry; // point to previous newest |
116 | newestCacheEntry.newer = e; // point previous newest to us |
117 | newestCacheEntry = e; // make us the newest |
118 | |
119 | if (debug) print("Touched page " + e.page + ". Older=" + e.older + ", newer=" + e.newer + ". Oldest=" + oldestCacheEntry + ", newest=" + newestCacheEntry); |
120 | } |
121 | |
122 | void removeFromLinkedList(CacheEntry e) { |
123 | if (e.older != null) |
124 | e.older.newer = e.newer; // There is an older page, point it to who was on top of us |
125 | else |
126 | oldestCacheEntry = e.newer; // We were the oldest, point it to who was on top uf os |
127 | if (e.newer != null) |
128 | e.newer.older = e.older; // Point who was on top of us to who was behind us (or no one) |
129 | else |
130 | newestCacheEntry = e.older; |
131 | } |
132 | |
133 | bool cacheFull() { ret cache.size() >= maxCachedPages; } |
134 | |
135 | void evictAPage { |
136 | ++evictions; |
137 | CacheEntry e = oldestCacheEntry; |
138 | flushPage(e); |
139 | if (debug || verboseEvictions) print("Evicting page " + e.page); |
140 | cache.remove(e.page); |
141 | removeFromLinkedList(e); |
142 | } |
143 | |
144 | void flushPage(CacheEntry e) ctex { |
145 | if (!e.dirty) ret; |
146 | if (debug) print("Saving page " + e.page); |
147 | raf.seek(uintToLong(e.page) << (pageShift+2)); |
148 | byte[] buf = bigEndian ? intArrayToBytes(e.data) : intArrayToBytes_littleEndian(e.data); |
149 | raf.write(buf); |
150 | e.dirty = false; |
151 | } |
152 | |
153 | CacheEntry loadPage(int page) ctex { |
154 | ++pageLoads; |
155 | if (cacheFull()) evictAPage(); |
156 | if (debug) print("Loading page " + page); |
157 | raf.seek(((long) page) << (pageShift+2)); |
158 | byte[] buf = new[pageSize*4]; |
159 | raf.read(buf); |
160 | new CacheEntry e; |
161 | e.page = page; |
162 | e.data = bigEndian ? intArrayFromBytes(buf) : intArrayFromBytes_littleEndian(buf); |
163 | cache.put(page, e); |
164 | |
165 | // put e in front of MRU list |
166 | e.older = newestCacheEntry; // point to previous top |
167 | if (newestCacheEntry != null) // list is not empty, update "newer" pointer of current top |
168 | newestCacheEntry.newer = e; |
169 | else oldestCacheEntry = e; // otherwise, we are also the oldest entry |
170 | newestCacheEntry = e; // we are new top |
171 | |
172 | if (debug) print("Loaded page " + e.page + ". Older=" + e.older + ", newer=" + e.newer + ". Oldest=" + oldestCacheEntry + ", newest=" + newestCacheEntry); |
173 | ret e; |
174 | } |
175 | |
176 | public void set(int idx, int val) { |
177 | checkWritable(); |
178 | rangeCheck(idx, size); |
179 | CacheEntry e = loadCell(idx); |
180 | e.data[idx & (pageSize-1)] = val; |
181 | e.dirty = true; |
182 | } |
183 | |
184 | void checkWritable { |
185 | if (!writable) fail("read-only"); |
186 | } |
187 | |
188 | public long size() { |
189 | ret size; |
190 | } |
191 | |
192 | double cacheFullPercentage() { |
193 | ret percentRatio(cache.size(), maxCachedPages); |
194 | } |
195 | |
196 | public void ensureSize(int size) { |
197 | this.size = max(this.size, size); |
198 | } |
199 | } |
Began life as a copy of #1029250
download show line numbers debug dex old transpilations
Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1029369 |
Snippet name: | BufferedDiskIntMemory |
Eternal ID of this version: | #1029369/52 |
Text MD5: | acc2b10492ffa350ba9487daafc51c30 |
Transpilation MD5: | 0b43d23519acb22c33603a56479c918a |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2020-08-07 14:12:13 |
Source code size: | 5630 bytes / 199 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 353 / 791 |
Version history: | 51 change(s) |
Referenced in: | [show references] |