View Javadoc

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 }