コード例 #1
0
        public DBPartition(Logger logger, string fileName)
        {
            this.partitionName = Path.GetFileName(fileName);
            this.path          = Path.GetDirectoryName(fileName);
            this.logger        = logger;

            if (string.IsNullOrEmpty(path))
            {
                throw new Exception("Rocksdb storage path was not configured properly");
            }

            if (!path.EndsWith("/"))
            {
                path += '/';
            }

            //logger.Message($"RocksDB partition path: {fileName}");

            this._db = RocksDbStore.Instance(logger, path);

            // Create partition if it doesn't exist already
            try
            {
                logger.Message("Getting partition: " + this.partitionName);
                this.partition = this._db.GetColumnFamily(partitionName);
            }
            catch
            {
                logger.Message("Partition not found, create it now: " + this.partitionName);
                var cf = new ColumnFamilyOptions();
                // TODO different partitions might need different options...
                this.partition = this._db.CreateColumnFamily(cf, partitionName);
            }
        }
コード例 #2
0
        public RocksDbColumnFamiliesCommandTest()
        {
            _temporaryDirectory = Path.Combine(
                Path.GetTempPath(),
                Guid.NewGuid().ToString());

            _columnFamilies = Enumerable.Range(0, 10)
                .Select(_ => Guid.NewGuid())
                .ToList();
            using (var db = OpenRocksDb(_temporaryDirectory))
            {
                var columnFamilyOptions = new ColumnFamilyOptions();
                foreach (var columnFamily in _columnFamilies)
                {
                    db.CreateColumnFamily(
                        columnFamilyOptions,
                        columnFamily.ToString());
                }
            }

            _rocksDbService = new RocksDbService();
            _stringInputOutputErrorContainer = new StringInputOutputErrorContainer(
                new StringReader(string.Empty),
                new StringWriter(),
                new StringWriter());
            _command = new RocksDbColumnFamiliesCommand(
                _stringInputOutputErrorContainer,
                _rocksDbService);

            _stringInputOutputErrorContainer.SetNewLines();
        }
コード例 #3
0
        public void RocksDbOptionsProviderCreateCfOptions()
        {
            var env32 = new Mock <ISystemEnvironment>();

            env32.SetupGet(s => s.Is32BitProcess)
            .Returns(() => true);

            var env64 = new Mock <ISystemEnvironment>();

            env64.SetupGet(s => s.Is32BitProcess)
            .Returns(() => false);
            var provider32 = new RocksDbOptionsProvider(
                env32.Object,
                true,
                Option.None <ulong>(),
                Option.None <ulong>(),
                Option.None <int>(),
                Option.None <StorageLogLevel>());
            var provider64 = new RocksDbOptionsProvider(
                env64.Object,
                true,
                Option.None <ulong>(),
                Option.None <ulong>(),
                Option.None <int>(),
                Option.None <StorageLogLevel>());

            // act
            ColumnFamilyOptions newOptions32 = provider32.GetColumnFamilyOptions();
            ColumnFamilyOptions newOptions64 = provider64.GetColumnFamilyOptions();

            // assert
            Assert.NotNull(newOptions32);
            Assert.NotNull(newOptions64);
        }
コード例 #4
0
 public ColumnFamilyHandle CreateColumnFamily(ColumnFamilyOptions columnFamilyOptions, string entityName)
 {
     lock (ColumnFamiliesLock)
     {
         this.columnFamiliesProvider.AddColumnFamily(entityName);
         ColumnFamilyHandle handle = this.db.CreateColumnFamily(columnFamilyOptions, entityName);
         return(handle);
     }
 }
コード例 #5
0
 /// <summary>
 /// Creates a new column family named as the given <paramref name="name"/>,
 /// on <see cref="RocksDbSharp.RocksDb"/> located at <paramref name="rocksdbPath"/>.
 /// </summary>
 /// <param name="name">The name of the column family to create.</param>
 /// <param name="rocksdbPath">The path of <see cref="RocksDbSharp.RocksDb"/> to load.</param>
 public void Create([Argument] string name, [Option] string? rocksdbPath = null)
 {
     rocksdbPath ??= Directory.GetCurrentDirectory();
     using var db = _rocksDbService.Load(rocksdbPath);
     var options = new ColumnFamilyOptions();
     db.CreateColumnFamily(
         options,
         name);
 }
コード例 #6
0
 private ColumnFamilyHandle CreateColumnFamilyIfMissing(RocksDb db, string columnFamily)
 {
     try
     {
         return(db.GetColumnFamily(columnFamily));
     }
     catch
     {
         var options = new ColumnFamilyOptions();
         return(db.CreateColumnFamily(options, columnFamily));
     }
 }
