Skip to content

Commit 935cb21

Browse files
committed
expose more pebble open options, add compact/debt and compact/inprogress metrics
1 parent cb4fc77 commit 935cb21

File tree

5 files changed

+104
-25
lines changed

5 files changed

+104
-25
lines changed

core/rawdb/database.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,8 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string, r
324324

325325
// NewPebbleDBDatabase creates a persistent key-value database without a freezer
326326
// moving immutable chain segments into cold storage.
327-
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly, ephemeral bool) (ethdb.Database, error) {
328-
db, err := pebble.New(file, cache, handles, namespace, readonly, ephemeral)
327+
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly, ephemeral bool, extraOptions *pebble.ExtraOptions) (ethdb.Database, error) {
328+
db, err := pebble.New(file, cache, handles, namespace, readonly, ephemeral, extraOptions)
329329
if err != nil {
330330
return nil, err
331331
}
@@ -366,6 +366,8 @@ type OpenOptions struct {
366366
// Ephemeral means that filesystem sync operations should be avoided: data integrity in the face of
367367
// a crash is not important. This option should typically be used in tests.
368368
Ephemeral bool
369+
370+
PebbleExtraOptions *pebble.ExtraOptions
369371
}
370372

371373
// openKeyValueDatabase opens a disk-based key-value database, e.g. leveldb or pebble.
@@ -387,15 +389,15 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) {
387389
}
388390
if o.Type == dbPebble || existingDb == dbPebble {
389391
log.Info("Using pebble as the backing database")
390-
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
392+
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral, o.PebbleExtraOptions)
391393
}
392394
if o.Type == dbLeveldb || existingDb == dbLeveldb {
393395
log.Info("Using leveldb as the backing database")
394396
return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
395397
}
396398
// No pre-existing database, no user-requested one either. Default to Pebble.
397399
log.Info("Defaulting to pebble as the backing database")
398-
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
400+
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral, o.PebbleExtraOptions)
399401
}
400402

401403
// Open opens both a disk-based key-value database such as leveldb or pebble, but also

ethdb/pebble/extraoptions.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package pebble
2+
3+
import "time"
4+
5+
type ExtraOptions struct {
6+
BytesPerSync int
7+
L0CompactionFileThreshold int
8+
L0CompactionThreshold int
9+
L0StopWritesThreshold int
10+
LBaseMaxBytes int64
11+
MaxConcurrentCompactions func() int
12+
DisableAutomaticCompactions bool
13+
WALBytesPerSync int
14+
WALDir string
15+
WALMinSyncInterval func() time.Duration
16+
TargetByteDeletionRate int
17+
Experimental ExtraOptionsExperimental
18+
}
19+
20+
type ExtraOptionsExperimental struct {
21+
L0CompactionConcurrency int
22+
CompactionDebtConcurrency uint64
23+
ReadCompactionRate int64
24+
ReadSamplingMultiplier int64
25+
MaxWriterConcurrency int
26+
ForceWriterParallelism bool
27+
}

ethdb/pebble/pebble.go

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const (
4747

4848
// metricsGatheringInterval specifies the interval to retrieve pebble database
4949
// compaction, io and pause stats to report to the user.
50-
metricsGatheringInterval = 3 * time.Second
50+
metricsGatheringInterval = 100 * time.Millisecond //3 * time.Second
5151
)
5252

