Exemple #1
0
 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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
                }
            }
        }
Exemple #5
0
        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);
            }
        }
Exemple #6
0
        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);
        }
Exemple #8
0
        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());
                    }
                }
            }
        }
Exemple #9
0
 private void RecordTransactionState(Transaction tx, DebugActionType state)
 {
     DebugJournal.RecordTransactionAction(tx, state);
 }
Exemple #10
0
        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);
                }
            }
        }