package org.juxtapose.streamline.stm; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.juxtapose.streamline.producer.ISTMEntryKey; import org.juxtapose.streamline.producer.ISTMEntryProducer; import org.juxtapose.streamline.tools.DataConstants; import org.juxtapose.streamline.tools.Preconditions; import org.juxtapose.streamline.tools.STMAssertionUtil; import org.juxtapose.streamline.util.Status; import org.juxtapose.streamline.util.data.DataType; import org.juxtapose.streamline.util.data.DataTypeRef; import org.juxtapose.streamline.util.data.DataTypeStatus; import com.trifork.clj_ds.IPersistentMap; /** * @author Pontus J�rgne * Jan 29, 2012 * Copyright (c) Pontus J�rgne. All rights reserved * * Transaction represents a set of instructions that will take a published data from � * one state to another in an atomic operation. * The commit method will be implemented by the programmer to create the new state instructions * Transaction should only exist in a single thread context * The data key will be write -locked or CAS referenced during execute * * Transactions only live inside one thread and should always be declared anonymous. */ public abstract class STMTransaction { private final ISTMEntryKey entryKey; private final boolean isFullUpdate; private IPersistentMap<String, DataType<?>> m_stateInstruction; private final Set<String> m_deltaState = new HashSet<String>(); private final Map<String, DataTypeRef> addedDataReferences; private final List<String> removedDataReferences; private ISTMEntryProducer m_producer = null; private Status status; private boolean disposed = false; private boolean m_inCompleteStateTransition = false; private boolean containesReferenceInstructions = false; /** * @param inDataKey */ public STMTransaction( ISTMEntryKey inEntryKey, int inAddedRefenrence, int inRemovedReferences, boolean inIsFullUpdate ) { entryKey = Preconditions.notNull( inEntryKey ); isFullUpdate = inIsFullUpdate; addedDataReferences = inAddedRefenrence == 0 ? null : new HashMap<String, DataTypeRef>( inAddedRefenrence ); removedDataReferences = inRemovedReferences == 0 ? null : new ArrayList<String>( inRemovedReferences ); } public STMTransaction( ISTMEntryKey inEntryKey, boolean inIsFullUpdate ) { entryKey = Preconditions.notNull( inEntryKey ); isFullUpdate = inIsFullUpdate; addedDataReferences = new HashMap<String, DataTypeRef>( 8 ); removedDataReferences = new ArrayList<String>( 8 ); } /** * @param inDataKey * @param inProducer */ public STMTransaction( ISTMEntryKey inEntryKey, ISTMEntryProducer inProducer, int inAddedRefenrence, int inRemovedReferences, boolean inIsFullUpdate ) { entryKey = Preconditions.notNull( inEntryKey ); m_producer = inProducer; isFullUpdate = inIsFullUpdate; addedDataReferences = inAddedRefenrence == 0 ? null : new HashMap<String, DataTypeRef>( inAddedRefenrence ); removedDataReferences = inRemovedReferences == 0 ? null : new ArrayList<String>( inRemovedReferences ); } /** * @param inDataKey * @param inProducer */ public STMTransaction( ISTMEntryKey inDataKey, ISTMEntryProducer inProducer, boolean inIsFullUpdate ) { entryKey = Preconditions.notNull( inDataKey ); m_producer = inProducer; isFullUpdate = inIsFullUpdate; addedDataReferences = new HashMap<String, DataTypeRef>( 8 ); removedDataReferences = new ArrayList<String>( 8 ); } /** * @param inMap */ public void putInitDataState( IPersistentMap<String, DataType<?>> inMap, Status inStatus ) { m_stateInstruction = inMap; status = inStatus; } public abstract void execute(); /** * @param inKey * @param inData */ public void putValue( String inKey, DataType<?> inData ) { assert STMAssertionUtil.validateTransactionStack() : "Transaction.addValue was not from called from within a STM commit as required"; assert !( inData instanceof DataTypeRef ) : "Reference values should be added via addReference method"; m_stateInstruction = m_stateInstruction.assoc( inKey, inData ); m_deltaState.add(inKey); } /** * @param inKey * @param inDataTypeRef */ public void updateReferenceValue( String inKey, DataTypeRef inDataTypeRef ) { assert STMAssertionUtil.validateTransactionStack() : "Transaction.updateReferenceValue was not from called from within a STM commit as required"; assert m_stateInstruction.valAt( inKey) != null : "Tried to update non existing Reference"; assert m_stateInstruction.valAt( inKey ) instanceof DataTypeRef : "Tried to update Reference that was not of reference type"; m_stateInstruction = m_stateInstruction.assoc( inKey, inDataTypeRef ); m_deltaState.add(inKey); } /** * @param inKey * @param inDataRef */ public void addReference( String inKey, DataTypeRef inDataRef ) { assert STMAssertionUtil.validateTransactionStack() : "Transaction.addValue was not from called from within a STM commit as required"; addedDataReferences.put( inKey, inDataRef ); m_stateInstruction = m_stateInstruction.assoc( inKey, inDataRef ); m_deltaState.add(inKey); containesReferenceInstructions = true; } /** * @param inKey * @throws Exception */ public void removeValue( String inKey )throws Exception { assert STMAssertionUtil.validateTransactionStack() : "Transaction.removeValue was not from called from within a STM commit as required"; assert m_deltaState.contains( inKey ) : "Transaction may not add and remove the same field value: "+inKey; DataType<?> removedData = m_stateInstruction.valAt( inKey ); m_stateInstruction = m_stateInstruction.without( inKey ); m_deltaState.add(inKey); if( removedData instanceof DataTypeRef ) { removedDataReferences.add( inKey ); containesReferenceInstructions = true; } } /** * @return */ protected IPersistentMap<String, DataType<?>> getStateInstruction() { return m_stateInstruction; } /** * @return */ protected Set<String> getDeltaState() { return m_deltaState; } /** * @return */ protected ISTMEntryKey getDataKey() { return entryKey; } public ISTMEntryProducer producedBy() { return m_producer; } /** * @return */ public Map<String, DataTypeRef> getAddedReferences() { return addedDataReferences; } /** * @return */ public List<String> getRemovedReferences() { return removedDataReferences; } /** * @param inStatus */ public void setStatus( Status inStatus ) { putValue( DataConstants.FIELD_STATUS, new DataTypeStatus( inStatus ) ); status = inStatus; } public Status getStatus() { return status; } public DataType<?> get( String inFieldKey ) { return m_stateInstruction.valAt( inFieldKey ); } public void dispose() { disposed = true; } public boolean isDisposed() { return disposed == true; } public void setIncompleteStateTransition( ) { m_inCompleteStateTransition = true; } public boolean isCompleteStateTransition( ) { return !m_inCompleteStateTransition; } public boolean containesReferenceInstructions() { return containesReferenceInstructions; } public boolean isFullUpdate() { return isFullUpdate; } }