// Copyright 2018 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" "fmt" "github.com/cockroachdb/pebble/internal/base" "github.com/cockroachdb/pebble/internal/keyspan" "github.com/cockroachdb/pebble/internal/manifest" "github.com/cockroachdb/pebble/sstable" ) // getIter is an internal iterator used to perform gets. It iterates through // the values for a particular key, level by level. It is not a general purpose // internalIterator, but specialized for Get operations so that it loads data // lazily. type getIter struct { logger Logger comparer *Comparer newIters tableNewIters snapshot uint64 key []byte iter internalIterator rangeDelIter keyspan.FragmentIterator tombstone *keyspan.Span levelIter levelIter level int batch *Batch mem flushableList l0 []manifest.LevelSlice version *version iterKey *InternalKey iterValue base.LazyValue err error } // TODO(sumeer): CockroachDB code doesn't use getIter, but, for completeness, // make this implement InternalIteratorWithStats. // getIter implements the base.InternalIterator interface. var _ base.InternalIterator = (*getIter)(nil) func (g *getIter) String() string { return fmt.Sprintf("len(l0)=%d, len(mem)=%d, level=%d", len(g.l0), len(g.mem), g.level) } func (g *getIter) SeekGE(key []byte, flags base.SeekGEFlags) (*InternalKey, base.LazyValue) { panic("pebble: SeekGE unimplemented") } func (g *getIter) SeekPrefixGE( prefix, key []byte, flags base.SeekGEFlags, ) (*base.InternalKey, base.LazyValue) { panic("pebble: SeekPrefixGE unimplemented") } func (g *getIter) SeekLT(key []byte, flags base.SeekLTFlags) (*InternalKey, base.LazyValue) { panic("pebble: SeekLT unimplemented") } func (g *getIter) First() (*InternalKey, base.LazyValue) { return g.Next() } func (g *getIter) Last() (*InternalKey, base.LazyValue) { panic("pebble: Last unimplemented") } func (g *getIter) Next() (*InternalKey, base.LazyValue) { if g.iter != nil { g.iterKey, g.iterValue = g.iter.Next() } for { if g.iter != nil { // We have to check rangeDelIter on each iteration because a single // user-key can be spread across multiple tables in a level. A range // tombstone will appear in the table corresponding to its start // key. Every call to levelIter.Next() potentially switches to a new // table and thus reinitializes rangeDelIter. if g.rangeDelIter != nil { g.tombstone = keyspan.Get(g.comparer.Compare, g.rangeDelIter, g.key) if g.err = g.rangeDelIter.Close(); g.err != nil { return nil, base.LazyValue{} } g.rangeDelIter = nil } if g.iterKey != nil { key := g.iterKey if g.tombstone != nil && g.tombstone.CoversAt(g.snapshot, key.SeqNum()) { // We have a range tombstone covering this key. Rather than return a // point or range deletion here, we return false and close our // internal iterator which will make Valid() return false, // effectively stopping iteration. g.err = g.iter.Close() g.iter = nil return nil, base.LazyValue{} } if g.comparer.Equal(g.key, key.UserKey) { if !key.Visible(g.snapshot, base.InternalKeySeqNumMax) { g.iterKey, g.iterValue = g.iter.Next() continue } return g.iterKey, g.iterValue } } // We've advanced the iterator passed the desired key. Move on to the // next memtable / level. g.err = g.iter.Close() g.iter = nil if g.err != nil { return nil, base.LazyValue{} } } // Create an iterator from the batch. if g.batch != nil { if g.batch.index == nil { g.err = ErrNotIndexed g.iterKey, g.iterValue = nil, base.LazyValue{} return nil, base.LazyValue{} } g.iter = g.batch.newInternalIter(nil) g.rangeDelIter = g.batch.newRangeDelIter( nil, // Get always reads the entirety of the batch's history, so no // batch keys should be filtered. base.InternalKeySeqNumMax, ) g.iterKey, g.iterValue = g.iter.SeekGE(g.key, base.SeekGEFlagsNone) g.batch = nil continue } // If we have a tombstone from a previous level it is guaranteed to delete // keys in lower levels. if g.tombstone != nil && g.tombstone.VisibleAt(g.snapshot) { return nil, base.LazyValue{} } // Create iterators from memtables from newest to oldest. if n := len(g.mem); n > 0 { m := g.mem[n-1] g.iter = m.newIter(nil) g.rangeDelIter = m.newRangeDelIter(nil) g.mem = g.mem[:n-1] g.iterKey, g.iterValue = g.iter.SeekGE(g.key, base.SeekGEFlagsNone) continue } if g.level == 0 { // Create iterators from L0 from newest to oldest. if n := len(g.l0); n > 0 { files := g.l0[n-1].Iter() g.l0 = g.l0[:n-1] iterOpts := IterOptions{ // TODO(sumeer): replace with a parameter provided by the caller. CategoryAndQoS: sstable.CategoryAndQoS{ Category: "pebble-get", QoSLevel: sstable.LatencySensitiveQoSLevel, }, logger: g.logger, snapshotForHideObsoletePoints: g.snapshot} g.levelIter.init(context.Background(), iterOpts, g.comparer, g.newIters, files, manifest.L0Sublevel(n), internalIterOpts{}) g.levelIter.initRangeDel(&g.rangeDelIter) bc := levelIterBoundaryContext{} g.levelIter.initBoundaryContext(&bc) g.iter = &g.levelIter // Compute the key prefix for bloom filtering if split function is // specified, or use the user key as default. prefix := g.key if g.comparer.Split != nil { prefix = g.key[:g.comparer.Split(g.key)] } g.iterKey, g.iterValue = g.iter.SeekPrefixGE(prefix, g.key, base.SeekGEFlagsNone) if bc.isSyntheticIterBoundsKey || bc.isIgnorableBoundaryKey { g.iterKey = nil g.iterValue = base.LazyValue{} } continue } g.level++ } if g.level >= numLevels { return nil, base.LazyValue{} } if g.version.Levels[g.level].Empty() { g.level++ continue } iterOpts := IterOptions{ // TODO(sumeer): replace with a parameter provided by the caller. CategoryAndQoS: sstable.CategoryAndQoS{ Category: "pebble-get", QoSLevel: sstable.LatencySensitiveQoSLevel, }, logger: g.logger, snapshotForHideObsoletePoints: g.snapshot} g.levelIter.init(context.Background(), iterOpts, g.comparer, g.newIters, g.version.Levels[g.level].Iter(), manifest.Level(g.level), internalIterOpts{}) g.levelIter.initRangeDel(&g.rangeDelIter) bc := levelIterBoundaryContext{} g.levelIter.initBoundaryContext(&bc) g.level++ g.iter = &g.levelIter // Compute the key prefix for bloom filtering if split function is // specified, or use the user key as default. prefix := g.key if g.comparer.Split != nil { prefix = g.key[:g.comparer.Split(g.key)] } g.iterKey, g.iterValue = g.iter.SeekPrefixGE(prefix, g.key, base.SeekGEFlagsNone) if bc.isSyntheticIterBoundsKey || bc.isIgnorableBoundaryKey { g.iterKey = nil g.iterValue = base.LazyValue{} } } } func (g *getIter) Prev() (*InternalKey, base.LazyValue) { panic("pebble: Prev unimplemented") } func (g *getIter) NextPrefix([]byte) (*InternalKey, base.LazyValue) { panic("pebble: NextPrefix unimplemented") } func (g *getIter) Valid() bool { return g.iterKey != nil && g.err == nil } func (g *getIter) Error() error { return g.err } func (g *getIter) Close() error { if g.iter != nil { if err := g.iter.Close(); err != nil && g.err == nil { g.err = err } g.iter = nil } return g.err } func (g *getIter) SetBounds(lower, upper []byte) { panic("pebble: SetBounds unimplemented") } func (g *getIter) SetContext(_ context.Context) {}