// Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use // of this source code is governed by a BSD-style license that can be found in // the LICENSE file. package pebble import ( "context" "github.com/cockroachdb/pebble/internal/base" "github.com/cockroachdb/pebble/internal/keyspan" "github.com/cockroachdb/pebble/internal/manifest" ) // scanInternalIterator is an iterator that returns all internal keys instead of // collapsing them by user keys. For instance, an InternalKeyKindDelete would be // returned as an InternalKeyKindDelete instead of the iterator skipping over to // the next key. Useful if an external user of Pebble needs to observe and // rebuild Pebble's history of internal keys, such as in node-to-node // replication. For use with {db,snapshot}.ScanInternal(). // // scanInternalIterator is allowed to ignorepoint keys deleted by range deletions, // and range keys shadowed by a range key unset or delete, however it *must* // return the range delete as well as the range key unset/delete that did the // shadowing. type scanInternalIterator struct { opts IterOptions comparer *base.Comparer iter internalIterator readState *readState rangeKey *iteratorRangeKeyState pointKeyIter keyspan.InterleavingIter iterKey *InternalKey iterValue LazyValue alloc *iterAlloc newIters tableNewIters newIterRangeKey keyspan.TableNewSpanIter seqNum uint64 // boundsBuf holds two buffers used to store the lower and upper bounds. // Whenever the InternalIterator's bounds change, the new bounds are copied // into boundsBuf[boundsBufIdx]. The two bounds share a slice to reduce // allocations. opts.LowerBound and opts.UpperBound point into this slice. boundsBuf [2][]byte boundsBufIdx int } // TODO(sumeer): scanInternalImpl is the implementation for the user-facing // ScanInternal. Make it accept a context parameter, and plumb it through for // tracing support. func scanInternalImpl( lower []byte, iter *scanInternalIterator, visitPointKey func(key *InternalKey, value LazyValue) error, visitRangeDel func(start, end []byte, seqNum uint64) error, visitRangeKey func(start, end []byte, keys []keyspan.Key) error, ) error { for valid := iter.seekGE(lower); valid && iter.error() == nil; valid = iter.next() { key := iter.unsafeKey() switch key.Kind() { case InternalKeyKindRangeKeyDelete, InternalKeyKindRangeKeyUnset, InternalKeyKindRangeKeySet: span := iter.unsafeSpan() if err := visitRangeKey(span.Start, span.End, span.Keys); err != nil { return err } case InternalKeyKindRangeDelete: rangeDel := iter.unsafeRangeDel() if err := visitRangeDel(rangeDel.Start, rangeDel.End, rangeDel.LargestSeqNum()); err != nil { return err } default: val := iter.lazyValue() if s := iter.pointKeyIter.Span(); s != nil && s.CoversAt(iter.seqNum, key.SeqNum()) { // Key deleted by a range deletion. Skip it. continue } if err := visitPointKey(key, val); err != nil { return err } } } return nil } // constructPointIter constructs a merging iterator and sets i.iter to it. func (i *scanInternalIterator) constructPointIter(memtables flushableList, buf *iterAlloc) { // Merging levels and levels from iterAlloc. mlevels := buf.mlevels[:0] levels := buf.levels[:0] // We compute the number of levels needed ahead of time and reallocate a slice if // the array from the iterAlloc isn't large enough. Doing this allocation once // should improve the performance. numMergingLevels := len(memtables) numLevelIters := 0 current := i.readState.current numMergingLevels += len(current.L0SublevelFiles) numLevelIters += len(current.L0SublevelFiles) for level := 1; level < len(current.Levels); level++ { if current.Levels[level].Empty() { continue } numMergingLevels++ numLevelIters++ } if numMergingLevels > cap(mlevels) { mlevels = make([]mergingIterLevel, 0, numMergingLevels) } if numLevelIters > cap(levels) { levels = make([]levelIter, 0, numLevelIters) } // TODO(bilal): Push these into the iterAlloc buf. var rangeDelMiter keyspan.MergingIter rangeDelIters := make([]keyspan.FragmentIterator, 0, numMergingLevels) rangeDelLevels := make([]keyspan.LevelIter, 0, numLevelIters) // Next are the memtables. for j := len(memtables) - 1; j >= 0; j-- { mem := memtables[j] mlevels = append(mlevels, mergingIterLevel{ iter: mem.newIter(&i.opts), }) if rdi := mem.newRangeDelIter(&i.opts); rdi != nil { rangeDelIters = append(rangeDelIters, rdi) } } // Next are the file levels: L0 sub-levels followed by lower levels. mlevelsIndex := len(mlevels) levelsIndex := len(levels) mlevels = mlevels[:numMergingLevels] levels = levels[:numLevelIters] rangeDelLevels = rangeDelLevels[:numLevelIters] addLevelIterForFiles := func(files manifest.LevelIterator, level manifest.Level) { li := &levels[levelsIndex] rli := &rangeDelLevels[levelsIndex] li.init( context.Background(), i.opts, i.comparer.Compare, i.comparer.Split, i.newIters, files, level, internalIterOpts{}) li.initBoundaryContext(&mlevels[mlevelsIndex].levelIterBoundaryContext) mlevels[mlevelsIndex].iter = li rli.Init(keyspan.SpanIterOptions{RangeKeyFilters: i.opts.RangeKeyFilters}, i.comparer.Compare, tableNewRangeDelIter(context.Background(), i.newIters), files, level, manifest.KeyTypePoint) rangeDelIters = append(rangeDelIters, rli) levelsIndex++ mlevelsIndex++ } // Add level iterators for the L0 sublevels, iterating from newest to // oldest. for i := len(current.L0SublevelFiles) - 1; i >= 0; i-- { addLevelIterForFiles(current.L0SublevelFiles[i].Iter(), manifest.L0Sublevel(i)) } // Add level iterators for the non-empty non-L0 levels. for level := 1; level < numLevels; level++ { if current.Levels[level].Empty() { continue } addLevelIterForFiles(current.Levels[level].Iter(), manifest.Level(level)) } buf.merging.init(&i.opts, &InternalIteratorStats{}, i.comparer.Compare, i.comparer.Split, mlevels...) buf.merging.snapshot = i.seqNum rangeDelMiter.Init(i.comparer.Compare, keyspan.VisibleTransform(i.seqNum), new(keyspan.MergingBuffers), rangeDelIters...) i.pointKeyIter.Init(i.comparer, &buf.merging, &rangeDelMiter, nil /* mask */, i.opts.LowerBound, i.opts.UpperBound) i.iter = &i.pointKeyIter } // constructRangeKeyIter constructs the range-key iterator stack, populating // i.rangeKey.rangeKeyIter with the resulting iterator. This is similar to // Iterator.constructRangeKeyIter, except it doesn't handle batches and ensures // iterConfig does *not* elide unsets/deletes. func (i *scanInternalIterator) constructRangeKeyIter() { // We want the bounded iter from iterConfig, but not the collapsing of // RangeKeyUnsets and RangeKeyDels. i.rangeKey.rangeKeyIter = i.rangeKey.iterConfig.Init( i.comparer, i.seqNum, i.opts.LowerBound, i.opts.UpperBound, nil /* hasPrefix */, nil /* prefix */, false, /* onlySets */ &i.rangeKey.rangeKeyBuffers.internal) // Next are the flushables: memtables and large batches. for j := len(i.readState.memtables) - 1; j >= 0; j-- { mem := i.readState.memtables[j] // We only need to read from memtables which contain sequence numbers older // than seqNum. if logSeqNum := mem.logSeqNum; logSeqNum >= i.seqNum { continue } if rki := mem.newRangeKeyIter(&i.opts); rki != nil { i.rangeKey.iterConfig.AddLevel(rki) } } current := i.readState.current // Next are the file levels: L0 sub-levels followed by lower levels. // // Add file-specific iterators for L0 files containing range keys. This is less // efficient than using levelIters for sublevels of L0 files containing // range keys, but range keys are expected to be sparse anyway, reducing the // cost benefit of maintaining a separate L0Sublevels instance for range key // files and then using it here. // // NB: We iterate L0's files in reverse order. They're sorted by // LargestSeqNum ascending, and we need to add them to the merging iterator // in LargestSeqNum descending to preserve the merging iterator's invariants // around Key Trailer order. iter := current.RangeKeyLevels[0].Iter() for f := iter.Last(); f != nil; f = iter.Prev() { spanIterOpts := &keyspan.SpanIterOptions{RangeKeyFilters: i.opts.RangeKeyFilters} spanIter, err := i.newIterRangeKey(f, spanIterOpts) if err != nil { i.rangeKey.iterConfig.AddLevel(&errorKeyspanIter{err: err}) continue } i.rangeKey.iterConfig.AddLevel(spanIter) } // Add level iterators for the non-empty non-L0 levels. for level := 1; level < len(current.RangeKeyLevels); level++ { if current.RangeKeyLevels[level].Empty() { continue } li := i.rangeKey.iterConfig.NewLevelIter() spanIterOpts := keyspan.SpanIterOptions{RangeKeyFilters: i.opts.RangeKeyFilters} li.Init(spanIterOpts, i.comparer.Compare, i.newIterRangeKey, current.RangeKeyLevels[level].Iter(), manifest.Level(level), manifest.KeyTypeRange) i.rangeKey.iterConfig.AddLevel(li) } } // seekGE seeks this iterator to the first key that's greater than or equal // to the specified user key. func (i *scanInternalIterator) seekGE(key []byte) bool { i.iterKey, i.iterValue = i.iter.SeekGE(key, base.SeekGEFlagsNone) return i.iterKey != nil } // unsafeKey returns the unsafe InternalKey at the current position. The value // is nil if the iterator is invalid or exhausted. func (i *scanInternalIterator) unsafeKey() *InternalKey { return i.iterKey } // lazyValue returns a value pointer to the value at the current iterator // position. Behaviour undefined if unsafeKey() returns a Range key or Rangedel // kind key. func (i *scanInternalIterator) lazyValue() LazyValue { return i.iterValue } // unsafeRangeDel returns a range key span. Behaviour undefined if UnsafeKey returns // a non-rangedel kind. func (i *scanInternalIterator) unsafeRangeDel() *keyspan.Span { return i.pointKeyIter.Span() } // unsafeSpan returns a range key span. Behaviour undefined if UnsafeKey returns // a non-rangekey type. func (i *scanInternalIterator) unsafeSpan() *keyspan.Span { return i.rangeKey.iiter.Span() } // next advances the iterator in the forward direction, and returns the // iterator's new validity state. func (i *scanInternalIterator) next() bool { i.iterKey, i.iterValue = i.iter.Next() return i.iterKey != nil } // error returns an error from the internal iterator, if there's any. func (i *scanInternalIterator) error() error { return i.iter.Error() } // close closes this iterator, and releases any pooled objects. func (i *scanInternalIterator) close() error { if err := i.iter.Close(); err != nil { return err } i.readState.unref() if i.rangeKey != nil { i.rangeKey.PrepareForReuse() *i.rangeKey = iteratorRangeKeyState{ rangeKeyBuffers: i.rangeKey.rangeKeyBuffers, } iterRangeKeyStateAllocPool.Put(i.rangeKey) i.rangeKey = nil } if alloc := i.alloc; alloc != nil { for j := range i.boundsBuf { if cap(i.boundsBuf[j]) >= maxKeyBufCacheSize { alloc.boundsBuf[j] = nil } else { alloc.boundsBuf[j] = i.boundsBuf[j] } } *alloc = iterAlloc{ keyBuf: alloc.keyBuf[:0], boundsBuf: alloc.boundsBuf, prefixOrFullSeekKey: alloc.prefixOrFullSeekKey[:0], } iterAllocPool.Put(alloc) i.alloc = nil } return nil } func (i *scanInternalIterator) initializeBoundBufs(lower, upper []byte) { buf := i.boundsBuf[i.boundsBufIdx][:0] if lower != nil { buf = append(buf, lower...) i.opts.LowerBound = buf } else { i.opts.LowerBound = nil } if upper != nil { buf = append(buf, upper...) i.opts.UpperBound = buf[len(buf)-len(upper):] } else { i.opts.UpperBound = nil } i.boundsBuf[i.boundsBufIdx] = buf i.boundsBufIdx = 1 - i.boundsBufIdx }