diff --git a/db/dboptions.go b/db/dboptions.go new file mode 100644 index 00000000..81ff82d3 --- /dev/null +++ b/db/dboptions.go @@ -0,0 +1,65 @@ +package db + +// #include "rocksdb/c.h" +import "C" +import ( + "reflect" + "unsafe" + + "github.com/tecbot/gorocksdb" +) + +func createAndSetDBOptions(bloomBits int, twoLevelIndex bool, c *gorocksdb.Cache) *gorocksdb.Options { + // get access to all db options, gorocksdb does not expose all + + // opts := gorocksdb.NewDefaultOptions() + cNativeOpts := C.rocksdb_options_create() + opts := &gorocksdb.Options{} + cField := reflect.Indirect(reflect.ValueOf(opts)).FieldByName("c") + cPtr := (**C.rocksdb_options_t)(unsafe.Pointer(cField.UnsafeAddr())) + *cPtr = cNativeOpts + + // blockOpts := gorocksdb.NewDefaultBlockBasedTableOptions() + cNativeBlockOpts := C.rocksdb_block_based_options_create() + blockOpts := &gorocksdb.BlockBasedTableOptions{} + cBlockField := reflect.Indirect(reflect.ValueOf(blockOpts)).FieldByName("c") + cBlockPtr := (**C.rocksdb_block_based_table_options_t)(unsafe.Pointer(cBlockField.UnsafeAddr())) + *cBlockPtr = cNativeBlockOpts + + blockOpts.SetBlockSize(32 << 10) // 32kB + blockOpts.SetBlockCache(c) + if bloomBits > 0 { + blockOpts.SetFilterPolicy(gorocksdb.NewBloomFilter(bloomBits)) + } + + // https://github.com/facebook/rocksdb/wiki/Partitioned-Index-Filters + if twoLevelIndex { + // blockOpts.SetCacheIndexAndFilterBlocks(true) + blockOpts.SetIndexType(gorocksdb.KTwoLevelIndexSearchIndexType) + C.rocksdb_block_based_options_set_partition_filters(cNativeBlockOpts, boolToChar(true)) + C.rocksdb_block_based_options_set_metadata_block_size(cNativeBlockOpts, C.uint64_t(4096)) + C.rocksdb_block_based_options_set_cache_index_and_filter_blocks_with_high_priority(cNativeBlockOpts, boolToChar(true)) + blockOpts.SetPinL0FilterAndIndexBlocksInCache(true) + } + + opts.SetBlockBasedTableFactory(blockOpts) + opts.SetCreateIfMissing(true) + opts.SetCreateIfMissingColumnFamilies(true) + opts.SetMaxBackgroundCompactions(6) + opts.SetMaxBackgroundFlushes(6) + opts.SetBytesPerSync(8 << 20) // 8MB + opts.SetWriteBufferSize(1 << 27) // 128MB + opts.SetMaxBytesForLevelBase(1 << 27) // 128MB + opts.SetMaxOpenFiles(25000) + opts.SetCompression(gorocksdb.LZ4HCCompression) + + return opts +} + +// boolToChar converts a bool value to C.uchar. +func boolToChar(b bool) C.uchar { + if b { + return 1 + } + return 0 +} diff --git a/db/rocksdb.go b/db/rocksdb.go index 35a52cde..704f3a90 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -59,47 +59,13 @@ const ( var cfNames = []string{"default", "height", "addresses", "txAddresses", "addressBalance", "blockTxs", "transactions"} func openDB(path string, c *gorocksdb.Cache) (*gorocksdb.DB, []*gorocksdb.ColumnFamilyHandle, error) { - bloom := gorocksdb.NewBloomFilter(10) - blockOpts := gorocksdb.NewDefaultBlockBasedTableOptions() - blockOpts.SetBlockSize(16 << 10) // 16kB - blockOpts.SetBlockCache(c) - blockOpts.SetFilterPolicy(bloom) - blockOpts.SetCacheIndexAndFilterBlocks(true) - blockOpts.SetPinL0FilterAndIndexBlocksInCache(true) - - opts := gorocksdb.NewDefaultOptions() - opts.SetBlockBasedTableFactory(blockOpts) - opts.SetCreateIfMissing(true) - opts.SetCreateIfMissingColumnFamilies(true) - opts.SetMaxBackgroundCompactions(6) - opts.SetMaxBackgroundFlushes(6) - opts.SetBytesPerSync(1 << 20) // 1MB - opts.SetWriteBufferSize(1 << 27) // 128MB - opts.SetMaxOpenFiles(25000) - opts.SetCompression(gorocksdb.LZ4HCCompression) - - // opts for addresses are different: - // no bloom filter - from documentation: If most of your queries are executed using iterators, you shouldn't set bloom filter - blockOptsAddress := gorocksdb.NewDefaultBlockBasedTableOptions() - blockOptsAddress.SetBlockSize(16 << 10) // 16kB - blockOptsAddress.SetBlockCache(c) // 8GB - blockOptsAddress.SetCacheIndexAndFilterBlocks(true) - blockOptsAddress.SetPinL0FilterAndIndexBlocksInCache(true) - - optsAddresses := gorocksdb.NewDefaultOptions() - optsAddresses.SetBlockBasedTableFactory(blockOptsAddress) - optsAddresses.SetCreateIfMissing(true) - optsAddresses.SetCreateIfMissingColumnFamilies(true) - optsAddresses.SetMaxBackgroundCompactions(6) - optsAddresses.SetMaxBackgroundFlushes(6) - optsAddresses.SetBytesPerSync(1 << 20) // 1MB - optsAddresses.SetWriteBufferSize(1 << 27) // 128MB - optsAddresses.SetMaxOpenFiles(25000) - optsAddresses.SetCompression(gorocksdb.LZ4HCCompression) - + // opts with bloom filter + opts := createAndSetDBOptions(10, true, c) + // opts for addresses without bloom filter + // from documentation: if most of your queries are executed using iterators, you shouldn't set bloom filter + optsAddresses := createAndSetDBOptions(0, true, c) // default, height, addresses, txAddresses, addressBalance, blockTxids, transactions fcOptions := []*gorocksdb.Options{opts, opts, optsAddresses, opts, opts, opts, opts} - db, cfh, err := gorocksdb.OpenDbColumnFamilies(opts, path, cfNames, fcOptions) if err != nil { return nil, nil, err @@ -111,7 +77,7 @@ func openDB(path string, c *gorocksdb.Cache) (*gorocksdb.DB, []*gorocksdb.Column // needs to be called to release it. func NewRocksDB(path string, parser bchain.BlockChainParser, metrics *common.Metrics) (d *RocksDB, err error) { glog.Infof("rocksdb: open %s, version %v", path, dbVersion) - c := gorocksdb.NewLRUCache(8 << 30) // 8GB + c := gorocksdb.NewLRUCache(1 << 30) // 1GB db, cfh, err := openDB(path, c) wo := gorocksdb.NewDefaultWriteOptions() ro := gorocksdb.NewDefaultReadOptions()