All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scalar.db.transaction.consensuscommit.ConsensusCommit Maven / Gradle / Ivy

Go to download

A universal transaction manager that achieves database-agnostic transactions and distributed transactions that span multiple databases

There is a newer version: 3.14.0
Show newest version
package com.scalar.db.transaction.consensuscommit;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.VisibleForTesting;
import com.scalar.db.api.Delete;
import com.scalar.db.api.Get;
import com.scalar.db.api.Mutation;
import com.scalar.db.api.Put;
import com.scalar.db.api.Result;
import com.scalar.db.api.Scan;
import com.scalar.db.api.Selection;
import com.scalar.db.common.AbstractDistributedTransaction;
import com.scalar.db.exception.storage.ExecutionException;
import com.scalar.db.exception.transaction.CommitException;
import com.scalar.db.exception.transaction.CrudException;
import com.scalar.db.exception.transaction.UnknownTransactionStatusException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;
import java.util.Optional;
import javax.annotation.concurrent.NotThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A transaction manager that implements a transaction protocol on the basis of two-phase commit on
 * the consensus of an underlying storage.
 *
 * 

When SERIALIZABLE is specified in {@link Isolation}, it makes schedule strict serializable or * serializable depending on underlying database operations. If a transaction runs on linearizable * operations, it makes it strict serializable. If a transaction runs on serializable operations, it * makes it serializable. * *

When SNAPSHOT is specified in {@link Isolation}, it makes it a weaker variant of snapshot * isolation (SI). This snapshot isolation could cause read skew anomalies in addition to write skew * and read-only anomalies, which are known to be usual SI anomalies. */ @NotThreadSafe public class ConsensusCommit extends AbstractDistributedTransaction { private static final Logger logger = LoggerFactory.getLogger(ConsensusCommit.class); private final CrudHandler crud; private final CommitHandler commit; private final RecoveryHandler recovery; private final ConsensusCommitMutationOperationChecker mutationOperationChecker; private Runnable beforeRecoveryHook; @SuppressFBWarnings("EI_EXPOSE_REP2") public ConsensusCommit( CrudHandler crud, CommitHandler commit, RecoveryHandler recovery, ConsensusCommitMutationOperationChecker mutationOperationChecker) { this.crud = checkNotNull(crud); this.commit = checkNotNull(commit); this.recovery = checkNotNull(recovery); this.mutationOperationChecker = mutationOperationChecker; this.beforeRecoveryHook = () -> {}; } @Override public String getId() { return crud.getSnapshot().getId(); } @Override public Optional get(Get get) throws CrudException { get = copyAndSetTargetToIfNot(get); try { return crud.get(get); } catch (UncommittedRecordException e) { lazyRecovery(get, e.getResults()); throw e; } } @Override public List scan(Scan scan) throws CrudException { scan = copyAndSetTargetToIfNot(scan); try { return crud.scan(scan); } catch (UncommittedRecordException e) { lazyRecovery(scan, e.getResults()); throw e; } } @Override public void put(Put put) throws CrudException { put = copyAndSetTargetToIfNot(put); checkMutation(put); crud.put(put); } @Override public void put(List puts) throws CrudException { checkArgument(puts.size() != 0); for (Put p : puts) { put(p); } } @Override public void delete(Delete delete) throws CrudException { delete = copyAndSetTargetToIfNot(delete); checkMutation(delete); crud.delete(delete); } @Override public void delete(List deletes) throws CrudException { checkArgument(deletes.size() != 0); for (Delete d : deletes) { delete(d); } } @Override public void mutate(List mutations) throws CrudException { checkArgument(mutations.size() != 0); for (Mutation m : mutations) { if (m instanceof Put) { put((Put) m); } else if (m instanceof Delete) { delete((Delete) m); } } } @Override public void commit() throws CommitException, UnknownTransactionStatusException { commit.commit(crud.getSnapshot()); } @Override public void rollback() { // do nothing for this implementation } @VisibleForTesting CrudHandler getCrudHandler() { return crud; } @VisibleForTesting CommitHandler getCommitHandler() { return commit; } @VisibleForTesting RecoveryHandler getRecoveryHandler() { return recovery; } @VisibleForTesting void setBeforeRecoveryHook(Runnable beforeRecoveryHook) { this.beforeRecoveryHook = beforeRecoveryHook; } private void lazyRecovery(Selection selection, List results) { logger.debug("recover uncommitted records: {}", results); beforeRecoveryHook.run(); results.forEach(r -> recovery.recover(selection, r)); } private void checkMutation(Mutation mutation) throws CrudException { try { mutationOperationChecker.check(mutation); } catch (ExecutionException e) { throw new CrudException("Checking the operation failed", e, getId()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy