private static void WaitOnReadset(Transaction me, ReadSet readSet, int readstamp) { #if DEBUG Console.WriteLine("ENTERED WAIT ON RETRY: " + me.ID); #endif if (readSet.Count == 0) { throw new STMInvalidRetryException(); } var waiton = new WaitHandle[readSet.Count()]; var i = 0; foreach (var item in readSet) { waiton[i] = item.Key.RegisterWaitHandle(); i++; } if (!readSet.Validate(me, readstamp)) { return; } #if DEBUG Console.WriteLine("WAIT ON RETRY: " + me.ID); #endif WaitHandle.WaitAny(waiton); #if DEBUG Console.WriteLine("WAIT ON RETRY: " + me.ID); #endif }
public void Merge(ReadSet other) { foreach (var kvpair in other) { if (!_lockObjects.ContainsKey(kvpair.Key)) { _lockObjects[kvpair.Key] = kvpair.Value; } } }
private static T AtomicInternal <T>(IList <Func <T> > stmActions) { Debug.Assert(stmActions.Count > 0); var result = default(T); var index = 0; var overAllReadSet = new ReadSet(); var ovarAllReadstamp = -1; var nrAttempts = 0; while (true) { var stmAction = stmActions[index]; //Start new or nested transaction var prevTransaction = Transaction.LocalTransaction; var me = prevTransaction.Status == TransactionStatus.Active ? Transaction.StartNestedTransaction(prevTransaction) : Transaction.StartTransaction(); if (index == 0) { ovarAllReadstamp = me.ReadStamp; } try { //Execute transaction body result = stmAction(); if (me.Commit()) { return(result); } } catch (STMAbortException) { //Skips straight to abort a reexecute } catch (STMRetryException) { index = HandleRetry(stmActions, me, index, overAllReadSet, ovarAllReadstamp); } catch (Exception) //Catch non stm related exceptions which occurs in transactions { //Throw exception of transaction can commit //Else abort and rerun transaction if (me.Commit()) { throw; } } nrAttempts++; me.Abort(); //If the transaction is nested restore the parent as current transaction before retrying if (me.IsNested) { Transaction.LocalTransaction = me.Parent; } if (nrAttempts == MAX_ATTEMPTS) { throw new STMMaxAttemptException("Fatal error: max attempts reached"); } } }
private static void WaitOnReadset(Transaction me, ReadSet readSet) { WaitOnReadset(me, readSet, me.ReadStamp); }
private static int HandleRetry <T>(IList <Func <T> > stmActions, Transaction me, int index, ReadSet overAllReadSet, int originalReadstamp) { if (stmActions.Count == 1) //Optimized for when there are no orelse blocks { WaitOnReadset(me, me.ReadSet); } else if (stmActions.Count == index + 1) //Final orelse block { overAllReadSet.Merge(me.ReadSet); WaitOnReadset(me, overAllReadSet, originalReadstamp); index = 0; } else //Non final atomic or orelse blocks { #if DEBUG Console.WriteLine("Transaction: " + me.ID + " ORELSE jump"); #endif overAllReadSet.Merge(me.ReadSet); index++; } return(index); }