package org.corfudb.runtime.object.transactions;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.stream.Collectors;
/** A class which allows access to transactional contexts, which manage
* transactions. The static methods of this class provide access to the
* thread's transaction stack, which is a stack of transaction contexts
* active for a particular thread.
*
* Created by mwei on 1/11/16.
*/
@Slf4j
public class TransactionalContext {
/** A thread local stack containing all transaction contexts
* for a given thread.
*/
private static final ThreadLocal<Deque<AbstractTransactionalContext>>
threadTransactionStack = ThreadLocal.withInitial(
LinkedList<AbstractTransactionalContext>::new);
/** Whether or not the current thread is in a nested transaction.
*
* @return True, if the current thread is in a nested transaction.
*/
public static boolean isInNestedTransaction() {return threadTransactionStack.get().size() > 1;}
/**
* Returns the transaction stack for the calling thread.
*
* @return The transaction stack for the calling thread.
*/
public static Deque<AbstractTransactionalContext> getTransactionStack() {
return threadTransactionStack.get();
}
/**
* Returns the current transactional context for the calling thread.
*
* @return The current transactional context for the calling thread.
*/
public static AbstractTransactionalContext getCurrentContext() {
return getTransactionStack().peekFirst();
}
/**
* Returns the last transactional context (parent/root) for the calling thread.
*
* @return The last transactional context for the calling thread.
*/
public static AbstractTransactionalContext getRootContext() {
return getTransactionStack().peekLast();
}
/**
* Returns whether or not the calling thread is in a transaction.
*
* @return True, if the calling thread is in a transaction.
* False otherwise.
*/
public static boolean isInTransaction() {
return getTransactionStack().peekFirst() != null;
}
/** Add a new transactional context to the thread's transaction stack.
*
* @param context The context to add to the transaction stack.
* @return The context which was added to the transaction stack.
*/
public static AbstractTransactionalContext newContext(AbstractTransactionalContext context) {
log.debug("TX begin[{}]", context);
getTransactionStack().addFirst(context);
return context;
}
/** Remove the most recent transaction context from the transaction stack.
*
* @return The context which was removed from the transaction stack.
*/
public static AbstractTransactionalContext removeContext() {
AbstractTransactionalContext r = getTransactionStack().pollFirst();
if (getTransactionStack().isEmpty()) {
synchronized (getTransactionStack())
{
getTransactionStack().notifyAll();
}
}
return r;
}
/**
* Get the transaction stack as a list.
* @return The transaction stack as a list.
*/
public static List<AbstractTransactionalContext> getTransactionStackAsList() {
List<AbstractTransactionalContext> listReverse =
getTransactionStack().stream().collect(Collectors.toList());
Collections.reverse(listReverse);
return listReverse;
}
}