package com.atlassian.bitbucket.mesh.coordination;

import java.io.Closeable;

/**
 * A write token used to implement exclusive write access to a repository using
 * <a href="https://en.wikipedia.org/wiki/Maekawa%27s_algorithm">Maekawa's algorithm</a>.
 * <p>
 * A token can be requested through {@link WriteTokenRegistry#acquireToken}, which returns a {@link Promise} to
 * eventually fulfill the request and grant the token.
 * <p>
 * Maekawa's algorithm grants the token to the token request with the lowest logical timestamp. However, when token
 * requests are received out of order, this can result in deadlocks. To prevent this, the algorithm requests the
 * token holder that prematurely received the token to yield it. Once released, the algorithm grants the token
 * to the higher priority (lower timestamp) request.
 * <p>
 * Token holders <em>MUST</em> {@link WriteToken#yieldToken() yield} the token as soon as possible when asked, unless
 * the token holder has already achieved a write lock (in which case the tokens are released after the critical
 * section is exited).
 * <p>
 * A token requester <em>MUST</em> {@link Promise#close() cancel} its request when it is done or no longer interested
 * in the token. This automatically releases the token if the token is currently held.
 *
 * @see WriteTokenRegistry
 */
public interface WriteToken {

    /**
     * Yields the token, if held. This implicitly re-queues the original token request. Call {@link Promise#close()} to
     * release the token and cancel the token request.
     */
    void yieldToken();

    /**
     * A promise to {@link WriteTokenHandler#onGranted(WriteToken) grant} the requested token to the
     * {@link WriteTokenHandler handler} when this request has the highest priority (lowest logical timestamp).
     *
     * @see WriteTokenRegistry#acquireToken
     */
    interface Promise extends Closeable {

        /**
         * Releases the token if held and cancels the request for the write token.
         */
        @Override
        void close();
    }
}