コード例 #7
0
ファイル: ColumnsDb.cs プロジェクト: annaszeszula/nethermind
        private static ColumnFamilies GetColumnFamilies(IDbConfig dbConfig, string name, T[] keys)
        {
            var result         = new ColumnFamilies();
            var blockCacheSize = ReadConfig <ulong>(dbConfig, nameof(dbConfig.BlockCacheSize), name);

            foreach (var key in keys)
            {
                var columnFamilyOptions = new ColumnFamilyOptions();
                columnFamilyOptions.OptimizeForPointLookup(blockCacheSize);
                columnFamilyOptions.SetBlockBasedTableFactory(new BlockBasedTableOptions().SetFilterPolicy(BloomFilterPolicy.Create()));
                result.Add(key.ToString(), columnFamilyOptions);
            }
            return(result);
        }
コード例 #8
0
        public ColumnFamilyOptions GetColumnFamilyOptions()
        {
            var options = new ColumnFamilyOptions();

            if (this.env.Is32BitProcess)
            {
                // restrict some sizes if 32 bit OS.
                options.SetWriteBufferSize(WriteBufferSize);
                options.SetTargetFileSizeBase(TargetFileSizeBase);
                options.SetMaxBytesForLevelBase(MaxBytesForLevelBase);
                options.SetSoftPendingCompactionBytesLimit(SoftPendingCompactionBytes);
                options.SetHardPendingCompactionBytesLimit(HardPendingCompactionBytes);
            }
            return(options);
        }
                static ColumnFamilies GetColumnFamilies(string path)
                {
                    if (RocksDb.TryListColumnFamilies(new DbOptions(), path, out var names))
                    {
                        var columnFamilyOptions = new ColumnFamilyOptions();
                        var families            = new ColumnFamilies();
                        foreach (var name in names)
                        {
                            families.Add(name, columnFamilyOptions);
                        }
                        return(families);
                    }

                    return(new ColumnFamilies());
                }
コード例 #10
0
        private static void RocksDb2()
        {
            string directory = @"C:\Users\Peska\source\repos\Esent.Tests\RocksDB";

            DbOptions options = new DbOptions().SetCreateIfMissing();

            using (RocksDb rocksDb = RocksDbSharp.RocksDb.Open(options, directory))
            {
                TestObject o1 = new TestObject {
                    EQNum = "3L1234", Mnemonic = "20013L1234011"
                };
                TestObject o2 = new TestObject {
                    EQNum = "3L5678", Mnemonic = "20023L5678011"
                };
                TestObject o3 = new TestObject {
                    EQNum = "3L9012", Mnemonic = "20033L9012011"
                };
                TestObject o4 = new TestObject {
                    EQNum = "3L9012", Mnemonic = "20013L9012012"
                };

                rocksDb.Put(o1.Mnemonic, JsonConvert.SerializeObject(o1));
                rocksDb.Put(o2.Mnemonic, JsonConvert.SerializeObject(o2));
                rocksDb.Put(o3.Mnemonic, JsonConvert.SerializeObject(o3));
                rocksDb.Put(o4.Mnemonic, JsonConvert.SerializeObject(o4));

                SliceTransform         sliceTransform         = SliceTransform.CreateFixedPrefix(4);
                BlockBasedTableOptions blockBasedTableOptions = new BlockBasedTableOptions().SetWholeKeyFiltering(false);

                ColumnFamilyOptions columnFamilyOptions = new ColumnFamilyOptions()
                                                          .SetPrefixExtractor(sliceTransform)
                                                          .SetBlockBasedTableFactory(blockBasedTableOptions);

                ColumnFamilies columnFamilies = new ColumnFamilies(columnFamilyOptions);

                Iterator iterator = rocksDb.NewIterator();
                iterator = iterator.Seek("2001");

                while (iterator.Valid())
                {
                    string key   = iterator.StringKey();
                    string value = iterator.StringValue();

                    iterator.Next();
                }
            }
        }