5353
// Database is a persistent key-value store based on the pebble storage engine.
@@ -71,6 +71,9 @@ type Database struct {
7171
seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
7272
manualMemAllocGauge metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated
7373

74+
compDebtGauge metrics.Gauge
75+
compInProgressGauge metrics.Gauge
76+
7477
levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels
7578

7679
quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag
@@ -138,7 +141,7 @@ func (l panicLogger) Fatalf(format string, args ...interface{}) {
138141

139142
// New returns a wrapped pebble DB object. The namespace is the prefix that the
140143
// metrics reporting should use for surfacing internal stats.
141-
func New(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool) (*Database, error) {
144+
func New(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool, extraOptions *ExtraOptions) (*Database, error) {
142145
// Ensure we have some minimal caching and file guarantees
143146
if cache < minCache {
144147
cache = minCache
@@ -181,7 +184,16 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
181184
quitChan: make(chan chan error),
182185
writeOptions: &pebble.WriteOptions{Sync: !ephemeral},
183186
}
184-
opt := &pebble.Options{
187+
188+
if extraOptions == nil {
189+
extraOptions = &ExtraOptions{}
190+
}
191+
if extraOptions.MaxConcurrentCompactions == nil {
192+
extraOptions.MaxConcurrentCompactions = func() int { return runtime.NumCPU() }
193+
}
194+
195+
var opt *pebble.Options
196+
opt = &pebble.Options{
185197
// Pebble has a single combined cache area and the write
186198
// buffers are taken from this too. Assign all available
187199
// memory allowance for cache.
@@ -195,16 +207,16 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
195207
// MemTableStopWritesThreshold places a hard limit on the size
196208
// of the existent MemTables(including the frozen one).
197209
// Note, this must be the number of tables not the size of all memtables
198-
// according to https://github.com/cockroachdb/pebble/blob/master/options.go#L738-L742
210+
// according to https://github.com/cockroachdb/pebble/blob/master/extraOptions.go#L738-L742
199211
// and to https://github.com/cockroachdb/pebble/blob/master/db.go#L1892-L1903.
200212
MemTableStopWritesThreshold: memTableLimit,
201213

202214
// The default compaction concurrency(1 thread),
203215
// Here use all available CPUs for faster compaction.
204-
MaxConcurrentCompactions: func() int { return runtime.NumCPU() },
216+
MaxConcurrentCompactions: extraOptions.MaxConcurrentCompactions,
205217

206-
// Per-level options. Options for at least one level must be specified. The
207-
// options for the last level are used for all subsequent levels.
218+
// Per-level extraOptions. Options for at least one level must be specified. The
219+
// extraOptions for the last level are used for all subsequent levels.
208220
Levels: []pebble.LevelOptions{
209221
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
210222
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
@@ -222,11 +234,32 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
222234
WriteStallEnd: db.onWriteStallEnd,
223235
},
224236
Logger: panicLogger{}, // TODO(karalabe): Delete when this is upstreamed in Pebble
237+
238+
BytesPerSync: extraOptions.BytesPerSync,
239+
L0CompactionFileThreshold: extraOptions.L0CompactionFileThreshold,
240+
L0CompactionThreshold: extraOptions.L0CompactionThreshold,
241+
L0StopWritesThreshold: extraOptions.L0StopWritesThreshold,
242+
LBaseMaxBytes: extraOptions.LBaseMaxBytes,
243+
DisableAutomaticCompactions: extraOptions.DisableAutomaticCompactions,
244+
WALBytesPerSync: extraOptions.WALBytesPerSync,
245+
WALDir: extraOptions.WALDir,
246+
WALMinSyncInterval: extraOptions.WALMinSyncInterval,
247+
TargetByteDeletionRate: extraOptions.TargetByteDeletionRate,
225248
}
249+
226250
// Disable seek compaction explicitly. Check https://github.com/ethereum/go-ethereum/pull/20130
227251
// for more details.
228252
opt.Experimental.ReadSamplingMultiplier = -1
229253

254+
if opt.Experimental.ReadSamplingMultiplier != 0 {
255+
opt.Experimental.ReadSamplingMultiplier = extraOptions.Experimental.ReadSamplingMultiplier
256+
}
257+
opt.Experimental.L0CompactionConcurrency = extraOptions.Experimental.L0CompactionConcurrency
258+
opt.Experimental.CompactionDebtConcurrency = extraOptions.Experimental.CompactionDebtConcurrency
259+
opt.Experimental.ReadCompactionRate = extraOptions.Experimental.ReadCompactionRate
260+
opt.Experimental.MaxWriterConcurrency = extraOptions.Experimental.MaxWriterConcurrency
261+
opt.Experimental.ForceWriterParallelism = extraOptions.Experimental.ForceWriterParallelism
262+
230263
// Open the db and recover any potential corruptions
231264
innerDB, err := pebble.Open(file, opt)
232265
if err != nil {
@@ -248,6 +281,9 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
248281
db.seekCompGauge = metrics.NewRegisteredGauge(namespace+"compact/seek", nil)
249282
db.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil)
250283

284+
db.compDebtGauge = metrics.NewRegisteredGauge(namespace+"compact/debt", nil)
285+
db.compInProgressGauge = metrics.NewRegisteredGauge(namespace+"compact/inprogress", nil)
286+
251287
// Start up the metrics gathering and return
252288
go db.meter(metricsGatheringInterval, namespace)
253289
return db, nil
@@ -525,6 +561,9 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
525561
d.level0CompGauge.Update(level0CompCount)
526562
d.seekCompGauge.Update(stats.Compact.ReadCount)
527563

564+
d.compDebtGauge.Update(int64(stats.Compact.EstimatedDebt))
565+
d.compInProgressGauge.Update(stats.Compact.NumInProgress)
566+
528567
for i, level := range stats.Levels {
529568
// Append metrics for additional layers
530569
if i >= len(d.levelsGauge) {

ethdb/pebble/pebble_non64bit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ import (
88
"github.com/ethereum/go-ethereum/ethdb"
99
)
1010

11-
func New(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool) (ethdb.Database, error) {
11+
func New(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool, extraOptions *ExtraOptions) (ethdb.Database, error) {
1212
return nil, errors.New("pebble is not supported on this platform")
1313
}

node/node.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/ethereum/go-ethereum/common/hexutil"
3535
"github.com/ethereum/go-ethereum/core/rawdb"
3636
"github.com/ethereum/go-ethereum/ethdb"
37+
"github.com/ethereum/go-ethereum/ethdb/pebble"
3738
"github.com/ethereum/go-ethereum/event"
3839
"github.com/ethereum/go-ethereum/log"
3940
"github.com/ethereum/go-ethereum/p2p"
@@ -744,6 +745,10 @@ func (n *Node) EventMux() *event.TypeMux {
744745
// previous can be found) from within the node's instance directory. If the node is
745746
// ephemeral, a memory database is returned.
746747
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) {
748+
return n.OpenDatabaseWithExtraOptions(name, cache, handles, namespace, readonly, nil)
749+
}
750+
751+
func (n *Node) OpenDatabaseWithExtraOptions(name string, cache, handles int, namespace string, readonly bool, pebbleExtraOptions *pebble.ExtraOptions) (ethdb.Database, error) {
747752
n.lock.Lock()
748753
defer n.lock.Unlock()
749754
if n.state == closedState {
@@ -756,12 +761,13 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r
756761
db = rawdb.NewMemoryDatabase()
757762
} else {
758763
db, err = rawdb.Open(rawdb.OpenOptions{
759-
Type: n.config.DBEngine,
760-
Directory: n.ResolvePath(name),
761-
Namespace: namespace,
762-
Cache: cache,
763-
Handles: handles,
764-
ReadOnly: readonly,
764+
Type: n.config.DBEngine,
765+
Directory: n.ResolvePath(name),
766+
Namespace: namespace,
767+
Cache: cache,
768+
Handles: handles,
769+
ReadOnly: readonly,
770+
PebbleExtraOptions: pebbleExtraOptions,
765771
})
766772
}
767773

@@ -777,6 +783,10 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r
777783
// database to immutable append-only files. If the node is an ephemeral one, a
778784
// memory database is returned.
779785
func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient string, namespace string, readonly bool) (ethdb.Database, error) {
786+
return n.OpenDatabaseWithFreezerWithExtraOptions(name, cache, handles, ancient, namespace, readonly, nil)
787+
}
788+
789+
func (n *Node) OpenDatabaseWithFreezerWithExtraOptions(name string, cache, handles int, ancient string, namespace string, readonly bool, pebbleExtraOptions *pebble.ExtraOptions) (ethdb.Database, error) {
780790
n.lock.Lock()
781791
defer n.lock.Unlock()
782792
if n.state == closedState {
@@ -788,13 +798,14 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient
788798
db = rawdb.NewMemoryDatabase()
789799
} else {
790800
db, err = rawdb.Open(rawdb.OpenOptions{
791-
Type: n.config.DBEngine,
792-
Directory: n.ResolvePath(name),
793-
AncientsDirectory: n.ResolveAncient(name, ancient),
794-
Namespace: namespace,
795-
Cache: cache,
796-
Handles: handles,
797-
ReadOnly: readonly,
801+
Type: n.config.DBEngine,
802+
Directory: n.ResolvePath(name),
803+
AncientsDirectory: n.ResolveAncient(name, ancient),
804+
Namespace: namespace,
805+
Cache: cache,
806+
Handles: handles,
807+
ReadOnly: readonly,
808+
PebbleExtraOptions: pebbleExtraOptions,
798809
})
799810
}
800811

0 commit comments

Comments
 (0)