Skip to content

Commit

Permalink
Optimization: export leveldb option (#144)
Browse files Browse the repository at this point in the history
* export leveldb config

* add more option

* fix golangci-lint error

* remove a never use method

* change default cache size,bloom bits

* fix comments

* leveldb storage create use builder pattern
  • Loading branch information
0xcb9ff9 authored Sep 1, 2022
1 parent 3348150 commit 760f842
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 47 deletions.
15 changes: 7 additions & 8 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import (
"errors"
"fmt"
"math/big"
"path/filepath"
"sync"
"sync/atomic"

"github.com/dogechain-lab/dogechain/blockchain/storage"
"github.com/dogechain-lab/dogechain/blockchain/storage/leveldb"
"github.com/dogechain-lab/dogechain/blockchain/storage/memory"
"github.com/dogechain-lab/dogechain/chain"
"github.com/dogechain-lab/dogechain/helper/common"
Expand Down Expand Up @@ -82,6 +80,10 @@ type gasPriceAverage struct {
count *big.Int // Param used in the avg. gas price calculation
}

type StorageBuilder interface {
Build() (storage.Storage, error)
}

type Verifier interface {
VerifyHeader(header *types.Header) error
ProcessHeaders(headers []*types.Header) error
Expand Down Expand Up @@ -180,8 +182,8 @@ func (b *Blockchain) GetAvgGasPrice() *big.Int {
// NewBlockchain creates a new blockchain object
func NewBlockchain(
logger hclog.Logger,
dataDir string,
config *chain.Chain,
storageBuilder StorageBuilder,
consensus Verifier,
executor Executor,
) (*Blockchain, error) {
Expand All @@ -202,15 +204,12 @@ func NewBlockchain(
err error
)

if dataDir == "" {
if storageBuilder == nil {
if db, err = memory.NewMemoryStorage(nil); err != nil {
return nil, err
}
} else {
if db, err = leveldb.NewLevelDBStorage(
filepath.Join(dataDir, "blockchain"),
logger,
); err != nil {
if db, err = storageBuilder.Build(); err != nil {
return nil, err
}
}
Expand Down
156 changes: 156 additions & 0 deletions blockchain/storage/leveldb/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package leveldb

import (
"fmt"

"github.com/dogechain-lab/dogechain/blockchain/storage"
"github.com/hashicorp/go-hclog"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/filter"
leveldbopt "github.com/syndtr/goleveldb/leveldb/opt"
)

const (
// minCache is the minimum memory allocate to leveldb
// half write, half read
minCache = 16 // 16 MiB

// minHandles is the minimum number of files handles to leveldb open files
minHandles = 16

DefaultCache = 1024 // 1 GiB
DefaultHandles = 512 // files handles to leveldb open files
DefaultBloomKeyBits = 2048 // bloom filter bits (256 bytes)
DefaultCompactionTableSize = 8 // 8 MiB
DefaultCompactionTotalSize = 32 // 32 MiB
DefaultNoSync = false
)

func max(a, b int) int {
if a > b {
return a
}

return b
}

type Builder interface {
// set cache size
SetCacheSize(int) Builder

// set handles
SetHandles(int) Builder

// set bloom key bits
SetBloomKeyBits(int) Builder

// set compaction table size
SetCompactionTableSize(int) Builder

// set compaction table total size
SetCompactionTotalSize(int) Builder

// set no sync
SetNoSync(bool) Builder

// build the storage
Build() (storage.Storage, error)
}

type leveldbBuilder struct {
logger hclog.Logger
path string
options *leveldbopt.Options
}

func (builder *leveldbBuilder) SetCacheSize(cacheSize int) Builder {
cacheSize = max(cacheSize, minCache)

builder.options.BlockCacheCapacity = (cacheSize / 2) * leveldbopt.MiB
builder.options.WriteBuffer = (cacheSize / 4) * leveldbopt.MiB

builder.logger.Info("leveldb",
"BlockCacheCapacity", fmt.Sprintf("%d Mib", cacheSize/2),
"WriteBuffer", fmt.Sprintf("%d Mib", cacheSize/4),
)

return builder
}

func (builder *leveldbBuilder) SetHandles(handles int) Builder {
builder.options.OpenFilesCacheCapacity = max(handles, minHandles)

builder.logger.Info("leveldb",
"OpenFilesCacheCapacity", builder.options.OpenFilesCacheCapacity,
)

return builder
}

func (builder *leveldbBuilder) SetBloomKeyBits(bloomKeyBits int) Builder {
builder.options.Filter = filter.NewBloomFilter(bloomKeyBits)

builder.logger.Info("leveldb",
"BloomFilter bits", bloomKeyBits,
)

return builder
}

func (builder *leveldbBuilder) SetCompactionTableSize(compactionTableSize int) Builder {
builder.options.CompactionTableSize = compactionTableSize * leveldbopt.MiB

builder.logger.Info("leveldb",
"CompactionTableSize", fmt.Sprintf("%d Mib", compactionTableSize),
)

return builder
}

func (builder *leveldbBuilder) SetCompactionTotalSize(compactionTotalSize int) Builder {
builder.options.CompactionTotalSize = compactionTotalSize * leveldbopt.MiB

builder.logger.Info("leveldb",
"CompactionTotalSize", fmt.Sprintf("%d Mib", compactionTotalSize),
)

return builder
}

func (builder *leveldbBuilder) SetNoSync(noSync bool) Builder {
builder.options.NoSync = noSync

builder.logger.Info("leveldb",
"NoSync", noSync,
)

return builder
}

func (builder *leveldbBuilder) Build() (storage.Storage, error) {
db, err := leveldb.OpenFile(builder.path, builder.options)
if err != nil {
return nil, err
}

kv := &levelDBKV{db}

return storage.NewKeyValueStorage(builder.logger.Named("leveldb"), kv), nil
}

// NewBuilder creates the new leveldb storage builder
func NewBuilder(logger hclog.Logger, path string) Builder {
return &leveldbBuilder{
logger: logger,
path: path,
options: &leveldbopt.Options{
OpenFilesCacheCapacity: minHandles,
CompactionTableSize: DefaultCompactionTableSize * leveldbopt.MiB,
CompactionTotalSize: DefaultCompactionTotalSize * leveldbopt.MiB,
BlockCacheCapacity: minCache / 2 * leveldbopt.MiB,
WriteBuffer: minCache / 4 * leveldbopt.MiB,
Filter: filter.NewBloomFilter(DefaultBloomKeyBits),
NoSync: false,
},
}
}
31 changes: 0 additions & 31 deletions blockchain/storage/leveldb/leveldb.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,9 @@
package leveldb

import (
"fmt"

"github.com/dogechain-lab/dogechain/blockchain/storage"
"github.com/hashicorp/go-hclog"
"github.com/syndtr/goleveldb/leveldb"
)

// Factory creates a leveldb storage
func Factory(config map[string]interface{}, logger hclog.Logger) (storage.Storage, error) {
path, ok := config["path"]
if !ok {
return nil, fmt.Errorf("path not found")
}

pathStr, ok := path.(string)
if !ok {
return nil, fmt.Errorf("path is not a string")
}

return NewLevelDBStorage(pathStr, logger)
}

// NewLevelDBStorage creates the new storage reference with leveldb
func NewLevelDBStorage(path string, logger hclog.Logger) (storage.Storage, error) {
db, err := leveldb.OpenFile(path, nil)
if err != nil {
return nil, err
}

kv := &levelDBKV{db}

return storage.NewKeyValueStorage(logger.Named("leveldb"), kv), nil
}

// levelDBKV is the leveldb implementation of the kv storage
type levelDBKV struct {
db *leveldb.DB
Expand Down
3 changes: 2 additions & 1 deletion blockchain/storage/leveldb/leveldb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ func newStorage(t *testing.T) (storage.Storage, func()) {
t.Fatal(err)
}

s, err := NewLevelDBStorage(path, hclog.NewNullLogger())
s, err := NewBuilder(
hclog.NewNullLogger(), path).Build()
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion blockchain/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ func newBlockChain(config *chain.Chain, executor Executor) (*Blockchain, error)
executor = &mockExecutor{}
}

b, err := NewBlockchain(hclog.NewNullLogger(), "", config, &MockVerifier{}, executor)
b, err := NewBlockchain(hclog.NewNullLogger(), config, nil, &MockVerifier{}, executor)
if err != nil {
return nil, err
}
Expand Down
31 changes: 26 additions & 5 deletions command/server/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ const (
configFlag = "config"
genesisPathFlag = "chain"
dataDirFlag = "data-dir"
leveldbCacheFlag = "leveldb.cache-size"
leveldbHandlesFlag = "leveldb.handles"
leveldbBloomKeyBitsFlag = "leveldb.bloom-bits"
leveldbTableSizeFlag = "leveldb.table-size"
leveldbTotalTableSizeFlag = "leveldb.total-table-size"
leveldbNoSyncFlag = "leveldb.nosync"
libp2pAddressFlag = "libp2p"
prometheusAddressFlag = "prometheus"
natFlag = "nat"
Expand Down Expand Up @@ -67,6 +73,13 @@ type serverParams struct {
rawConfig *Config
configPath string

leveldbCacheSize int
leveldbHandles int
leveldbBloomKeyBits int
leveldbTableSize int
leveldbTotalTableSize int
leveldbNoSync bool

libp2pAddress *net.TCPAddr
prometheusAddress *net.TCPAddr
natAddress net.IP
Expand Down Expand Up @@ -198,10 +211,18 @@ func (p *serverParams) generateConfig() *server.Config {
PromoteOutdateSeconds: p.rawConfig.TxPool.PromoteOutdateSeconds,
SecretsManager: p.secretsConfig,
RestoreFile: p.getRestoreFilePath(),
BlockTime: p.rawConfig.BlockTime,
LogLevel: hclog.LevelFromString(p.rawConfig.LogLevel),
LogFilePath: p.logFileLocation,
Daemon: p.isDaemon,
ValidatorKey: p.validatorKey,
LeveldbOptions: &server.LeveldbOptions{
CacheSize: p.leveldbCacheSize,
Handles: p.leveldbHandles,
BloomKeyBits: p.leveldbBloomKeyBits,
CompactionTableSize: p.leveldbTableSize,
CompactionTotalSize: p.leveldbTotalTableSize,
NoSync: p.leveldbNoSync,
},
BlockTime: p.rawConfig.BlockTime,
LogLevel: hclog.LevelFromString(p.rawConfig.LogLevel),
LogFilePath: p.logFileLocation,
Daemon: p.isDaemon,
ValidatorKey: p.validatorKey,
}
}
43 changes: 43 additions & 0 deletions command/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strconv"
"strings"

"github.com/dogechain-lab/dogechain/blockchain/storage/leveldb"
"github.com/dogechain-lab/dogechain/command"
"github.com/dogechain-lab/dogechain/crypto"
"github.com/dogechain-lab/dogechain/helper/daemon"
Expand Down Expand Up @@ -63,6 +64,48 @@ func setFlags(cmd *cobra.Command) {
"the path to the CLI config. Supports .json and .hcl",
)

cmd.Flags().IntVar(
&params.leveldbCacheSize,
leveldbCacheFlag,
leveldb.DefaultCache,
"the size of the leveldb cache in MB",
)

cmd.Flags().IntVar(
&params.leveldbHandles,
leveldbHandlesFlag,
leveldb.DefaultHandles,
"the number of handles to leveldb open files",
)

cmd.Flags().IntVar(
&params.leveldbBloomKeyBits,
leveldbBloomKeyBitsFlag,
leveldb.DefaultBloomKeyBits,
"the bits of leveldb bloom filters",
)

cmd.Flags().IntVar(
&params.leveldbTableSize,
leveldbTableSizeFlag,
leveldb.DefaultCompactionTableSize,
"the leveldb 'sorted table' size in MB",
)

cmd.Flags().IntVar(
&params.leveldbTotalTableSize,
leveldbTotalTableSizeFlag,
leveldb.DefaultCompactionTotalSize,
"limits leveldb total size of 'sorted table' for each level in MB",
)

cmd.Flags().BoolVar(
&params.leveldbNoSync,
leveldbNoSyncFlag,
leveldb.DefaultNoSync,
"leveldb nosync allows completely disable fsync",
)

cmd.Flags().StringVar(
&params.rawConfig.DataDir,
dataDirFlag,
Expand Down
Loading

0 comments on commit 760f842

Please sign in to comment.