package org.multiverse.stms.gamma;
import org.multiverse.api.*;
import org.multiverse.api.collections.TxnCollectionsFactory;
import org.multiverse.api.lifecycle.TxnListener;
import org.multiverse.collections.NaiveTxnCollectionFactory;
import org.multiverse.stms.gamma.transactionalobjects.*;
import org.multiverse.stms.gamma.transactions.*;
import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxn;
import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn;
import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn;
import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn;
import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn;
import static org.multiverse.stms.gamma.transactions.ThreadLocalGammaTxnPool.getThreadLocalGammaTxnPool;
@SuppressWarnings({"ClassWithTooManyFields"})
public final class GammaStm implements Stm {
/**
* Creates a GammaStm implementation optimized for speed. This method probably will be invoked
* by the {@link GlobalStmInstance}.
*
* @return the created GammaStm.
*/
@SuppressWarnings({"UnusedDeclaration"})
public static GammaStm createFast() {
return new GammaStm();
}
public final int defaultMaxRetries;
public final int spinCount;
public final BackoffPolicy defaultBackoffPolicy;
public final GlobalConflictCounter globalConflictCounter = new GlobalConflictCounter();
public final GammaTxnRefFactoryImpl defaultRefFactory = new GammaTxnRefFactoryImpl();
public final GammaTxnRefFactoryBuilder refFactoryBuilder = new GammaTxnRefFactoryBuilderImpl();
public final GammaTxnExecutor defaultxnExecutor;
public final GammaTxnConfig defaultConfig;
public final NaiveTxnCollectionFactory defaultTransactionalCollectionFactory
= new NaiveTxnCollectionFactory(this);
public final int readBiasedThreshold;
public final GammaOrElseBlock defaultOrElseBlock = new GammaOrElseBlock();
public GammaStm() {
this(new GammaStmConfig());
}
public GammaStm(GammaStmConfig config) {
config.validate();
this.defaultMaxRetries = config.maxRetries;
this.spinCount = config.spinCount;
this.defaultBackoffPolicy = config.backoffPolicy;
this.defaultConfig = new GammaTxnConfig(this, config)
.setSpinCount(spinCount);
this.defaultxnExecutor = newTxnFactoryBuilder()
.setSpeculative(false)
.newTxnExecutor();
this.readBiasedThreshold = config.readBiasedThreshold;
}
@Override
public final GammaTxn newDefaultTxn() {
return new FatVariableLengthGammaTxn(this);
}
@Override
public final GammaTxnExecutor getDefaultTxnExecutor() {
return defaultxnExecutor;
}
@Override
public final GammaOrElseBlock newOrElseBlock() {
return defaultOrElseBlock;
}
public final GlobalConflictCounter getGlobalConflictCounter() {
return globalConflictCounter;
}
private final class GammaTxnFactoryBuilderImpl implements GammaTxnFactoryBuilder {
private final GammaTxnConfig config;
GammaTxnFactoryBuilderImpl(final GammaTxnConfig config) {
this.config = config;
}
@Override
public final GammaTxnFactoryBuilder setFat() {
if (config.isFat) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setFat());
}
@Override
public final GammaTxnConfig getConfig() {
return config;
}
@Override
public GammaTxnFactoryBuilder addPermanentListener(final TxnListener listener) {
return new GammaTxnFactoryBuilderImpl(config.addPermanentListener(listener));
}
@Override
public final GammaTxnFactoryBuilder setControlFlowErrorsReused(final boolean reused) {
if (config.controlFlowErrorsReused = reused) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setControlFlowErrorsReused(reused));
}
@Override
public final GammaTxnFactoryBuilder setReadLockMode(final LockMode lockMode) {
if (config.readLockMode == lockMode) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setReadLockMode(lockMode));
}
@Override
public final GammaTxnFactoryBuilder setWriteLockMode(final LockMode lockMode) {
if (config.writeLockMode == lockMode) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setWriteLockMode(lockMode));
}
@Override
public final GammaTxnFactoryBuilder setFamilyName(final String familyName) {
if (config.familyName.equals(familyName)) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setFamilyName(familyName));
}
@Override
public final GammaTxnFactoryBuilder setPropagationLevel(final PropagationLevel level) {
if (level == config.propagationLevel) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setPropagationLevel(level));
}
@Override
public final GammaTxnFactoryBuilder setBlockingAllowed(final boolean blockingAllowed) {
if (blockingAllowed == config.blockingAllowed) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setBlockingAllowed(blockingAllowed));
}
@Override
public final GammaTxnFactoryBuilder setIsolationLevel(final IsolationLevel isolationLevel) {
if (isolationLevel == config.isolationLevel) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setIsolationLevel(isolationLevel));
}
@Override
public final GammaTxnFactoryBuilder setTraceLevel(final TraceLevel traceLevel) {
if (traceLevel == config.traceLevel) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setTraceLevel(traceLevel));
}
@Override
public final GammaTxnFactoryBuilder setTimeoutNs(final long timeoutNs) {
if (timeoutNs == config.timeoutNs) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setTimeoutNs(timeoutNs));
}
@Override
public final GammaTxnFactoryBuilder setInterruptible(final boolean interruptible) {
if (interruptible == config.interruptible) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setInterruptible(interruptible));
}
@Override
public final GammaTxnFactoryBuilder setBackoffPolicy(final BackoffPolicy backoffPolicy) {
//noinspection ObjectEquality
if (backoffPolicy == config.backoffPolicy) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setBackoffPolicy(backoffPolicy));
}
@Override
public final GammaTxnFactoryBuilder setDirtyCheckEnabled(final boolean dirtyCheckEnabled) {
if (dirtyCheckEnabled == config.dirtyCheck) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setDirtyCheckEnabled(dirtyCheckEnabled));
}
@Override
public final GammaTxnFactoryBuilder setSpinCount(final int spinCount) {
if (spinCount == config.spinCount) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setSpinCount(spinCount));
}
@Override
public final GammaTxnFactoryBuilder setSpeculative(final boolean enabled) {
if (enabled == config.speculative) {
return this;
}
return new GammaTxnFactoryBuilderImpl(
config.setSpeculative(enabled));
}
@Override
public final GammaTxnFactoryBuilder setReadonly(final boolean readonly) {
if (readonly == config.readonly) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setReadonly(readonly));
}
@Override
public final GammaTxnFactoryBuilder setReadTrackingEnabled(final boolean enabled) {
if (enabled == config.trackReads) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setReadTrackingEnabled(enabled));
}
@Override
public final GammaTxnFactoryBuilder setMaxRetries(final int maxRetries) {
if (maxRetries == config.maxRetries) {
return this;
}
return new GammaTxnFactoryBuilderImpl(config.setMaxRetries(maxRetries));
}
@Override
public final GammaTxnExecutor newTxnExecutor() {
config.init();
if (isLean()) {
return new LeanGammaTxnExecutor(newTransactionFactory());
} else {
return new FatGammaTxnExecutor(newTransactionFactory());
}
}
private boolean isLean() {
return config.propagationLevel == PropagationLevel.Requires;
}
@Override
public GammaTxnFactory newTransactionFactory() {
config.init();
if (config.isSpeculative()) {
return new SpeculativeGammaTxnFactory(config, this);
} else {
return new NonSpeculativeGammaTxnFactory(config,this);
}
}
}
@Override
public final GammaTxnRefFactory getDefaultRefFactory() {
return defaultRefFactory;
}
private final class GammaTxnRefFactoryImpl implements GammaTxnRefFactory {
@Override
public final <E> GammaTxnRef<E> newTxnRef(E value) {
return new GammaTxnRef<E>(GammaStm.this, value);
}
@Override
public final GammaTxnInteger newTxnInteger(int value) {
return new GammaTxnInteger(GammaStm.this, value);
}
@Override
public final GammaTxnBoolean newTxnBoolean(boolean value) {
return new GammaTxnBoolean(GammaStm.this, value);
}
@Override
public final GammaTxnDouble newTxnDouble(double value) {
return new GammaTxnDouble(GammaStm.this, value);
}
@Override
public final GammaTxnLong newTxnLong(long value) {
return new GammaTxnLong(GammaStm.this, value);
}
}
@Override
public final GammaTxnFactoryBuilder newTxnFactoryBuilder() {
final GammaTxnConfig config = new GammaTxnConfig(this);
return new GammaTxnFactoryBuilderImpl(config);
}
@Override
public final TxnCollectionsFactory getDefaultTxnCollectionFactory() {
return defaultTransactionalCollectionFactory;
}
@Override
public final GammaTxnRefFactoryBuilder getTxRefFactoryBuilder() {
return refFactoryBuilder;
}
private final class GammaTxnRefFactoryBuilderImpl implements GammaTxnRefFactoryBuilder {
@Override
public GammaTxnRefFactory build() {
return new GammaTxnRefFactoryImpl();
}
}
private static final class NonSpeculativeGammaTxnFactory implements GammaTxnFactory {
private final GammaTxnConfig config;
private final GammaTxnFactoryBuilder builder;
NonSpeculativeGammaTxnFactory(final GammaTxnConfig config, GammaTxnFactoryBuilder builder) {
this.config = config.init();
this.builder = builder;
}
@Override
public TxnFactoryBuilder getTxnFactoryBuilder() {
return builder;
}
@Override
public final GammaTxnConfig getConfig() {
return config;
}
@Override
public final GammaTxn newTxn() {
return newTransaction(getThreadLocalGammaTxnPool());
}
@Override
public final GammaTxn newTransaction(final GammaTxnPool pool) {
FatVariableLengthGammaTxn tx = pool.takeMap();
if (tx == null) {
tx = new FatVariableLengthGammaTxn(config);
} else {
tx.init(config);
}
return tx;
}
@Override
public final GammaTxn upgradeAfterSpeculativeFailure(final GammaTxn tailingTx, final GammaTxnPool pool) {
throw new UnsupportedOperationException();
}
}
private static final class SpeculativeGammaTxnFactory implements GammaTxnFactory {
private final GammaTxnConfig config;
private final GammaTxnFactoryBuilder builder;
SpeculativeGammaTxnFactory(final GammaTxnConfig config, GammaTxnFactoryBuilder builder) {
this.config = config.init();
this.builder = builder;
}
@Override
public GammaTxnFactoryBuilder getTxnFactoryBuilder() {
return builder;
}
@Override
public final GammaTxnConfig getConfig() {
return config;
}
@Override
public final GammaTxn newTxn() {
return newTransaction(getThreadLocalGammaTxnPool());
}
@Override
public final GammaTxn upgradeAfterSpeculativeFailure(final GammaTxn failingTx, final GammaTxnPool pool) {
final GammaTxn tx = newTransaction(pool);
tx.copyForSpeculativeFailure(failingTx);
return tx;
}
@Override
public final GammaTxn newTransaction(final GammaTxnPool pool) {
final SpeculativeGammaConfiguration speculativeConfiguration = config.speculativeConfiguration.get();
final int length = speculativeConfiguration.minimalLength;
if (length <= 1) {
if (speculativeConfiguration.fat) {
FatMonoGammaTxn tx = pool.takeFatMono();
if (tx == null) {
return new FatMonoGammaTxn(config);
}
tx.init(config);
return tx;
} else {
LeanMonoGammaTxn tx = pool.takeLeanMono();
if (tx == null) {
return new LeanMonoGammaTxn(config);
}
tx.init(config);
return tx;
}
} else if (length <= config.maxFixedLengthTransactionSize) {
if (speculativeConfiguration.fat) {
final FatFixedLengthGammaTxn tx = pool.takeFatFixedLength();
if (tx == null) {
return new FatFixedLengthGammaTxn(config);
}
tx.init(config);
return tx;
} else {
final LeanFixedLengthGammaTxn tx = pool.takeLeanFixedLength();
if (tx == null) {
return new LeanFixedLengthGammaTxn(config);
}
tx.init(config);
return tx;
}
} else {
final FatVariableLengthGammaTxn tx = pool.takeMap();
if (tx == null) {
return new FatVariableLengthGammaTxn(config);
}
tx.init(config);
return tx;
}
}
}
}