[infinispan-dev] Today's topic: eviction

Pedro Ruivo pedro at infinispan.org
Thu Nov 21 13:48:46 EST 2013


(re: https://issues.jboss.org/browse/ISPN-3048)
(ps. sorry for the long mail. I hope that is clear)

* Automatic eviction:

I've been writing some scenario involving eviction and concurrent 
operations. This test shows a very reliable eviction but we have a 
problem when passivation is enabled. The passivation phase is ok but 
when we need to activate a key, we have a huge window in which the 
read/write operation does not find the key neither in-memory data 
container neither in the cache loader. This happens because the check 
in-memory data container is not synchronized with the check in cache loader.

Passivation phase works fine, as I said, because it happens inside the 
data container, i.e., the bounded concurrent hash map (BCHM) evict the 
key under the segment lock.

* Manual eviction

I haven't finish my test suite but so far it does not work as expected. 
If you are a backup owner, you are unable to evict any keys (because the 
EvictCommand is handled as a RemoveCommand and the key is not wrapped in 
EntryWrappingInterceptor). In addition, I believe that it has the same 
problems with activation as above.

Also, I believe that passivation phase does not work well because it 
first tries to passivate than it removes from DataContainer. Nothing is 
preventing to passivate an old value, a put occurs and modifies the data 
in DataContainer and finally the EvictCommand removes the new value 
(that is lost).

* New implementation

Since we are stating a new major release, I would like to "propose" the 
following improvements. One aspect of the implementation is the dropping 
of the *Cache[Writer or Loader]Interceptor and the EvictCommand. Also, 
it would add a new method in DataContainer (void evict(K key)) and 
possible change the interface in PersistenceManager.

My idea is based on the current implementation of the BCHM. The BCHM 
implementation is aware of the persistence and it performs internally 
the passivate() and activate() operations. I would like to extend this 
and make it full aware of the PersistenceManager. Also, it would be 
required to have ConcurrentHashMap (CHM) with the same features

Enter in more detail, the (B)CHM.get() will be responsible to load the 
key from persistence (and activate it) if it is not found in-memory. 
Also, it stores the entry in memory. In other hand, the put() stores the 
entry in-memory and in the persistence (if passivation==false) and we 
add an evict(k) to the CHM interface to remove from memory and passivate 
it to persistence a single key.

* Pros

** solves all the problems :)
** remove all the interceptors related to cache writer and cache loader 
=> small interceptor chain
** remove evict command => lower process time(?)
** cache writer and cache loader does not need to have per key lock 
based (however, they should be thread safe)
** when passivation==true, we don't loose any key/value (yey)
** no need to acquire locks in lock manager (as the current manual 
eviction does)
** all the logic for cache loader/writer will be located in a single mode

* Cons

** difficult to maintain. We have to maintain the code for the (B)CHM
** new API and contract for DataContainer interface => it should handle 
all the load/write from cache loader/writer
** new API for PersistenceManager

toughs?

Cheers
Pedro

* Open question in case this is going forward

** should contains(key) put the entry loaded in-memory (if loaded from 
cache loader)?
** how iterator(), keys(), values() and entrySet() should behave? should 
they put the entries in memory? And size()?

* API changes

DataContainer

(new) void evict(K key)

PersistenceManager

(new) Entry onRead(K key) //shoud read the key. if passivation, remove 
from loader
(new) void onWrite(K key, Entry entry) //if passivation, then do 
nothing, else store it
(new) Entry onRemove(K key) //remove and return old
(new) void onEvict(K key, Entry entry) //if passivation, then store it

* Some (B)CHM pseudo-code

V get(K key)
   Segment s = segment(key)
   V value = s.get(key)
   if (value == null) {
     s.lock()
     //recheck if s.get(key) is still null
     value = persistenceManager.onLoad(key); //this activates the key if 
needed
     if (value != null) s.put(key, value)
     s.unlock()
   }
   return value

V put(K key, V value)
   Segment s = segment(key)
   s.lock()
   V oldValue = s.get(key)
   persistenceManager.onWrite(key, value) //first try the persistence
   s.put(key, value) //can trigger eviction
   s.unlock()

void evict(K key, V value)
   Segment s = segment(key)
   s.lock()
   persistenceManager.onEvict(key, value) //first try the persistence
   s.remove(key) //remove from memory if peristence is successful (we 
don't wanna loose the value, right?)
   s.unlock()


More information about the infinispan-dev mailing list