Skip to content

Commit b83f030

Browse files
committed
save
1 parent 19e6e35 commit b83f030

2 files changed

Lines changed: 21 additions & 88 deletions

File tree

db/kv/mdbx/kv_mdbx.go

Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ import (
3636
"github.com/c2h5oh/datasize"
3737
"github.com/erigontech/mdbx-go/mdbx"
3838
stack2 "github.com/go-stack/stack"
39-
"golang.org/x/sync/errgroup"
4039
"golang.org/x/sync/semaphore"
4140

42-
"github.com/erigontech/erigon/common"
4341
"github.com/erigontech/erigon/common/dbg"
4442
"github.com/erigontech/erigon/common/dir"
4543
"github.com/erigontech/erigon/common/estimate"
@@ -883,90 +881,7 @@ func (db *MdbxKV) WarmupTable(ctx context.Context, bucket string) {
883881
if workers <= 0 {
884882
return
885883
}
886-
const lvl = log.LvlInfo
887-
888-
var total, size uint64
889-
var bounds [][]byte
890-
if err := db.View(ctx, func(tx kv.Tx) error {
891-
var err error
892-
if total, err = tx.Count(bucket); err != nil {
893-
return err
894-
}
895-
if size, err = tx.BucketSize(bucket); err != nil {
896-
return err
897-
}
898-
if total == 0 {
899-
return nil
900-
}
901-
b, err := tx.(*MdbxTx).SplitBucketByCount(bucket, nil, workers*4) // count-balanced via b-tree, even when keys cluster
902-
if err != nil {
903-
return err
904-
}
905-
bounds = make([][]byte, len(b)) // b's interior keys are zero-copy, valid only until this tx ends
906-
for i, k := range b {
907-
bounds[i] = bytes.Clone(k)
908-
}
909-
return nil
910-
}); err != nil {
911-
if !errors.Is(err, context.Canceled) {
912-
db.log.Warn("[warmup] inspect failed", "table", bucket, "err", err)
913-
}
914-
return
915-
}
916-
if len(bounds) < 2 {
917-
return
918-
}
919-
920-
started := time.Now()
921-
var progress, alive atomic.Int64
922-
logEvery := time.NewTicker(20 * time.Second)
923-
defer logEvery.Stop()
924-
925-
g, ctx := errgroup.WithContext(ctx)
926-
g.SetLimit(workers)
927-
for i := 0; i+1 < len(bounds); i++ {
928-
from, to := bounds[i], bounds[i+1]
929-
g.Go(func() error {
930-
alive.Add(1)
931-
defer alive.Add(-1)
932-
return db.View(ctx, func(tx kv.Tx) error {
933-
it, err := tx.Range(bucket, from, to, order.Asc, -1)
934-
if err != nil {
935-
return err
936-
}
937-
defer it.Close()
938-
for it.HasNext() {
939-
k, v, err := it.Next()
940-
if err != nil {
941-
return err
942-
}
943-
if len(v) > 0 {
944-
_, _ = v[0], v[len(v)-1]
945-
}
946-
if len(k) > 0 {
947-
_, _ = k[0], k[len(k)-1]
948-
}
949-
if p := progress.Add(1); p%128 == 0 {
950-
select {
951-
case <-ctx.Done():
952-
return ctx.Err()
953-
case <-logEvery.C:
954-
pct := min(100, 100*float64(progress.Load())/float64(total))
955-
db.log.Log(lvl, fmt.Sprintf("[warmup] Progress: %s %s %.2f%%, workers: %d/%d", bucket, common.ByteCount(size), pct, alive.Load(), workers))
956-
default:
957-
}
958-
}
959-
}
960-
return nil
961-
})
962-
})
963-
}
964-
if err := g.Wait(); err != nil && !errors.Is(err, context.Canceled) {
965-
db.log.Warn("[warmup] failed", "table", bucket, "err", err)
966-
}
967-
if took := time.Since(started); took > 30*time.Second {
968-
db.log.Log(lvl, "[warmup] done", "table", bucket, "size", common.ByteCount(size), "keys", common.PrettyCounter(total), "took", took.Round(time.Second), "workers", workers)
969-
}
884+
kv.WarmupTable(ctx, db, bucket, workers)
970885
}
971886

972887
// SplitBucketByCount partitions bucket into n approximately equal-COUNT key

db/kv/readahead.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,31 @@ type ReadAheader struct {
4747
consumerChunk atomic.Int64
4848
cancel context.CancelFunc
4949
done chan struct{}
50+
label string
51+
full bool // warm every chunk ignoring consumer position (whole-table warmup)
5052
}
5153

5254
// NewReadAheader starts `workers` background prefetchers over `table` from `from`
5355
// (nil = table start). Call SetPos as the consumer advances, and Close when done.
5456
func NewReadAheader(ctx context.Context, db RoDB, table string, from []byte, workers int) *ReadAheader {
57+
return newReadAheader(ctx, db, table, from, workers, "read-ahead", false)
58+
}
59+
60+
// WarmupTable pulls the whole table into the OS page cache with `workers`
61+
// parallel readers and blocks until done or ctx is cancelled — a ReadAheader
62+
// with no consumer to throttle to, so every chunk gets warmed.
63+
func WarmupTable(ctx context.Context, db RoDB, table string, workers int) {
64+
r := newReadAheader(ctx, db, table, nil, workers, "warmup", true)
65+
<-r.done
66+
r.cancel()
67+
}
68+
69+
func newReadAheader(ctx context.Context, db RoDB, table string, from []byte, workers int, label string, full bool) *ReadAheader {
5570
if workers < 1 {
5671
workers = 1
5772
}
5873
ctx, cancel := context.WithCancel(ctx)
59-
r := &ReadAheader{cancel: cancel, done: make(chan struct{})}
74+
r := &ReadAheader{cancel: cancel, done: make(chan struct{}), label: label, full: full}
6075
go r.run(ctx, db, table, from, workers)
6176
return r
6277
}
@@ -68,6 +83,9 @@ func (r *ReadAheader) run(ctx context.Context, db RoDB, table string, from []byt
6883
if len(bounds) < 2 {
6984
return
7085
}
86+
if r.full {
87+
ahead = int64(len(bounds)) // no consumer to follow: keep every chunk in the window
88+
}
7189
r.bounds.Store(&bounds)
7290

7391
var doneChunks, alive atomic.Int64
@@ -87,7 +105,7 @@ func (r *ReadAheader) run(ctx context.Context, db RoDB, table string, from []byt
87105
doneChunks.Add(1) // count only chunks actually warmed, not the skipped ones
88106
select {
89107
case <-logEvery.C:
90-
log.Info("[read-ahead]", "table", table, "consumer-chunk", r.consumerChunk.Load(), "done", doneChunks.Load(), "chunks", len(bounds)-1, "alive", alive.Load(), "workers", workers)
108+
log.Info("["+r.label+"]", "table", table, "consumer-chunk", r.consumerChunk.Load(), "done", doneChunks.Load(), "chunks", len(bounds)-1, "alive", alive.Load(), "workers", workers)
91109
default:
92110
}
93111
return nil

0 commit comments

Comments
 (0)