package org.infinispan.persistence.async; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; import org.infinispan.persistence.modifications.Clear; import org.infinispan.persistence.modifications.Modification; import org.infinispan.persistence.modifications.ModificationsList; import org.infinispan.persistence.modifications.Remove; import org.infinispan.persistence.modifications.Store; /** * @author Karsten Blees * @since 6.0 */ public class State { final static Clear CLEAR = new Clear(); /** * True if the state has been cleared before making modifications. */ final boolean clear; /** * Modifications to apply to the back-end CacheStore. */ final ConcurrentMap<Object, Modification> modifications; /** * Next state in the chain, initialized in constructor, may be set to <code>null</code> * asynchronously at any time. */ volatile State next; /** * Number of worker threads that currently work with this instance. */ CountDownLatch workerThreads; public State(boolean clear, ConcurrentMap<Object, Modification> modMap, State next) { this.clear = clear; this.modifications = modMap; this.next = next; } /** * Gets the Modification for the specified key from this State object or chained ( * <code>next</code>) State objects. * * @param key * the key to look up * @return the Modification for the specified key, or <code>CLEAR</code> if the state was * cleared, or <code>null</code> if the key is not in the state map */ Modification get(Object key) { for (State state = this; state != null; state = state.next) { Modification mod = state.modifications.get(key); if (mod != null) return mod; else if (state.clear) return CLEAR; } return null; } /** * Adds the Modification(s) to the state map. * * @param mod * the Modification to add, supports modification types STORE, REMOVE and LIST */ void put(Modification mod) { switch (mod.getType()) { case STORE: modifications.put(((Store) mod).getKey(), mod); break; case REMOVE: modifications.put(((Remove) mod).getKey(), mod); break; case LIST: for (Modification m : ((ModificationsList) mod).getList()) put(m); break; default: throw new IllegalArgumentException("Unknown modification type " + mod.getType()); } } public Set getKeysInTransit() { Set result = new HashSet(); _loadKeys(this, result); return result; } private void _loadKeys(State s, Set result) { // if not cleared, get keys from next State or the back-end store if (!s.clear) { State next = s.next; if (next != null) _loadKeys(next, result); } // merge keys of the current State for (Modification mod : s.modifications.values()) { switch (mod.getType()) { case STORE: Object key = ((Store) mod).getKey(); result.add(key); break; case REMOVE: result.remove(((Remove) mod).getKey()); break; } } } }