Skip to content

Commit 4ad0e5f

Browse files
committed
Revert "sstable: lazy load the index block in single level iterator"
This reverts commit 527eebf.
1 parent f535156 commit 4ad0e5f

File tree

7 files changed

+31
-102
lines changed

7 files changed

+31
-102
lines changed

sstable/reader_iter_single_lvl.go

Lines changed: 17 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,6 @@ type singleLevelIterator[I any, PI indexBlockIterator[I], D any, PD dataBlockIte
165165
useFilterBlock bool
166166
lastBloomFilterMatched bool
167167

168-
// Lazy loading flag
169-
indexLoaded bool
170-
171168
transforms IterTransforms
172169

173170
// All fields above this field are cleared when resetting the iterator for reuse.
@@ -217,9 +214,14 @@ func newColumnBlockSingleLevelIterator(
217214
i.vbRH = r.blockReader.UsePreallocatedReadHandle(objstorage.NoReadBefore, &i.vbRHPrealloc)
218215
}
219216
i.data.InitOnce(r.keySchema, r.Comparer, &i.internalValueConstructor)
220-
221-
// Use lazy loading by default - index will be loaded on first access
222-
i.indexLoaded = false
217+
indexH, err := r.readTopLevelIndexBlock(ctx, i.readEnv.Block, i.indexFilterRH)
218+
if err == nil {
219+
err = i.index.InitHandle(r.Comparer, indexH, opts.Transforms)
220+
}
221+
if err != nil {
222+
_ = i.Close()
223+
return nil, err
224+
}
223225
return i, nil
224226
}
225227

@@ -252,8 +254,14 @@ func newRowBlockSingleLevelIterator(
252254
i.data.SetHasValuePrefix(true)
253255
}
254256

255-
// Use lazy loading by default - index will be loaded on first access
256-
i.indexLoaded = false
257+
indexH, err := r.readTopLevelIndexBlock(ctx, i.readEnv.Block, i.indexFilterRH)
258+
if err == nil {
259+
err = i.index.InitHandle(r.Comparer, indexH, opts.Transforms)
260+
}
261+
if err != nil {
262+
_ = i.Close()
263+
return nil, err
264+
}
257265
return i, nil
258266
}
259267

