private StorageResult <TValue> UpdateDocumentInternal <TKey, TValue>(ITransaction transaction, string collection, TKey key, TValue update)
        {
            StorageResult <TValue> result = new StorageResult <TValue>();

            ValidateTransaction(transaction);
            LightningTransaction lmdbTransaction = (LightningTransaction)transaction.InnerObject;

            byte[] keyBytes    = _environment.ConverterStore.GetToBytes <TKey>().Convert(_collectionTable[collection].Collection, key);
            byte[] oldValBytes = lmdbTransaction.Get(_collectionTable[collection].Collection, keyBytes);

            long netSize = 0;

            netSize = -CaclulateSize(keyBytes, oldValBytes);

            byte[] valueBytes = _environment.ConverterStore.GetToBytes <TValue>().Convert(_collectionTable[collection].Collection, update);
            try
            {
                lmdbTransaction.Put(_collectionTable[collection].Collection, keyBytes, valueBytes);
                //Incase of update previous size is not being subtracted at the moment
                long size = CaclulateSize(keyBytes, valueBytes);
                netSize += size;
                ((LMDBTransaction)transaction).ChangeSize(netSize);
                _collectionTable[collection].IncrementTemporaryStats(netSize);
                result.Document = update;
                result.Status   = StoreResult.SuccessOverwrite;
                return(result);
            }
            catch (LightningException le)
            {
                result.Status = HandleException(le);
                return(result);
            }
        }
        private void DbPut(LightningTransaction tx, LightningDatabase db, string key, DurableDataEnvelope data)
        {
            var byteKey   = Encoding.UTF8.GetBytes(key);
            var byteValue = _serializer.ToBinary(data);

            tx.Put(db, byteKey, byteValue);
        }
        private int FailedToSend(LightningTransaction tx, OutgoingMessage message)
        {
            var db    = OpenDatabase(tx, OutgoingQueue);
            var value = tx.Get(db, message.Id.MessageIdentifier.ToByteArray());

            if (value.resultCode == MDBResultCode.NotFound)
            {
                return(int.MaxValue);
            }
            var msg      = value.value.CopyToNewArray().ToOutgoingMessage();
            int attempts = message.SentAttempts;

            if (attempts >= message.MaxAttempts)
            {
                RemoveMessageFromStorage(tx, OutgoingQueue, msg);
            }
            else if (msg.DeliverBy.HasValue)
            {
                var expire = msg.DeliverBy.Value;
                if (expire != DateTime.MinValue && DateTime.Now >= expire)
                {
                    RemoveMessageFromStorage(tx, OutgoingQueue, msg);
                }
            }
            else
            {
                tx.Put(db, message.Id.MessageIdentifier.ToByteArray(), message.Serialize());
            }
            return(attempts);
        }
Exemple #4
0
        public static string Get(this LightningTransaction tx, LightningDatabase db, string key)
        {
            var enc    = System.Text.Encoding.UTF8;
            var result = tx.Get(db, enc.GetBytes(key));

            return(enc.GetString(result.value.CopyToNewArray()));
        }
        private void CommitInternal(ITransaction transaction)
        {
            Stopwatch sw = new Stopwatch();

            ValidateTransaction(transaction);
            LightningTransaction lmdbTransaction = (LightningTransaction)transaction.InnerObject;

            sw.Start();
            lmdbTransaction.Commit();
            sw.Stop();

            ChangeDataSize(((LMDBTransaction)transaction).Size);

            if (!transaction.IsReadOnly)
            {
                if (_readerTransaction != null)
                {
                    lock (_readerTransactionLock)
                    {
                        if (_readerTransaction != null)
                        {
                            _readerTransaction.MarkForCommit();
                            //_readerTransaction = null;
                        }
                    }
                }
            }

            if (LoggerManager.Instance.StorageLogger != null)
            {
                LoggerManager.Instance.StorageLogger.Debug("LMDBPersistanceProvider", "LMDB Commit Time: " + sw.ElapsedMilliseconds + " (ms)");
            }
        }
