github.com/m3db/m3@v1.5.0/src/m3ninx/index/segment/builder/multi_segments_multi_key_iter.go (about) 1 // Copyright (c) 2019 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 xerrors "github.com/m3db/m3/src/x/errors" 27 ) 28 29 type keyIterator interface { 30 Next() bool 31 Current() []byte 32 Err() error 33 Close() error 34 } 35 36 var _ keyIterator = &multiKeyIterator{} 37 38 type multiKeyIterator struct { 39 closeIters []keyIterator 40 iters []keyIterator 41 currIters []keyIterator 42 } 43 44 func newMultiKeyIterator() *multiKeyIterator { 45 i := new(multiKeyIterator) 46 i.reset() 47 return i 48 } 49 50 func (i *multiKeyIterator) reset() { 51 for j := range i.closeIters { 52 i.closeIters[j] = nil 53 } 54 i.closeIters = i.closeIters[:0] 55 56 for j := range i.iters { 57 i.iters[j] = nil 58 } 59 i.iters = i.iters[:0] 60 61 for j := range i.currIters { 62 i.currIters[j] = nil 63 } 64 i.currIters = i.currIters[:0] 65 } 66 67 func (i *multiKeyIterator) add(iter keyIterator) { 68 i.closeIters = append(i.closeIters, iter) 69 i.iters = append(i.iters, iter) 70 i.tryAddCurr(iter) 71 } 72 73 func (i *multiKeyIterator) Empty() bool { 74 // Use i.closeIters to indicate if any iters were added instead of 75 // i.iters or i.currIter since those are popped off during iteration, 76 // whereas i.closeIters are only removed on reset. 77 return len(i.closeIters) == 0 78 } 79 80 func (i *multiKeyIterator) Next() bool { 81 if len(i.iters) == 0 { 82 return false 83 } 84 85 for _, currIter := range i.currIters { 86 currNext := currIter.Next() 87 if currNext { 88 // Next has a value, forward other matching too 89 continue 90 } 91 92 // Remove iter 93 n := len(i.iters) 94 idx := -1 95 for j, iter := range i.iters { 96 if iter == currIter { 97 idx = j 98 break 99 } 100 } 101 i.iters[idx] = i.iters[n-1] 102 i.iters[n-1] = nil 103 i.iters = i.iters[:n-1] 104 } 105 if len(i.iters) == 0 { 106 return false 107 } 108 109 // Re-evaluate current value 110 i.currEvaluate() 111 return true 112 } 113 114 func (i *multiKeyIterator) currEvaluate() { 115 i.currIters = i.currIters[:0] 116 for _, iter := range i.iters { 117 i.tryAddCurr(iter) 118 } 119 } 120 121 func (i *multiKeyIterator) tryAddCurr(iter keyIterator) { 122 var ( 123 hasCurr = len(i.currIters) > 0 124 cmp int 125 ) 126 if hasCurr { 127 cmp = bytes.Compare(iter.Current(), i.Current()) 128 } 129 if !hasCurr || cmp < 0 { 130 // Set the current lowest key value 131 i.currIters = i.currIters[:0] 132 i.currIters = append(i.currIters, iter) 133 } else if hasCurr && cmp == 0 { 134 // Set a matching duplicate curr iter 135 i.currIters = append(i.currIters, iter) 136 } 137 } 138 139 func (i *multiKeyIterator) Current() []byte { 140 return i.currIters[0].Current() 141 } 142 143 func (i *multiKeyIterator) CurrentIters() []keyIterator { 144 return i.currIters 145 } 146 147 func (i *multiKeyIterator) Err() error { 148 multiErr := xerrors.NewMultiError() 149 for _, iter := range i.closeIters { 150 multiErr = multiErr.Add(iter.Err()) 151 } 152 return multiErr.FinalError() 153 } 154 155 func (i *multiKeyIterator) Close() error { 156 multiErr := xerrors.NewMultiError() 157 for _, iter := range i.closeIters { 158 multiErr = multiErr.Add(iter.Close()) 159 } 160 // Free resources 161 i.reset() 162 return multiErr.FinalError() 163 }