github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/roachpb/merge_spans.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package roachpb 12 13 import "sort" 14 15 type sortedSpans []Span 16 17 func (s sortedSpans) Less(i, j int) bool { 18 // Sort first on the start key and second on the end key. Note that we're 19 // relying on EndKey = nil (and len(EndKey) == 0) sorting before other 20 // EndKeys. 21 c := s[i].Key.Compare(s[j].Key) 22 if c != 0 { 23 return c < 0 24 } 25 return s[i].EndKey.Compare(s[j].EndKey) < 0 26 } 27 28 func (s sortedSpans) Swap(i, j int) { 29 s[i], s[j] = s[j], s[i] 30 } 31 32 func (s sortedSpans) Len() int { 33 return len(s) 34 } 35 36 // MergeSpans sorts the incoming spans and merges overlapping spans. Returns 37 // true iff all of the spans are distinct. Note that even if it returns true, 38 // adjacent spans might have been merged (i.e. [a, b) is distinct from [b,c), 39 // but the two are still merged. 40 // 41 // The input spans are not safe for re-use. 42 func MergeSpans(spans []Span) ([]Span, bool) { 43 if len(spans) == 0 { 44 return spans, true 45 } 46 47 sort.Sort(sortedSpans(spans)) 48 49 // We build up the resulting slice of merged spans in place. This is safe 50 // because "r" grows by at most 1 element on each iteration, staying abreast 51 // or behind the iteration over "spans". 52 r := spans[:1] 53 distinct := true 54 55 for _, cur := range spans[1:] { 56 prev := &r[len(r)-1] 57 if len(cur.EndKey) == 0 && len(prev.EndKey) == 0 { 58 if cur.Key.Compare(prev.Key) != 0 { 59 // [a, nil] merge [b, nil] 60 r = append(r, cur) 61 } else { 62 // [a, nil] merge [a, nil] 63 distinct = false 64 } 65 continue 66 } 67 if len(prev.EndKey) == 0 { 68 if cur.Key.Compare(prev.Key) == 0 { 69 // [a, nil] merge [a, b] 70 prev.EndKey = cur.EndKey 71 distinct = false 72 } else { 73 // [a, nil] merge [b, c] 74 r = append(r, cur) 75 } 76 continue 77 } 78 if c := prev.EndKey.Compare(cur.Key); c >= 0 { 79 if cur.EndKey != nil { 80 if prev.EndKey.Compare(cur.EndKey) < 0 { 81 // [a, c] merge [b, d] 82 prev.EndKey = cur.EndKey 83 if c > 0 { 84 distinct = false 85 } 86 } else { 87 // [a, c] merge [b, c] 88 distinct = false 89 } 90 } else if c == 0 { 91 // [a, b] merge [b, nil] 92 prev.EndKey = cur.Key.Next() 93 } else { 94 // [a, c] merge [b, nil] 95 distinct = false 96 } 97 continue 98 } 99 r = append(r, cur) 100 } 101 return r, distinct 102 } 103 104 // SubtractSpans subtracts the subspans covered by a set of non-overlapping 105 // spans from another set of non-overlapping spans. 106 // 107 // Specifically, it returns a non-overlapping set of spans that cover the spans 108 // covered by the minuend but not the subtrahend. For example, given a single 109 // minuend span [0, 10) and a subspan subtrahend [4,5) yields: [0, 4), [5, 10). 110 // 111 // The todo input is mutated during execution and is not safe for reuse after. 112 // The done input is left as-is and is safe for later reuse. 113 // 114 // Internally the minuend and subtrahend are labeled as "todo" and "done", i.e. 115 // conceptually it discusses them as a set of spans "to do" with a subset that 116 // has been "done" and need to be removed from the set "todo". 117 func SubtractSpans(todo, done Spans) Spans { 118 if len(done) == 0 { 119 return todo 120 } 121 sort.Sort(todo) 122 sort.Sort(done) 123 124 remaining := make(Spans, 0, len(todo)) 125 appendRemaining := func(s Span) { 126 if len(remaining) > 0 && remaining[len(remaining)-1].EndKey.Equal(s.Key) { 127 remaining[len(remaining)-1].EndKey = s.EndKey 128 } else { 129 remaining = append(remaining, s) 130 } 131 } 132 133 var d int 134 var t int 135 for t < len(todo) && d < len(done) { 136 tStart, tEnd := todo[t].Key, todo[t].EndKey 137 dStart, dEnd := done[d].Key, done[d].EndKey 138 if tStart.Equal(tEnd) { 139 // We've shrunk the todo span to nothing: pop it off and move on. 140 t++ 141 continue 142 } 143 if dStart.Compare(tEnd) >= 0 { 144 // Done span starts after todo span: todo is kept in its entirety. 145 appendRemaining(todo[t]) 146 t++ 147 continue 148 } 149 if dEnd.Compare(tStart) <= 0 { 150 // Done span isn't in todo at all, so pop it off and move on. 151 d++ 152 continue 153 } 154 155 // At this point, we know that the two spans overlap. 156 endCmp := dEnd.Compare(tEnd) 157 if dStart.Compare(tStart) <= 0 { 158 // The done span starts at or before the todo span starts. 159 if endCmp < 0 { 160 // Covers strict prefix of todo: pop done and shrink remaining todo. 161 todo[t].Key = dEnd 162 d++ 163 } else if endCmp > 0 { 164 // Covers all of todo and more: pop todo, keep consuming done. 165 t++ 166 } else { 167 // cmp == 0 means exactly matches: pop both. 168 t++ 169 d++ 170 } 171 } else { 172 // The beginning of todo is uncovered: split it to remaining. 173 appendRemaining(Span{Key: tStart, EndKey: dStart}) 174 175 if endCmp < 0 { 176 // There is todo uncovered after done: Pop done, shrink and keep todo. 177 todo[t].Key = dEnd 178 d++ 179 } else if endCmp > 0 { 180 // Done covers beyond todo: pop todo, keep consuming done. 181 t++ 182 } else { 183 // cmp == 0: covers to end, uncovered prefix already copied: pop both. 184 t++ 185 d++ 186 } 187 } 188 } 189 // Just append anything that's left. 190 if t < len(todo) { 191 remaining = append(remaining, todo[t:]...) 192 } 193 return remaining 194 }