コード例 #11
0
        /// <summary>
        /// Create rocksdb config and open rocksdb database.
        /// </summary>
        /// <param name="context"></param>
        protected void OpenDatabase(ProcessorContext context)
        {
            DbOptions           dbOptions           = new DbOptions();
            ColumnFamilyOptions columnFamilyOptions = new ColumnFamilyOptions();

            writeOptions = new WriteOptions();
            BlockBasedTableOptions tableConfig = new BlockBasedTableOptions();

            RocksDbOptions rocksDbOptions = new RocksDbOptions(dbOptions, columnFamilyOptions);

            tableConfig.SetBlockCache(RocksDbSharp.Cache.CreateLru(BLOCK_CACHE_SIZE));
            tableConfig.SetBlockSize(BLOCK_SIZE);
            tableConfig.SetFilterPolicy(BloomFilterPolicy.Create());

            rocksDbOptions.SetOptimizeFiltersForHits(1);
            rocksDbOptions.SetBlockBasedTableFactory(tableConfig);
            rocksDbOptions.SetCompression(COMPRESSION_TYPE);
            rocksDbOptions.SetWriteBufferSize(WRITE_BUFFER_SIZE);
            rocksDbOptions.SetCompactionStyle(COMPACTION_STYLE);
            rocksDbOptions.SetMaxWriteBufferNumber(MAX_WRITE_BUFFERS);
            rocksDbOptions.SetCreateIfMissing(true);
            rocksDbOptions.SetErrorIfExists(false);
            rocksDbOptions.SetInfoLogLevel(RocksLogLevel.ERROR);
            // this is the recommended way to increase parallelism in RocksDb
            // note that the current implementation of setIncreaseParallelism affects the number
            // of compaction threads but not flush threads (the latter remains one). Also
            // the parallelism value needs to be at least two because of the code in
            // https://github.com/facebook/rocksdb/blob/62ad0a9b19f0be4cefa70b6b32876e764b7f3c11/util/options.cc#L580
            // subtracts one from the value passed to determine the number of compaction threads
            // (this could be a bug in the RocksDB code and their devs have been contacted).
            rocksDbOptions.IncreaseParallelism(Math.Max(Environment.ProcessorCount, 2));

            // TODO : wrap writeOptions in rocksDbOptions too
            writeOptions.DisableWal(1);

            context.Configuration.RocksDbConfigHandler?.Invoke(Name, rocksDbOptions);
            rocksDbOptions.SetMinWriteBufferNumberToMerge(2);

            DbDir = new DirectoryInfo(Path.Combine(context.StateDir, parentDir, Name));

            Directory.CreateDirectory(DbDir.FullName);

            OpenRocksDb(dbOptions, columnFamilyOptions);

            IsOpen = true;
        }
コード例 #12
0
        /// <summary>
        /// Open rocksdb handle
        /// </summary>
        /// <param name="dbOptions">Rocksdb options</param>
        /// <param name="columnFamilyOptions">Columnfamily options</param>
        /// <exception cref="ProcessorStateException">throws if the rocksdb can't be open</exception>
        private void OpenRocksDb(DbOptions dbOptions, ColumnFamilyOptions columnFamilyOptions)
        {
            int              maxRetries       = 5;
            int              i                = 0;
            bool             open             = false;
            RocksDbException rocksDbException = null;

            var columnFamilyDescriptors = new ColumnFamilies(columnFamilyOptions);

            while (!open && i < maxRetries)
            {
                try
                {
                    Db = RocksDbSharp.RocksDb.Open(
                        dbOptions,
                        DbDir.FullName,
                        columnFamilyDescriptors);

                    var columnFamilyHandle = Db.GetDefaultColumnFamily();
                    DbAdapter = new SingleColumnFamilyAdapter(
                        Name,
                        Db,
                        writeOptions,
                        KeyComparator,
                        columnFamilyHandle);
                    open = true;
                }
                catch (RocksDbException e)
                {
                    ++i;
                    rocksDbException = e;
                }
            }

            if (!open)
            {
                throw new ProcessorStateException("Error opening store " + Name + " at location " + DbDir.ToString(), rocksDbException);
            }
        }
