/KiwiDb.Tests/JsonDb/ConcurrencyFixture.cs

https://github.com/jlarsson/KiwiDB · C# · 163 lines · 133 code · 24 blank · 6 comment · 5 complexity · 4ccbbd8b3c6ddfd1455173d76808259c MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using NUnit.Framework;
  7. namespace KiwiDb.Tests.JsonDb
  8. {
  9. [TestFixture]
  10. public class ConcurrencyFixture: IsolatedDatabaseFixture
  11. {
  12. [Test, Explicit]
  13. public void ConcurrentReadIsUnrestricted()
  14. {
  15. var numberOfActiveReaders = 0;
  16. const int readerCount = 4;
  17. var allReadersActiveEvent = new ManualResetEvent(false);
  18. var tasks = (from i in Enumerable.Range(0, readerCount)
  19. select new Task(() => GetCollection().ExecuteRead(c =>
  20. {
  21. //Console.Out.WriteLine("starting thread " + i);
  22. c.Find(null);
  23. if (Interlocked.Increment(ref numberOfActiveReaders) == readerCount-1)
  24. {
  25. //Console.Out.WriteLine("thread " + i + " is the last");
  26. allReadersActiveEvent.Set();
  27. }
  28. if (!allReadersActiveEvent.WaitOne(10000))
  29. {
  30. throw new Exception("apa");
  31. }
  32. //Console.Out.WriteLine("exiting thread " + i);
  33. return 0;
  34. }))).ToArray();
  35. foreach (var task in tasks)
  36. {
  37. task.Start();
  38. }
  39. Task.WaitAll(tasks);
  40. }
  41. [Test]
  42. public void OnlyOneWriterIsAllowed()
  43. {
  44. var enteredConflictingWriter = false;
  45. var enteredWinningWriter = false;
  46. var conflictingWriter = new Task(() => GetCollection().ExecuteWrite(c =>
  47. {
  48. enteredConflictingWriter = true;
  49. Assert.Fail("SHOULD NOT HAPPEN, WOULD LEAD TO CONCURRENT WRITES");
  50. return false;
  51. }));
  52. // The winning writer will block until the second writer is terminated
  53. var winningWriter = new Task(() => GetCollection().ExecuteWrite(c =>
  54. {
  55. // Start write operation in another thread
  56. conflictingWriter.Start();
  57. // Which, of course should fail
  58. Assert.Throws<AggregateException>(conflictingWriter.Wait);
  59. enteredWinningWriter = true;
  60. return true;
  61. }));
  62. winningWriter.Start();
  63. winningWriter.Wait();
  64. Assert.IsTrue(enteredWinningWriter);
  65. Assert.IsFalse(enteredConflictingWriter);
  66. }
  67. [Test]
  68. public void ReadersAndWriters()
  69. {
  70. var sync = new object();
  71. var writeOperations = 0;
  72. var readOperations = 0;
  73. var readerCount = 0;
  74. var writerCount = 0;
  75. var maxConcurrentReaders = 0;
  76. var maxConcurrentWriters = 0;
  77. var quitEvent = new ManualResetEvent(false);
  78. DatabaseFileProvider.Timeout = TimeSpan.FromSeconds(10);
  79. var writers = from i in Enumerable.Range(0, 5) select new Task(() =>
  80. {
  81. while (!quitEvent.WaitOne(0))
  82. {
  83. GetCollection().ExecuteWrite(c =>
  84. {
  85. lock (sync)
  86. {
  87. ++writeOperations;
  88. ++writerCount;
  89. maxConcurrentWriters =
  90. Math.Max(
  91. maxConcurrentWriters,
  92. writerCount);
  93. }
  94. Thread.Sleep(100);
  95. lock (sync)
  96. {
  97. --writerCount;
  98. }
  99. return 0;
  100. });
  101. }
  102. }
  103. );
  104. var readers = from i in Enumerable.Range(0, 5)
  105. select new Task(() =>
  106. {
  107. while (!quitEvent.WaitOne(0))
  108. {
  109. GetCollection().ExecuteRead(c =>
  110. {
  111. lock (sync)
  112. {
  113. ++readOperations;
  114. ++readerCount;
  115. maxConcurrentReaders = Math.Max( maxConcurrentReaders,readerCount);
  116. }
  117. Thread.Sleep(100);
  118. lock (sync)
  119. {
  120. --readerCount;
  121. }
  122. return 0;
  123. });
  124. }
  125. }
  126. );
  127. var tasks = new List<Task>(readers.Concat(writers)).ToArray();
  128. foreach (var task in tasks)
  129. {
  130. task.Start();
  131. }
  132. Task.WaitAll(tasks, TimeSpan.FromSeconds(5));
  133. quitEvent.Set();
  134. Task.WaitAll(tasks);
  135. Console.Out.WriteLine("Read/write operations: {0}/{1}", readOperations, writeOperations);
  136. Console.Out.WriteLine("Read/write concurrency max: {0}/{1}", maxConcurrentReaders, maxConcurrentWriters);
  137. }
  138. }
  139. }