github.com/m3db/m3@v1.5.0/src/m3ninx/index/segment/builder/bytes_slice_iter.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package builder
    22  
    23  import (
    24  	"bytes"
    25  
    26  	"github.com/m3db/m3/src/m3ninx/index/segment"
    27  	"github.com/m3db/m3/src/m3ninx/postings"
    28  
    29  	"github.com/twotwotwo/sorts"
    30  )
    31  
    32  type uniqueField struct {
    33  	field        []byte
    34  	postingsList postings.List
    35  }
    36  
    37  // orderedFieldsPostingsListIter is a new ordered fields/postings list iterator.
    38  type orderedFieldsPostingsListIter struct {
    39  	err  error
    40  	done bool
    41  
    42  	currentIdx    int
    43  	current       uniqueField
    44  	backingSlices *sortableSliceOfSliceOfUniqueFieldsAsc
    45  }
    46  
    47  var _ segment.FieldsPostingsListIterator = &orderedFieldsPostingsListIter{}
    48  
    49  // newOrderedFieldsPostingsListIter sorts a slice of slices of unique fields and then
    50  // returns an iterator over them.
    51  func newOrderedFieldsPostingsListIter(
    52  	maybeUnorderedFields [][]uniqueField,
    53  ) *orderedFieldsPostingsListIter {
    54  	sortable := &sortableSliceOfSliceOfUniqueFieldsAsc{data: maybeUnorderedFields}
    55  	// NB(r): See SetSortConcurrency why this RLock is required.
    56  	sortConcurrencyLock.RLock()
    57  	sorts.ByBytes(sortable)
    58  	sortConcurrencyLock.RUnlock()
    59  	return &orderedFieldsPostingsListIter{
    60  		currentIdx:    -1,
    61  		backingSlices: sortable,
    62  	}
    63  }
    64  
    65  // Next returns true if there is a next result.
    66  func (b *orderedFieldsPostingsListIter) Next() bool {
    67  	if b.done || b.err != nil {
    68  		return false
    69  	}
    70  	b.currentIdx++
    71  	if b.currentIdx >= b.backingSlices.Len() {
    72  		b.done = true
    73  		return false
    74  	}
    75  	iOuter, iInner := b.backingSlices.getIndices(b.currentIdx)
    76  	b.current = b.backingSlices.data[iOuter][iInner]
    77  	return true
    78  }
    79  
    80  // Current returns the current entry.
    81  func (b *orderedFieldsPostingsListIter) Current() ([]byte, postings.List) {
    82  	return b.current.field, b.current.postingsList
    83  }
    84  
    85  // Err returns an error if an error occurred iterating.
    86  func (b *orderedFieldsPostingsListIter) Err() error {
    87  	return nil
    88  }
    89  
    90  // Len returns the length of the slice.
    91  func (b *orderedFieldsPostingsListIter) Len() int {
    92  	return b.backingSlices.Len()
    93  }
    94  
    95  // Close releases resources.
    96  func (b *orderedFieldsPostingsListIter) Close() error {
    97  	b.current = uniqueField{}
    98  	return nil
    99  }
   100  
   101  type sortableSliceOfSliceOfUniqueFieldsAsc struct {
   102  	data   [][]uniqueField
   103  	length int
   104  }
   105  
   106  func (s *sortableSliceOfSliceOfUniqueFieldsAsc) Len() int {
   107  	if s.length > 0 {
   108  		return s.length
   109  	}
   110  
   111  	totalLen := 0
   112  	for _, innerSlice := range s.data {
   113  		totalLen += len(innerSlice)
   114  	}
   115  	s.length = totalLen
   116  
   117  	return s.length
   118  }
   119  
   120  func (s *sortableSliceOfSliceOfUniqueFieldsAsc) Less(i, j int) bool {
   121  	iOuter, iInner := s.getIndices(i)
   122  	jOuter, jInner := s.getIndices(j)
   123  	return bytes.Compare(s.data[iOuter][iInner].field, s.data[jOuter][jInner].field) < 0
   124  }
   125  
   126  func (s *sortableSliceOfSliceOfUniqueFieldsAsc) Swap(i, j int) {
   127  	iOuter, iInner := s.getIndices(i)
   128  	jOuter, jInner := s.getIndices(j)
   129  	s.data[iOuter][iInner], s.data[jOuter][jInner] = s.data[jOuter][jInner], s.data[iOuter][iInner]
   130  }
   131  
   132  func (s *sortableSliceOfSliceOfUniqueFieldsAsc) Key(i int) []byte {
   133  	iOuter, iInner := s.getIndices(i)
   134  	return s.data[iOuter][iInner].field
   135  }
   136  
   137  func (s *sortableSliceOfSliceOfUniqueFieldsAsc) getIndices(idx int) (int, int) {
   138  	currentSliceIdx := 0
   139  	for idx >= len(s.data[currentSliceIdx]) {
   140  		idx -= len(s.data[currentSliceIdx])
   141  		currentSliceIdx++
   142  	}
   143  	return currentSliceIdx, idx
   144  }