github.com/coocood/badger@v1.5.1-0.20200528065104-c02ac3616d04/table/concat_iterator.go (about) 1 package table 2 3 import ( 4 "bytes" 5 "sort" 6 7 "github.com/coocood/badger/y" 8 ) 9 10 // ConcatIterator concatenates the sequences defined by several iterators. (It only works with 11 // TableIterators, probably just because it's faster to not be so generic.) 12 type ConcatIterator struct { 13 idx int // Which iterator is active now. 14 cur y.Iterator 15 iters []y.Iterator // Corresponds to tables. 16 tables []Table // Disregarding reversed, this is in ascending order. 17 reversed bool 18 } 19 20 // NewConcatIterator creates a new concatenated iterator 21 func NewConcatIterator(tbls []Table, reversed bool) *ConcatIterator { 22 return &ConcatIterator{ 23 reversed: reversed, 24 iters: make([]y.Iterator, len(tbls)), 25 tables: tbls, 26 idx: -1, // Not really necessary because s.it.Valid()=false, but good to have. 27 } 28 } 29 30 func (s *ConcatIterator) setIdx(idx int) { 31 s.idx = idx 32 if idx < 0 || idx >= len(s.iters) { 33 s.cur = nil 34 } else { 35 if s.iters[s.idx] == nil { 36 ti := s.tables[s.idx].NewIterator(s.reversed) 37 ti.Rewind() 38 s.iters[s.idx] = ti 39 } 40 s.cur = s.iters[s.idx] 41 } 42 } 43 44 // Rewind implements y.Interface 45 func (s *ConcatIterator) Rewind() { 46 if len(s.iters) == 0 { 47 return 48 } 49 if !s.reversed { 50 s.setIdx(0) 51 } else { 52 s.setIdx(len(s.iters) - 1) 53 } 54 s.cur.Rewind() 55 } 56 57 // Valid implements y.Interface 58 func (s *ConcatIterator) Valid() bool { 59 return s.cur != nil && s.cur.Valid() 60 } 61 62 // Key implements y.Interface 63 func (s *ConcatIterator) Key() y.Key { 64 return s.cur.Key() 65 } 66 67 // Value implements y.Interface 68 func (s *ConcatIterator) Value() y.ValueStruct { 69 return s.cur.Value() 70 } 71 72 func (s *ConcatIterator) FillValue(vs *y.ValueStruct) { 73 s.cur.FillValue(vs) 74 } 75 76 // Seek brings us to element >= key if reversed is false. Otherwise, <= key. 77 func (s *ConcatIterator) Seek(key []byte) { 78 var idx int 79 if !s.reversed { 80 idx = sort.Search(len(s.tables), func(i int) bool { 81 return bytes.Compare(s.tables[i].Biggest().UserKey, key) >= 0 82 }) 83 } else { 84 n := len(s.tables) 85 idx = n - 1 - sort.Search(n, func(i int) bool { 86 return bytes.Compare(s.tables[n-1-i].Smallest().UserKey, key) <= 0 87 }) 88 } 89 if idx >= len(s.tables) || idx < 0 { 90 s.setIdx(-1) 91 return 92 } 93 // For reversed=false, we know s.tables[i-1].Biggest() < key. Thus, the 94 // previous table cannot possibly contain key. 95 s.setIdx(idx) 96 s.cur.Seek(key) 97 } 98 99 // Next advances our concat iterator. 100 func (s *ConcatIterator) Next() { 101 s.cur.Next() 102 if s.cur.Valid() { 103 // Nothing to do. Just stay with the current table. 104 return 105 } 106 for { // In case there are empty tables. 107 if !s.reversed { 108 s.setIdx(s.idx + 1) 109 } else { 110 s.setIdx(s.idx - 1) 111 } 112 if s.cur == nil { 113 // End of list. Valid will become false. 114 return 115 } 116 s.cur.Rewind() 117 if s.cur.Valid() { 118 break 119 } 120 } 121 } 122 123 func (s *ConcatIterator) NextVersion() bool { 124 return s.cur.NextVersion() 125 }