1 | package org.mapdb;
|
---|
2 |
|
---|
3 | import java.util.concurrent.locks.ReentrantLock;
|
---|
4 |
|
---|
5 | /**
|
---|
6 | * Least Recently Used cache.
|
---|
7 | * If cache is full it removes less used items to make a space
|
---|
8 | */
|
---|
9 | public class CacheLRU extends EngineWrapper {
|
---|
10 |
|
---|
11 |
|
---|
12 | protected LongMap<Object> cache;
|
---|
13 |
|
---|
14 | protected final ReentrantLock[] locks = Utils.newLocks(32);
|
---|
15 |
|
---|
16 |
|
---|
17 | public CacheLRU(Engine engine, int cacheSize) {
|
---|
18 | this(engine, new LongConcurrentLRUMap<Object>(cacheSize, (int) (cacheSize*0.8)));
|
---|
19 | }
|
---|
20 |
|
---|
21 | public CacheLRU(Engine engine, LongMap<Object> cache){
|
---|
22 | super(engine);
|
---|
23 | this.cache = cache;
|
---|
24 | }
|
---|
25 |
|
---|
26 | @Override
|
---|
27 | public <A> long put(A value, Serializer<A> serializer) {
|
---|
28 | long recid = super.put(value, serializer);
|
---|
29 | try{
|
---|
30 | Utils.lock(locks,recid);
|
---|
31 | checkClosed(cache).put(recid, value);
|
---|
32 | }finally {
|
---|
33 | Utils.unlock(locks,recid);
|
---|
34 | }
|
---|
35 | return recid;
|
---|
36 | }
|
---|
37 |
|
---|
38 | @SuppressWarnings("unchecked")
|
---|
39 | @Override
|
---|
40 | public <A> A get(long recid, Serializer<A> serializer) {
|
---|
41 | Object ret = cache.get(recid);
|
---|
42 | if(ret!=null) return (A) ret;
|
---|
43 | try{
|
---|
44 | Utils.lock(locks,recid);
|
---|
45 | ret = super.get(recid, serializer);
|
---|
46 | if(ret!=null) checkClosed(cache).put(recid, ret);
|
---|
47 | return (A) ret;
|
---|
48 | }finally {
|
---|
49 | Utils.unlock(locks,recid);
|
---|
50 | }
|
---|
51 | }
|
---|
52 |
|
---|
53 | @Override
|
---|
54 | public <A> void update(long recid, A value, Serializer<A> serializer) {
|
---|
55 | try{
|
---|
56 | Utils.lock(locks,recid);
|
---|
57 | checkClosed(cache).put(recid, value);
|
---|
58 | super.update(recid, value, serializer);
|
---|
59 | }finally {
|
---|
60 | Utils.unlock(locks,recid);
|
---|
61 | }
|
---|
62 | }
|
---|
63 |
|
---|
64 | @Override
|
---|
65 | public <A> void delete(long recid, Serializer<A> serializer){
|
---|
66 | try{
|
---|
67 | Utils.lock(locks,recid);
|
---|
68 | checkClosed(cache).remove(recid);
|
---|
69 | super.delete(recid,serializer);
|
---|
70 | }finally {
|
---|
71 | Utils.unlock(locks,recid);
|
---|
72 | }
|
---|
73 | }
|
---|
74 |
|
---|
75 | @Override
|
---|
76 | public <A> boolean compareAndSwap(long recid, A expectedOldValue, A newValue, Serializer<A> serializer) {
|
---|
77 | try{
|
---|
78 | Utils.lock(locks,recid);
|
---|
79 | Engine engine = getWrappedEngine();
|
---|
80 | LongMap<Object> cache2 = checkClosed(cache);
|
---|
81 | Object oldValue = cache.get(recid);
|
---|
82 | if(oldValue == expectedOldValue || oldValue.equals(expectedOldValue)){
|
---|
83 | //found matching entry in cache, so just update and return true
|
---|
84 | cache2.put(recid, newValue);
|
---|
85 | engine.update(recid, newValue, serializer);
|
---|
86 | return true;
|
---|
87 | }else{
|
---|
88 | boolean ret = engine.compareAndSwap(recid, expectedOldValue, newValue, serializer);
|
---|
89 | if(ret) cache2.put(recid, newValue);
|
---|
90 | return ret;
|
---|
91 | }
|
---|
92 | }finally {
|
---|
93 | Utils.unlock(locks,recid);
|
---|
94 | }
|
---|
95 | }
|
---|
96 |
|
---|
97 | @SuppressWarnings("rawtypes")
|
---|
98 | @Override
|
---|
99 | public void close() {
|
---|
100 | Object cache2 = cache;
|
---|
101 | if(cache2 instanceof LongConcurrentLRUMap)
|
---|
102 | ((LongConcurrentLRUMap)cache2).destroy();
|
---|
103 | cache = null;
|
---|
104 | super.close();
|
---|
105 | }
|
---|
106 |
|
---|
107 | @Override
|
---|
108 | public void rollback() {
|
---|
109 | //TODO locking here?
|
---|
110 | checkClosed(cache).clear();
|
---|
111 | super.rollback();
|
---|
112 | }
|
---|
113 | }
|
---|