public void ExceptionPassedOn() { var variable = new TV<int>(); TransactionManager.Run(() => { variable.Value = 42; throw new InvalidCastException("exception thrown inside transaction"); }); }
public void HostChangesAreVisible() { var variable = new TV<int>(0); int actual = TransactionManager.Run(() => { variable.Value = 42; return TransactionManager.Run(() => { return variable.Value; }); }); Assert.AreEqual(42, actual); }
public void BankAccounts() { var vars = new TV<long>[]{ new TV<long>(), new TV<long>(), new TV<long>(), new TV<long>() }; Random random = new Random(); int threadCount = 20; Thread[] threads = new Thread[threadCount]; for (int t = 0; t < threadCount; t++) threads[t] = new Thread( (object r) => { Random rand = (Random)r; for (int i = 0; i < 1E3; i++) { int i1 = 0; int i2 = 0; while (i1 == i2) { i1 = rand.Next(4); i2 = rand.Next(4); } int value = rand.Next(10); TransactionManager.Run(() => { long randVar1Start = vars[i1].Value; long randVar2Start = vars[i2].Value; long randVar1After = randVar1Start + value; long randVar2After = randVar2Start - value; vars[i1].Value = randVar1After; vars[i2].Value = randVar2After; return 0; }); } } ); foreach (var t in threads) t.Start(new Random(random.Next())); foreach (var t in threads) t.Join(); long sum = TransactionManager.Run(() => { return vars.Select(v => v.Value).Sum(); }); Assert.AreEqual(0, sum); }
public void WriteRead() { var variable = new TV<int>(); int actual = TransactionManager.Run(() => { variable.Value = 42; return variable.Value; }); Assert.AreEqual(42, actual); }
public void TransactionCloses() { var variable = new TV<int>(42); TransactionManager.Run(() => variable.Value); Assert.IsFalse(TransactionManager.TransactionRunning); }
public void TransactionRunningTrue() { var variable = new TV<int>(42); bool wasRunningInTransaction = TransactionManager.Run(() => { return TransactionManager.TransactionRunning; }); Assert.IsTrue(wasRunningInTransaction); }
public void ReadWithoutTransaction() { var variable = new TV<int>(42); int dummy = variable.Value; }
public void RollbackOnException() { var variable = new TV<int>(); try { TransactionManager.Run(() => { variable.Value = 42; throw new Exception("exception thrown inside transaction"); }); } catch (Exception) { } int actual = TransactionManager.Run(() => variable.Value); Assert.AreEqual(0, actual); }
public void RWRWWrite() { var variable = new TV<int>(0); TransactionManager.Run(() => { TransactionManager.Run(() => { variable.Value = 42; }); }); int actual = TransactionManager.Run(() => variable.Value); Assert.AreEqual(42, actual); }
public void ReadWriteWithinReadOnlyWithinReadWrite() { var variable = new TV<int>(42); TransactionManager.Run(() => { var actual = TransactionManager.RunReadOnly(() => { return TransactionManager.Run(() => { return variable.Value; }); }); }); }
public void RollbackedChangesAreInvisible() { var variable = new TV<int>(0); int actual = TransactionManager.Run(() => { try { TransactionManager.Run(() => { variable.Value = 42; throw new InvalidCastException("within nested transaction"); }); } catch (InvalidCastException) { } return variable.Value; }); Assert.AreEqual(0, actual); }
/// <summary> /// Reads the value of a variable. /// </summary> /// <param name="variable">Variable to read from.</param> /// <returns>Value of the variable.</returns> /// <exception cref="OutsideOfTransactionException">Thrown if no transaction is running.</exception> /// <exception cref="ConflictException">Thrown if a conflict is detected. /// The transaction and all its host transactions must be roll-backed immediately. The outermost transaction /// may then be restarted. /// </exception> /// <remarks> /// ACID properties are guarnateed. /// </remarks> public object Read(TV variable) { if (_nestedTransactions <= 0) throw new OutsideOfTransactionException(ExceptionMessages.InternalError); // Read the variable, ensure that it is not changed or locked by spinning. object value; long preVLock; long postVLock; do { preVLock = Interlocked.Read(ref variable.__vLock); value = variable.__Value; postVLock = Interlocked.Read(ref variable.__vLock); } while (preVLock != postVLock || TransactionManager.IsLocked(preVLock)); // abort if another thread has written to it since our transaction started if (preVLock > _readVersion) throw new ConflictException(); return value; }
public void ValidationSuccess() { var variable = new TV<int>(0); variable.Validation += (sender, e) => { }; TransactionManager.Run(() => { variable.Value = 1; }); int actual = TransactionManager.Run(() => variable.Value); Assert.AreEqual(1, actual); }
public void WriteWithinNestedReadOnly() { var variable = new TV<int>(42); TransactionManager.Run(() => { return TransactionManager.RunReadOnly(() => { variable.Value = 42; return 0; }); }); }
public void ValidationInTransaction() { var variable = new TV<int>(0); variable.Validation += (sender, e) => { Assert.IsTrue(TransactionManager.TransactionRunning); }; TransactionManager.Run(() => { variable.Value = 1; }); }
public void ValidationFailureRollback() { var variable = new TV<int>(0); variable.Validation += (sender, e) => e.Cancel = true; try { TransactionManager.Run(() => { variable.Value = 1; }); } catch { } int actual = TransactionManager.Run(() => variable.Value); Assert.AreEqual(0, actual); }
public void ValidationFails() { var variable = new TV<int>(0); variable.Validation += (sender, e) => e.Cancel = true; TransactionManager.Run(() => { variable.Value = 1; }); }
public void WriteTwo() { var variableA = new TV<int>(); var variableB = new TV<int>(); TransactionManager.Run(() => { variableA.Value = 42; variableB.Value = 43; }); int actualA = TransactionManager.Run(() => variableA.Value); int actualB = TransactionManager.Run(() => variableB.Value); Assert.AreEqual(42, actualA); Assert.AreEqual(43, actualB); }
public void Serializability() { var variableA = new TV<int>(); var variableB = new TV<int>(); Thread t1 = new Thread(() => { TransactionManager.Run(() => { variableA.Value = 10; Thread.Sleep(20); variableB.Value = 11; }); }); Thread t2 = new Thread(() => { TransactionManager.Run(() => { variableA.Value = 20; Thread.Sleep(20); variableB.Value = 21; }); }); t1.Start(); t2.Start(); t1.Join(); t2.Join(); int actual = TransactionManager.Run(() => { return variableB.Value - variableA.Value; }); Assert.AreEqual(1, actual); }
public void WriteWithoutTransaction() { var variable = new TV<int>(); variable.Value = 42; }
public void RWRWRead() { var variable = new TV<int>(42); var actual = TransactionManager.Run(() => { return TransactionManager.Run(() => { return variable.Value; }); }); Assert.AreEqual(42, actual); }
public void Read() { var variable = new TV<int>(42); int actual = TransactionManager.Run(() => variable.Value); Assert.AreEqual(42, actual); }
public void PropertyChangedOutsideTransaction() { var variable = new TV<int>(0); variable.PropertyChanged += (sender, e) => { Assert.IsFalse(TransactionManager.TransactionRunning); }; TransactionManager.Run(() => { variable.Value = 1; }); }
/// <summary> /// Writes a value into a variable. /// </summary> /// <param name="variable">Variable to write to.</param> /// <param name="value">Value to store in the variable.</param> /// <exception cref="OutsideOfTransactionException">Thrown if no transaction is running.</exception> /// <exception cref="ReadOnlyTransactionException">Thrown if called within a read-only transaction.</exception> /// <remarks> /// This method always throws an exception. Either a <c>OutsideOfTransactionException</c> if no /// transaction is running, or a <c>ReadOnlyTransactionException</c> if one is running (since all transactions /// used with this strategy are read-only. /// </remarks> public void Write(TV variable, object value) { if (_nestedTransactions <= 0) throw new OutsideOfTransactionException(ExceptionMessages.InternalError); throw new ReadOnlyTransactionException(ExceptionMessages.WriteInReadonlyTransaction); }
public void ReadOnlyWrite() { var variable = new TV<int>(0); TransactionManager.RunReadOnly(() => { variable.Value = 42; return 0; }); }
public void ReadTwo() { var variableA = new TV<int>(42); var variableB = new TV<int>(43); int actual = TransactionManager.Run(() => variableB.Value - variableA.Value); Assert.AreEqual(1, actual); }
public void PropertyChangedRaised() { int called = 0; var variable = new TV<int>(0); variable.PropertyChanged += (sender, e) => called++; TransactionManager.Run(() => { variable.Value = 1; }); Assert.AreEqual(1, called); }