コード例 #13
0
        public void FunctionalTest()
        {
            string temp   = Path.GetTempPath();
            var    testdb = Path.Combine(temp, "functional_test");
            string path   = Environment.ExpandEnvironmentVariables(testdb);

            if (Directory.Exists(testdb))
            {
                Directory.Delete(testdb, true);
            }

            var options = new DbOptions()
                          .SetCreateIfMissing(true)
                          .EnableStatistics();

            // Using standard open
            using (var db = RocksDb.Open(options, path))
            {
                // With strings
                string value = db.Get("key");
                db.Put("key", "value");
                Assert.Equal("value", db.Get("key"));
                Assert.Null(db.Get("non-existent-key"));
                db.Remove("key");
                Assert.Null(db.Get("value"));

                // With bytes
                db.Put(Encoding.UTF8.GetBytes("key"), Encoding.UTF8.GetBytes("value"));
                Assert.True(BinaryComparer.Default.Equals(Encoding.UTF8.GetBytes("value"), db.Get(Encoding.UTF8.GetBytes("key"))));
                // non-existent kiey
                Assert.Null(db.Get(new byte[] { 0, 1, 2 }));
                db.Remove(Encoding.UTF8.GetBytes("key"));
                Assert.Null(db.Get(Encoding.UTF8.GetBytes("key")));

                db.Put(Encoding.UTF8.GetBytes("key"), new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 });

                // With buffers
                var  buffer = new byte[100];
                long length = db.Get(Encoding.UTF8.GetBytes("key"), buffer, 0, buffer.Length);
                Assert.Equal(8, length);
                Assert.Equal(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, buffer.Take((int)length).ToList());

                // Write batches
                // With strings
                using (WriteBatch batch = new WriteBatch()
                                          .Put("one", "uno")
                                          .Put("two", "deuce")
                                          .Put("two", "dos")
                                          .Put("three", "tres"))
                {
                    db.Write(batch);
                }
                Assert.Equal("uno", db.Get("one"));

                // With save point
                using (WriteBatch batch = new WriteBatch())
                {
                    batch
                    .Put("hearts", "red")
                    .Put("diamonds", "red");
                    batch.SetSavePoint();
                    batch
                    .Put("clubs", "black");
                    batch.SetSavePoint();
                    batch
                    .Put("spades", "black");
                    batch.RollbackToSavePoint();
                    db.Write(batch);
                }
                Assert.Equal("red", db.Get("diamonds"));
                Assert.Equal("black", db.Get("clubs"));
                Assert.Null(db.Get("spades"));

                // With bytes
                var utf8 = Encoding.UTF8;
                using (WriteBatch batch = new WriteBatch()
                                          .Put(utf8.GetBytes("four"), new byte[] { 4, 4, 4 })
                                          .Put(utf8.GetBytes("five"), new byte[] { 5, 5, 5 }))
                {
                    db.Write(batch);
                }
                Assert.True(BinaryComparer.Default.Equals(new byte[] { 4, 4, 4 }, db.Get(utf8.GetBytes("four"))));

                // Snapshots
                using (var snapshot = db.CreateSnapshot())
                {
                    var before = db.Get("one");
                    db.Put("one", "1");

                    var useSnapshot = new ReadOptions()
                                      .SetSnapshot(snapshot);

                    // the database value was written
                    Assert.Equal("1", db.Get("one"));
                    // but the snapshot still sees the old version
                    var after = db.Get("one", readOptions: useSnapshot);
                    Assert.Equal(before, after);
                }

                var two = db.Get("two");
                Assert.Equal("dos", two);

                // Iterators
                using (var iterator = db.NewIterator(
                           readOptions: new ReadOptions()
                           .SetIterateUpperBound("t")
                           ))
                {
                    iterator.Seek("k");
                    Assert.True(iterator.Valid());
                    Assert.Equal("key", iterator.StringKey());
                    iterator.Next();
                    Assert.True(iterator.Valid());
                    Assert.Equal("one", iterator.StringKey());
                    Assert.Equal("1", iterator.StringValue());
                    iterator.Next();
                    Assert.False(iterator.Valid());
                }

                // MultiGet
                var multiGetResult = db.MultiGet(new[] { "two", "three", "nine" });
                Assert.Equal(
                    expected: new[]
                {
                    new KeyValuePair <string, string>("two", "dos"),
                    new KeyValuePair <string, string>("three", "tres"),
                    new KeyValuePair <string, string>("nine", null)
                },
                    actual: multiGetResult
                    );
            }

            // Test with column families
            var optionsCf = new DbOptions()
                            .SetCreateIfMissing(true)
                            .SetCreateMissingColumnFamilies(true);

            var columnFamilies = new ColumnFamilies
            {
                { "reverse", new ColumnFamilyOptions() },
            };

            using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");

                db.Put("one", "uno");
                db.Put("two", "dos");
                db.Put("three", "tres");

                db.Put("uno", "one", cf: reverse);
                db.Put("dos", "two", cf: reverse);
                db.Put("tres", "three", cf: reverse);
            }

            // Test Cf Delete
            using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");

                db.Put("cuatro", "four", cf: reverse);
                db.Put("cinco", "five", cf: reverse);

                Assert.Equal("four", db.Get("cuatro", cf: reverse));
                Assert.Equal("five", db.Get("cinco", cf: reverse));

                byte[] keyBytes = Encoding.UTF8.GetBytes("cuatro");
                db.Remove(keyBytes, reverse);
                db.Remove("cinco", reverse);

                Assert.Null(db.Get("cuatro", cf: reverse));
                Assert.Null(db.Get("cinco", cf: reverse));
            }

            // Test list
            {
                var list = RocksDb.ListColumnFamilies(optionsCf, path);
                Assert.Equal(new[] { "default", "reverse" }, list.ToArray());
            }

            // Test reopen with column families
            using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");

                Assert.Equal("uno", db.Get("one"));
                Assert.Equal("one", db.Get("uno", cf: reverse));
                Assert.Null(db.Get("uno"));
                Assert.Null(db.Get("one", cf: reverse));
            }

            // Test dropping and creating column family
            using (var db = RocksDb.Open(options, path, columnFamilies))
            {
                db.DropColumnFamily("reverse");
                var reverse = db.CreateColumnFamily(new ColumnFamilyOptions(), "reverse");
                Assert.Null(db.Get("uno", cf: reverse));
                db.Put("red", "rouge", cf: reverse);
                Assert.Equal("rouge", db.Get("red", cf: reverse));
            }

            // Test reopen after drop and create
            using (var db = RocksDb.Open(options, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");
                Assert.Null(db.Get("uno", cf: reverse));
                Assert.Equal("rouge", db.Get("red", cf: reverse));
            }

            // Test read only
            using (var db = RocksDb.OpenReadOnly(options, path, columnFamilies, false))
            {
                Assert.Equal("uno", db.Get("one"));
            }

            // Test SstFileWriter
            {
                var envOpts  = new EnvOptions();
                var ioOpts   = new ColumnFamilyOptions();
                var sst      = new SstFileWriter(envOpts, ioOpts);
                var filename = Path.Combine(temp, "test.sst");
                if (File.Exists(filename))
                {
                    File.Delete(filename);
                }
                sst.Open(filename);
                sst.Add("four", "quatro");
                sst.Add("one", "uno");
                sst.Add("two", "dos");
                sst.Finish();

                using (var db = RocksDb.Open(options, path, columnFamilies))
                {
                    Assert.NotEqual("four", db.Get("four"));
                    var ingestOptions = new IngestExternalFileOptions()
                                        .SetMoveFiles(true);
                    db.IngestExternalFiles(new string[] { filename }, ingestOptions);
                    Assert.Equal("quatro", db.Get("four"));
                }
            }

            // test comparator
            unsafe {
                var comparator = new IntegerStringComparator();

                var opts = new ColumnFamilyOptions()
                           .SetComparator(comparator);

                var filename = Path.Combine(temp, "test.sst");
                if (File.Exists(filename))
                {
                    File.Delete(filename);
                }
                var sst = new SstFileWriter(ioOptions: opts);
                sst.Open(filename);
                sst.Add("111", "111");
                sst.Add("1001", "1001"); // this order is only allowed using an integer comparator
                sst.Finish();
            }

            // test write batch with index
            {
                var wbwi = new WriteBatchWithIndex(reservedBytes: 1024);
                wbwi.Put("one", "un");
                wbwi.Put("two", "deux");
                var oneValueIn  = Encoding.UTF8.GetBytes("one");
                var oneValueOut = wbwi.Get("one");
                Assert.Equal("un", oneValueOut);
                using (var db = RocksDb.Open(options, path, columnFamilies))
                {
                    var oneCombinedOut   = wbwi.Get(db, "one");
                    var threeCombinedOut = wbwi.Get(db, "three");
                    Assert.Equal("un", oneCombinedOut);
                    Assert.Equal("tres", threeCombinedOut);

                    using (var wbIterator = wbwi.NewIterator(db.NewIterator()))
                    {
                        wbIterator.Seek("o");
                        Assert.True(wbIterator.Valid());
                        var itkey = wbIterator.StringKey();
                        Assert.Equal("one", itkey);
                        var itval = wbIterator.StringValue();
                        Assert.Equal("un", itval);

                        wbIterator.Next();
                        Assert.True(wbIterator.Valid());
                        itkey = wbIterator.StringKey();
                        Assert.Equal("three", itkey);
                        itval = wbIterator.StringValue();
                        Assert.Equal("tres", itval);

                        wbIterator.Next();
                        Assert.True(wbIterator.Valid());
                        itkey = wbIterator.StringKey();
                        Assert.Equal("two", itkey);
                        itval = wbIterator.StringValue();
                        Assert.Equal("deux", itval);

                        wbIterator.Next();
                        Assert.False(wbIterator.Valid());
                    }

                    db.Write(wbwi);

                    var oneDbOut = wbwi.Get("one");
                    Assert.Equal("un", oneDbOut);
                }
            }

            // compact range
            {
                using (var db = RocksDb.Open(options, path, columnFamilies))
                {
                    db.CompactRange("o", "tw");
                }
            }
        }
