Skip to content

Commit 8615b15

Browse files
committed
db: pool scan internal iterators separately
The ScanInternal API allow the caller to scan the internal keys within the engine. Because these internal scans require maintaining additional state, these scans are backed by a separate 'scanInternalIterator' type. This commit bundles this along with iterAlloc into a new pooled scanInternalIterAlloc struct. The inclusion of the scanInternalIterator struct avoids that allocation, but more importantly, the separate pool prevents ScanInternal from sharing objects with ordinary Iterators. The different access patterns of ScanInternal and Iterators can yield different buffer sizes. Since the code paths are separate, code drift can accidentally result in discarding buffers when returning an iterAlloc for reuse. Using separate pools sidesteps these concerns.
1 parent e542217 commit 8615b15

File tree

1 file changed

+31
-15
lines changed

1 file changed

+31
-15
lines changed

scan_internal.go

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"fmt"
1010
"slices"
11+
"sync"
1112

1213
"github.com/cockroachdb/errors"
1314
"github.com/cockroachdb/pebble/internal/base"
@@ -181,8 +182,9 @@ func (d *DB) newInternalIter(
181182

182183
// Bundle various structures under a single umbrella in order to allocate
183184
// them together.
184-
buf := newIterAlloc()
185-
dbi := &scanInternalIterator{
185+
buf := scanInternalIteratorIterAllocPool.Get().(*scanInternalIterAlloc)
186+
dbi := &buf.scanIter
187+
*dbi = scanInternalIterator{
186188
ctx: ctx,
187189
db: d,
188190
comparer: d.opts.Comparer,
@@ -193,7 +195,7 @@ func (d *DB) newInternalIter(
193195
newIters: d.newIters,
194196
newIterRangeKey: d.tableNewRangeKeyIter,
195197
seqNum: seqNum,
196-
mergingIter: &buf.merging,
198+
mergingIter: &buf.iterAlloc.merging,
197199
}
198200
dbi.blobValueFetcher.Init(&vers.BlobFiles, d.fileCache, block.ReadEnv{},
199201
blob.SuggestedCachedReaders(vers.MaxReadAmp()))
@@ -219,7 +221,7 @@ type internalIterOpts struct {
219221
}
220222

221223
func finishInitializingInternalIter(
222-
buf *iterAlloc, i *scanInternalIterator,
224+
buf *scanInternalIterAlloc, i *scanInternalIterator,
223225
) (*scanInternalIterator, error) {
224226
// Short-hand.
225227
var memtables flushableList
@@ -236,7 +238,7 @@ func finishInitializingInternalIter(
236238
}
237239
i.initializeBoundBufs(i.opts.LowerBound, i.opts.UpperBound)
238240

239-
if err := i.constructPointIter(i.opts.Category, memtables, buf); err != nil {
241+
if err := i.constructPointIter(i.opts.Category, memtables, &buf.iterAlloc); err != nil {
240242
return nil, err
241243
}
242244

@@ -585,7 +587,7 @@ type scanInternalIterator struct {
585587
rangeKey *iteratorRangeKeyState
586588
pointKeyIter internalIterator
587589
iterKV *base.InternalKV
588-
alloc *iterAlloc
590+
alloc *scanInternalIterAlloc
589591
newIters tableNewIters
590592
newIterRangeKey keyspanimpl.TableNewSpanIter
591593
seqNum base.SeqNum
@@ -1300,18 +1302,19 @@ func (i *scanInternalIterator) Close() error {
13001302
if alloc := i.alloc; alloc != nil {
13011303
for j := range i.boundsBuf {
13021304
if cap(i.boundsBuf[j]) >= maxKeyBufCacheSize {
1303-
alloc.boundsBuf[j] = nil
1305+
alloc.iterAlloc.boundsBuf[j] = nil
13041306
} else {
1305-
alloc.boundsBuf[j] = i.boundsBuf[j]
1307+
alloc.iterAlloc.boundsBuf[j] = i.boundsBuf[j]
13061308
}
13071309
}
1308-
*alloc = iterAlloc{
1309-
keyBuf: alloc.keyBuf[:0],
1310-
boundsBuf: alloc.boundsBuf,
1311-
prefixOrFullSeekKey: alloc.prefixOrFullSeekKey[:0],
1312-
}
1313-
iterAllocPool.Put(alloc)
1314-
i.alloc = nil
1310+
keyBuf := alloc.iterAlloc.keyBuf[:0]
1311+
boundsBuf := alloc.iterAlloc.boundsBuf
1312+
prefixOrFullSeekKey := alloc.iterAlloc.prefixOrFullSeekKey[:0]
1313+
*alloc = scanInternalIterAlloc{}
1314+
alloc.iterAlloc.keyBuf = keyBuf
1315+
alloc.iterAlloc.boundsBuf = boundsBuf
1316+
alloc.iterAlloc.prefixOrFullSeekKey = prefixOrFullSeekKey
1317+
scanInternalIteratorIterAllocPool.Put(alloc)
13151318
}
13161319
return err
13171320
}
@@ -1333,3 +1336,16 @@ func (i *scanInternalIterator) initializeBoundBufs(lower, upper []byte) {
13331336
i.boundsBuf[i.boundsBufIdx] = buf
13341337
i.boundsBufIdx = 1 - i.boundsBufIdx
13351338
}
1339+
1340+
// scanInternalIterAlloc is a wrapper around iterAlloc that includes a
1341+
// scanInternalIterator.
1342+
type scanInternalIterAlloc struct {
1343+
iterAlloc iterAlloc
1344+
scanIter scanInternalIterator
1345+
}
1346+
1347+
var scanInternalIteratorIterAllocPool = sync.Pool{
1348+
New: func() interface{} {
1349+
return &scanInternalIterAlloc{}
1350+
},
1351+
}

0 commit comments

Comments
 (0)