diff --git a/x/merkledb/db.go b/x/merkledb/db.go index b3251878216..b8f83556f3e 100644 --- a/x/merkledb/db.go +++ b/x/merkledb/db.go @@ -15,7 +15,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/attribute" "golang.org/x/exp/maps" - "golang.org/x/sync/semaphore" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/ids" @@ -218,7 +217,7 @@ type merkleDB struct { // calculateNodeIDsSema controls the number of goroutines inside // [calculateNodeIDsHelper] at any given time. - calculateNodeIDsSema *semaphore.Weighted + calculateNodeIDsSema semaphore tokenSize int } @@ -274,7 +273,7 @@ func newDatabase( debugTracer: getTracerIfEnabled(config.TraceLevel, DebugTrace, config.Tracer), infoTracer: getTracerIfEnabled(config.TraceLevel, InfoTrace, config.Tracer), childViews: make([]*view, 0, defaultPreallocationSize), - calculateNodeIDsSema: semaphore.NewWeighted(int64(rootGenConcurrency)), + calculateNodeIDsSema: make(semaphore, rootGenConcurrency), tokenSize: BranchFactorToTokenSize[config.BranchFactor], } diff --git a/x/merkledb/semaphore.go b/x/merkledb/semaphore.go new file mode 100644 index 00000000000..21171ec1ed3 --- /dev/null +++ b/x/merkledb/semaphore.go @@ -0,0 +1,27 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package merkledb + +type semaphore chan struct{} + +func (s semaphore) Acquire() { + s <- struct{}{} +} + +func (s semaphore) TryAcquire() bool { + select { + case s <- struct{}{}: + return true + default: + return false + } +} + +func (s semaphore) Release() { + select { + case <-s: + default: + panic("release of unacquired semaphore") + } +} diff --git a/x/merkledb/semaphore_test.go b/x/merkledb/semaphore_test.go new file mode 100644 index 00000000000..faa9595377e --- /dev/null +++ b/x/merkledb/semaphore_test.go @@ -0,0 +1,46 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package merkledb + +import "testing" + +func Benchmark_Semaphore_Acquire(b *testing.B) { + s := make(semaphore, b.N) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + s.Acquire() + } +} + +func Benchmark_Semaphore_Release(b *testing.B) { + s := make(semaphore, b.N) + for i := 0; i < b.N; i++ { + s.Acquire() + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + s.Release() + } +} + +func Benchmark_Semaphore_TryAcquire_Success(b *testing.B) { + s := make(semaphore, b.N) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + s.TryAcquire() + } +} + +func Benchmark_Semaphore_TryAcquire_Failure(b *testing.B) { + s := make(semaphore, 1) + s.Acquire() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + s.TryAcquire() + } +} diff --git a/x/merkledb/view.go b/x/merkledb/view.go index dd564afefdd..d87f0ec6cc4 100644 --- a/x/merkledb/view.go +++ b/x/merkledb/view.go @@ -244,9 +244,9 @@ func (v *view) calculateNodeIDs(ctx context.Context) error { } if !v.root.IsNothing() { - _ = v.db.calculateNodeIDsSema.Acquire(context.Background(), 1) + v.db.calculateNodeIDsSema.Acquire() v.changes.rootID = v.calculateNodeIDsHelper(v.root.Value()) - v.db.calculateNodeIDsSema.Release(1) + v.db.calculateNodeIDsSema.Release() } else { v.changes.rootID = ids.Empty } @@ -282,11 +282,11 @@ func (v *view) calculateNodeIDsHelper(n *node) ids.ID { childEntry.hasValue = childNodeChange.after.hasValue() // Try updating the child and its descendants in a goroutine. - if ok := v.db.calculateNodeIDsSema.TryAcquire(1); ok { + if v.db.calculateNodeIDsSema.TryAcquire() { wg.Add(1) go func() { childEntry.id = v.calculateNodeIDsHelper(childNodeChange.after) - v.db.calculateNodeIDsSema.Release(1) + v.db.calculateNodeIDsSema.Release() wg.Done() }() } else {