Skip to content

Package: LruCacheManager

LruCacheManager

nameinstructionbranchcomplexitylinemethod
LruCacheManager()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
LruCacheManager(Map)
M: 0 C: 36
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
add(Object, Object, URI)
M: 0 C: 23
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
clearInferredObjects()
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
close()
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
contains(Class, Object)
M: 0 C: 20
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
contains(Class, Object, URI)
M: 0 C: 21
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
evict(Class)
M: 0 C: 14
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
evict(Class, Object, URI)
M: 0 C: 23
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
evict(URI)
M: 0 C: 11
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
evictAll()
M: 0 C: 14
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
get(Class, Object, URI)
M: 0 C: 21
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 5
100%
M: 0 C: 1
100%
getCapacity()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getInferredClasses()
M: 2 C: 6
75%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
resolveCapacitySetting(Map)
M: 4 C: 27
87%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 2 C: 8
80%
M: 0 C: 1
100%
setInferredClasses(Set)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

Coverage

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.sessions.cache;
16:
17: import cz.cvut.kbss.jopa.model.JOPAPersistenceProperties;
18: import cz.cvut.kbss.jopa.sessions.CacheManager;
19: import cz.cvut.kbss.jopa.utils.ErrorUtils;
20:
21: import java.net.URI;
22: import java.util.Collections;
23: import java.util.Map;
24: import java.util.Objects;
25: import java.util.Set;
26: import java.util.concurrent.locks.Lock;
27: import java.util.concurrent.locks.ReadWriteLock;
28: import java.util.concurrent.locks.ReentrantReadWriteLock;
29: import java.util.function.Consumer;
30: import java.util.logging.Logger;
31:
32: /**
33: * This is a fixed-size second level cache implementation with LRU eviction policy.
34: * <p>
35: * When the capacity is reached, the least recently used entry is removed from the cache.
36: *
37: * @author kidney
38: */
39: public class LruCacheManager implements CacheManager {
40:
41: private static final Logger LOG = Logger.getLogger(LruCacheManager.class.getName());
42:
43: /**
44: * Default cache size limit in number of entries.
45: */
46: public static final int DEFAULT_CAPACITY = 512;
47:
48: private final int capacity;
49:
50: private final Lock readLock;
51: private final Lock writeLock;
52:
53: private LruEntityCache entityCache;
54:
55: private Set<Class<?>> inferredClasses;
56:
57: public LruCacheManager() {
58: this(Collections.emptyMap());
59: }
60:
61: public LruCacheManager(Map<String, String> properties) {
62: Objects.requireNonNull(properties);
63:• this.capacity = properties.containsKey(JOPAPersistenceProperties.LRU_CACHE_CAPACITY) ?
64: resolveCapacitySetting(properties) : DEFAULT_CAPACITY;
65: final ReadWriteLock rwLock = new ReentrantReadWriteLock();
66: this.readLock = rwLock.readLock();
67: this.writeLock = rwLock.writeLock();
68: this.entityCache = new LruEntityCache(capacity);
69: }
70:
71: private int resolveCapacitySetting(Map<String, String> properties) {
72: int capacitySetting = DEFAULT_CAPACITY;
73: try {
74: capacitySetting =
75: Integer.parseInt(properties.get(JOPAPersistenceProperties.LRU_CACHE_CAPACITY));
76:• if (capacitySetting <= 0) {
77: LOG.warning("Invalid LRU cache capacity value " + capacitySetting + ". Using default value.");
78: capacitySetting = DEFAULT_CAPACITY;
79: }
80: } catch (NumberFormatException e) {
81: LOG.severe("Unable to parse LRU cache capacity setting. Using default capacity " + DEFAULT_CAPACITY);
82: }
83: return capacitySetting;
84: }
85:
86: int getCapacity() {
87: return capacity;
88: }
89:
90: @Override
91: public void add(Object primaryKey, Object entity, URI context) {
92: Objects.requireNonNull(primaryKey, ErrorUtils.constructNPXMessage("primaryKey"));
93: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
94:
95: writeLock.lock();
96: try {
97: entityCache.put(primaryKey, entity, context);
98: } finally {
99: writeLock.unlock();
100: }
101: }
102:
103: @Override
104: public <T> T get(Class<T> cls, Object primaryKey, URI context) {
105:• if (cls == null || primaryKey == null) {
106: return null;
107: }
108: readLock.lock();
109: try {
110: return entityCache.get(cls, primaryKey, context);
111: } finally {
112: readLock.unlock();
113: }
114: }
115:
116: @Override
117: public void clearInferredObjects() {
118: writeLock.lock();
119: try {
120: getInferredClasses().forEach(this::evict);
121: } finally {
122: writeLock.unlock();
123: }
124: }
125:
126: private Set<Class<?>> getInferredClasses() {
127:• if (inferredClasses == null) {
128: return Collections.emptySet();
129: }
130: return inferredClasses;
131: }
132:
133: @Override
134: public void setInferredClasses(Set<Class<?>> inferredClasses) {
135: this.inferredClasses = inferredClasses;
136: }
137:
138: @Override
139: public void close() {
140: // No-op
141: }
142:
143: @Override
144: public boolean contains(Class<?> cls, Object primaryKey) {
145:• if (cls == null || primaryKey == null) {
146: return false;
147: }
148: readLock.lock();
149: try {
150: return entityCache.contains(cls, primaryKey);
151: } finally {
152: readLock.unlock();
153: }
154: }
155:
156: @Override
157: public boolean contains(Class<?> cls, Object primaryKey, URI context) {
158:• if (cls == null || primaryKey == null) {
159: return false;
160: }
161: readLock.lock();
162: try {
163: return entityCache.contains(cls, primaryKey, context);
164: } finally {
165: readLock.unlock();
166: }
167: }
168:
169: @Override
170: public void evict(Class<?> cls, Object primaryKey, URI context) {
171: Objects.requireNonNull(cls, ErrorUtils.constructNPXMessage("cls"));
172: Objects.requireNonNull(primaryKey, ErrorUtils.constructNPXMessage("primaryKey"));
173:
174: writeLock.lock();
175: try {
176: entityCache.evict(cls, primaryKey, context);
177: } finally {
178: writeLock.unlock();
179: }
180: }
181:
182: @Override
183: public void evict(Class<?> cls) {
184: Objects.requireNonNull(cls);
185:
186: writeLock.lock();
187: try {
188: entityCache.evict(cls);
189: } finally {
190: writeLock.unlock();
191: }
192: }
193:
194: @Override
195: public void evict(URI context) {
196: writeLock.lock();
197: try {
198: entityCache.evict(context);
199: } finally {
200: writeLock.unlock();
201: }
202: }
203:
204: @Override
205: public void evictAll() {
206: writeLock.lock();
207: try {
208: this.entityCache = new LruEntityCache(capacity);
209: } finally {
210: writeLock.unlock();
211: }
212: }
213:
214: static final class LruEntityCache extends EntityCache implements Consumer<LruCache.CacheNode> {
215:
216: private static final Object NULL_VALUE = null;
217:
218: private final LruCache cache;
219:
220: LruEntityCache(int capacity) {
221: this.cache = new LruCache(capacity, this);
222: }
223:
224: @Override
225: public void accept(LruCache.CacheNode cacheNode) {
226: super.evict(cacheNode.getCls(), cacheNode.getIdentifier(), cacheNode.getContext());
227: }
228:
229: @Override
230: void put(Object primaryKey, Object entity, URI context) {
231: final URI ctx = context != null ? context : defaultContext;
232: super.put(primaryKey, entity, ctx);
233: cache.put(new LruCache.CacheNode(ctx, entity.getClass(), primaryKey), NULL_VALUE);
234: }
235:
236: @Override
237: <T> T get(Class<T> cls, Object primaryKey, URI context) {
238: final URI ctx = context != null ? context : defaultContext;
239: T result = super.get(cls, primaryKey, ctx);
240: if (result != null) {
241: cache.get(new LruCache.CacheNode(ctx, cls, primaryKey));
242: }
243: return result;
244: }
245:
246: @Override
247: void evict(Class<?> cls, Object primaryKey, URI context) {
248: final URI ctx = context != null ? context : defaultContext;
249: super.evict(cls, primaryKey, ctx);
250: cache.remove(new LruCache.CacheNode(ctx, cls, primaryKey));
251: }
252:
253: @Override
254: void evict(URI context) {
255: if (context == null) {
256: context = defaultContext;
257: }
258: if (!repoCache.containsKey(context)) {
259: return;
260: }
261: final Map<Class<?>, Map<Object, Object>> ctxContent = repoCache.get(context);
262: for (Map.Entry<Class<?>, Map<Object, Object>> e : ctxContent.entrySet()) {
263: for (Object id : e.getValue().keySet()) {
264: cache.remove(new LruCache.CacheNode(context, e.getKey(), id));
265: }
266: }
267: ctxContent.clear();
268: }
269:
270: @Override
271: void evict(Class<?> cls) {
272: for (Map.Entry<URI, Map<Class<?>, Map<Object, Object>>> e : repoCache.entrySet()) {
273: final Map<Class<?>, Map<Object, Object>> m = e.getValue();
274: final Map<Object, Object> cached = m.remove(cls);
275: if (cached != null) {
276: for (Object id : cached.keySet()) {
277: cache.remove(new LruCache.CacheNode(e.getKey(), cls, id));
278: }
279: }
280: }
281: }
282: }
283: }