Exemple #6
0
        IEnumerable <TOut> InternalScan <TOut>(LightningTransaction lt, FdbKeyRange range,
                                               Func <Slice, byte[], TOut> convert)
        {
            ushort x = 0;

            using (var c = lt.CreateCursor(_ld)) {
                if (!c.MoveToFirstAfter(range.Begin.GetBytes()))
                {
                    yield break;
                }

                var pair = c.Current;

                for (var i = 0; i < int.MaxValue; i++)
                {
                    var current = Slice.Create(pair.Key);
                    if (!range.Contains(current))
                    {
                        break;
                    }
                    x += 1;
                    yield return(convert(current, pair.Value));

                    if (!c.MoveNext())
                    {
                        break;
                    }
                    pair = c.Current;
                }
            }
        }
        private LightningDatabase CreateCollectionInternal(string name, Type keyType)
        {
            ITransaction transaction = BeginTransactionInternal(null, TransactionBeginFlags.None);

            ValidateTransaction(transaction);

            LightningTransaction lmdbTransaction = (LightningTransaction)transaction.InnerObject;

            LightningDB.DatabaseConfiguration dbOptions = new LightningDB.DatabaseConfiguration();
            dbOptions.Flags = DatabaseOpenFlags.Create;
            //todo: maybe add other integer types too
            if (keyType == typeof(long) || keyType == typeof(ulong) || keyType == typeof(int) || keyType == typeof(uint) || keyType == typeof(short) || keyType == typeof(ushort))
            {
                dbOptions.Flags |= DatabaseOpenFlags.IntegerKey;
            }
            LightningDatabase collectionInstance = lmdbTransaction.OpenDatabase(name, dbOptions);

            if (name != METADATA_COLLECTION)
            {
                StoreCollectionInfo(name, transaction);
            }
            ((LMDBTransaction)transaction).ChangeSize(8192);
            CommitInternal(transaction);

            return(collectionInstance);
        }
        public void DropCollection(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException("Collection name cant not be null or empty.");
            }

            if (!CollectionExists(name))
            {
                throw new ArgumentException("Specified collection not found in " + GetFileInfo() + " Collection = " + name);
            }

            ITransaction transaction = BeginTransactionInternal(null, TransactionBeginFlags.None);

            ValidateTransaction(transaction);
            LightningTransaction lmdbTransaction = (LightningTransaction)transaction.InnerObject;

            LightningDatabase dbInstance = _collectionTable[name].Collection;
            long dataSize = _collectionTable[name].Stats.DataSize;

            lmdbTransaction.DropDatabase(dbInstance);
            _collectionTable.Remove(name);

            StoreCollectionInfo(null, transaction);
            //StoreDocument(transaction, _metadataCollection, "collections", _collectionTable.Keys.ToArray());

            ((LMDBTransaction)transaction).ChangeSize(-8192);
            ((LMDBTransaction)transaction).ChangeSize(-dataSize);

            CommitInternal(transaction);
        }
        private void ValidateTransaction(ITransaction transaction)
        {
            if (transaction == null)
            {
                throw new TransactionException("Invalid Transaction.Transaction can not be null.");
            }

            if (transaction.InnerObject == null)
            {
                throw new TransactionException("Invalid Transaction. Inner Transaction can not be null.");
            }

            if (transaction.InnerObject.GetType() != typeof(LightningTransaction))
            {
                throw new TransactionException("Invalid Transaction. Inner Transaction type not valid. Expected type = " + typeof(LightningTransaction) + " Type present = " + transaction.InnerObject.GetType());
            }

            LightningTransaction lmdbTransaction = (LightningTransaction)transaction.InnerObject;

            if (lmdbTransaction.State == LightningTransactionState.Aborted)
            {
                throw new TransactionAobrtException("Invalid Transaction. Inner Transaction was aborted. File = " + GetFileInfo());
            }

            if (lmdbTransaction.State == LightningTransactionState.Commited)
            {
                throw new TransactionComittedException("Invalid Transaction. Inner Transaction was commited. File = " + GetFileInfo());
            }
        }
