Skip to content

Commit fdf3825

Browse files
authored
Merge pull request #977 from nspcc-dev/optional-statistics
Make statistics optional
2 parents fde6016 + 87d0cf7 commit fdf3825

File tree

2 files changed

+43
-27
lines changed

2 files changed

+43
-27
lines changed

db.go

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,6 @@ const (
3636
// All data access is performed through transactions which can be obtained through the DB.
3737
// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
3838
type DB struct {
39-
// Put `stats` at the first field to ensure it's 64-bit aligned. Note that
40-
// the first word in an allocated struct can be relied upon to be 64-bit
41-
// aligned. Refer to https://pkg.go.dev/sync/atomic#pkg-note-BUG. Also
42-
// refer to discussion in https://github.com/etcd-io/bbolt/issues/577.
43-
stats Stats
44-
4539
// When enabled, the database will perform a Check() after every commit.
4640
// A panic is issued if the database is in an inconsistent state. This
4741
// flag has a large performance impact so it should only be used for
@@ -138,6 +132,7 @@ type DB struct {
138132
pageSize int
139133
opened bool
140134
rwtx *Tx
135+
stats *Stats
141136

142137
freelist fl.Interface
143138
freelistLoad sync.Once
@@ -203,6 +198,10 @@ func Open(path string, mode os.FileMode, options *Options) (db *DB, err error) {
203198
db.MaxBatchDelay = common.DefaultMaxBatchDelay
204199
db.AllocSize = common.DefaultAllocSize
205200

201+
if !options.NoStatistics {
202+
db.stats = new(Stats)
203+
}
204+
206205
if options.Logger == nil {
207206
db.logger = getDiscardLogger()
208207
} else {
@@ -430,7 +429,9 @@ func (db *DB) loadFreelist() {
430429
// Read free list from freelist page.
431430
db.freelist.Read(db.page(db.meta().Freelist()))
432431
}
433-
db.stats.FreePageN = db.freelist.FreeCount()
432+
if db.stats != nil {
433+
db.stats.FreePageN = db.freelist.FreeCount()
434+
}
434435
})
435436
}
436437

@@ -808,10 +809,12 @@ func (db *DB) beginTx() (*Tx, error) {
808809
db.metalock.Unlock()
809810

810811
// Update the transaction stats.
811-
db.statlock.Lock()
812-
db.stats.TxN++
813-
db.stats.OpenTxN++
814-
db.statlock.Unlock()
812+
if db.stats != nil {
813+
db.statlock.Lock()
814+
db.stats.TxN++
815+
db.stats.OpenTxN++
816+
db.statlock.Unlock()
817+
}
815818

816819
return t, nil
817820
}
@@ -867,10 +870,12 @@ func (db *DB) removeTx(tx *Tx) {
867870
db.metalock.Unlock()
868871

869872
// Merge statistics.
870-
db.statlock.Lock()
871-
db.stats.OpenTxN--
872-
db.stats.TxStats.add(&tx.stats)
873-
db.statlock.Unlock()
873+
if db.stats != nil {
874+
db.statlock.Lock()
875+
db.stats.OpenTxN--
876+
db.stats.TxStats.add(&tx.stats)
877+
db.statlock.Unlock()
878+
}
874879
}
875880

876881
// Update executes a function within the context of a read-write managed transaction.
@@ -1088,9 +1093,13 @@ func (db *DB) Sync() (err error) {
10881093
// Stats retrieves ongoing performance stats for the database.
10891094
// This is only updated when a transaction closes.
10901095
func (db *DB) Stats() Stats {
1091-
db.statlock.RLock()
1092-
defer db.statlock.RUnlock()
1093-
return db.stats
1096+
var s Stats
1097+
if db.stats != nil {
1098+
db.statlock.RLock()
1099+
s = *db.stats
1100+
db.statlock.RUnlock()
1101+
}
1102+
return s
10941103
}
10951104

10961105
// This is for internal access to the raw data bytes from the C cursor, use
@@ -1340,15 +1349,20 @@ type Options struct {
13401349

13411350
// Logger is the logger used for bbolt.
13421351
Logger Logger
1352+
1353+
// NoStatistics turns off statistics collection, Stats method will
1354+
// return empty structure in this case. This can be beneficial for
1355+
// performance under high-concurrency read-only transactions.
1356+
NoStatistics bool
13431357
}
13441358

13451359
func (o *Options) String() string {
13461360
if o == nil {
13471361
return "{}"
13481362
}
13491363

1350-
return fmt.Sprintf("{Timeout: %s, NoGrowSync: %t, NoFreelistSync: %t, PreLoadFreelist: %t, FreelistType: %s, ReadOnly: %t, MmapFlags: %x, InitialMmapSize: %d, PageSize: %d, MaxSize: %d, NoSync: %t, OpenFile: %p, Mlock: %t, Logger: %p}",
1351-
o.Timeout, o.NoGrowSync, o.NoFreelistSync, o.PreLoadFreelist, o.FreelistType, o.ReadOnly, o.MmapFlags, o.InitialMmapSize, o.PageSize, o.MaxSize, o.NoSync, o.OpenFile, o.Mlock, o.Logger)
1364+
return fmt.Sprintf("{Timeout: %s, NoGrowSync: %t, NoFreelistSync: %t, PreLoadFreelist: %t, FreelistType: %s, ReadOnly: %t, MmapFlags: %x, InitialMmapSize: %d, PageSize: %d, MaxSize: %d, NoSync: %t, OpenFile: %p, Mlock: %t, Logger: %p, NoStatistics: %t}",
1365+
o.Timeout, o.NoGrowSync, o.NoFreelistSync, o.PreLoadFreelist, o.FreelistType, o.ReadOnly, o.MmapFlags, o.InitialMmapSize, o.PageSize, o.MaxSize, o.NoSync, o.OpenFile, o.Mlock, o.Logger, o.NoStatistics)
13521366

13531367
}
13541368

tx.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,15 @@ func (tx *Tx) close() {
357357
tx.db.rwlock.Unlock()
358358

359359
// Merge statistics.
360-
tx.db.statlock.Lock()
361-
tx.db.stats.FreePageN = freelistFreeN
362-
tx.db.stats.PendingPageN = freelistPendingN
363-
tx.db.stats.FreeAlloc = (freelistFreeN + freelistPendingN) * tx.db.pageSize
364-
tx.db.stats.FreelistInuse = freelistAlloc
365-
tx.db.stats.TxStats.add(&tx.stats)
366-
tx.db.statlock.Unlock()
360+
if tx.db.stats != nil {
361+
tx.db.statlock.Lock()
362+
tx.db.stats.FreePageN = freelistFreeN
363+
tx.db.stats.PendingPageN = freelistPendingN
364+
tx.db.stats.FreeAlloc = (freelistFreeN + freelistPendingN) * tx.db.pageSize
365+
tx.db.stats.FreelistInuse = freelistAlloc
366+
tx.db.stats.TxStats.add(&tx.stats)
367+
tx.db.statlock.Unlock()
368+
}
367369
} else {
368370
tx.db.removeTx(tx)
369371
}

0 commit comments

Comments
 (0)