public void TestThreadSafety(int cnt, int tcount, int seconds) { using (var pile = new DefaultPile()) { // pile.SegmentSize = 64 * 1024 * 1024; pile.Start(); var data = new PilePointer[cnt]; for (var i = 0; i < cnt; i++) { data[i] = pile.Put(new byte[0], preallocateBlockSize: Memory.PTR_RAW_BYTE_SIZE + (137 * (i % 17))); } var lst = new List <Task>(); long statRead = 0; long statPut = 0; long statDelete = 0; var sw = Stopwatch.StartNew(); var sd = DateTime.UtcNow; var deleteLock = new object(); for (var i = 0; i < tcount; i++) { lst.Add(Task.Factory.StartNew(() => { while (true) { var now = DateTime.UtcNow; if ((now - sd).TotalSeconds > seconds) { break; } var it = ExternalRandomGenerator.Instance.NextScaledRandomInteger(10, 100); for (var j = 0; j < it; j++) { var pp = data[ExternalRandomGenerator.Instance.NextScaledRandomInteger(0, cnt - 1)]; Aver.IsTrue(pile.Get(pp) is byte[]); Interlocked.Increment(ref statRead); } it = ExternalRandomGenerator.Instance.NextScaledRandomInteger(10, 100); for (var j = 0; j < it; j++) { var pp = data[ExternalRandomGenerator.Instance.NextScaledRandomInteger(0, cnt - 1)]; Aver.IsTrue(pile.Put(pp, new byte[ExternalRandomGenerator.Instance.NextScaledRandomInteger(0, 3791)], link: true)); Interlocked.Increment(ref statPut); } if (ExternalRandomGenerator.Instance.NextScaledRandomInteger(0, 100) > 50 && Monitor.TryEnter(deleteLock)) { try { var newData = (PilePointer[])data.Clone(); it = ExternalRandomGenerator.Instance.NextScaledRandomInteger(0, 10 + (cnt / 2)); var toDelete = new List <PilePointer>(); for (var j = 0; j < it; j++) { var idx = ExternalRandomGenerator.Instance.NextScaledRandomInteger(0, cnt - 1); toDelete.Add(newData[idx]); newData[idx] = pile.Put(new byte[12], preallocateBlockSize: ExternalRandomGenerator.Instance.NextScaledRandomInteger(24, 1024)); } data = newData;//atomic; Thread.Sleep(1000); foreach (var pp in toDelete) { Aver.IsTrue(pile.Delete(pp)); Interlocked.Increment(ref statDelete); } } finally { Monitor.Exit(deleteLock); } } } }, TaskCreationOptions.LongRunning)); } Task.WaitAll(lst.ToArray()); var el = sw.ElapsedMilliseconds; Console.WriteLine("Read {0:n0} at {1:n0} ops/sec".Args(statRead, statRead / (el / 1000d))); Console.WriteLine("Put {0:n0} at {1:n0} ops/sec".Args(statPut, statPut / (el / 1000d))); Console.WriteLine("Deleted {0:n0} at {1:n0} ops/sec".Args(statDelete, statDelete / (el / 1000d))); for (var i = 0; i < data.Length; i++) { Aver.IsTrue(pile.Delete(data[i])); } Aver.AreEqual(0, pile.ObjectCount); Aver.AreEqual(0, pile.ObjectLinkCount); Aver.AreEqual(0, pile.AllocatedMemoryBytes); } }