1 17 package org.apache.excalibur.store.impl; 18 19 import java.io.IOException; 20 import java.util.Enumeration; 21 import java.util.Hashtable; 22 import java.util.LinkedList; 23 import java.util.NoSuchElementException; 24 25 import org.apache.avalon.framework.activity.Disposable; 26 import org.apache.avalon.framework.logger.AbstractLogEnabled; 27 import org.apache.avalon.framework.parameters.ParameterException; 28 import org.apache.avalon.framework.parameters.Parameterizable; 29 import org.apache.avalon.framework.parameters.Parameters; 30 import org.apache.avalon.framework.service.ServiceException; 31 import org.apache.avalon.framework.service.ServiceManager; 32 import org.apache.avalon.framework.service.Serviceable; 33 import org.apache.avalon.framework.thread.ThreadSafe; 34 import org.apache.excalibur.instrument.CounterInstrument; 35 import org.apache.excalibur.instrument.Instrument; 36 import org.apache.excalibur.instrument.Instrumentable; 37 import org.apache.excalibur.instrument.ValueInstrument; 38 import org.apache.excalibur.store.Store; 39 import org.apache.excalibur.store.StoreJanitor; 40 41 54 public class MRUMemoryStore 55 extends AbstractLogEnabled 56 implements Store, Parameterizable, Serviceable, Disposable, ThreadSafe, Instrumentable 57 { 58 private String m_instrumentableName; 59 private int m_maxobjects; 60 private boolean m_persistent; 61 private Hashtable m_cache; 62 private LinkedList m_mrulist; 63 private Store m_persistentStore; 64 private StoreJanitor m_storeJanitor; 65 private ServiceManager m_manager; 66 67 private ValueInstrument m_sizeInstrument = new ValueInstrument("size"); 68 private CounterInstrument m_hitsInstrument = new CounterInstrument("hits"); 69 private CounterInstrument m_missesInstrument = new CounterInstrument("misses"); 70 71 78 public void service( ServiceManager manager ) 79 throws ServiceException 80 { 81 m_manager = manager; 82 if( getLogger().isDebugEnabled() ) 83 { 84 getLogger().debug( "Looking up " + StoreJanitor.ROLE ); 85 } 86 m_storeJanitor = (StoreJanitor)manager.lookup( StoreJanitor.ROLE ); 87 } 88 89 101 public void parameterize( Parameters params ) throws ParameterException 102 { 103 m_maxobjects = params.getParameterAsInteger( "maxobjects", 100 ); 104 m_persistent = params.getParameterAsBoolean( "use-persistent-cache", false ); 105 if( ( m_maxobjects < 1 ) ) 106 { 107 throw new ParameterException( "MRUMemoryStore maxobjects must be at least 1!" ); 108 } 109 110 if ( m_persistent ) 111 { 112 if( getLogger().isDebugEnabled() ) 113 { 114 getLogger().debug( "Looking up " + Store.PERSISTENT_STORE ); 115 } 116 try 117 { 118 m_persistentStore = (Store)m_manager.lookup( Store.PERSISTENT_STORE ); 119 } 120 catch (ServiceException se) 121 { 122 throw new ParameterException("Unable to look up persistent store.", se); 123 } 124 } 125 126 m_cache = new Hashtable( (int)( m_maxobjects * 1.2 ) ); 127 m_mrulist = new LinkedList(); 128 m_storeJanitor.register( this ); 129 } 130 131 134 public void dispose() 135 { 136 if( m_manager != null ) 137 { 138 getLogger().debug( "Disposing component!" ); 139 140 if( m_storeJanitor != null ) 141 { 142 m_storeJanitor.unregister( this ); 143 } 144 m_manager.release( m_storeJanitor ); 145 m_storeJanitor = null; 146 147 if( m_persistent ) 149 { 150 getLogger().debug( "Final cache size: " + m_cache.size() ); 151 Enumeration enum = m_cache.keys(); 152 while( enum.hasMoreElements() ) 153 { 154 Object key = enum.nextElement(); 155 if( key == null ) 156 { 157 continue; 158 } 159 try 160 { 161 Object value = m_cache.remove( key ); 162 if( checkSerializable( value ) ) 163 { 164 m_persistentStore.store( key, value ); 165 } 166 } 167 catch( IOException ioe ) 168 { 169 getLogger().error( "Error in dispose()", ioe ); 170 } 171 } 172 } 173 m_manager.release( m_persistentStore ); 174 m_persistentStore = null; 175 } 176 177 m_manager = null; 178 } 179 180 188 public synchronized void store( Object key, Object value ) 189 { 190 hold( key, value ); 191 } 192 193 201 public synchronized void hold( Object key, Object value ) 202 { 203 if( getLogger().isDebugEnabled() ) 204 { 205 getLogger().debug( "Holding object in memory:" ); 206 getLogger().debug( " key: " + key ); 207 getLogger().debug( " value: " + value ); 208 } 209 210 while( m_mrulist.size() >= m_maxobjects ) 211 { 212 213 free(); 214 } 215 216 m_cache.put( key, value ); 217 m_mrulist.remove( key ); 218 m_mrulist.addFirst( key ); 219 m_sizeInstrument.setValue( m_mrulist.size() ); 220 } 221 222 228 public synchronized Object get( Object key ) 229 { 230 Object value = m_cache.get( key ); 231 if( value != null ) 232 { 233 234 m_mrulist.remove( key ); 235 m_mrulist.addFirst( key ); 236 if( getLogger().isDebugEnabled() ) 237 { 238 getLogger().debug( "Found key: " + key.toString() ); 239 } 240 m_hitsInstrument.increment(); 241 return value; 242 } 243 244 if( getLogger().isDebugEnabled() ) 245 { 246 getLogger().debug( "NOT Found key: " + key.toString() ); 247 } 248 249 250 if( m_persistent ) 251 { 252 value = m_persistentStore.get( key ); 253 if( value != null ) 254 { 255 try 256 { 257 if( !m_cache.containsKey( key ) ) 258 { 259 hold( key, value ); 260 } 261 m_hitsInstrument.increment(); 262 return value; 263 } 264 catch( Exception e ) 265 { 266 getLogger().error( "Error in get()!", e ); 267 } 268 } 269 } 270 m_missesInstrument.increment(); 271 return null; 272 } 273 274 279 public synchronized void remove( Object key ) 280 { 281 if( getLogger().isDebugEnabled() ) 282 { 283 getLogger().debug( "Removing object from store" ); 284 getLogger().debug( " key: " + key ); 285 } 286 m_cache.remove( key ); 287 m_mrulist.remove( key ); 288 m_sizeInstrument.setValue( m_mrulist.size() ); 289 290 if( m_persistent && key != null ) 291 { 292 m_persistentStore.remove( key ); 293 } 294 } 295 296 299 public synchronized void clear() 300 { 301 Enumeration enum = m_cache.keys(); 302 while( enum.hasMoreElements() ) 303 { 304 Object key = enum.nextElement(); 305 if( key == null ) 306 { 307 continue; 308 } 309 remove( key ); 310 } 311 m_sizeInstrument.setValue( 0 ); 312 } 313 314 320 public synchronized boolean containsKey( Object key ) 321 { 322 if( m_persistent ) 323 { 324 return ( m_cache.containsKey( key ) || m_persistentStore.containsKey( key ) ); 325 } 326 else 327 { 328 return m_cache.containsKey( key ); 329 } 330 } 331 332 337 public synchronized Enumeration keys() 338 { 339 return m_cache.keys(); 340 } 341 342 346 public synchronized int size() 347 { 348 return m_cache.size(); 349 } 350 351 355 public synchronized void free() 356 { 357 try 358 { 359 if( m_cache.size() > 0 ) 360 { 361 Object key = m_mrulist.removeLast(); 363 Object value = m_cache.remove( key ); 364 if( value == null ) 365 { 366 getLogger().warn( "Concurrency condition in free()" ); 367 } 368 369 if( getLogger().isDebugEnabled() ) 370 { 371 getLogger().debug( "Freeing cache." ); 372 getLogger().debug( " key: " + key ); 373 getLogger().debug( " value: " + value ); 374 } 375 376 if( m_persistent ) 377 { 378 if( checkSerializable( value ) ) 380 { 381 try 382 { 383 m_persistentStore.store( key, value ); 384 } 385 catch( Exception e ) 386 { 387 getLogger().error( "Error storing object on fs", e ); 388 } 389 } 390 } 391 392 m_sizeInstrument.setValue( m_mrulist.size() ); 393 } 394 } 395 catch( NoSuchElementException e ) 396 { 397 getLogger().warn( "Concurrency error in free()", e ); 398 } 399 catch( Exception e ) 400 { 401 getLogger().error( "Error in free()", e ); 402 } 403 } 404 405 411 private boolean checkSerializable( Object object ) 412 { 413 414 if( object == null ) return false; 415 416 return ( object instanceof java.io.Serializable ); 417 } 418 419 public void setInstrumentableName(String name) 420 { 421 m_instrumentableName = name; 422 } 423 424 public String getInstrumentableName() 425 { 426 return m_instrumentableName; 427 } 428 429 public Instrument[] getInstruments() 430 { 431 return new Instrument[] { m_sizeInstrument, m_hitsInstrument, m_missesInstrument }; 432 } 433 434 public Instrumentable[] getChildInstrumentables() { 435 return Instrumentable.EMPTY_INSTRUMENTABLE_ARRAY; 436 } 437 } 438 439 | Popular Tags |