internal TransactionMergingWriter(StorageEnvironment env, DebugJournal debugJournal = null) { _env = env; _stopWrites.Set(); _debugJournal = debugJournal; _backgroundTask = new Lazy <Task>(() => Task.Factory.StartNew(BackgroundWriter, _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Current)); }
public StorageEnvironment(StorageEnvironmentOptions options, string debugJournalName) : this(options) { DebugJournal = new DebugJournal(debugJournalName, this); if (Writer != null) { Writer.Dispose(); } Writer = new TransactionMergingWriter(this, _cancellationTokenSource.Token, DebugJournal); }
public unsafe Tree CreateTree(Transaction tx, string name, bool keysPrefixing = false) { if (tx.Flags == (TransactionFlags.ReadWrite) == false) { throw new ArgumentException("Cannot create a new tree with a read only transaction"); } Tree tree = tx.ReadTree(name); if (tree != null) { return(tree); } if (name.Equals(Constants.RootTreeName, StringComparison.InvariantCultureIgnoreCase) || name.Equals(Constants.FreeSpaceTreeName, StringComparison.InvariantCultureIgnoreCase)) { throw new InvalidOperationException("Cannot create a tree with reserved name: " + name); } Slice key = (Slice)name; // we are in a write transaction, no need to handle locks var header = (TreeRootHeader *)tx.State.Root.DirectRead(key); if (header != null) { tree = Tree.Open(tx, header); tree.Name = name; tx.AddTree(name, tree); return(tree); } tree = Tree.Create(tx, keysPrefixing); tree.Name = name; var space = tx.State.Root.DirectAdd(key, sizeof(TreeRootHeader)); tree.State.CopyTo((TreeRootHeader *)space); tree.State.IsModified = true; tx.AddTree(name, tree); if (IsDebugRecording) { DebugJournal.RecordWriteAction(DebugActionType.CreateTree, tx, Slice.Empty, name, Stream.Null); } return(tree); }
public void PageNotSorted_ValidateDebugOption() { using (var env = new StorageEnvironment(StorageEnvironmentOptions.CreateMemoryOnly())) { env.DebugJournal = DebugJournal.FromFile("Bugs/Data/mapped", env); env.DebugJournal.Replay(); using (var tx = env.NewTransaction(TransactionFlags.Read)) { var tree = tx.ReadTree("mapped_results_by_view_and_reduce_key"); DebugStuff.RenderAndShow(tx, tree.State.RootPageNumber, 1); } } }
public unsafe void RenameTree(Transaction tx, string fromName, string toName) { if (tx.Flags == (TransactionFlags.ReadWrite) == false) { throw new ArgumentException("Cannot rename a new tree with a read only transaction"); } if (toName.Equals(Constants.RootTreeName, StringComparison.InvariantCultureIgnoreCase) || toName.Equals(Constants.FreeSpaceTreeName, StringComparison.InvariantCultureIgnoreCase)) { throw new InvalidOperationException("Cannot create a tree with reserved name: " + toName); } if (tx.ReadTree(toName) != null) { throw new ArgumentException("Cannot rename a tree with the name of an existing tree: " + toName); } Tree fromTree = tx.ReadTree(fromName); if (fromTree == null) { throw new ArgumentException("Tree " + fromName + " does not exists"); } Slice key = (Slice)toName; tx.State.Root.Delete((Slice)fromName); var ptr = tx.State.Root.DirectAdd(key, sizeof(TreeRootHeader)); fromTree.State.CopyTo((TreeRootHeader *)ptr); fromTree.Name = toName; fromTree.State.IsModified = true; tx.RemoveTree(fromName); tx.RemoveTree(toName); tx.AddTree(toName, fromTree); if (IsDebugRecording) { DebugJournal.RecordWriteAction(DebugActionType.RenameTree, tx, (Slice)toName, fromName, Stream.Null); } }
public void Record_debug_journal_and_replay_it_with_manual_flushing() { using (var env = new StorageEnvironment(StorageEnvironmentOptions.CreateMemoryOnly())) { env.DebugJournal = new DebugJournal(debugJouralName, env, true); using (var tx = env.NewTransaction(TransactionFlags.ReadWrite)) { env.CreateTree(tx, "test-tree"); tx.Commit(); } using (var writeBatch = new WriteBatch()) { var valueBuffer = new MemoryStream(Encoding.UTF8.GetBytes("{ \"title\": \"foo\",\"name\":\"bar\"}")); writeBatch.Add("foo", valueBuffer, "test-tree"); env.Writer.Write(writeBatch); } using (env.Options.AllowManualFlushing()) { env.FlushLogToDataFile(); } using (var tx = env.NewTransaction(TransactionFlags.ReadWrite)) using (env.Options.AllowManualFlushing()) { env.FlushLogToDataFile(tx); tx.Commit(); } } using (var env = new StorageEnvironment(StorageEnvironmentOptions.CreateMemoryOnly())) { env.DebugJournal = DebugJournal.FromFile(debugJouralName, env); env.DebugJournal.Replay(); using (var snapshot = env.CreateSnapshot()) { Assert.Equal("{ \"title\": \"foo\",\"name\":\"bar\"}", snapshot.Read("test-tree", "foo").Reader.ToStringValue()); } } }
public unsafe Tree CreateTree(Transaction tx, string name, bool keysPrefixing = false) { Tree tree = tx.ReadTree(name); if (tree != null) { return(tree); } if (name.Equals(Constants.RootTreeName, StringComparison.InvariantCultureIgnoreCase)) { return(tx.Root); } if (name.Equals(Constants.FreeSpaceTreeName, StringComparison.InvariantCultureIgnoreCase)) { return(tx.FreeSpaceRoot); } if (tx.Flags == (TransactionFlags.ReadWrite) == false) { throw new InvalidOperationException("No such tree: " + name + " and cannot create trees in read transactions"); } Slice key = name; tree = Tree.Create(tx, keysPrefixing); tree.Name = name; var space = tx.Root.DirectAdd(key, sizeof(TreeRootHeader)); tree.State.CopyTo((TreeRootHeader *)space); tree.State.IsModified = true; tx.AddTree(name, tree); if (IsDebugRecording) { DebugJournal.RecordWriteAction(DebugActionType.CreateTree, tx, Slice.Empty, name, Stream.Null); } return(tree); }
public void Record_debug_journal_and_replay_it() { using (var env = new StorageEnvironment(StorageEnvironmentOptions.CreateMemoryOnly())) { env.DebugJournal = new DebugJournal(debugJouralName, env, true); using (var tx = env.NewTransaction(TransactionFlags.ReadWrite)) { env.CreateTree(tx, "test-tree"); tx.Commit(); } using (var writeBatch = new WriteBatch()) { var valueBuffer = new MemoryStream(Encoding.UTF8.GetBytes("{ \"title\": \"foo\",\"name\":\"bar\"}")); writeBatch.Add("foo", valueBuffer, "test-tree"); valueBuffer = new MemoryStream(Encoding.UTF8.GetBytes("testing testing 1 2!")); writeBatch.Add("bar", valueBuffer, "test-tree"); valueBuffer = new MemoryStream(Encoding.UTF8.GetBytes("testing testing 1 2 3!")); writeBatch.Add("foo-bar", valueBuffer, "test-tree"); writeBatch.MultiAdd("multi-foo", "AA", "test-tree"); env.Writer.Write(writeBatch); } using (var writeBatch = new WriteBatch()) { writeBatch.Increment("incr-key", 5, "test-tree"); env.Writer.Write(writeBatch); } using (var tx = env.NewTransaction(TransactionFlags.Read)) { Assert.Equal(5, tx.ReadTree("test-tree").Read("incr-key").Reader.ReadLittleEndianInt64()); using (var writeBatch = new WriteBatch()) { writeBatch.Increment("incr-key", 5, "test-tree"); env.Writer.Write(writeBatch); } Assert.Equal(5, tx.ReadTree("test-tree").Read("incr-key").Reader.ReadLittleEndianInt64()); } using (var tx = env.NewTransaction(TransactionFlags.Read)) { Assert.Equal(10, tx.ReadTree("test-tree").Read("incr-key").Reader.ReadLittleEndianInt64()); } using (var writeBatch = new WriteBatch()) { writeBatch.MultiAdd("multi-foo", "BB", "test-tree"); writeBatch.MultiAdd("multi-foo", "CC", "test-tree"); writeBatch.Delete("foo-bar", "test-tree"); env.Writer.Write(writeBatch); } using (var tx = env.NewTransaction(TransactionFlags.ReadWrite)) { env.CreateTree(tx, "test-tree2"); tx.Commit(); } using (var writeBatch = new WriteBatch()) { var valueBuffer = new MemoryStream(Encoding.UTF8.GetBytes("testing testing 1!")); writeBatch.Add("foo", valueBuffer, "test-tree2"); valueBuffer = new MemoryStream(Encoding.UTF8.GetBytes("testing testing 1 2!")); writeBatch.Add("bar", valueBuffer, "test-tree2"); valueBuffer = new MemoryStream(Encoding.UTF8.GetBytes("testing testing 1 2 3!")); writeBatch.Add("foo-bar", valueBuffer, "test-tree2"); env.Writer.Write(writeBatch); } } using (var env = new StorageEnvironment(StorageEnvironmentOptions.CreateMemoryOnly())) { env.DebugJournal = DebugJournal.FromFile(debugJouralName, env); env.DebugJournal.Replay(); using (var snapshot = env.CreateSnapshot()) { Assert.Equal("{ \"title\": \"foo\",\"name\":\"bar\"}", snapshot.Read("test-tree", "foo").Reader.ToStringValue()); Assert.Equal("testing testing 1 2!", snapshot.Read("test-tree", "bar").Reader.ToStringValue()); Assert.Equal("testing testing 1!", snapshot.Read("test-tree2", "foo").Reader.ToStringValue()); Assert.Equal("testing testing 1 2!", snapshot.Read("test-tree2", "bar").Reader.ToStringValue()); Assert.Equal("testing testing 1 2 3!", snapshot.Read("test-tree2", "foo-bar").Reader.ToStringValue()); Assert.Equal(10, snapshot.Read("test-tree", "incr-key").Reader.ReadLittleEndianInt64()); Assert.Equal(0, snapshot.ReadVersion("test-tree", "foo-bar")); using (var iter = snapshot.MultiRead("test-tree", "multi-foo")) { iter.Seek(Slice.BeforeAllKeys); Assert.Equal("AA", iter.CurrentKey.ToString()); Assert.DoesNotThrow(() => iter.MoveNext()); Assert.Equal("BB", iter.CurrentKey.ToString()); Assert.DoesNotThrow(() => iter.MoveNext()); Assert.Equal("CC", iter.CurrentKey.ToString()); } } } }
private void RecordTransactionState(Transaction tx, DebugActionType state) { DebugJournal.RecordTransactionAction(tx, state); }
public void Dispose() { if (DebugJournal != null) { DebugJournal.Dispose(); } _cancellationTokenSource.Cancel(); _flushWriter.Set(); try { var flushingTaskCopy = _flushingTask; if (flushingTaskCopy != null) { switch (flushingTaskCopy.Status) { case TaskStatus.RanToCompletion: case TaskStatus.Canceled: break; default: try { flushingTaskCopy.Wait(); } catch (AggregateException ae) { if (ae.InnerException is OperationCanceledException == false) { throw; } } break; } } } finally { var errors = new List <Exception>(); foreach (var disposable in new IDisposable[] { Writer, _headerAccessor, _scratchBufferPool, _options.OwnsPagers ? _options : null, _journal }.Concat(_tempPagesPool)) { try { if (disposable != null) { disposable.Dispose(); } } catch (Exception e) { errors.Add(e); } } if (errors.Count != 0) { throw new AggregateException(errors); } } }