1 /*
2 * RCache - A collection of simple reference-based cache implementations.
3 * Copyright (C) 2007 Rodrigo Ruiz
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Alternatively, the contents of this file may be used under the terms
20 * of the Apache 2.0 license (the "Apache License"), in which case its
21 * provisions are applicable instead of those above. If you wish to allow use
22 * of your version of this file only* under the terms of the Apache License
23 * and not to allow others to use your version of this file under the LGPL,
24 * indicate your decision by* deleting the provisions above and replace them
25 * with the notice and other provisions required by the Apache License. If
26 * you do not delete the provisions above, a recipient may use your version of
27 * this file under either the LGPL or the Apache License.
28 */
29 package net.sourceforge.rcache.decorator;
30
31 import java.util.Iterator;
32 import java.util.LinkedHashMap;
33 import java.util.Map;
34
35 import net.sourceforge.rcache.Cache;
36
37 /**
38 * <p>Decorator for Cache instances that adds an MRU list containing hard
39 * references to the most recently used entries.</p>
40 *
41 * <p>This decorator prevents the most recently used entries from being
42 * garbage collected.</p>
43 *
44 * @author Rodrigo Ruiz
45 * @param <K> the type of keys maintained by this cache
46 * @param <V> the type of cached values
47 */
48 public final class MruGuard<K, V> implements Cache<K, V> {
49
50 /**
51 * The wrapped cache.
52 */
53 private final Cache<K, V> cache;
54
55 /**
56 * Map containing the most recently used entries.
57 */
58 private final MruMap<V> mru;
59
60 /**
61 * Creates an instance.
62 *
63 * @param cache The cache instance to wrap
64 * @param mruSize The number of items to maintain in the MRU list
65 */
66 public MruGuard(Cache<K, V> cache, int mruSize) {
67 this.cache = cache;
68 this.mru = new MruMap<V>(mruSize);
69 }
70
71 /**
72 * {@inheritDoc}
73 */
74 public V get(Object key) {
75 V value = this.cache.get(key);
76 this.mru.put(value);
77 return value;
78 }
79
80 /**
81 * {@inheritDoc}
82 */
83 public V put(K key, V value) {
84 this.mru.put(value);
85 value = this.cache.put(key, value);
86 return value;
87 }
88
89 /**
90 * {@inheritDoc}
91 */
92 public V remove(Object key) {
93 V value = this.cache.remove(key);
94 this.mru.remove(value);
95 return value;
96 }
97
98 /**
99 * {@inheritDoc}
100 */
101 public void clear() {
102 this.mru.clear();
103 this.cache.clear();
104 }
105
106 /**
107 * Gets the maximum size of the MRU list.
108 *
109 * @return the MRU list max size
110 */
111 public int getMaxSize() {
112 return this.mru.maxSize();
113 }
114
115 /**
116 * Gets an iterator for the internal MRU list.
117 * <p>
118 * This method is for test purposes only.
119 *
120 * @return An iterator for the MRU list
121 */
122 protected Iterator<V> mruIterator() {
123 return this.mru.keySet().iterator();
124 }
125
126 /**
127 * Fixed-size map for MRU management.
128 */
129 private static final class MruMap<V> extends LinkedHashMap<V, Object> {
130 /**
131 * <code>serialVersionUID</code> attribute.
132 */
133 private static final long serialVersionUID = -5316259183944411057L;
134
135 /**
136 * Load factor for the internal map.
137 */
138 private static final float MRU_LOAD_FACTOR = 0.75f;
139
140 /**
141 * Size of the map.
142 */
143 private final int maxSize;
144
145 /**
146 * Creates an instance.
147 *
148 * @param maxSize The max size of the map
149 */
150 public MruMap(int maxSize) {
151 super(2 * maxSize, MRU_LOAD_FACTOR, true);
152 this.maxSize = maxSize;
153 }
154
155 /**
156 * Enforces the max size of the map.
157 *
158 * {@inheritDoc}
159 */
160 @Override protected boolean removeEldestEntry(Map.Entry<V, Object> entry) {
161 return this.size() > maxSize;
162 }
163
164 /**
165 * Puts a value in this MRU map.
166 *
167 * @param value The value to put
168 */
169 public void put(V value) {
170 if (value != null) {
171 synchronized (this) {
172 super.put(value, null);
173 }
174 }
175 }
176
177 /**
178 * Gets the max size of this map.
179 *
180 * @return The max size of this map
181 */
182 public int maxSize() {
183 return this.maxSize;
184 }
185 }
186 }