Exemple #10
0
        public void DatabaseFromCommitedTransactionShouldBeAccessable()
        {
            //arrange
            _env.Open();

            LightningDatabase db;

            using (var committed = _env.BeginTransaction())
            {
                db = committed.OpenDatabase(null, DatabaseOpenFlags.None);
                committed.Commit();
            }

            //act
            try
            {
                _txn = _env.BeginTransaction();
                _txn.Put(db, "key", 1);
            }
            finally
            {
                db.Close();
            }

            //assert
        }
        public void DatabaseShouldBeDropped()
        {
            _env.MaxDatabases = 2;
            _env.Open();
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase("notmaster", new DatabaseConfiguration {
                Flags = DatabaseOpenFlags.Create
            });

            _txn.Commit();
            _txn.Dispose();
            db.Dispose();

            _txn = _env.BeginTransaction();
            db   = _txn.OpenDatabase("notmaster");

            db.Drop(_txn);
            _txn.Commit();
            _txn.Dispose();

            _txn = _env.BeginTransaction();

            var ex = Assert.Throws <LightningException>(() => _txn.OpenDatabase("notmaster"));

            Assert.Equal(ex.StatusCode, -30798);
        }
        private StorageResult <TValue> StoreDocumentInternal <TKey, TValue>(ITransaction transaction, string collection, TKey key, TValue value)
        {
            StorageResult <TValue> result = new StorageResult <TValue>();

            ValidateTransaction(transaction);
            LightningTransaction lmdbTransaction = (LightningTransaction)transaction.InnerObject;

            byte[] keyBytes   = _environment.ConverterStore.GetToBytes <TKey>().Convert(_collectionTable[collection].Collection, key);
            byte[] valueBytes = _environment.ConverterStore.GetToBytes <TValue>().Convert(_collectionTable[collection].Collection, value);

            try
            {
                lmdbTransaction.Put(_collectionTable[collection].Collection, keyBytes, valueBytes);
                long size = CaclulateSize(keyBytes, valueBytes);
                ((LMDBTransaction)transaction).ChangeSize(size);
                _collectionTable[collection].IncrementTemporaryStats(size);

                result.Document = value;
                result.Status   = StoreResult.Success;
                return(result);
            }
            catch (LightningException le)
            {
                result.Status = HandleException(le);
                return(result);
            }
        }
        private DatabaseHandleCacheEntry OpenDatabaseHandle(string name, LightningTransaction tran, DatabaseOpenFlags flags)
        {
            name = FromInternalDatabaseName(name);

            var handle = default(UInt32);
            NativeMethods.Execute(lib => lib.mdb_dbi_open(tran._handle, name, flags, out handle));

            return new DatabaseHandleCacheEntry(handle, flags);
        }               
 public LMDBTransaction(LightningTransaction transaction, bool isReadOnly)
 {
     if (transaction == null)
     {
         throw new ArgumentException("Parameter transaction can not be null.");
     }
     _transaction = transaction;
     _isReadOnly  = isReadOnly;
 }
        private void RemoveMessageFromStorage(LightningTransaction tx, string queueName, params Message[] messages)
        {
            var db = OpenDatabase(tx, queueName);

            foreach (var message in messages)
            {
                tx.Delete(db, message.Id.MessageIdentifier.ToByteArray());
            }
        }
Exemple #16
0
        public CursorManager(LightningTransaction transaction)
        {
            if (transaction == null)
                throw new ArgumentNullException("transaction");

            _transaction = transaction;

            _cursors = new ConcurrentDictionary<IntPtr, bool>();
        }
Exemple #17
0
 internal ObjectRepositoryTransaction(
     ObjectRepositorySettings <TKey, T> settings,
     LightningTransaction tx,
     LightningDatabase db)
 {
     _settings = settings;
     _tx       = tx;
     _db       = db;
 }
