package org.infinispan.remoting.inboundhandler.action; import static java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.infinispan.interceptors.locking.ClusteringDependentLogic; import org.infinispan.util.concurrent.locks.LockUtil; import org.infinispan.util.concurrent.locks.RemoteLockCommand; /** * A base {@link Action} implementation for locking. * <p/> * This contains the basic steps for lock acquisition: try to acquire, check when it is available and acquired (or not). * * @author Pedro Ruivo * @since 8.0 */ public abstract class BaseLockingAction implements Action { private static final AtomicReferenceFieldUpdater<BaseLockingAction, InternalState> UPDATER = newUpdater(BaseLockingAction.class, InternalState.class, "internalState"); private final ClusteringDependentLogic clusteringDependentLogic; private volatile InternalState internalState; public BaseLockingAction(ClusteringDependentLogic clusteringDependentLogic) { this.clusteringDependentLogic = clusteringDependentLogic; this.internalState = InternalState.INIT; } @Override public final ActionStatus check(ActionState state) { switch (internalState) { case INIT: return init(state); case CHECKING: return checking(state); case MAKE_READY: return ActionStatus.NOT_READY; //some thread is calculating the final state case READY: return ActionStatus.READY; //ready final state case CANCELED: return ActionStatus.CANCELED; //canceled final state } return ActionStatus.NOT_READY; //not ready } protected abstract ActionStatus checking(ActionState state); protected abstract ActionStatus init(ActionState state); protected final boolean cas(InternalState expectedState, InternalState newState) { return UPDATER.compareAndSet(this, expectedState, newState); } private void filterByLockOwner(Collection<?> keys, Collection<Object> toAdd) { keys.forEach(key -> { if (LockUtil.isLockOwner(key, clusteringDependentLogic)) { toAdd.add(key); } }); } protected final List<Object> getAndUpdateFilteredKeys(ActionState state) { List<Object> filteredKeys = state.getFilteredKeys(); if (filteredKeys == null) { RemoteLockCommand remoteLockCommand = state.getCommand(); Collection<?> rawKeys = remoteLockCommand.getKeysToLock(); filteredKeys = new ArrayList<>(rawKeys.size()); filterByLockOwner(rawKeys, filteredKeys); state.updateFilteredKeys(filteredKeys); } return filteredKeys; } protected enum InternalState { INIT, CHECKING, CANCELED, MAKE_READY, READY } }