/** * Copyright 2016, Xiaomi. * All rights reserved. * Author: xiajun@xiaomi.com */ package com.xiaomi.infra.galaxy.lcs.log.core.transaction; import java.util.concurrent.atomic.AtomicReference; public abstract class Transaction<T> { private enum TransactionState { /** * NEW state */ NEW, /** * Init */ INIT, /** * You are ready for transaction; */ READY, /** * You are already in transaction state; */ STARTED, /** * You have finished transaction, that is you can call startTransaction; */ STOPED, /** * Transaction is in close, that is you can not call startTransaction anymore. */ CLOSED, } private AtomicReference<TransactionState> transactionState; private final Object transactionLock; protected Transaction() { transactionState = new AtomicReference<TransactionState>(TransactionState.NEW); transactionLock = new Object(); } public void initTransaction() { synchronized (transactionLock) { if (!transactionState.compareAndSet(TransactionState.NEW, TransactionState.INIT)) { throw new RuntimeException("You should first call init for transaction"); } doInitTransaction(); } } public void startTransaction() { synchronized (transactionLock) { if (!transactionState.compareAndSet(TransactionState.STOPED, TransactionState.READY) && !transactionState.compareAndSet(TransactionState.INIT, TransactionState.READY)) { throw new RuntimeException("We are already in transaction state"); } doStartTransaction(); } } public T take() { synchronized (transactionLock) { if (!transactionState.compareAndSet(TransactionState.READY, TransactionState.STARTED)) { throw new RuntimeException("We are no in transaction state"); } return doTake(); } } public void commitTransaction() { synchronized (transactionLock) { if (!transactionState.compareAndSet(TransactionState.STARTED, TransactionState.STOPED)) { throw new RuntimeException("We are no in transaction state"); } doCommitTransaction(); } } public void rollbackTransaction() { synchronized (transactionLock) { if (!transactionState.compareAndSet(TransactionState.STARTED, TransactionState.STOPED)) { throw new RuntimeException("We are no in transaction state"); } doRollbackTransaction(); } } public void closeTransaction() { synchronized (transactionLock) { if (!transactionState.compareAndSet(TransactionState.STOPED, TransactionState.CLOSED) && !transactionState.compareAndSet(TransactionState.INIT, TransactionState.CLOSED)) { throw new RuntimeException("We are in transaction state, can not close this transaction"); } doCloseTransaction(); } } abstract protected void doInitTransaction(); abstract protected void doStartTransaction(); abstract protected T doTake(); abstract protected void doCommitTransaction(); abstract protected void doRollbackTransaction(); abstract protected void doCloseTransaction(); }