Exemple #18
0
        public void TransactionShouldBeCreated()
        {
            //arrange

            //act
            _txn = _env.BeginTransaction();

            //assert
            Assert.AreEqual(LightningTransactionState.Active, _txn.State);
        }
        public void Init()
        {
            Directory.CreateDirectory(_path);

            _env = new LightningEnvironment(_path, EnvironmentOpenFlags.None);
            _env.Open();

            _txn = _env.BeginTransaction();
            _db = _txn.OpenDatabase();
        }
        public void TransactionShouldBeCreated()
        {
            //arrange

            //act
            _txn = _env.BeginTransaction();

            //assert
            Assert.AreEqual(LightningTransactionState.Active, _txn.State);
        }
        public CursorTests(SharedFileSystem fileSystem)
        {
            var path = fileSystem.CreateNewDirectoryForTest();
            

            _env = new LightningEnvironment(path);
            _env.Open();

            _txn = _env.BeginTransaction();            
        }
        public void DatabaseShouldBeClosed()
        {
            _env.Open();
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase();

            db.Dispose();

            Assert.Equal(false, db.IsOpened);
        }
Exemple #23
0
        public void Init()
        {
            Directory.CreateDirectory(_path);

            _env = new LightningEnvironment(_path, EnvironmentOpenFlags.None);
            _env.Open();

            _txn = _env.BeginTransaction();
            _db  = _txn.OpenDatabase();
        }
Exemple #24
0
        public static bool TryGet(this LightningTransaction tx, LightningDatabase db, string key, out string value)
        {
            var enc = System.Text.Encoding.UTF8;

            byte[] result;
            var    found = tx.TryGet(db, enc.GetBytes(key), out result);

            value = enc.GetString(result);
            return(found);
        }
        public void DatabaseShouldBeClosed()
        {
            _env.Open();
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase();

            db.Dispose();

            Assert.False(db.IsOpened);
        }
Exemple #26
0
        public CursorTests(SharedFileSystem fileSystem)
        {
            var path = fileSystem.CreateNewDirectoryForTest();


            _env = new LightningEnvironment(path);
            _env.Open();

            _txn = _env.BeginTransaction();
        }
Exemple #27
0
        public void TransactionShouldBeAbortedIfEnvironmentCloses()
        {
            //arrange
            _txn = _env.BeginTransaction();

            //act
            _env.Close();

            //assert
            Assert.AreEqual(LightningTransactionState.Aborted, _txn.State);
        }
        private LightningDatabase OpenDatabase(LightningTransaction transaction, string database)
        {
            if (_databaseCache.ContainsKey(database))
            {
                return(_databaseCache[database]);
            }
            var db = transaction.OpenDatabase(database);

            _databaseCache[database] = db;
            return(db);
        }
Exemple #29
0
        public void ReadOnlyTransactionShouldChangeStateOnReset()
        {
            //arrange
            _txn = _env.BeginTransaction(TransactionBeginFlags.ReadOnly);

            //act
            _txn.Reset();

            //assert
            Assert.AreEqual(LightningTransactionState.Reseted, _txn.State);
        }
        public DatabaseIOTests(SharedFileSystem fileSystem)
        {
            var path = fileSystem.CreateNewDirectoryForTest();

            _env = new LightningEnvironment(path);
            _env.MaxDatabases = 2;
            _env.Open();

            _txn = _env.BeginTransaction();
            _db = _txn.OpenDatabase(configuration: new DatabaseConfiguration {Flags = DatabaseOpenFlags.Create});
        }
Exemple #31
0
        public void ChildTransactionShouldBeCreated()
        {
            //arrange
            _txn = _env.BeginTransaction();

            //act
            var subTxn = _txn.BeginTransaction();

            //assert
            Assert.AreEqual(LightningTransactionState.Active, subTxn.State);
        }
Exemple #32
0
        public void TransactionShouldChangeStateOnCommit()
        {
            //arrange
            _txn = _env.BeginTransaction();

            //act
            _txn.Commit();

            //assert
            Assert.AreEqual(LightningTransactionState.Commited, _txn.State);
        }
