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
14 changes: 13 additions & 1 deletion db/state/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func newAggregator(ctx context.Context, dirs datadir.Dirs, reorgBlockDepth uint6
leakDetector: dbg.NewLeakDetector("agg", dbg.SlowTx()),
backgroundProgress: background.NewProgressSet(),
logger: logger,
workers: workersCfg{merge: 1, collateAndBuild: 1},
workers: workersCfg{merge: dbg.MergeWorkers, collateAndBuild: dbg.CollateWorkers},

produce: true,
}
Expand Down Expand Up @@ -242,6 +242,7 @@ func (a *Aggregator) RegisterDomain(cfg statecfg.DomainCfg, salt *uint32, dirs d
}
a.d[cfg.Name].salt.Store(salt)
a.AddDependencyBtwnHistoryII(cfg.Name)
a.applyEnvCompressWorkers()
return nil
}

Expand All @@ -259,6 +260,7 @@ func (a *Aggregator) RegisterII(cfg statecfg.InvIdxCfg, salt *uint32, dirs datad
}
a.iis[a.iisCount] = ii
a.iisCount++
a.applyEnvCompressWorkers()
return nil
}

Expand Down Expand Up @@ -787,6 +789,16 @@ func (a *Aggregator) setBuildAccessorsWorkers(i int) {
})
}

// applyEnvCompressWorkers covers the window before the first preset lands: a restart with
// files on disk merges with whatever the compressor config holds at registration.
Comment on lines +792 to +793
func (a *Aggregator) applyEnvCompressWorkers() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this func is not related to env

if dbg.CompressWorkers <= 0 {
return
}
a.setCompressWorkers(dbg.CompressWorkers)
a.setBuildAccessorsWorkers(dbg.CompressWorkers)
Comment on lines +794 to +799
}

func (a *Aggregator) setCompressWorkers(i int) {
a.workers.trySet(func() {
for _, d := range a.d {
Expand Down
31 changes: 17 additions & 14 deletions db/state/aggregator2.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,10 @@ func (opts AggOpts) WithErigonDBSettings(s *ErigonDBSettings) AggOpts { //nolint

type workersCfg struct {
mu sync.Mutex
editLocks int // >0 while background build/merge pins config; Preset* writes are no-ops
editLocks int // >0 while background build/merge pins config
merge int // usually 1
collateAndBuild int
pending []func() // requests that arrived while pinned
}

func (w *workersCfg) getMerge() int {
Expand All @@ -156,11 +157,7 @@ func (w *workersCfg) getMerge() int {
}

func (w *workersCfg) setMerge(n int) {
w.mu.Lock()
defer w.mu.Unlock()
if w.editLocks == 0 {
w.merge = n
}
w.trySet(func() { w.merge = n })
}

func (w *workersCfg) getCollateAndBuild() int {
Expand All @@ -170,20 +167,19 @@ func (w *workersCfg) getCollateAndBuild() int {
}

func (w *workersCfg) setCollateAndBuild(n int) {
w.mu.Lock()
defer w.mu.Unlock()
if w.editLocks == 0 {
w.collateAndBuild = n
}
w.trySet(func() { w.collateAndBuild = n })
}

// trySet runs fn under mu only while editing is unlocked (no background op holds it).
// trySet runs fn under mu, or queues it for the last unlockEditing while a background op pins
// the config: dropping the request loses it for the process — a restart merges before any preset.
Comment on lines +173 to +174
func (w *workersCfg) trySet(fn func()) {
w.mu.Lock()
defer w.mu.Unlock()
if w.editLocks == 0 {
fn()
if w.editLocks > 0 {
w.pending = append(w.pending, fn)
return
Comment on lines +178 to +180
}
fn()
}

// lockEditing is reentrant: overlapping build/merge ops each hold a lock, and
Expand All @@ -200,6 +196,13 @@ func (w *workersCfg) unlockEditing() {
if w.editLocks > 0 {
w.editLocks--
}
if w.editLocks != 0 {
return
}
for _, fn := range w.pending {
fn()
}
w.pending = nil
}

func CheckSnapshotsCompatibility(d datadir.Dirs) error {
Expand Down
54 changes: 54 additions & 0 deletions db/state/aggregator2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,57 @@ func TestWorkersCfgEditingLockIsReentrant(t *testing.T) {
w.unlockEditing()
require.True(t, editable(), "extra unlock must not underflow and disable editing")
}

func TestWorkersCfgAppliesRequestDeferredWhilePinned(t *testing.T) {
t.Parallel()
w := &workersCfg{merge: 1, collateAndBuild: 1}
compress := 0

w.lockEditing()
w.setMerge(2)
w.setCollateAndBuild(4)
w.trySet(func() { compress = 8 })
require.Equal(t, 1, w.getMerge(), "must not change under a running build or merge")
require.Equal(t, 1, w.getCollateAndBuild())
require.Zero(t, compress)

w.unlockEditing()
require.Equal(t, 2, w.getMerge(), "held request applies on release")
require.Equal(t, 4, w.getCollateAndBuild())
require.Equal(t, 8, compress, "every queued request runs, not just the last")
}

func TestWorkersCfgHoldsRequestUntilLastPinReleases(t *testing.T) {
t.Parallel()
w := &workersCfg{merge: 1, collateAndBuild: 1}

w.lockEditing()
w.lockEditing()
w.setMerge(2)
w.setCollateAndBuild(4)

w.unlockEditing()
require.Equal(t, 1, w.getCollateAndBuild(), "one of two overlapping pins released is still pinned")

w.unlockEditing()
require.Equal(t, 4, w.getCollateAndBuild())
}

func TestWorkersCfgKeepsOnlyTheNewestRequest(t *testing.T) {
t.Parallel()
w := &workersCfg{merge: 1, collateAndBuild: 1}

w.lockEditing()
w.setMerge(2)
w.setCollateAndBuild(4)
w.setMerge(3)
w.setCollateAndBuild(6)
w.unlockEditing()
require.Equal(t, 3, w.getMerge())
require.Equal(t, 6, w.getCollateAndBuild())

// A pin/release cycle with no request in between must not resurrect a stale value.
w.lockEditing()
w.unlockEditing()
require.Equal(t, 6, w.getCollateAndBuild())
}
Loading