Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions TreeDB/caching/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -6553,6 +6553,7 @@ func Open(dir string, backend BackendDB, opts Options) (*DB, error) {
go db.flushLoop()
db.startVlogGenerationLoop()
db.startVlogShapeLoop()
registerTreeDBExpvarStatsDB(db)

return db, nil
}
Expand Down Expand Up @@ -12602,6 +12603,7 @@ func (db *DB) Close() error {
var errs []error
hadMemtables := false
db.closing.Store(true)
unregisterTreeDBExpvarStatsDB(db)
db.stopDomainIngressWorkers()
db.waitForRetainedValueLogPrune()

Expand Down
94 changes: 94 additions & 0 deletions TreeDB/caching/expvar_stats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package caching

import (
"expvar"
"os"
"strconv"
"strings"
"sync"
"sync/atomic"
)

const treedbExpvarEnabledEnvKey = "TREEDB_ENABLE_EXPVAR_STATS"

var (
treedbExpvarEnabled = parseBoolEnvDefault(treedbExpvarEnabledEnvKey, true)
treedbExpvarPublishOnce sync.Once
treedbExpvarCurrentDB atomic.Pointer[DB]
)

func parseBoolEnvDefault(key string, def bool) bool {
raw := strings.TrimSpace(os.Getenv(key))
if raw == "" {
return def
}
switch strings.ToLower(raw) {
case "1", "true", "on", "yes":
return true
case "0", "false", "off", "no":
return false
default:
return def
}
}

func publishTreeDBExpvarStats() {
treedbExpvarPublishOnce.Do(func() {
expvar.Publish("treedb", expvar.Func(func() any {
return currentTreeDBExpvarStats()
}))
})
}

func registerTreeDBExpvarStatsDB(db *DB) {
if db == nil || !treedbExpvarEnabled {
return
}
publishTreeDBExpvarStats()
treedbExpvarCurrentDB.Store(db)
}

func unregisterTreeDBExpvarStatsDB(db *DB) {
if db == nil || !treedbExpvarEnabled {
return
}
treedbExpvarCurrentDB.CompareAndSwap(db, nil)
}

func currentTreeDBExpvarStats() map[string]any {
db := treedbExpvarCurrentDB.Load()
if db == nil {
return map[string]any{}
}
return selectTreeDBExpvarStats(db.Stats())
}

func selectTreeDBExpvarStats(stats map[string]string) map[string]any {
if len(stats) == 0 {
return map[string]any{}
}
out := make(map[string]any)
for k, v := range stats {
if strings.HasPrefix(k, "treedb.cache.vlog_mmap.") ||
strings.HasPrefix(k, "treedb.process.memory.") {
out[k] = coerceStatsValue(v)
}
}
return out
}

func coerceStatsValue(v string) any {
if i, err := strconv.ParseInt(v, 10, 64); err == nil {
return i
}
if u, err := strconv.ParseUint(v, 10, 64); err == nil {
return u
}
if f, err := strconv.ParseFloat(v, 64); err == nil {
return f
}
if b, err := strconv.ParseBool(v); err == nil {
return b
}
return v
}
47 changes: 47 additions & 0 deletions TreeDB/caching/expvar_stats_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package caching

import "testing"

func TestSelectTreeDBExpvarStatsFiltersAndCoerces(t *testing.T) {
stats := map[string]string{
"treedb.cache.vlog_mmap.active_bytes": "12345",
"treedb.cache.vlog_mmap.read.hit_ratio": "0.625000",
"treedb.cache.vlog_mmap.enabled": "true",
"treedb.process.memory.heap_inuse_bytes": "4096",
"treedb.process.memory.pool_pressure_level": "critical",
"treedb.cache.backpressure_mode": "adaptive",
"treedb.cache.entry_slice.trim_runs_total": "77",
"treedb.process.memory.pool_pressure_high_pct": "85.5",
}

got := selectTreeDBExpvarStats(stats)
if len(got) != 6 {
t.Fatalf("selectTreeDBExpvarStats len=%d want 6", len(got))
}

if v, ok := got["treedb.cache.vlog_mmap.active_bytes"].(int64); !ok || v != 12345 {
t.Fatalf("active_bytes=%T(%v) want int64(12345)", got["treedb.cache.vlog_mmap.active_bytes"], got["treedb.cache.vlog_mmap.active_bytes"])
}
if v, ok := got["treedb.cache.vlog_mmap.read.hit_ratio"].(float64); !ok || v != 0.625 {
t.Fatalf("hit_ratio=%T(%v) want float64(0.625)", got["treedb.cache.vlog_mmap.read.hit_ratio"], got["treedb.cache.vlog_mmap.read.hit_ratio"])
}
if v, ok := got["treedb.cache.vlog_mmap.enabled"].(bool); !ok || !v {
t.Fatalf("enabled=%T(%v) want bool(true)", got["treedb.cache.vlog_mmap.enabled"], got["treedb.cache.vlog_mmap.enabled"])
}
if v, ok := got["treedb.process.memory.heap_inuse_bytes"].(int64); !ok || v != 4096 {
t.Fatalf("heap_inuse_bytes=%T(%v) want int64(4096)", got["treedb.process.memory.heap_inuse_bytes"], got["treedb.process.memory.heap_inuse_bytes"])
}
if v, ok := got["treedb.process.memory.pool_pressure_level"].(string); !ok || v != "critical" {
t.Fatalf("pool_pressure_level=%T(%v) want string(critical)", got["treedb.process.memory.pool_pressure_level"], got["treedb.process.memory.pool_pressure_level"])
}
if _, ok := got["treedb.cache.backpressure_mode"]; ok {
t.Fatalf("unexpected backpressure_mode key in expvar selection")
}
}

func TestSelectTreeDBExpvarStatsEmpty(t *testing.T) {
got := selectTreeDBExpvarStats(nil)
if len(got) != 0 {
t.Fatalf("selectTreeDBExpvarStats(nil) len=%d want 0", len(got))
}
}
Loading