001package org.apache.commons.jcs.engine.memory; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.Map; 026import java.util.Set; 027import java.util.concurrent.atomic.AtomicLong; 028import java.util.concurrent.locks.Lock; 029import java.util.concurrent.locks.ReentrantLock; 030 031import org.apache.commons.jcs.engine.CacheStatus; 032import org.apache.commons.jcs.engine.behavior.ICacheElement; 033import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; 034import org.apache.commons.jcs.engine.control.CompositeCache; 035import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache; 036import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor; 037import org.apache.commons.jcs.engine.stats.StatElement; 038import org.apache.commons.jcs.engine.stats.Stats; 039import org.apache.commons.jcs.engine.stats.behavior.IStatElement; 040import org.apache.commons.jcs.engine.stats.behavior.IStats; 041import org.apache.commons.logging.Log; 042import org.apache.commons.logging.LogFactory; 043 044/** 045 * This base includes some common code for memory caches. 046 * <p> 047 * This keeps a static reference to a memory shrinker clock daemon. If this region is configured to 048 * use the shrinker, the clock daemon will be setup to run the shrinker on this region. 049 */ 050public abstract class AbstractMemoryCache<K, V> 051 implements IMemoryCache<K, V> 052{ 053 /** Log instance */ 054 private static final Log log = LogFactory.getLog( AbstractMemoryCache.class ); 055 056 /** Cache Attributes. Regions settings. */ 057 private ICompositeCacheAttributes cacheAttributes; 058 059 /** The cache region this store is associated with */ 060 private CompositeCache<K, V> cache; 061 062 /** status */ 063 private CacheStatus status; 064 065 /** How many to spool at a time. */ 066 protected int chunkSize; 067 068 protected final Lock lock = new ReentrantLock(); 069 070 /** Map where items are stored by key. This is created by the concrete child class. */ 071 protected Map<K, MemoryElementDescriptor<K, V>> map;// TODO privatise 072 073 /** number of hits */ 074 protected AtomicLong hitCnt; 075 076 /** number of misses */ 077 protected AtomicLong missCnt; 078 079 /** number of puts */ 080 protected AtomicLong putCnt; 081 082 /** 083 * For post reflection creation initialization 084 * <p> 085 * @param hub 086 */ 087 @Override 088 public void initialize( CompositeCache<K, V> hub ) 089 { 090 hitCnt = new AtomicLong(0); 091 missCnt = new AtomicLong(0); 092 putCnt = new AtomicLong(0); 093 094 this.cacheAttributes = hub.getCacheAttributes(); 095 this.chunkSize = cacheAttributes.getSpoolChunkSize(); 096 this.cache = hub; 097 098 this.map = createMap(); 099 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<K, V> 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}