package org.multiverse.stms.gamma; import org.multiverse.api.blocking.RetryLatch; /** * A Listeners object contains all the Latches of blockingAllowed transactions that listen to a write on a * transactional object. Essentially it is a single linked list. * <p/> * This is an 'immutable' class. As long as it is registered to a transactional object, it should not be mutated. * But as soon as it is removed as listener, only a single thread has access to this Listeners object. This means * that it can be pooled. * <p/> * Setting the Listeners and removing the it should provide the happens before relation so that all changes made * to the Listener before it is getAndSet, are visible when it is removed. * * @author Peter Veentjer */ public final class Listeners { public Listeners next; public RetryLatch listener; public long listenerEra; //public String threadName; /** * Prepares this Listeners object for pooling. This is done by: * <ol> * <li>setting the next to null</li> * <li>setting the listener to null</li> * <li>setting the listenerEra to Long.MIN_VALUE</li> * </ol> * <p/> * This call is not threadsafe and should only be done by a transaction that has exclusive access to * the listeners. The most logical place would be in the object pool when the Listeners is placed there. */ public void prepareForPooling() { next = null; listener = null; listenerEra = Long.MIN_VALUE; } /** * Opens all latches. * <p/> * All Listeners are put in the pool. The Latches are not put in the pool since no guarantee can be given * that the Latch is still registered on a different transactional object. * <p/> * This call should only be done by the transaction that removed the listeners from * the transactional object. So it is not threadsafe, * * @param pool the GammaObjectPool to store the discarded Listeners in. */ public void openAll(final GammaObjectPool pool) { Listeners current = this; do { Listeners next = current.next; current.listener.open(current.listenerEra); pool.putListeners(current); current = next; } while (current != null); } /** * Opens all the listeners. As soon as in the array a null element is found, it signals the end of * the list of listeners. This makes is possible to place an array that is larger than the actual * number of writes. * <p/> * The call safely can be made with a null listenersArray. In that case the call is ignored. * * @param listenersArray the array of Listeners to notify. * @param pool the GammaObjectPool to pool the Listeners and the array containing the listeners. */ public static void openAll(final Listeners[] listenersArray, final GammaObjectPool pool) { if (listenersArray == null) { return; } for (int k = 0; k < listenersArray.length; k++) { Listeners listeners = listenersArray[k]; //we can end as soon as a null is found. if (listeners == null) { break; } listenersArray[k] = null; listeners.openAll(pool); } } }