View Javadoc
1   package org.apache.commons.jcs.engine.memory;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.concurrent.atomic.AtomicLong;
28  import java.util.concurrent.locks.Lock;
29  import java.util.concurrent.locks.ReentrantLock;
30  
31  import org.apache.commons.jcs.engine.CacheStatus;
32  import org.apache.commons.jcs.engine.behavior.ICacheElement;
33  import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
34  import org.apache.commons.jcs.engine.control.CompositeCache;
35  import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
36  import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
37  import org.apache.commons.jcs.engine.stats.StatElement;
38  import org.apache.commons.jcs.engine.stats.Stats;
39  import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
40  import org.apache.commons.jcs.engine.stats.behavior.IStats;
41  import org.apache.commons.logging.Log;
42  import org.apache.commons.logging.LogFactory;
43  
44  /**
45   * This base includes some common code for memory caches.
46   * <p>
47   * This keeps a static reference to a memory shrinker clock daemon. If this region is configured to
48   * use the shrinker, the clock daemon will be setup to run the shrinker on this region.
49   */
50  public abstract class AbstractMemoryCache<K, V>
51      implements IMemoryCache<K, V>
52  {
53      /** Log instance */
54      private static final Log log = LogFactory.getLog( AbstractMemoryCache.class );
55  
56      /** Cache Attributes.  Regions settings. */
57      private ICompositeCacheAttributes cacheAttributes;
58  
59      /** The cache region this store is associated with */
60      private CompositeCache<K, V> cache;
61  
62      /** status */
63      private CacheStatus status;
64  
65      /** How many to spool at a time. */
66      protected int chunkSize;
67  
68      protected final Lock lock = new ReentrantLock();
69  
70      /** Map where items are stored by key.  This is created by the concrete child class. */
71      protected Map<K, MemoryElementDescriptor<K, V>> map;// TODO privatise
72  
73      /** number of hits */
74      protected AtomicLong hitCnt;
75  
76      /** number of misses */
77      protected AtomicLong missCnt;
78  
79      /** number of puts */
80      protected AtomicLong putCnt;
81  
82      /**
83       * For post reflection creation initialization
84       * <p>
85       * @param hub
86       */
87      @Override
88      public void initialize( CompositeCache<K, V> hub )
89      {
90          hitCnt = new AtomicLong(0);
91          missCnt = new AtomicLong(0);
92          putCnt = new AtomicLong(0);
93  
94          this.cacheAttributes = hub.getCacheAttributes();
95          this.chunkSize = cacheAttributes.getSpoolChunkSize();
96          this.cache = hub;
97  
98          this.map = createMap();
99  
100         this.status = CacheStatus.ALIVE;
101     }
102 
103     /**
104      * Children must implement this method. A FIFO implementation may use a tree map. An LRU might
105      * use a hashtable. The map returned should be threadsafe.
106      * <p>
107      * @return a threadsafe Map
108      */
109     public abstract Map<K, MemoryElementDescriptor<K, V>> createMap();
110 
111     /**
112      * Removes an item from the cache
113      * <p>
114      * @param key Identifies item to be removed
115      * @return Description of the Return Value
116      * @throws IOException Description of the Exception
117      */
118     @Override
119     public abstract boolean remove( K key )
120         throws IOException;
121 
122     /**
123      * Get an item from the cache
124      * <p>
125      * @param key Description of the Parameter
126      * @return Description of the Return Value
127      * @throws IOException Description of the Exception
128      */
129     @Override
130     public abstract ICacheElement<K, V> get( K key )
131         throws IOException;
132 
133     /**
134      * Gets multiple items from the cache based on the given set of keys.
135      * <p>
136      * @param keys
137      * @return a map of K key to ICacheElement&lt;K, V&gt; element, or an empty map if there is no
138      *         data in cache for any of these keys
139      * @throws IOException
140      */
141     @Override
142     public Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
143         throws IOException
144     {
145         Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>();
146 
147         if ( keys != null && !keys.isEmpty() )
148         {
149             for (K key : keys)
150             {
151                 ICacheElement<K, V> element = get( key );
152 
153                 if ( element != null )
154                 {
155                     elements.put( key, element );
156                 }
157             }
158         }
159 
160         return elements;
161     }
162 
163     /**
164      * Get an item from the cache without affecting its last access time or position. Not all memory
165      * cache implementations can get quietly.
166      * <p>
167      * @param key Identifies item to find
168      * @return Element matching key if found, or null
169      * @throws IOException
170      */
171     @Override
172     public ICacheElement<K, V> getQuiet( K key )
173         throws IOException
174     {
175         ICacheElement<K, V> ce = null;
176 
177         MemoryElementDescriptor<K, V> me = map.get( key );
178         if ( me != null )
179         {
180             if ( log.isDebugEnabled() )
181             {
182                 log.debug( getCacheName() + ": MemoryCache quiet hit for " + key );
183             }
184 
185             ce = me.getCacheElement();
186         }
187         else if ( log.isDebugEnabled() )
188         {
189             log.debug( getCacheName() + ": MemoryCache quiet miss for " + key );
190         }
191 
192         return ce;
193     }
194 
195     /**
196      * Puts an item to the cache.
197      * <p>
198      * @param ce Description of the Parameter
199      * @throws IOException Description of the Exception
200      */
201     @Override
202     public abstract void update( ICacheElement<K, V> ce )
203         throws IOException;
204 
205     /**
206      * Get a set of the keys for all elements in the memory cache
207      * <p>
208      * @return A set of the key type
209      */
210     @Override
211     public abstract Set<K> getKeySet();
212 
213     /**
214      * Removes all cached items from the cache.
215      * <p>
216      * @throws IOException
217      */
218     @Override
219     public void removeAll()
220         throws IOException
221     {
222         map.clear();
223     }
224 
225     /**
226      * Prepares for shutdown. Reset statistics
227      * <p>
228      * @throws IOException
229      */
230     @Override
231     public void dispose()
232         throws IOException
233     {
234         removeAll();
235         hitCnt.set(0);
236         missCnt.set(0);
237         putCnt.set(0);
238         log.info( "Memory Cache dispose called." );
239     }
240 
241     /**
242      * @return statistics about the cache
243      */
244     @Override
245     public IStats getStatistics()
246     {
247         IStats stats = new Stats();
248         stats.setTypeName( "Abstract Memory Cache" );
249 
250         ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
251         stats.setStatElements(elems);
252 
253         elems.add(new StatElement<AtomicLong>("Put Count", putCnt));
254         elems.add(new StatElement<AtomicLong>("Hit Count", hitCnt));
255         elems.add(new StatElement<AtomicLong>("Miss Count", missCnt));
256         elems.add(new StatElement<Integer>( "Map Size", Integer.valueOf(getSize()) ) );
257 
258         return stats;
259     }
260 
261     /**
262      * Returns the current cache size.
263      * <p>
264      * @return The size value
265      */
266     @Override
267     public int getSize()
268     {
269         return this.map.size();
270     }
271 
272     /**
273      * Returns the cache status.
274      * <p>
275      * @return The status value
276      */
277     public CacheStatus getStatus()
278     {
279         return this.status;
280     }
281 
282     /**
283      * Returns the cache (aka "region") name.
284      * <p>
285      * @return The cacheName value
286      */
287     public String getCacheName()
288     {
289         String attributeCacheName = this.cacheAttributes.getCacheName();
290         if(attributeCacheName != null)
291         {
292             return attributeCacheName;
293         }
294         return cache.getCacheName();
295     }
296 
297     /**
298      * Puts an item to the cache.
299      * <p>
300      * @param ce the item
301      */
302     @Override
303     public void waterfal( ICacheElement<K, V> ce )
304     {
305         this.cache.spoolToDisk( ce );
306     }
307 
308     // ---------------------------------------------------------- debug method
309     /**
310      * Dump the cache map for debugging.
311      */
312     public void dumpMap()
313     {
314         log.debug( "dumpingMap" );
315         for (Map.Entry<K, MemoryElementDescriptor<K, V>> e : map.entrySet())
316         {
317             MemoryElementDescriptor<K, V> me = e.getValue();
318             log.debug( "dumpMap> key=" + e.getKey() + ", val=" + me.getCacheElement().getVal() );
319         }
320     }
321 
322     /**
323      * Returns the CacheAttributes.
324      * <p>
325      * @return The CacheAttributes value
326      */
327     @Override
328     public ICompositeCacheAttributes getCacheAttributes()
329     {
330         return this.cacheAttributes;
331     }
332 
333     /**
334      * Sets the CacheAttributes.
335      * <p>
336      * @param cattr The new CacheAttributes value
337      */
338     @Override
339     public void setCacheAttributes( ICompositeCacheAttributes cattr )
340     {
341         this.cacheAttributes = cattr;
342     }
343 
344     /**
345      * Gets the cache hub / region that the MemoryCache is used by
346      * <p>
347      * @return The cache value
348      */
349     @Override
350     public CompositeCache<K, V> getCompositeCache()
351     {
352         return this.cache;
353     }
354 }