github.com/pingcap/badger@v1.5.1-0.20230103063557-828f39b09b6d/table/concat_iterator.go (about)

     1  package table
     2  
     3  import (
     4  	"bytes"
     5  	"sort"
     6  
     7  	"github.com/pingcap/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  }
   126  
   127  // Close implements y.Interface.
   128  func (s *ConcatIterator) Close() error {
   129  	for _, it := range s.iters {
   130  		if it == nil {
   131  			continue
   132  		}
   133  		if err := it.Close(); err != nil {
   134  			return y.Wrapf(err, "ConcatIterator")
   135  		}
   136  	}
   137  	return nil
   138  }