1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.cache.decorators;
17
18 import java.lang.ref.ReferenceQueue;
19 import java.lang.ref.SoftReference;
20 import java.util.Deque;
21 import java.util.LinkedList;
22 import java.util.concurrent.locks.ReentrantLock;
23
24 import org.apache.ibatis.cache.Cache;
25
26
27
28
29
30
31
32
33 public class SoftCache implements Cache {
34 private final Deque<Object> hardLinksToAvoidGarbageCollection;
35 private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
36 private final Cache delegate;
37 private int numberOfHardLinks;
38 private final ReentrantLock lock = new ReentrantLock();
39
40 public SoftCache(Cache delegate) {
41 this.delegate = delegate;
42 this.numberOfHardLinks = 256;
43 this.hardLinksToAvoidGarbageCollection = new LinkedList<>();
44 this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();
45 }
46
47 @Override
48 public String getId() {
49 return delegate.getId();
50 }
51
52 @Override
53 public int getSize() {
54 removeGarbageCollectedItems();
55 return delegate.getSize();
56 }
57
58 public void setSize(int size) {
59 this.numberOfHardLinks = size;
60 }
61
62 @Override
63 public void putObject(Object key, Object value) {
64 removeGarbageCollectedItems();
65 delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries));
66 }
67
68 @Override
69 public Object getObject(Object key) {
70 Object result = null;
71 @SuppressWarnings("unchecked")
72 SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key);
73 if (softReference != null) {
74 result = softReference.get();
75 if (result == null) {
76 delegate.removeObject(key);
77 } else {
78
79 lock.lock();
80 try {
81 hardLinksToAvoidGarbageCollection.addFirst(result);
82 if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
83 hardLinksToAvoidGarbageCollection.removeLast();
84 }
85 } finally {
86 lock.unlock();
87 }
88 }
89 }
90 return result;
91 }
92
93 @Override
94 public Object removeObject(Object key) {
95 removeGarbageCollectedItems();
96 @SuppressWarnings("unchecked")
97 SoftReference<Object> softReference = (SoftReference<Object>) delegate.removeObject(key);
98 return softReference == null ? null : softReference.get();
99 }
100
101 @Override
102 public void clear() {
103 lock.lock();
104 try {
105 hardLinksToAvoidGarbageCollection.clear();
106 } finally {
107 lock.unlock();
108 }
109 removeGarbageCollectedItems();
110 delegate.clear();
111 }
112
113 private void removeGarbageCollectedItems() {
114 SoftEntry sv;
115 while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) {
116 delegate.removeObject(sv.key);
117 }
118 }
119
120 private static class SoftEntry extends SoftReference<Object> {
121 private final Object key;
122
123 SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {
124 super(value, garbageCollectionQueue);
125 this.key = key;
126 }
127 }
128
129 }