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