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
5 changes: 1 addition & 4 deletions cmd/opera/launcher/launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
gmetrics "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/discover/discfilter"
"github.com/ethereum/go-ethereum/params"
Expand Down Expand Up @@ -301,9 +300,7 @@ func makeNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store) (
_ = genesisStore.Close()
}

if gmetrics.Enabled {
metrics.SetDataDir(cfg.Node.DataDir)
}
metrics.SetDataDir(cfg.Node.DataDir)
memorizeDBPreset(cfg)

// substitute default bootnodes if requested
Expand Down
66 changes: 37 additions & 29 deletions cmd/opera/launcher/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,40 @@ var once sync.Once

func SetDataDir(datadir string) {
once.Do(func() {
go measureDbDir("db_size", datadir)
})
}

func measureDbDir(name, datadir string) {
var (
dbSize int64
gauge metrics.Gauge
rescan = (len(datadir) > 0 && datadir != "inmemory")
)
for {
time.Sleep(10 * time.Second)
var dbSize int64
_ = metrics.NewRegisteredFunctionalGauge("db_size", nil, func() int64 {
return atomic.LoadInt64(&dbSize)
})

if rescan {
size := sizeOfDir(datadir, new(int))
atomic.StoreInt64(&dbSize, size)
if !metrics.Enabled {
return
}

if gauge == nil {
gauge = metrics.NewRegisteredFunctionalGauge(name, nil, func() int64 {
return atomic.LoadInt64(&dbSize)
})
if len(datadir) == 0 || datadir == "inmemory" {
return
}

if !rescan {
break
}
go measureDbDir(datadir, &dbSize)

})
}

func measureDbDir(datadir string, dbSize *int64) {
for {
time.Sleep(10 * time.Second)
size := sizeOfDir(datadir)
atomic.StoreInt64(dbSize, size)
}
}

func sizeOfDir(dir string, counter *int) (size int64) {
var (
symlinksCache = make(map[string]string, 10e6)
symlinksThrottler = &throttler{Period: 1000, Timeout: 100 * time.Millisecond}
)

func sizeOfDir(dir string) (size int64) {
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
*counter++
if *counter % 100 == 0 {
time.Sleep(100 * time.Millisecond)
}
if err != nil {
log.Debug("datadir walk", "path", path, "err", err)
return filepath.SkipDir
Expand All @@ -60,9 +58,19 @@ func sizeOfDir(dir string, counter *int) (size int64) {
return nil
}

dst, err := filepath.EvalSymlinks(path)
if err == nil && dst != path {
size += sizeOfDir(dst, counter)
dst, cached := symlinksCache[path]
if !cached {
symlinksThrottler.Do()
var err error
dst, err = filepath.EvalSymlinks(path)
if err != nil || dst == path {
dst = ""
}
symlinksCache[path] = dst
}

if dst != "" {
size += sizeOfDir(dst)
} else {
size += info.Size()
}
Expand Down
21 changes: 21 additions & 0 deletions cmd/opera/launcher/metrics/metrics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package metrics

import (
"testing"
)

func BenchmarkSizeOfDir(b *testing.B) {
var (
datadir = "~/.opera"
size int64
)

symlinksThrottler = new(throttler) // disabled throttling
size = sizeOfDir(datadir) // cache warming
b.ResetTimer()

for i := 0; i < (b.N * 10); i++ {
size = sizeOfDir(datadir)
}
b.Log(size)
}
22 changes: 22 additions & 0 deletions cmd/opera/launcher/metrics/throttler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package metrics

import (
"time"
)

type throttler struct {
Period uint
Timeout time.Duration
count uint
}

func (t *throttler) Do() {
if t.Period == 0 {
return
}

t.count++
if t.count%t.Period == 0 {
time.Sleep(t.Timeout)
}
}