コード例 #14
0
ファイル: RocksDbService.cs プロジェクト: moreal/rocksdb-cli
 /// <summary>
 /// Initializes a new instance of the <see cref="RocksDbService"/> class.
 /// </summary>
 public RocksDbService()
 {
     _options             = new DbOptions();
     _columnFamilyOptions = new ColumnFamilyOptions();
 }
コード例 #15
0
        public void CreateCF(string name)
        {
            var cf = new ColumnFamilyOptions();

            _db.CreateColumnFamily(cf, name);
        }
コード例 #16
0
ファイル: RocksDbWrapper.cs プロジェクト: rdivossen/iotedge
 public ColumnFamilyHandle CreateColumnFamily(ColumnFamilyOptions columnFamilyOptions, string entityName) => this.db.CreateColumnFamily(columnFamilyOptions, entityName);
コード例 #17
0
        public void FunctionalTest()
        {
            string temp    = Path.GetTempPath();
            var    testdir = Path.Combine(temp, "functional_test");
            var    testdb  = Path.Combine(testdir, "main");
            var    testcp  = Path.Combine(testdir, "cp");
            var    path    = Environment.ExpandEnvironmentVariables(testdb);
            var    cppath  = Environment.ExpandEnvironmentVariables(testcp);

            if (Directory.Exists(testdir))
            {
                Directory.Delete(testdir, true);
            }
            Directory.CreateDirectory(testdir);

            var options = new DbOptions()
                          .SetCreateIfMissing(true)
                          .EnableStatistics();

            // Using standard open
            using (var db = RocksDb.Open(options, path))
            {
                // With strings
                string value = db.Get("key");
                db.Put("key", "value");
                Assert.Equal("value", db.Get("key"));
                Assert.Null(db.Get("non-existent-key"));
                db.Remove("key");
                Assert.Null(db.Get("value"));

                // With bytes
                db.Put(Encoding.UTF8.GetBytes("key"), Encoding.UTF8.GetBytes("value"));
                Assert.True(BinaryComparer.Default.Equals(Encoding.UTF8.GetBytes("value"), db.Get(Encoding.UTF8.GetBytes("key"))));
                // non-existent kiey
                Assert.Null(db.Get(new byte[] { 0, 1, 2 }));
                db.Remove(Encoding.UTF8.GetBytes("key"));
                Assert.Null(db.Get(Encoding.UTF8.GetBytes("key")));

                db.Put(Encoding.UTF8.GetBytes("key"), new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 });

                // With buffers
                var  buffer = new byte[100];
                long length = db.Get(Encoding.UTF8.GetBytes("key"), buffer, 0, buffer.Length);
                Assert.Equal(8, length);
                Assert.Equal(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, buffer.Take((int)length).ToList());

                buffer = new byte[5];
                length = db.Get(Encoding.UTF8.GetBytes("key"), buffer, 0, buffer.Length);
                Assert.Equal(8, length);
                Assert.Equal(new byte[] { 0, 1, 2, 3, 4 }, buffer.Take((int)Math.Min(buffer.Length, length)));

                length = db.Get(Encoding.UTF8.GetBytes("bogus"), buffer, 0, buffer.Length);
                Assert.Equal(-1, length);

                // Write batches
                // With strings
                using (WriteBatch batch = new WriteBatch()
                                          .Put("one", "uno")
                                          .Put("two", "deuce")
                                          .Put("two", "dos")
                                          .Put("three", "tres"))
                {
                    db.Write(batch);
                }
                Assert.Equal("uno", db.Get("one"));

                // With save point
                using (WriteBatch batch = new WriteBatch())
                {
                    batch
                    .Put("hearts", "red")
                    .Put("diamonds", "red");
                    batch.SetSavePoint();
                    batch
                    .Put("clubs", "black");
                    batch.SetSavePoint();
                    batch
                    .Put("spades", "black");
                    batch.RollbackToSavePoint();
                    db.Write(batch);
                }
                Assert.Equal("red", db.Get("diamonds"));
                Assert.Equal("black", db.Get("clubs"));
                Assert.Null(db.Get("spades"));

                // Save a checkpoint
                using (var cp = db.Checkpoint())
                {
                    cp.Save(cppath);
                }

                // With bytes
                var utf8 = Encoding.UTF8;
                using (WriteBatch batch = new WriteBatch()
                                          .Put(utf8.GetBytes("four"), new byte[] { 4, 4, 4 })
                                          .Put(utf8.GetBytes("five"), new byte[] { 5, 5, 5 }))
                {
                    db.Write(batch);
                }
                Assert.True(BinaryComparer.Default.Equals(new byte[] { 4, 4, 4 }, db.Get(utf8.GetBytes("four"))));

                // Snapshots
                using (var snapshot = db.CreateSnapshot())
                {
                    var before = db.Get("one");
                    db.Put("one", "1");

                    var useSnapshot = new ReadOptions()
                                      .SetSnapshot(snapshot);

                    // the database value was written
                    Assert.Equal("1", db.Get("one"));
                    // but the snapshot still sees the old version
                    var after = db.Get("one", readOptions: useSnapshot);
                    Assert.Equal(before, after);
                }

                var two = db.Get("two");
                Assert.Equal("dos", two);

                // Iterators
                using (var iterator = db.NewIterator(
                           readOptions: new ReadOptions()
                           .SetIterateUpperBound("t")
                           ))
                {
                    iterator.Seek("k");
                    Assert.True(iterator.Valid());
                    Assert.Equal("key", iterator.StringKey());
                    iterator.Next();
                    Assert.True(iterator.Valid());
                    Assert.Equal("one", iterator.StringKey());
                    Assert.Equal("1", iterator.StringValue());
                    iterator.Next();
                    Assert.False(iterator.Valid());
                }

                // MultiGet
                var multiGetResult = db.MultiGet(new[] { "two", "three", "nine" });
                Assert.Equal(
                    expected: new[]
                {
                    new KeyValuePair <string, string>("two", "dos"),
                    new KeyValuePair <string, string>("three", "tres"),
                    new KeyValuePair <string, string>("nine", null)
                },
                    actual: multiGetResult
                    );
            }

            // Test reading checkpointed db
            using (var cpdb = RocksDb.Open(options, cppath))
            {
                Assert.Equal("red", cpdb.Get("diamonds"));
                Assert.Equal("black", cpdb.Get("clubs"));
                Assert.Null(cpdb.Get("spades"));
                // Checkpoint occurred before these changes:
                Assert.Null(cpdb.Get("four"));
            }

            // Test with column families
            var optionsCf = new DbOptions()
                            .SetCreateIfMissing(true)
                            .SetCreateMissingColumnFamilies(true);

            var columnFamilies = new ColumnFamilies
            {
                { "reverse", new ColumnFamilyOptions() },
            };

            using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");

                db.Put("one", "uno");
                db.Put("two", "dos");
                db.Put("three", "tres");

                db.Put("uno", "one", cf: reverse);
                db.Put("dos", "two", cf: reverse);
                db.Put("tres", "three", cf: reverse);
            }

            // Test Cf Delete
            using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");

                db.Put("cuatro", "four", cf: reverse);
                db.Put("cinco", "five", cf: reverse);

                Assert.Equal("four", db.Get("cuatro", cf: reverse));
                Assert.Equal("five", db.Get("cinco", cf: reverse));

                byte[] keyBytes = Encoding.UTF8.GetBytes("cuatro");
                db.Remove(keyBytes, reverse);
                db.Remove("cinco", reverse);

                Assert.Null(db.Get("cuatro", cf: reverse));
                Assert.Null(db.Get("cinco", cf: reverse));
            }

            // Test list
            {
                var list = RocksDb.ListColumnFamilies(optionsCf, path);
                Assert.Equal(new[] { "default", "reverse" }, list.ToArray());
            }

            // Test reopen with column families
            using (var db = RocksDb.Open(optionsCf, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");

                Assert.Equal("uno", db.Get("one"));
                Assert.Equal("one", db.Get("uno", cf: reverse));
                Assert.Null(db.Get("uno"));
                Assert.Null(db.Get("one", cf: reverse));
            }

            // Test dropping and creating column family
            using (var db = RocksDb.Open(options, path, columnFamilies))
            {
                db.DropColumnFamily("reverse");
                var reverse = db.CreateColumnFamily(new ColumnFamilyOptions(), "reverse");
                Assert.Null(db.Get("uno", cf: reverse));
                db.Put("red", "rouge", cf: reverse);
                Assert.Equal("rouge", db.Get("red", cf: reverse));
            }

            // Test reopen after drop and create
            using (var db = RocksDb.Open(options, path, columnFamilies))
            {
                var reverse = db.GetColumnFamily("reverse");
                Assert.Null(db.Get("uno", cf: reverse));
                Assert.Equal("rouge", db.Get("red", cf: reverse));
            }

            // Test read only
            using (var db = RocksDb.OpenReadOnly(options, path, columnFamilies, false))
            {
                Assert.Equal("uno", db.Get("one"));
            }

            // Test SstFileWriter
            {
                using (var writer = new SstFileWriter())
                {
                }

                var envOpts = new EnvOptions();
                var ioOpts  = new ColumnFamilyOptions();
                using (var sst = new SstFileWriter(envOpts, ioOpts))
                {
                    var filename = Path.Combine(temp, "test.sst");
                    if (File.Exists(filename))
                    {
                        File.Delete(filename);
                    }
                    sst.Open(filename);
                    sst.Add("four", "quatro");
                    sst.Add("one", "uno");
                    sst.Add("two", "dos");
                    sst.Finish();

                    using (var db = RocksDb.Open(options, path, columnFamilies))
                    {
                        Assert.NotEqual("four", db.Get("four"));
                        var ingestOptions = new IngestExternalFileOptions()
                                            .SetMoveFiles(true);
                        db.IngestExternalFiles(new string[] { filename }, ingestOptions);
                        Assert.Equal("quatro", db.Get("four"));
                    }
                }
            }

            // test comparator
            unsafe {
                var opts = new ColumnFamilyOptions()
                           .SetComparator(new IntegerStringComparator());

                var filename = Path.Combine(temp, "test.sst");
                if (File.Exists(filename))
                {
                    File.Delete(filename);
                }
                using (var sst = new SstFileWriter(ioOptions: opts))
                {
                    sst.Open(filename);
                    sst.Add("111", "111");
                    sst.Add("1001", "1001"); // this order is only allowed using an integer comparator
                    sst.Finish();
                }
            }

            // test write batch with index
            {
                var wbwi = new WriteBatchWithIndex(reservedBytes: 1024);
                wbwi.Put("one", "un");
                wbwi.Put("two", "deux");
                var oneValueIn  = Encoding.UTF8.GetBytes("one");
                var oneValueOut = wbwi.Get("one");
                Assert.Equal("un", oneValueOut);
                using (var db = RocksDb.Open(options, path, columnFamilies))
                {
                    var oneCombinedOut   = wbwi.Get(db, "one");
                    var threeCombinedOut = wbwi.Get(db, "three");
                    Assert.Equal("un", oneCombinedOut);
                    Assert.Equal("tres", threeCombinedOut);

                    using (var wbIterator = wbwi.NewIterator(db.NewIterator()))
                    {
                        wbIterator.Seek("o");
                        Assert.True(wbIterator.Valid());
                        var itkey = wbIterator.StringKey();
                        Assert.Equal("one", itkey);
                        var itval = wbIterator.StringValue();
                        Assert.Equal("un", itval);

                        wbIterator.Next();
                        Assert.True(wbIterator.Valid());
                        itkey = wbIterator.StringKey();
                        Assert.Equal("three", itkey);
                        itval = wbIterator.StringValue();
                        Assert.Equal("tres", itval);

                        wbIterator.Next();
                        Assert.True(wbIterator.Valid());
                        itkey = wbIterator.StringKey();
                        Assert.Equal("two", itkey);
                        itval = wbIterator.StringValue();
                        Assert.Equal("deux", itval);

                        wbIterator.Next();
                        Assert.False(wbIterator.Valid());
                    }

                    db.Write(wbwi);

                    var oneDbOut = wbwi.Get("one");
                    Assert.Equal("un", oneDbOut);
                }
            }

            // compact range
            {
                using (var db = RocksDb.Open(options, path, columnFamilies))
                {
                    db.CompactRange("o", "tw");
                }
            }

            // Smoke test various options
            {
                var dbname = "test-options";
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
                var optsTest = (DbOptions) new RocksDbSharp.DbOptions()
                               .SetCreateIfMissing(true)
                               .SetCreateMissingColumnFamilies(true)
                               .SetBlockBasedTableFactory(new BlockBasedTableOptions().SetBlockCache(Cache.CreateLru(1024 * 1024)));
                GC.Collect();
                using (var db = RocksDbSharp.RocksDb.Open(optsTest, dbname))
                {
                }
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
            }

            // Smoke test OpenWithTtl
            {
                var dbname = "test-with-ttl";
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
                var optsTest = (DbOptions) new RocksDbSharp.DbOptions()
                               .SetCreateIfMissing(true)
                               .SetCreateMissingColumnFamilies(true);
                using (var db = RocksDbSharp.RocksDb.OpenWithTtl(optsTest, dbname, 1))
                {
                }
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
            }

            // Smoke test MergeOperator
            {
                var dbname = "test-merge-operator";
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
                var optsTest = (DbOptions) new RocksDbSharp.DbOptions()
                               .SetCreateIfMissing(true)
                               .SetMergeOperator(MergeOperators.Create(
                                                     name: "test-merge-operator",
                                                     partialMerge: (key, keyLength, operandsList, operandsListLength, numOperands, success, newValueLength) => IntPtr.Zero,
                                                     fullMerge: (key, keyLength, existingValue, existingValueLength, operandsList, operandsListLength, numOperands, success, newValueLength) => IntPtr.Zero,
                                                     deleteValue: (value, valueLength) => { }
                                                     ));
                GC.Collect();
                using (var db = RocksDbSharp.RocksDb.Open(optsTest, dbname))
                {
                }
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
            }

            // Test that GC does not cause access violation on Comparers
            {
                var dbname = "test-av-error";
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
                options = new RocksDbSharp.DbOptions()
                          .SetCreateIfMissing(true)
                          .SetCreateMissingColumnFamilies(true);
                var sc = new RocksDbSharp.StringComparator(StringComparer.InvariantCultureIgnoreCase);
                columnFamilies = new RocksDbSharp.ColumnFamilies
                {
                    { "cf1", new RocksDbSharp.ColumnFamilyOptions()
                      .SetComparator(sc) },
                };
                GC.Collect();
                using (var db = RocksDbSharp.RocksDb.Open(options, dbname, columnFamilies))
                {
                }
                if (Directory.Exists(dbname))
                {
                    Directory.Delete(dbname, true);
                }
            }
        }