Exemple #33
0
 public static void TryDelete(this LightningTransaction tx, LightningDatabase db, byte[] key)
 {
     try {
         tx.Delete(db, key);
     } catch (LightningException ex) {
         if (ex.StatusCode != Lmdb.MDB_NOTFOUND)
         {
             throw;
         }
     }
 }
        public StorageResult <TValue> GetDocument <TKey, TValue>(string collection, TKey key)
        {
            StorageResult <TValue> result = new StorageResult <TValue>();

            if (string.IsNullOrEmpty(collection))
            {
                throw new ArgumentException("Collection name can not be null or empty.");
            }

            if (!CollectionExists(collection))
            {
                throw new ArgumentException("Specified collection not found in " + GetFileInfo() + " Collection = " + collection);
            }
            ReadTransaction transaction = null;

            try
            {
                if (_readerTransaction != null)
                {
                    if (_readerTransaction.ShouldRenew)
                    {
                        _readerTransaction.WaitUntillFree();
                    }
                }

                lock (_readerTransactionLock)
                {
                    if (_readerTransaction == null || !_readerTransaction.Running)
                    {
                        _readerTransaction = new ReadTransaction(BeginTransaction(null, true));
                    }

                    transaction = _readerTransaction;
                    transaction.Enter();
                }

                ValidateTransaction(transaction.Transaction);
                LightningTransaction lmdbTransaction = (LightningTransaction)transaction.Transaction.InnerObject;

                byte[] keyBytes   = _environment.ConverterStore.GetToBytes <TKey>().Convert(_collectionTable[collection].Collection, key);
                byte[] valueBytes = lmdbTransaction.Get(_collectionTable[collection].Collection, keyBytes);
                result.Document = _environment.ConverterStore.GetFromBytes <TValue>().Convert(_collectionTable[collection].Collection, valueBytes);
            }
            finally
            {
                if (transaction != null)
                {
                    transaction.Exit();
                }
            }

            result.Status = StoreResult.Success;
            return(result);
        }
        public void ChildTransactionShouldBeCreated()
        {
            //arrange
            _txn = _env.BeginTransaction();

            //act
            var subTxn = _txn.BeginTransaction();

            //assert
            Assert.AreEqual(LightningTransactionState.Active, subTxn.State);
        }
        public void TransactionShouldBeAbortedIfEnvironmentCloses()
        {
            //arrange
            _txn = _env.BeginTransaction();

            //act
            _env.Close();

            //assert
            Assert.AreEqual(LightningTransactionState.Aborted, _txn.State);
        }
        public void TransactionShouldChangeStateOnCommit()
        {
            //arrange
            _txn = _env.BeginTransaction();

            //act
            _txn.Commit();

            //assert
            Assert.AreEqual(LightningTransactionState.Commited, _txn.State);
        }
        private void SaveKV(LightningTransaction tx, byte[] key, double value)
        {
            var byteValue = BitConverter.GetBytes(value);

            using (var db = tx.OpenDatabase("kv", new DatabaseConfiguration {
                Flags = DatabaseOpenFlags.Create
            }))
            {
                tx.Put(db, key, byteValue);
                tx.Commit();
            }
        }
Exemple #39
0
        public void ChildTransactionShouldBeAbortedIfParentIsAborted()
        {
            //arrange
            _txn = _env.BeginTransaction();
            var child = _txn.BeginTransaction();

            //act
            _txn.Abort();

            //assert
            Assert.AreEqual(LightningTransactionState.Aborted, child.State);
        }
Exemple #40
0
        public void DefaultDatabaseShouldBeOpened()
        {
            _env.Open();
            _txn = _env.BeginTransaction();
            //arrange

            //act
            var db = _txn.OpenDatabase(null, DatabaseOpenFlags.None);

            //assert
            Assert.AreEqual(true, db.IsOpened);
        }
        public void DefaultDatabaseShouldBeOpened()
        {
            _env.Open();
            _txn = _env.BeginTransaction();
            //arrange

            //act
            var db = _txn.OpenDatabase(null, DatabaseOpenFlags.None);

            //assert
            Assert.AreEqual(true, db.IsOpened);
        }
