PageRenderTime 72ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Rachis/Rachis.Tests/SnapshotTests.cs

http://github.com/ayende/ravendb
C# | 176 lines | 145 code | 30 blank | 1 comment | 6 complexity | d8aac6ea7a9236cb58a817c225f57541 MD5 | raw file
Possible License(s): GPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Apache-2.0, BSD-3-Clause, CC-BY-SA-3.0
  1. using System.Diagnostics;
  2. using System.Linq;
  3. using System.Threading;
  4. using FizzWare.NBuilder;
  5. using FluentAssertions;
  6. using FluentAssertions.Events;
  7. using Rachis.Commands;
  8. using Rachis.Storage;
  9. using Rachis.Transport;
  10. using Voron;
  11. using Xunit;
  12. using Xunit.Extensions;
  13. namespace Rachis.Tests
  14. {
  15. public class SnapshotTests : RaftTestsBase
  16. {
  17. [Fact]
  18. public void CanProperlySnapshot()
  19. {
  20. using (var state = new PersistentState("self", StorageEnvironmentOptions.CreateMemoryOnly(), CancellationToken.None)
  21. {
  22. CommandSerializer = new JsonCommandSerializer()
  23. })
  24. {
  25. state.UpdateTermTo(null, 1);
  26. state.AppendToLeaderLog(new NopCommand());
  27. for (int i = 0; i < 5; i++)
  28. {
  29. state.AppendToLeaderLog(new DictionaryCommand.Set
  30. {
  31. Key = i.ToString(),
  32. Value = i
  33. });
  34. }
  35. state.MarkSnapshotFor(6, 1, 5);
  36. state.AppendToLeaderLog(new DictionaryCommand.Set
  37. {
  38. Key = "1",
  39. Value = 4
  40. });
  41. var lastLogEntry = state.LastLogEntry();
  42. Assert.Equal(7, lastLogEntry.Index);
  43. }
  44. }
  45. [Theory]
  46. [InlineData(1)]
  47. [InlineData(2)]
  48. [InlineData(3)]
  49. [InlineData(5)]
  50. [InlineData(7)]
  51. public void AfterSnapshotInstalled_CanContinueGettingLogEntriesNormally(int amount)
  52. {
  53. var leader = CreateNetworkAndGetLeader(amount);
  54. leader.Options.MaxLogLengthBeforeCompaction = 5;
  55. var snapshot = WaitForSnapshot(leader);
  56. var commits = WaitForCommitsOnCluster(
  57. machine => machine.Data.Count == 5);
  58. for (int i = 0; i < 5; i++)
  59. {
  60. leader.AppendCommand(new DictionaryCommand.Set
  61. {
  62. Key = i.ToString(),
  63. Value = i
  64. });
  65. }
  66. Assert.True(snapshot.Wait(3000));
  67. Assert.True(commits.Wait(3000));
  68. Assert.NotNull(leader.StateMachine.GetSnapshotWriter());
  69. var newNode = NewNodeFor(leader);
  70. WriteLine("<-- adding node");
  71. var waitForSnapshotInstallation = WaitForSnapshotInstallation(newNode);
  72. Assert.True(leader.AddToClusterAsync(new NodeConnectionInfo { Name = newNode.Name }).Wait(3000));
  73. Assert.True(waitForSnapshotInstallation.Wait(3000));
  74. Assert.Equal(newNode.CurrentLeader, leader.Name);
  75. var commit = WaitForCommit(newNode,
  76. machine => machine.Data.ContainsKey("c"));
  77. leader.AppendCommand(new DictionaryCommand.Set
  78. {
  79. Key = "c",
  80. Value = 1
  81. });
  82. Assert.True(commit.Wait(3000));
  83. var dictionary = ((DictionaryStateMachine)newNode.StateMachine).Data;
  84. for (int i = 0; i < 5; i++)
  85. {
  86. Assert.Equal(i, dictionary[i.ToString()]);
  87. }
  88. Assert.Equal(1, dictionary["c"]);
  89. }
  90. [Fact]
  91. public void Snapshot_after_enough_command_applies_snapshot_is_applied_only_once()
  92. {
  93. var snapshotCreationEndedEvent = new ManualResetEventSlim();
  94. const int commandsCount = 5;
  95. var commands = Builder<DictionaryCommand.Set>.CreateListOfSize(commandsCount)
  96. .All()
  97. .With(x => x.Completion = null)
  98. .Build()
  99. .ToList();
  100. var appliedAllCommandsEvent = new CountdownEvent(commandsCount);
  101. var leader = CreateNetworkAndGetLeader(3);
  102. leader.MonitorEvents();
  103. leader.CreatedSnapshot += snapshotCreationEndedEvent.Set;
  104. leader.CommitIndexChanged += (old, @new) => appliedAllCommandsEvent.Signal();
  105. leader.Options.MaxLogLengthBeforeCompaction = commandsCount - 3;
  106. commands.ForEach(leader.AppendCommand);
  107. Assert.True(appliedAllCommandsEvent.Wait(3000));
  108. Assert.True(snapshotCreationEndedEvent.Wait(3000));
  109. //should only raise the event once
  110. leader.ShouldRaise("CreatedSnapshot");
  111. leader.GetRecorderForEvent("CreatedSnapshot")
  112. .Should().HaveCount(1);
  113. }
  114. [Fact]
  115. public void Snaphot_after_enough_command_applies_snapshot_is_created()
  116. {
  117. var snapshotCreationEndedEvent = new ManualResetEventSlim();
  118. const int commandsCount = 9;
  119. var commands = Builder<DictionaryCommand.Set>.CreateListOfSize(commandsCount)
  120. .All()
  121. .With(x => x.Completion = null)
  122. .Build()
  123. .ToList();
  124. var leader = CreateNetworkAndGetLeader(3);
  125. var lastLogEntry = leader.PersistentState.LastLogEntry();
  126. leader.Options.MaxLogLengthBeforeCompaction = commandsCount - 4;
  127. var appliedAllCommandsEvent = new CountdownEvent(commandsCount);
  128. leader.CreatedSnapshot += snapshotCreationEndedEvent.Set;
  129. leader.CommitApplied += cmd =>
  130. {
  131. if (cmd is DictionaryCommand.Set)
  132. {
  133. appliedAllCommandsEvent.Signal();
  134. }
  135. };
  136. WriteLine("<--- Started appending commands..");
  137. commands.ForEach(leader.AppendCommand);
  138. WriteLine("<--- Ended appending commands..");
  139. var millisecondsTimeout = Debugger.IsAttached ? 600000 : 4000;
  140. Assert.True(snapshotCreationEndedEvent.Wait(millisecondsTimeout));
  141. Assert.True(appliedAllCommandsEvent.Wait(millisecondsTimeout), "Not all commands were applied, there are still " + appliedAllCommandsEvent.CurrentCount + " commands left");
  142. var entriesAfterSnapshotCreation = leader.PersistentState.LogEntriesAfter(0).ToList();
  143. Assert.Empty(entriesAfterSnapshotCreation.Where(x=>x.Index == lastLogEntry.Index));
  144. }
  145. }
  146. }