Skip to content

Commit efc7e3d

Browse files
jholdstockdavecgh
authored andcommitted
primitives: Dont cache duplicate subsidy intervals
The subsidy cache releases its mutex while calculating the subsidy for an interval that is not already cached and only reacquires it to store the result. This meant that concurrent goroutines calculating the same subsidy interval could insert the result twice.
1 parent ae4c581 commit efc7e3d

1 file changed

Lines changed: 16 additions & 4 deletions

File tree

internal/staging/primitives/subsidy.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2015-2022 The Decred developers
1+
// Copyright (c) 2015-2026 The Decred developers
22
// Use of this source code is governed by an ISC
33
// license that can be found in the LICENSE file.
44

@@ -262,10 +262,22 @@ func (c *SubsidyCache) CalcBlockSubsidy(height int64) int64 {
262262
// subsidy became zero when applicable. The cached intervals are stored in
263263
// a map for O(1) lookup and also tracked via a sorted array to support the
264264
// binary searches for efficient sparse interval query support.
265+
//
266+
// Note that the mutex is not held while performing the calculation above,
267+
// so another goroutine might have already cached the same interval in the
268+
// interim. Avoid inserting the interval again in that case since doing so
269+
// would add duplicate entries to the sorted interval array, causing it to
270+
// grow without bound and require repeated sorting.
271+
//
272+
// The calculation is fully deterministic so any subsidy another goroutine
273+
// cached for the interval is necessarily identical to the one calculated
274+
// here.
265275
c.mtx.Lock()
266-
c.cache[reqInterval] = subsidy
267-
c.cachedIntervals = append(c.cachedIntervals, reqInterval)
268-
sort.Sort((*uint64s)(&c.cachedIntervals))
276+
if _, ok := c.cache[reqInterval]; !ok {
277+
c.cache[reqInterval] = subsidy
278+
c.cachedIntervals = append(c.cachedIntervals, reqInterval)
279+
sort.Sort((*uint64s)(&c.cachedIntervals))
280+
}
269281
c.mtx.Unlock()
270282
return subsidy
271283
}

0 commit comments

Comments
 (0)