Exemple #42
0
        public void DefaultDatabaseShouldBeClosed()
        {
            _env.Open();
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase(null, new DatabaseOptions { Flags = DatabaseOpenFlags.None });
            //arrange

            //act
            db.Close();

            //assert
            Assert.AreEqual(false, db.IsOpened);
        }
        public void DatabaseShouldBeCreated()
        {
            var dbName = "test";
            _env.MapDatabases = 2;
            _env.Open();
            _txn = _env.BeginTransaction();
            //arrange

            //act
            _txn.OpenDatabase(dbName, DatabaseOpenFlags.Create);

            //assert
        }
        public LightningTransaction Create(TransactionBeginFlags beginFlags)
        {
            EnsureEnvironmentOpened();

            IntPtr handle = default(IntPtr);
            NativeMethods.Execute(lib => lib.mdb_txn_begin(_environment._handle, _parentHandle, beginFlags, out handle));

            var tran = new LightningTransaction(_environment, handle, _parentTransaction, beginFlags);

            _transactions.TryAdd(tran, true);

            return tran;
        }
        public TransactionManager(LightningEnvironment environment, LightningTransaction parentTransaction)
        {
            if (environment == null)
                throw new ArgumentNullException("environment");

            _environment = environment;

            _parentTransaction = parentTransaction;
            _parentHandle = parentTransaction != null
                ? parentTransaction._handle
                : IntPtr.Zero;

            _transactions = new ConcurrentDictionary<LightningTransaction, bool>();
            _comparatorsStore = new ConcurrentDictionary<CompareFunction, bool>();
        }
        public LightningDatabase OpenDatabase(string name, LightningTransaction tran, DatabaseOpenFlags flags, Encoding encoding)
        {
            var internalName = ToInternalDatabaseName(name);

            var cacheEntry = _openedDatabases.AddOrUpdate(
                internalName,
                key =>
                {
                    var entry = OpenDatabaseHandle(name, tran, flags);                    

                    return entry;
                },
                (key, entry) =>
                {
                    if (entry.OpenFlags != flags)
                        entry = OpenDatabaseHandle(name, tran, flags);

                    return entry;
                });

            _databasesForReuse.Add(cacheEntry.Handle);

            return new LightningDatabase(internalName, tran, cacheEntry, encoding);
        }
        public void ChildTransactionShouldBeAbortedIfParentIsAborted()
        {
            //arrange
            _txn = _env.BeginTransaction();
            var child = _txn.BeginTransaction();

            //act
            _txn.Abort();

            //assert
            Assert.AreEqual(LightningTransactionState.Aborted, child.State);
        }
 public void WasDiscarded(LightningTransaction tn)
 {
     bool value;
     _transactions.TryRemove(tn, out value);
 }
        public void DatabaseShouldBeDropped()
        {
            _env.MaxDatabases = 2;
            _env.Open();
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase("notmaster", new DatabaseConfiguration {Flags = DatabaseOpenFlags.Create});
            _txn.Commit();
            _txn.Dispose();
            db.Dispose();

            _txn = _env.BeginTransaction();
            db = _txn.OpenDatabase("notmaster");

            db.Drop(_txn);
            _txn.Commit();
            _txn.Dispose();

            _txn = _env.BeginTransaction();

            var ex = Assert.Throws<LightningException>(() => _txn.OpenDatabase("notmaster"));

            Assert.Equal(ex.StatusCode, -30798);
        }
        public void TruncatingTheDatabase()
        {
            _env.Open();
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase();

            _txn.Put(db, "hello", "world");
            _txn.Commit();
            _txn.Dispose();
            _txn = _env.BeginTransaction();
            db = _txn.OpenDatabase();
            db.Truncate(_txn);
            _txn.Commit();
            _txn.Dispose();
            _txn = _env.BeginTransaction();
            db = _txn.OpenDatabase();
            var result = _txn.Get(db, UTF8.GetBytes("hello"));

            Assert.Null(result);
        }
        public void ChildTransactionShouldBeAbortedIfEnvironmentIsClosed()
        {
            //arrange
            _txn = _env.BeginTransaction();
            var child = _txn.BeginTransaction();

            //act
            _env.Close();

            //assert
            Assert.AreEqual(LightningTransacrionState.Aborted, child.State);
        }
        public void ReadOnlyTransactionShouldChangeStateOnRenew()
        {
            //arrange
            _txn = _env.BeginTransaction(TransactionBeginFlags.ReadOnly);
            _txn.Reset();

            //act
            _txn.Renew();

            //assert
            Assert.AreEqual(LightningTransactionState.Active, _txn.State);
        }
        public void DefaultDatabaseShouldBeDropped()
        {
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase(null, DatabaseOpenFlags.None);
            //arrange

            //act
            _txn.DropDatabase(db, true);

            //assert
            Assert.AreEqual(false, db.IsOpened);
        }
        public void TransactionShouldSupportCustomComparer()
        {
            //arrange
            Func<int, int, int> comparison = (l, r) => -Math.Sign(l - r);

            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase(
                options: new DatabaseOptions { Compare = b => b.FromFunc(comparison) });

            var keysUnsorted = new int[] { 2, 10, 5 };
            var keysSorted = keysUnsorted.ToArray();
            Array.Sort(keysSorted, new Comparison<int>(comparison));

            //act
            for (var i = 0; i < keysUnsorted.Length; i++)
                _txn.Put(keysUnsorted[i], i);

            //assert
            using (var c = _txn.CreateCursor(db))
            {
                int order = 0;

                KeyValuePair<int, int> pair;
                while (c.MoveNext(out pair))
                    Assert.AreEqual(keysSorted[order++], pair.Key);
            }
        }
        public void DatabaseFromCommitedTransactionShouldBeAccessable()
        {
            //arrange
            _env.Open();

            LightningDatabase db;
            using (var committed = _env.BeginTransaction())
            {
                db = committed.OpenDatabase(null, DatabaseOpenFlags.None);
                committed.Commit();
            }
            
            //act
            try
            {
                _txn = _env.BeginTransaction();
                _txn.Put(db, "key", 1);
            }
            finally
            {
                db.Close();
            }

            //assert
            
        }
        public void CanCountTransactionEntries()
        {
            //arrange
            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase(null, new DatabaseOptions { Flags = DatabaseOpenFlags.None });

            const int entriesCount = 10;
            for (var i = 0; i < entriesCount; i++)
                _txn.Put(db, i.ToString(), i.ToString());

            //act
            var count = _txn.GetEntriesCount(db);

            //assert;
            Assert.AreEqual(entriesCount, count);
        }
        public void TransactionShouldSupportCustomDupSorter()
        {
            //arrange
            Func<int, int, int> comparison = (l, r) => -Math.Sign(l - r);

            _txn = _env.BeginTransaction();
            var db = _txn.OpenDatabase(
                options: new DatabaseOptions 
                { 
                    Flags = DatabaseOpenFlags.DuplicatesFixed,
                    DuplicatesSort = b => b.FromFunc(comparison) 
                });

            var valuesUnsorted = new int[] { 2, 10, 5, 0 };
            var valuesSorted = valuesUnsorted.ToArray();
            Array.Sort(valuesSorted, new Comparison<int>(comparison));

            //act
            using (var c = _txn.CreateCursor(db))
                c.PutMultiple(123, valuesUnsorted);

            //assert
            using (var c = _txn.CreateCursor(db))
            {
                int order = 0;

                KeyValuePair<int, int> pair;
                while (c.MoveNextDuplicate(out pair))
                    Assert.AreEqual(valuesSorted[order++], pair.Value);
            }
        }