package org.multiverse.api.blocking;
/**
* A blockingAllowed structure that can be used to create blocking transactions. When a transaction blocks, a
* 'listener' is added to each read transactional object. This listener is the Latch. Each transactional object
* can have a set of listeners.
* <p/>
* The Latch can safely be created once by a Txn and reused by the same Txn because it works based on
* an listenerEra. So of opens happen with an older listener-era, the open is ignored. So even though the Latch could
* be attached to an older ref that didn't get updated, but is updated eventually even though the latch is notified
* by another ref, there is no problem.
* <p/>
* By resetting it, the listenerEra-counter is incremented, so that call to open or await are ignored.
*
* @author Peter Veentjer.
*/
public interface RetryLatch {
/**
* Checks if the Latch is open.
*
* @return true if the Latch is open, false otherwise.
*/
boolean isOpen();
/**
* Opens this latch only if the expectedEra is the same. If the expectedEra is not the same, the call is ignored.
* If the Latch already is open, this call is also ignored.
*
* @param expectedEra the expected era.
*/
void open(long expectedEra);
/**
* Gets the current era.
*
* @return the current era.
*/
long getEra();
/**
* Awaits for this latch to open. This call is not responsive to interrupts.
*
* @param expectedEra the expected era. If the era is different, the await always succeeds.
*/
void awaitUninterruptible(long expectedEra);
/**
* Awaits for this Latch to open. There are 3 possible ways for this methods to complete;
* <ol>
* <li>the era doesn't match the expected era</li>
* <li>the latch is opened while waiting</li>
* <li>the latch is interrupted while waiting. When this happens the RetryInterruptedException
* is thrown and the Thread.interrupt status is restored.</li>
* </ol>
*
* @param expectedEra the expected era.
* @param transactionFamilyName the name of the transaction (only needed for creating
* a usable message in the RetryInterruptedException).
* @throws org.multiverse.api.exceptions.RetryInterruptedException
*
*/
void await(long expectedEra, String transactionFamilyName);
/**
* Awaits for this latch to open with a timeout. This call is not responsive to interrupts.
* <p/>
* When the calling thread is interrupted, the Thread.interrupt status will not be eaten by
* this method and safely be restored.
*
* @param expectedEra the expected era.
* @param nanosTimeout the timeout in nanoseconds
* @return the remaining timeout. A negative value indicates that the Latch is not opened in time.
*/
long awaitNanosUninterruptible(long expectedEra, long nanosTimeout);
/**
* Awaits for this latch to open with a timeout. This call is responsive to interrupts.
* <p/>
* When the calling thread is interrupted, the Thread.interrupt status will not be eaten by
* this method and safely be restored.
*
* @param expectedEra the expected era
* @param nanosTimeout the timeout in nanoseconds. Can safely be called with a zero or negative timeout
* @param transactionFamilyName the name of the transaction (only needed for creating
* a usable message in the RetryInterruptedException).
* @return the remaining timeout. A 0 or negative value indicates that the latch is not opened in time.
* @throws org.multiverse.api.exceptions.RetryInterruptedException
*
*/
long awaitNanos(long expectedEra, long nanosTimeout, String transactionFamilyName);
/**
* Prepares the Latch for pooling. All waiting threads will be notified and the era is increased.
*/
void reset();
}