@@ -441,7 +449,7 @@ func (i *singleLevelIterator[I, PI, P, PD]) SetContext(ctx context.Context) {
441449
// unpositioned. If unsuccessful, it sets i.err to any error encountered, which
442450
// may be nil if we have simply exhausted the entire table.
443451
func (i *singleLevelIterator[I, PI, P, PD]) loadDataBlock(dir int8) loadBlockResult {
444-
if i.err != nil || !PI(&i.index).Valid() {
452+
if !PI(&i.index).Valid() {
445453
// Ensure the data block iterator is invalidated even if loading of the block
446454
// fails.
447455
PD(&i.data).Invalidate()
@@ -513,12 +521,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) ReadValueBlock(
513521
// apprioriate bound, depending on the iteration direction, and returns either
514522
// `blockIntersects` or `blockExcluded`.
515523
func (i *singleLevelIterator[I, PI, D, PD]) resolveMaybeExcluded(dir int8) intersectsResult {
516-
if !i.indexLoaded {
517-
if err := i.ensureIndexLoaded(); err != nil {
518-
i.err = err
519-
return blockExcluded
520-
}
521-
}
522524
// TODO(jackson): We could first try comparing to top-level index block's
523525
// key, and if within bounds avoid per-data block key comparisons.
524526

@@ -680,13 +682,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) SeekGE(
680682
func (i *singleLevelIterator[I, PI, D, PD]) seekGEHelper(
681683
key []byte, boundsCmp int, flags base.SeekGEFlags,
682684
) *base.InternalKV {
683-
if !i.indexLoaded {
684-
if err := i.ensureIndexLoaded(); err != nil {
685-
i.err = err
686-
return nil
687-
}
688-
}
689-
690685
// Invariant: trySeekUsingNext => !i.data.isDataInvalidated() && i.exhaustedBounds != +1
691686

692687
// SeekGE performs various step-instead-of-seeking optimizations: eg enabled
@@ -823,7 +818,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) seekPrefixGE(
823818
flags = flags.DisableTrySeekUsingNext()
824819
}
825820
i.lastBloomFilterMatched = false
826-
827821
// Check prefix bloom filter.
828822
var mayContain bool
829823
mayContain, i.err = i.bloomFilterMayContain(prefix)
@@ -928,13 +922,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) virtualLastSeekLE() *base.InternalKV
928922
i.boundsCmp = 0
929923
i.positionedUsingLatestBounds = true
930924

931-
if !i.indexLoaded {
932-
if err := i.ensureIndexLoaded(); err != nil {
933-
i.err = err
934-
return nil
935-
}
936-
}
937-
938925
indexOk := PI(&i.index).SeekGE(key)
939926
// We can have multiple internal keys with the same user key as the seek
940927
// key. In that case, we want the last (greatest) internal key.
@@ -1006,12 +993,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) virtualLastSeekLE() *base.InternalKV
1006993
func (i *singleLevelIterator[I, PI, D, PD]) SeekLT(
1007994
key []byte, flags base.SeekLTFlags,
1008995
) *base.InternalKV {
1009-
if !i.indexLoaded {
1010-
if err := i.ensureIndexLoaded(); err != nil {
1011-
i.err = err
1012-
return nil
1013-
}
1014-
}
1015996
if i.readEnv.Virtual != nil {
1016997
// Might have to fix upper bound since virtual sstable bounds are not
1017998
// known to callers of SeekLT.
@@ -1135,12 +1116,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) First() *base.InternalKV {
11351116
// index file. For the latter, one cannot make any claims about absolute
11361117
// positioning.
11371118
func (i *singleLevelIterator[I, PI, D, PD]) firstInternal() *base.InternalKV {
1138-
if !i.indexLoaded {
1139-
if err := i.ensureIndexLoaded(); err != nil {
1140-
i.err = err
1141-
return nil
1142-
}
1143-
}
11441119
i.exhaustedBounds = 0
11451120
i.err = nil // clear cached iteration error
11461121
// Seek optimization only applies until iterator is first positioned after SetBounds.
@@ -1205,12 +1180,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) Last() *base.InternalKV {
12051180
// index file. For the latter, one cannot make any claims about absolute
12061181
// positioning.
12071182
func (i *singleLevelIterator[I, PI, D, PD]) lastInternal() *base.InternalKV {
1208-
if !i.indexLoaded {
1209-
if err := i.ensureIndexLoaded(); err != nil {
1210-
i.err = err
1211-
return nil
1212-
}
1213-
}
12141183
i.exhaustedBounds = 0
12151184
i.err = nil // clear cached iteration error
12161185
// Seek optimization only applies until iterator is first positioned after SetBounds.
@@ -1280,12 +1249,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) Next() *base.InternalKV {
12801249

12811250
// NextPrefix implements (base.InternalIterator).NextPrefix.
12821251
func (i *singleLevelIterator[I, PI, D, PD]) NextPrefix(succKey []byte) *base.InternalKV {
1283-
if !i.indexLoaded {
1284-
if err := i.ensureIndexLoaded(); err != nil {
1285-
i.err = err
1286-
return nil
1287-
}
1288-
}
12891252
if i.exhaustedBounds == +1 {
12901253
panic("NextPrefix called even though exhausted upper bound")
12911254
}
@@ -1380,12 +1343,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) Prev() *base.InternalKV {
13801343
}
13811344

13821345
func (i *singleLevelIterator[I, PI, D, PD]) skipForward() *base.InternalKV {
1383-
if !i.indexLoaded {
1384-
if err := i.ensureIndexLoaded(); err != nil {
1385-
i.err = err
1386-
return nil
1387-
}
1388-
}
13891346
for {
13901347
if !PI(&i.index).Next() {
13911348
PD(&i.data).Invalidate()
@@ -1464,12 +1421,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) skipForward() *base.InternalKV {
14641421
}
14651422

14661423
func (i *singleLevelIterator[I, PI, D, PD]) skipBackward() *base.InternalKV {
1467-
if !i.indexLoaded {
1468-
if err := i.ensureIndexLoaded(); err != nil {
1469-
i.err = err
1470-
return nil
1471-
}
1472-
}
14731424
for {
14741425
if !PI(&i.index).Prev() {
14751426
PD(&i.data).Invalidate()
@@ -1563,8 +1514,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) closeInternal() error {
15631514
}
15641515
var err error
15651516
err = firstError(err, PD(&i.data).Close())
1566-
// Always close index iterator unconditionally to avoid BufferPool panic
1567-
// Even if lazy loading wasn't used, the index might have been initialized
15681517
err = firstError(err, PI(&i.index).Close())
15691518
if i.indexFilterRH != nil {
15701519
err = firstError(err, i.indexFilterRH.Close())
@@ -1583,7 +1532,6 @@ func (i *singleLevelIterator[I, PI, D, PD]) closeInternal() error {
15831532
err = firstError(err, i.vbRH.Close())
15841533
i.vbRH = nil
15851534
}
1586-
i.indexLoaded = false
15871535
return err
15881536
}
15891537

@@ -1598,16 +1546,3 @@ func (i *singleLevelIterator[I, PI, D, PD]) String() string {
15981546
func (i *singleLevelIterator[I, PI, D, PD]) DebugTree(tp treeprinter.Node) {
15991547
tp.Childf("%T(%p) fileNum=%s", i, i, i.String())
16001548
}
1601-
1602-
func (i *singleLevelIterator[I, PI, D, PD]) ensureIndexLoaded() error {
1603-
indexH, err := i.reader.readTopLevelIndexBlock(i.ctx, i.readEnv.Block, i.indexFilterRH)
1604-
if err == nil {
1605-
err = PI(&i.index).InitHandle(i.reader.Comparer, indexH, i.transforms)
1606-
}
1607-
if err != nil {
1608-
return err
1609-
}
1610-
1611-
i.indexLoaded = true
1612-
return nil
1613-
}

sstable/reader_iter_test.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,15 @@ func TestIteratorErrorOnInit(t *testing.T) {
5353
defer toggle.Off()
5454

5555
var stats base.InternalIteratorStats
56-
for range 20 {
56+
for k := 0; k < 20; k++ {
5757
if rand.IntN(2) == 0 {
58-
iter, err := newRowBlockSingleLevelIterator(context.Background(), r, IterOptions{
58+
_, err := newRowBlockSingleLevelIterator(context.Background(), r, IterOptions{
5959
Transforms: NoTransforms,
6060
FilterBlockSizeLimit: NeverUseFilterBlock,
6161
Env: ReadEnv{Block: block.ReadEnv{Stats: &stats, BufferPool: &pool}},
6262
ReaderProvider: MakeTrivialReaderProvider(r),
6363
})
64-
// Single-level iterators use lazy loading - creation succeeds but first access fails
65-
require.NoError(t, err)
66-
// Error should surface when trying to use the iterator
67-
_ = iter.First()
68-
require.Error(t, iter.Error())
69-
iter.Close()
64+
require.Error(t, err)
7065
} else {
7166
_, err := newRowBlockTwoLevelIterator(context.Background(), r, IterOptions{
7267
Transforms: NoTransforms,

sstable/reader_iter_two_lvl.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ func (i *twoLevelIterator[I, PI, D, PD]) loadSecondLevelIndexBlock(dir int8) loa
7878
i.secondLevel.err = err
7979
return loadBlockFailed
8080
}
81-
i.secondLevel.indexLoaded = true
8281
return loadBlockOK
8382
}
8483

testdata/checkpoint

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,16 +261,16 @@ open: db/000007.sst (options: *vfs.randomReadsOption)
261261
read-at(700, 61): db/000007.sst
262262
read-at(649, 51): db/000007.sst
263263
read-at(132, 517): db/000007.sst
264-
open: db/000005.sst (options: *vfs.sequentialReadsOption)
265264
read-at(91, 41): db/000005.sst
265+
open: db/000005.sst (options: *vfs.sequentialReadsOption)
266266
read-at(0, 91): db/000005.sst
267-
open: db/000007.sst (options: *vfs.sequentialReadsOption)
268267
read-at(91, 41): db/000007.sst
268+
open: db/000007.sst (options: *vfs.sequentialReadsOption)
269269
read-at(0, 91): db/000007.sst
270270
create: db/000010.sst
271271
close: db/000005.sst
272-
open: db/000009.sst (options: *vfs.sequentialReadsOption)
273272
read-at(95, 41): db/000009.sst
273+
open: db/000009.sst (options: *vfs.sequentialReadsOption)
274274
read-at(0, 95): db/000009.sst
275275
close: db/000007.sst
276276
close: db/000009.sst

testdata/cleaner

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ open: db/000007.sst (options: *vfs.randomReadsOption)
8282
read-at(501, 61): db/000007.sst
8383
read-at(472, 37): db/000007.sst
8484
read-at(53, 419): db/000007.sst
85-
open: db/000005.sst (options: *vfs.sequentialReadsOption)
8685
read-at(52, 27): db/000005.sst
86+
open: db/000005.sst (options: *vfs.sequentialReadsOption)
8787
read-at(0, 52): db/000005.sst
8888
create: db/000008.sst
8989
close: db/000005.sst
90-
open: db/000007.sst (options: *vfs.sequentialReadsOption)
9190
read-at(26, 27): db/000007.sst
91+
open: db/000007.sst (options: *vfs.sequentialReadsOption)
9292
read-at(0, 26): db/000007.sst
9393
close: db/000007.sst
9494
sync-data: db/000008.sst

testdata/event_listener

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,11 @@ open: db/000008.sst (options: *vfs.randomReadsOption)
145145
read-at(686, 61): db/000008.sst
146146
read-at(636, 50): db/000008.sst
147147
read-at(119, 517): db/000008.sst
148-
open: db/000005.sst (options: *vfs.sequentialReadsOption)
149148
read-at(78, 41): db/000005.sst
149+
open: db/000005.sst (options: *vfs.sequentialReadsOption)
150150
read-at(0, 78): db/000005.sst
151-
open: db/000008.sst (options: *vfs.sequentialReadsOption)
152151
read-at(78, 41): db/000008.sst
152+
open: db/000008.sst (options: *vfs.sequentialReadsOption)
153153
read-at(0, 78): db/000008.sst
154154
close: db/000008.sst
155155
close: db/000005.sst

testdata/flushable_ingest

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -701,17 +701,17 @@ allowFlush
701701
get with-fs-logging
702702
small-00001
703703
----
704-
read-at(199, 74): 000004.sst
705704
read-at(158, 41): 000004.sst
705+
read-at(199, 74): 000004.sst
706706
read-at(0, 158): 000004.sst
707707
small-00001:val-00001
708708

709-
# When the key doesn't pass the bloom filter, we should see only one block
710-
# read due to lazy loading optimization - bloom filter is checked first,
711-
# and if it rejects the key, we can avoid loading the index block entirely.
709+
# When the key doesn't pass the bloom filter, we should see only two block
710+
# reads.
712711
get with-fs-logging
713712
small-00001-does-not-exist
714713
----
714+
read-at(158, 41): 000004.sst
715715
read-at(199, 74): 000004.sst
716716
small-00001-does-not-exist: pebble: not found
717717

0 commit comments

Comments
 (0)