public ConsistencyTestHarness( IGrainFactory grainFactory, int numGrains, int seed, bool avoidDeadlocks, bool avoidTimeouts, ReadWriteDetermination readWrite, bool tolerateUnknownExceptions) { this.grainFactory = grainFactory; numGrains.Should().BeLessThan(ConsistencyTestOptions.MaxGrains); this.options = new ConsistencyTestOptions() { AvoidDeadlocks = avoidDeadlocks, ReadWrite = readWrite, MaxDepth = 5, NumGrains = numGrains, RandomSeed = seed, AvoidTimeouts = avoidTimeouts, GrainOffset = (DateTime.UtcNow.Ticks & 0xFFFFFFFF) * ConsistencyTestOptions.MaxGrains, }; this.tuples = new Dictionary <int, SortedDictionary <int, Dictionary <string, HashSet <string> > > >(); this.succeeded = new HashSet <string>(); this.aborted = new HashSet <string>(); this.indoubt = new Dictionary <string, string>(); // determine what to check for in the end this.tolerateUnknownExceptions = tolerateUnknownExceptions; }
public async Task <Observation[]> Run(ConsistencyTestOptions options, int depth, string stack, int maxgrain, DateTime stopAfter) { if (random == null) { random = new Random(options.RandomSeed * options.NumGrains + MyNumber); } if (depth < options.MaxDepth && random.NextDouble() < recursionProbability) { switch (random.Next(2)) { case 0: return(await Recurse(options, depth, stack, random, 10, !options.AvoidDeadlocks, maxgrain, stopAfter)); case 1: return(await Recurse(options, depth, stack, random, 10, false, maxgrain, stopAfter)); case 2: return(await Recurse(options, depth, stack, random, 3, false, maxgrain, stopAfter)); } } //if (random.Next(20 + 6 * depth) == 0) //{ // logger.LogTrace($"g{MyNumber} {data.CurrentTransactionId} {partition}.{iteration} L{depth} UserAbort"); // throw new UserAbort(); //} var txhash = stack.Substring(0, stack.IndexOf(')')).GetHashCode(); var whethertoreadorwrite = (options.ReadWrite == ReadWriteDetermination.PerTransaction) ? new Random(options.RandomSeed + txhash) : (options.ReadWrite == ReadWriteDetermination.PerGrain) ? new Random(options.RandomSeed + txhash * 10000 + MyNumber) : random; try { switch (whethertoreadorwrite.Next(4)) { case 0: logger.LogTrace("g{MyNumber} {CurrentTransactionId} {Stack} Write", MyNumber, TransactionContext.CurrentTransactionId, stack); return(await Write()); default: logger.LogTrace( "g{MyNumber} {CurrentTransactionId} {stack} Read", MyNumber, TransactionContext.CurrentTransactionId, stack); return(await Read()); } } catch (Exception e) { logger.LogTrace("g{MyNumber} {CurrentTransactionId} {Stack} --> {ExceptionType}", MyNumber, TransactionContext.CurrentTransactionId, stack, e.GetType().Name); throw; } }
private async Task <Observation[]> Recurse(ConsistencyTestOptions options, int depth, string stack, Random random, int count, bool parallel, int maxgrain, DateTime stopAfter) { logger.LogTrace("g{MyNumber} {CurrentTransactionId} {Stack} Recurse {Count} {ParallelOrSequential}", MyNumber, TransactionContext.CurrentTransactionId, stack, count, (parallel ? "par" : "seq")); try { int min = options.AvoidDeadlocks ? MyNumber : 0; int max = options.AvoidDeadlocks ? maxgrain : options.NumGrains; var tasks = new List <Task <Observation[]> >(); int[] targets = new int[count]; for (int i = 0; i < count; i++) { targets[i] = random.Next(min, max); } if (options.AvoidDeadlocks) { Array.Sort(targets); } for (int i = 0; i < count; i++) { var randomTarget = GrainFactory.GetGrain <IConsistencyTestGrain>(options.GrainOffset + targets[i]); var maxgrainfornested = (i < count - 1) ? targets[i + 1] : max; var task = randomTarget.Run(options, depth + 1, $"{stack}.{(parallel ? 'P' : 'S')}{i}", maxgrainfornested, stopAfter); tasks.Add(task); if (!parallel) { await task; } if (DateTime.UtcNow > stopAfter) { break; } } await Task.WhenAll(tasks); var result = new HashSet <Observation>(); for (int i = 0; i < count; i++) { foreach (var x in tasks[i].Result) { result.Add(x); } } return(result.ToArray()); } catch (Exception e) { logger.LogTrace( "g{MyNumber} {CurrentTransactionId} {Stack} --> {ExceptionType}", MyNumber, TransactionContext.CurrentTransactionId, stack, e.GetType().Name); throw; } }