1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.util; |
7 | |
8 | import java.util.ArrayList; |
9 | |
10 | /** |
11 | * An alternative cache implementation. This implementation uses two caches: a |
12 | * LRU cache and a FIFO cache. Entries are first kept in the FIFO cache, and if |
13 | * referenced again then marked in a hash set. If referenced again, they are |
14 | * moved to the LRU cache. Stream pages are never added to the LRU cache. It is |
15 | * supposed to be more or less scan resistant, and it doesn't cache large rows |
16 | * in the LRU cache. |
17 | */ |
18 | public class CacheTQ implements Cache { |
19 | |
20 | static final String TYPE_NAME = "TQ"; |
21 | |
22 | private final Cache lru; |
23 | private final Cache fifo; |
24 | private final SmallLRUCache<Integer, Object> recentlyUsed = |
25 | SmallLRUCache.newInstance(1024); |
26 | private int lastUsed = -1; |
27 | |
28 | private int maxMemory; |
29 | |
30 | CacheTQ(CacheWriter writer, int maxMemoryKb) { |
31 | this.maxMemory = maxMemoryKb; |
32 | lru = new CacheLRU(writer, (int) (maxMemoryKb * 0.8), false); |
33 | fifo = new CacheLRU(writer, (int) (maxMemoryKb * 0.2), true); |
34 | setMaxMemory(4 * maxMemoryKb); |
35 | } |
36 | |
37 | @Override |
38 | public void clear() { |
39 | lru.clear(); |
40 | fifo.clear(); |
41 | recentlyUsed.clear(); |
42 | lastUsed = -1; |
43 | } |
44 | |
45 | @Override |
46 | public CacheObject find(int pos) { |
47 | CacheObject r = lru.find(pos); |
48 | if (r == null) { |
49 | r = fifo.find(pos); |
50 | } |
51 | return r; |
52 | } |
53 | |
54 | @Override |
55 | public CacheObject get(int pos) { |
56 | CacheObject r = lru.find(pos); |
57 | if (r != null) { |
58 | return r; |
59 | } |
60 | r = fifo.find(pos); |
61 | if (r != null && !r.isStream()) { |
62 | if (recentlyUsed.get(pos) != null) { |
63 | if (lastUsed != pos) { |
64 | fifo.remove(pos); |
65 | lru.put(r); |
66 | } |
67 | } else { |
68 | recentlyUsed.put(pos, this); |
69 | } |
70 | lastUsed = pos; |
71 | } |
72 | return r; |
73 | } |
74 | |
75 | @Override |
76 | public ArrayList<CacheObject> getAllChanged() { |
77 | ArrayList<CacheObject> changed = New.arrayList(); |
78 | changed.addAll(lru.getAllChanged()); |
79 | changed.addAll(fifo.getAllChanged()); |
80 | return changed; |
81 | } |
82 | |
83 | @Override |
84 | public int getMaxMemory() { |
85 | return maxMemory; |
86 | } |
87 | |
88 | @Override |
89 | public int getMemory() { |
90 | return lru.getMemory() + fifo.getMemory(); |
91 | } |
92 | |
93 | @Override |
94 | public void put(CacheObject r) { |
95 | if (r.isStream()) { |
96 | fifo.put(r); |
97 | } else if (recentlyUsed.get(r.getPos()) != null) { |
98 | lru.put(r); |
99 | } else { |
100 | fifo.put(r); |
101 | lastUsed = r.getPos(); |
102 | } |
103 | } |
104 | |
105 | @Override |
106 | public boolean remove(int pos) { |
107 | boolean result = lru.remove(pos); |
108 | if (!result) { |
109 | result = fifo.remove(pos); |
110 | } |
111 | recentlyUsed.remove(pos); |
112 | return result; |
113 | } |
114 | |
115 | @Override |
116 | public void setMaxMemory(int maxMemoryKb) { |
117 | this.maxMemory = maxMemoryKb; |
118 | lru.setMaxMemory((int) (maxMemoryKb * 0.8)); |
119 | fifo.setMaxMemory((int) (maxMemoryKb * 0.2)); |
120 | recentlyUsed.setMaxSize(4 * maxMemoryKb); |
121 | } |
122 | |
123 | @Override |
124 | public CacheObject update(int pos, CacheObject record) { |
125 | if (lru.find(pos) != null) { |
126 | return lru.update(pos, record); |
127 | } |
128 | return fifo.update(pos, record); |
129 | } |
130 | |
131 | } |