cachinginfinispanremove-ifinfinispan-9

Best way to remove cache entry based on predicate in infinispan?


I want to remove few cache entries if the key in the cache matches some pattern.

For example, I've the following key-value pair in the cache,

("key-1", "value-1"), ("key-2", "value-2"), ("key-3", "value-3"), ("key-4", "value-4")

Since cache implements a map interface, i can do like this

cache.entrySet().removeIf(entry -> entry.getKey().indexOf("key-") > 0);

Is there a better way to do this in infinispan (may be using functional or cache stream api)?


Solution

  • The removeIf method on entrySet should work just fine. It will be pretty slow though for a distributed cache as it will pull down every entry in the cache and evaluate the predicate locally and then perform a remove for each entry that matches. Even in a replicated cache it still has to do all of the remove calls (at least the iterator will be local though). This method may be changed in the future as we are updating the Map methods already [a].

    Another option is to instead use the functional API as you said [1]. Unfortunately the way this is implemented is it will still pull all the entries locally first. This may be changed at a later point if the Functional Map APIs become more popular.

    Yet another choice is the cache stream API which may be a little more cumbersome to use, but will provide you the best performance of all of the options. Glad you mentioned it :) What I would recommend is to apply any intermediate operations first (luckily in your case you can use filter since your keys won't change concurrently). Then use the forEach terminal operation which passes the Cache on that node [2] (note this is an override). Inside the forEach callable you can call the remove command just as you wanted.

    cache.entrySet().parallelStream() // stream() if you want single thread per node
       .filter(e -> e.getKey().indexOf("key-") > 0)
       .forEach((cache, e) -> cache.remove(e.getKey()));
    

    You could also use indexing to avoid the iteration of the container as well, but I won't go into that here. Indexing is a whole different beast.

    [a] https://issues.jboss.org/browse/ISPN-5728

    [1] https://docs.jboss.org/infinispan/9.0/apidocs/org/infinispan/commons/api/functional/FunctionalMap.ReadWriteMap.html#evalAll-java.util.function.Function-

    [2] https://docs.jboss.org/infinispan/9.0/apidocs/org/infinispan/CacheStream.html#forEach-org.infinispan.util.function.SerializableBiConsumer-