From b9efe565973c21850c2e91c56167e0cba85ca8e6 Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Tue, 19 Jul 2022 10:39:48 +0700 Subject: [PATCH] mdbx: use OS pagesize by default (but > 4Kb, and < 64Kb) #530 --- kv/helpers.go | 13 +++++++++++++ kv/mdbx/kv_mdbx.go | 44 ++++++++++++++++++++++++++++++++------------ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/kv/helpers.go b/kv/helpers.go index 984298a78..a012c0807 100644 --- a/kv/helpers.go +++ b/kv/helpers.go @@ -3,12 +3,25 @@ package kv import ( "context" "fmt" + "os" "time" "github.com/ledgerwatch/erigon-lib/common" + "github.com/torquem-ch/mdbx-go/mdbx" "go.uber.org/atomic" ) +func DefaultPageSize() uint64 { + osPageSize := os.Getpagesize() + if osPageSize < 4096 { // reduce further may lead to errors (because some data is just big) + osPageSize = 4096 + } else if osPageSize > mdbx.MaxPageSize { + osPageSize = mdbx.MaxPageSize + } + osPageSize = osPageSize / 4096 * 4096 // ensure it's rounded + return uint64(osPageSize) +} + // BigChunks - read `table` by big chunks - restart read transaction after each 1 minutes func BigChunks(db RoDB, table string, from []byte, walker func(tx Tx, k, v []byte) (bool, error)) error { rollbackEvery := time.NewTicker(1 * time.Minute) diff --git a/kv/mdbx/kv_mdbx.go b/kv/mdbx/kv_mdbx.go index 99a1fa1fe..b08f68f37 100644 --- a/kv/mdbx/kv_mdbx.go +++ b/kv/mdbx/kv_mdbx.go @@ -75,7 +75,7 @@ func NewMDBX(log log.Logger) MdbxOpts { bucketsCfg: WithChaindataTables, flags: mdbx.NoReadahead | mdbx.Coalesce | mdbx.Durable, log: log, - pageSize: 4096, + pageSize: kv.DefaultPageSize(), } } @@ -208,11 +208,24 @@ func (opts MdbxOpts) Open() (kv.RwDB, error) { } } - defaultDirtyPagesLimit, err := env.GetOption(mdbx.OptTxnDpLimit) + err = env.Open(opts.path, opts.flags, 0664) if err != nil { - return nil, err + if err != nil { + return nil, fmt.Errorf("%w, label: %s, trace: %s", err, opts.label.String(), stack2.Trace().String()) + } } + // mdbx will not change pageSize if db already exists. means need read real value after env.open() + in, err := env.Info(nil) + if err != nil { + if err != nil { + return nil, fmt.Errorf("%w, label: %s, trace: %s", err, opts.label.String(), stack2.Trace().String()) + } + } + opts.pageSize = uint64(in.PageSize) + + // erigon using big transactions + // increase "page measured" options. need do it after env.Open() because default are depend on pageSize known only after env.Open() if opts.flags&mdbx.Accede == 0 && opts.flags&mdbx.Readonly == 0 { // 1/8 is good for transactions with a lot of modifications - to reduce invalidation size. // But Erigon app now using Batch and etl.Collectors to avoid writing to DB frequently changing data. @@ -220,10 +233,24 @@ func (opts MdbxOpts) Open() (kv.RwDB, error) { //if err = env.SetOption(mdbx.OptSpillMinDenominator, 8); err != nil { // return nil, err //} - if err = env.SetOption(mdbx.OptTxnDpInitial, 16*1024); err != nil { + + txnDpInitial, err := env.GetOption(mdbx.OptTxnDpInitial) + if err != nil { return nil, err } - if err = env.SetOption(mdbx.OptDpReverseLimit, 16*1024); err != nil { + if err = env.SetOption(mdbx.OptTxnDpInitial, txnDpInitial*2); err != nil { + return nil, err + } + dpReserveLimit, err := env.GetOption(mdbx.OptDpReverseLimit) + if err != nil { + return nil, err + } + if err = env.SetOption(mdbx.OptDpReverseLimit, dpReserveLimit*2); err != nil { + return nil, err + } + + defaultDirtyPagesLimit, err := env.GetOption(mdbx.OptTxnDpLimit) + if err != nil { return nil, err } if err = env.SetOption(mdbx.OptTxnDpLimit, defaultDirtyPagesLimit*2); err != nil { // default is RAM/42 @@ -241,13 +268,6 @@ func (opts MdbxOpts) Open() (kv.RwDB, error) { return nil, err } - err = env.Open(opts.path, opts.flags, 0664) - if err != nil { - if err != nil { - return nil, fmt.Errorf("%w, label: %s, trace: %s", err, opts.label.String(), stack2.Trace().String()) - } - } - if opts.syncPeriod != 0 { if err = env.SetSyncPeriod(opts.syncPeriod); err != nil { env.Close()