package org.multiverse.api;
import org.multiverse.api.lifecycle.TxnListener;
/**
* A Builder for creating a {@link TxnFactory} and {@link TxnExecutor}. This builder provides full control
* on transaction settings.
*
* <p>Since the {@link Txn} and {@link TxnExecutor} are very closely integrated, both of them are created
* by this TxnFactoryBuilder.
*
* <p>Instances of this class are considered immutable, so when you call one of the modifying methods, make sure
* that you use the resulting TxnFactoryBuilder. Normally with the builder implementation the same
* instance is returned. In this case this isn't true because a new instance is returned every time.
*
* @author Peter Veentjer
* @see TxnFactory
* @see TxnConfig
*/
public interface TxnFactoryBuilder {
/**
* Returns the {@link TxnConfig} used by this TxnFactoryBuilder.
*
* @return the used TxnConfig.
*/
TxnConfig getConfig();
/**
* Sets if the {@link org.multiverse.api.exceptions.ControlFlowError} is reused. Normally you don't want to reuse them
* because they can be expensive to create (especially the stacktrace) and they could be created very often. But for
* debugging purposes it can be quite annoying because you want to see the stacktrace.
*
* @param reused true if ControlFlowErrors should be reused.
* @return the updated TxnFactoryBuilder.
* @see TxnConfig#isControlFlowErrorsReused()
*/
TxnFactoryBuilder setControlFlowErrorsReused(boolean reused);
/**
* Sets the {@link Txn} familyname. If an {@link TxnExecutor} is used inside a method, a useful familyname could
* be the full name of the class and the method.
* <p/>
* The transaction familyName is useful debugging purposes, but has not other meaning.
*
* @param familyName the familyName of the transaction.
* @return the updated TxnFactoryBuilder
* @throws NullPointerException if familyName is null.
* @see TxnConfig#getFamilyName()
*/
TxnFactoryBuilder setFamilyName(String familyName);
/**
* Sets the {@link org.multiverse.api.PropagationLevel} used. With the PropagationLevel you have control
* on how the transaction deals with transaction nesting. The default is {@link PropagationLevel#Requires}
* which automatically starts a transaction is one is missing, or lifts on a transaction if available.
*
* @param propagationLevel the new PropagationLevel
* @return the updated TxnFactoryBuilder
* @throws NullPointerException if propagationLevel is null.
* @see TxnConfig#getPropagationLevel()
* @see PropagationLevel
*/
TxnFactoryBuilder setPropagationLevel(PropagationLevel propagationLevel);
/**
* Sets the {@link Txn} {@link LockMode} for all reads. If a LockMode is set higher than {@link LockMode#None}, this transaction
* will locks all reads (and writes since a read is needed for a write) and the transaction automatically becomes
* serialized.
*
* @param lockMode the LockMode to set.
* @return the updated TxnFactoryBuilder.
* @throws NullPointerException if lockMode is null.
* @see TxnConfig#getReadLockMode()
* @see LockMode
*/
TxnFactoryBuilder setReadLockMode(LockMode lockMode);
/**
* Sets the {@link Txn} {@link LockMode} for all writes. For a write, always a read needs to be done, so if the read LockMode is
*
* <p>Freshly constructed objects that are not committed, automatically are locked with {@link LockMode#Exclusive}.
*
* <p>If the write LockMode is set after the read LockMode and the write LockMode is lower than the read LockMode,
* an {@code IllegalTxnFactoryException} will be thrown when a {@link TxnFactory} is created.
*
* <p>If the write LockMode is set before the read LockMode and the write LockMode is lower than the read LockMode,
* the write LockMode automatically is upgraded to that of the read LockMode. This makes setting the readLock
* mode less of a nuisance.
*
* @param lockMode the LockMode to set.
* @return the updated TxnFactoryBuilder.
* @throws NullPointerException if lockMode is null.
* @see TxnConfig#getWriteLockMode()
* @see LockMode
*/
TxnFactoryBuilder setWriteLockMode(LockMode lockMode);
/**
* Adds a permanent {@link Txn} {@link org.multiverse.api.lifecycle.TxnListener}. All permanent listeners are always executed after all normal
* listeners are executed. If the same listener is added multiple times, it will be executed multiple times.
*
* <p>This method is very useful for integrating Multiverse in other JVM based environments because with this
* approach you have a callback when transaction aborts/commit and can add your own logic. See the
* {@link org.multiverse.api.lifecycle.TxnListener} for more information about normal vs permanent listeners.
*
* @param listener the permanent listener to add.
* @return the updated TxnFactoryBuilder.
* @throws NullPointerException if listener is null.
* @see TxnConfig#getPermanentListeners()
*/
TxnFactoryBuilder addPermanentListener(TxnListener listener);
/**
* Sets the {@link Txn} {@link TraceLevel}. With tracing it is possible to see what is happening inside a transaction.
*
* @param traceLevel the new traceLevel.
* @return the updated TxnFactoryBuilder.
* @throws NullPointerException if traceLevel is null.
* @see TxnConfig#getTraceLevel()
* @see TraceLevel
*/
TxnFactoryBuilder setTraceLevel(TraceLevel traceLevel);
/**
* Sets the timeout (the maximum time a {@link Txn} is allowed to block. Long.MAX_VALUE indicates that an
* unbound timeout should be used.
*
* @param timeoutNs the timeout specified in nano seconds
* @return the updated TxnFactoryBuilder
* @see TxnConfig#getTimeoutNs()
* @see Txn#getRemainingTimeoutNs()
*/
TxnFactoryBuilder setTimeoutNs(long timeoutNs);
/**
* Sets if the {@link Txn} can be interrupted while doing blocking operations.
*
* @param interruptible if the transaction can be interrupted while doing blocking operations.
* @return the updated TxnFactoryBuilder
* @see TxnConfig#isInterruptible()
*/
TxnFactoryBuilder setInterruptible(boolean interruptible);
/**
* Sets the {@link Txn} {@link BackoffPolicy}. Policy is used to backoff when a transaction conflicts with another {@link Txn}.
* See the {@link BackoffPolicy} for more information.
*
* @param backoffPolicy the backoff policy to use.
* @return the updated TxnFactoryBuilder
* @throws NullPointerException if backoffPolicy is null.
* @see TxnConfig#getBackoffPolicy()
*/
TxnFactoryBuilder setBackoffPolicy(BackoffPolicy backoffPolicy);
/**
* Sets if the {@link Txn} dirty check is enabled. Dirty check is that something only needs to be written,
* if there really is a change (else it will be interpreted as a read). If it is disabled, it will always write, and
* this could prevent the aba isolation anomaly, but causes more conflicts so more contention. In most cases enabling
* it is the best option.
*
* @param dirtyCheckEnabled true if dirty check should be executed, false otherwise.
* @return the updated TxnFactoryBuilder.
* @see TxnConfig#isDirtyCheckEnabled()
*/
TxnFactoryBuilder setDirtyCheckEnabled(boolean dirtyCheckEnabled);
/**
* Sets the maximum number of spins that are allowed when a {@link Txn} can't be read/written/locked
* because it is locked by another transaction.
*
* <p>Setting the value to a very high value, could lead to more an increased chance of a live locking.
*
* @param spinCount the maximum number of spins
* @return the updated TxnFactoryBuilder.
* @throws IllegalArgumentException if spinCount smaller than 0.
* @see TxnConfig#getSpinCount()
*/
TxnFactoryBuilder setSpinCount(int spinCount);
/**
* Sets the readonly property on a {@link Txn}. If a transaction is configured as readonly, no write operations
* (also no construction of new transactional objects making use of that transaction) is allowed
*
* @param readonly true if the transaction should be readonly, false otherwise.
* @return the updated TxnFactoryBuilder
* @see TxnConfig#isReadonly()
*/
TxnFactoryBuilder setReadonly(boolean readonly);
/**
* Sets if the {@link Txn} should automatically track all reads that have been done. This is needed for blocking
* operations, but also for other features like writeskew detection.
*
* <p>Tracking reads puts more pressure on the transaction since it needs to store all reads, but it reduces the chance
* of read conflicts, since once read from main memory, it can be retrieved from the transaction.
*
* The transaction is free to track reads even though this property is disabled.
*
* @param enabled true if read tracking enabled, false otherwise.
* @return the updated TxnFactoryBuilder
* @see TxnConfig#isReadTrackingEnabled()
*/
TxnFactoryBuilder setReadTrackingEnabled(boolean enabled);
/**
* With the speculative configuration enabled, the {@link Stm} is allowed to determine optimal settings for
* a {@link Txn}.
*
* <p>Some behavior like readonly or the need for tracking reads can be determined runtime. The system can start with
* a readonly non readtracking transaction and upgrade to an update or a read tracking once a write or retry
* happens.
*
* <p>It depends on the {@link Stm} implementation on which properties it is going to speculate.
*
* <p>Enabling it can cause a few unexpected 'retries' of transactions, but it can seriously improve performance.
*
* @param speculative indicates if speculative configuration should be enabled.
* @return the updated TxnFactoryBuilder
* @see TxnConfig#isSpeculative()
*/
TxnFactoryBuilder setSpeculative(boolean speculative);
/**
* Sets the the maximum count a {@link Txn} can be retried. The default is 1000. Setting it to a very low value
* could mean that a transaction can't complete. Setting it to a very high value could lead to live-locking.
*
* <p>If the speculative configuration mechanism is enabled ({@link #setSpeculative(boolean)}), a few retries
* are done in the beginning to figure out the best settings.
*
* @param maxRetries the maximum number of times a transaction can be tried.
* @return the updated TxnFactoryBuilder
* @throws IllegalArgumentException if maxRetries smaller than 0.
* @see TxnConfig#getMaxRetries()
*/
TxnFactoryBuilder setMaxRetries(int maxRetries);
/**
* Sets the {@link IsolationLevel} on the {@link Txn}.
*
* <p>The {@link Txn} is free to upgraded to a higher {@link IsolationLevel}. This is essentially the same
* behavior you get when Oracle is used, where a read uncommitted is upgraded to a read committed and a repeatable
* read is upgraded to the Oracle version of serialized (so with the writeskew problem still there).
*
* @param isolationLevel the new IsolationLevel
* @return the updated TxnFactoryBuilder
* @throws NullPointerException if isolationLevel is null.
* @see TxnConfig#getIsolationLevel()
* @see IsolationLevel
*/
TxnFactoryBuilder setIsolationLevel(IsolationLevel isolationLevel);
/**
* Sets if the {@link Txn} is allowed to do an explicit retry (needed for a blocking operation). One use case
* for disallowing it, it when the transaction is used inside an actor, and you don't want that inside the logic
* executed by the agent a blocking operations is done (e.g. taking an item of a blocking queue).
*
* @param blockingAllowed true if explicit retry is allowed, false otherwise.
* @return the updated TxnFactoryBuilder
*/
TxnFactoryBuilder setBlockingAllowed(boolean blockingAllowed);
/**
* Builds a new {@link TxnFactory}.
*
* @return the build TxnFactory.
* @throws org.multiverse.api.exceptions.IllegalTxnFactoryException
* if the TxnFactory could not be build
* because the configuration was not correct.
*/
TxnFactory newTransactionFactory();
/**
* Builds a new {@link TxnExecutor} optimized for executing transactions created by this TxnFactoryBuilder.
*
* @return the created TxnExecutor.
* @throws org.multiverse.api.exceptions.IllegalTxnFactoryException
* if the TxnFactory could not be build
* because the configuration was not correct.
*/
TxnExecutor newTxnExecutor();
}