Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

199
LINES

< > BotCompany Repo | #1029369 // BufferedDiskIntMemory

JavaX fragment (include) [tags: use-pretranspiled]

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  
}

Author comment

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]