func (db *DB) newIterator(seq uint64, slice *util.Range, ro *opt.ReadOptions) *dbIter { var islice *util.Range if slice != nil { islice = &util.Range{} if slice.Start != nil { islice.Start = newIKey(slice.Start, kMaxSeq, tSeek) } if slice.Limit != nil { islice.Limit = newIKey(slice.Limit, kMaxSeq, tSeek) } } rawIter := db.newRawIterator(islice, ro) iter := &dbIter{ db: db, icmp: db.s.icmp, iter: rawIter, seq: seq, strict: db.s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator), key: make([]byte, 0), value: make([]byte, 0), } atomic.AddInt32(&db.aliveIters, 1) runtime.SetFinalizer(iter, (*dbIter).Release) return iter }
// Find finds key/value pair whose key is greater than or equal to the // given key. It returns ErrNotFound if the table doesn't contain // such pair. // // The caller should not modify the contents of the returned slice, but // it is safe to modify the contents of the argument after Find returns. func (r *Reader) Find(key []byte, ro *opt.ReadOptions) (rkey, value []byte, err error) { r.mu.RLock() defer r.mu.RUnlock() if r.err != nil { err = r.err return } indexBlock, rel, err := r.getIndexBlock(true) if err != nil { return } defer rel.Release() index := indexBlock.newIterator(nil, true, nil) defer index.Release() if !index.Seek(key) { err = index.Error() if err == nil { err = ErrNotFound } return } dataBH, n := decodeBlockHandle(index.Value()) if n == 0 { err = errors.New("leveldb/table: Reader: invalid table (bad data block handle)") return } if r.filter != nil { filterBlock, rel, ferr := r.getFilterBlock(true) if ferr == nil { if !filterBlock.contains(dataBH.offset, key) { rel.Release() return nil, nil, ErrNotFound } rel.Release() } } data := r.getDataIter(dataBH, nil, ro.GetStrict(opt.StrictBlockChecksum), !ro.GetDontFillCache()) defer data.Release() if !data.Seek(key) { err = data.Error() if err == nil { err = ErrNotFound } return } // Don't use block buffer, no need to copy the buffer. rkey = data.Key() if r.bpool == nil { value = data.Value() } else { // Use block buffer, and since the buffer will be recycled, the buffer // need to be copied. value = append([]byte{}, data.Value()...) } return }
func (db *DB) newIterator(seq uint64, ro *opt.ReadOptions) *dbIter { rawIter := db.newRawIterator(ro) iter := &dbIter{ cmp: db.s.cmp.cmp, iter: rawIter, seq: seq, strict: db.s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator), } runtime.SetFinalizer(iter, (*dbIter).Release) return iter }
// NewIterator returns an iterator of the table. // // The returned iterator is not goroutine-safe and should be released // when not used. // // Also read Iterator documentation of the leveldb/iterator package. func (r *Reader) NewIterator(ro *opt.ReadOptions) iterator.Iterator { if r.err != nil { return iterator.NewEmptyIterator(r.err) } index := &indexIter{ blockIter: *r.indexBlock.newIterator(nil), tableReader: r, checksum: ro.GetStrict(opt.StrictBlockChecksum), fillCache: !ro.GetDontFillCache(), } return iterator.NewIndexedIterator(index, r.strictIter || ro.GetStrict(opt.StrictIterator)) }
func (db *DB) newRawIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { em, fm := db.getMems() v := db.s.version() ti := v.getIterators(slice, ro) n := len(ti) + 2 i := make([]iterator.Iterator, 0, n) i = append(i, em.NewIterator(slice)) if fm != nil { i = append(i, fm.NewIterator(slice)) } i = append(i, ti...) strict := db.s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator) mi := iterator.NewMergedIterator(i, db.s.icmp, strict) mi.SetReleaser(&versionReleaser{v: v}) return mi }
func (db *DB) newRawIterator(ro *opt.ReadOptions) iterator.Iterator { s := db.s mem, frozenMem := db.getMem() v := s.version() tableIters := v.getIterators(ro) iters := make([]iterator.Iterator, 0, len(tableIters)+2) iters = append(iters, mem.NewIterator()) if frozenMem != nil { iters = append(iters, frozenMem.NewIterator()) } iters = append(iters, tableIters...) strict := s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator) mi := iterator.NewMergedIterator(iters, s.cmp, strict) mi.SetReleaser(&versionReleaser{v: v}) return mi }
// NewIterator creates an iterator from the table. // // Slice allows slicing the iterator to only contains keys in the given // range. A nil Range.Start is treated as a key before all keys in the // table. And a nil Range.Limit is treated as a key after all keys in // the table. // // The returned iterator is not goroutine-safe and should be released // when not used. // // Also read Iterator documentation of the leveldb/iterator package. func (r *Reader) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { if r.err != nil { return iterator.NewEmptyIterator(r.err) } fillCache := !ro.GetDontFillCache() b, rel, err := r.readBlockCached(r.indexBH, true, fillCache) if err != nil { return iterator.NewEmptyIterator(err) } index := &indexIter{ blockIter: b.newIterator(slice, true, rel), slice: slice, checksum: ro.GetStrict(opt.StrictBlockChecksum), fillCache: !ro.GetDontFillCache(), } return iterator.NewIndexedIterator(index, r.strictIter || ro.GetStrict(opt.StrictIterator), false) }
func (v *version) getIterators(slice *util.Range, ro *opt.ReadOptions) (its []iterator.Iterator) { // Merge all level zero files together since they may overlap for _, t := range v.tables[0] { it := v.s.tops.newIterator(t, slice, ro) its = append(its, it) } strict := v.s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator) for _, tables := range v.tables[1:] { if len(tables) == 0 { continue } it := iterator.NewIndexedIterator(tables.newIndexIterator(v.s.tops, v.s.icmp, slice, ro), strict, true) its = append(its, it) } return }
// NewIterator creates an iterator from the table. // // Slice allows slicing the iterator to only contains keys in the given // range. A nil Range.Start is treated as a key before all keys in the // table. And a nil Range.Limit is treated as a key after all keys in // the table. // // The returned iterator is not goroutine-safe and should be released // when not used. // // Also read Iterator documentation of the leveldb/iterator package. func (r *Reader) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { r.mu.RLock() defer r.mu.RUnlock() if r.err != nil { return iterator.NewEmptyIterator(r.err) } fillCache := !ro.GetDontFillCache() indexBlock, rel, err := r.getIndexBlock(fillCache) if err != nil { return iterator.NewEmptyIterator(err) } index := &indexIter{ blockIter: indexBlock.newIterator(slice, true, rel), slice: slice, checksum: ro.GetStrict(opt.StrictBlockChecksum), fillCache: !ro.GetDontFillCache(), } return iterator.NewIndexedIterator(index, r.strictIter || ro.GetStrict(opt.StrictIterator), true) }
func (v *version) getIterators(ro *opt.ReadOptions) (its []iterator.Iterator) { s := v.s icmp := s.cmp // Merge all level zero files together since they may overlap for _, t := range v.tables[0] { it := s.tops.newIterator(t, ro) its = append(its, it) } strict := s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator) for _, tt := range v.tables[1:] { if len(tt) == 0 { continue } it := iterator.NewIndexedIterator(tt.newIndexIterator(s.tops, icmp, ro), strict) its = append(its, it) } return }
func (db *DB) newIterator(seq uint64, slice *util.Range, ro *opt.ReadOptions) *dbIter { var slice_ *util.Range if slice != nil { slice_ = &util.Range{} if slice.Start != nil { slice_.Start = newIKey(slice.Start, kMaxSeq, tSeek) } if slice.Limit != nil { slice_.Limit = newIKey(slice.Limit, kMaxSeq, tSeek) } } rawIter := db.newRawIterator(slice_, ro) iter := &dbIter{ cmp: db.s.cmp.cmp, iter: rawIter, seq: seq, strict: db.s.o.GetStrict(opt.StrictIterator) || ro.GetStrict(opt.StrictIterator), key: make([]byte, 0), value: make([]byte, 0), } runtime.SetFinalizer(iter, (*dbIter).Release) return iter }
// Find finds key/value pair whose key is greater than or equal to the // given key. It returns ErrNotFound if the table doesn't contain // such pair. // // The caller should not modify the contents of the returned slice, but // it is safe to modify the contents of the argument after Find returns. func (r *Reader) Find(key []byte, ro *opt.ReadOptions) (rkey, value []byte, err error) { if r.err != nil { err = r.err return } index := r.indexBlock.newIterator(nil) defer index.Release() if !index.Seek(key) { err = index.Error() if err == nil { err = ErrNotFound } return } dataBH, n := decodeBlockHandle(index.Value()) if n == 0 { err = errors.New("leveldb/table: Reader: invalid table (bad data block handle)") return } if r.filterBlock != nil && !r.filterBlock.contains(dataBH.offset, key) { err = ErrNotFound return } data := r.getDataIter(dataBH, ro.GetStrict(opt.StrictBlockChecksum), !ro.GetDontFillCache()) defer data.Release() if !data.Seek(key) { err = data.Error() if err == nil { err = ErrNotFound } return } rkey = data.Key() value = data.Value() return }