github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/pkg/regionspan/span.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package regionspan 15 16 import ( 17 "bytes" 18 "encoding/hex" 19 "fmt" 20 21 "github.com/pingcap/log" 22 cerror "github.com/pingcap/ticdc/pkg/errors" 23 "github.com/pingcap/tidb/kv" 24 "github.com/pingcap/tidb/tablecodec" 25 "github.com/pingcap/tidb/util/codec" 26 "go.uber.org/zap" 27 ) 28 29 // Span represents a arbitrary kv range 30 type Span struct { 31 Start []byte 32 End []byte 33 } 34 35 // String returns a string that encodes Span in hex format. 36 func (s Span) String() string { 37 return fmt.Sprintf("[%s, %s)", hex.EncodeToString(s.Start), hex.EncodeToString(s.End)) 38 } 39 40 // UpperBoundKey represents the maximum value. 41 var UpperBoundKey = []byte{255, 255, 255, 255, 255} 42 43 // ComparableSpan represents a arbitrary kv range which is comparable 44 type ComparableSpan Span 45 46 // String returns a string that encodes ComparableSpan in hex format. 47 func (s ComparableSpan) String() string { 48 return Span(s).String() 49 } 50 51 // Hack will set End as UpperBoundKey if End is Nil. 52 func (s ComparableSpan) Hack() ComparableSpan { 53 s.Start, s.End = hackSpan(s.Start, s.End) 54 return s 55 } 56 57 // Clone clones a ComparableSpan 58 func (s ComparableSpan) Clone() ComparableSpan { 59 return ComparableSpan{ 60 Start: append(make([]byte, 0, len(s.Start)), s.Start...), 61 End: append(make([]byte, 0, len(s.End)), s.End...), 62 } 63 } 64 65 // Hack will set End as UpperBoundKey if End is Nil. 66 func (s Span) Hack() Span { 67 s.Start, s.End = hackSpan(s.Start, s.End) 68 return s 69 } 70 71 func hackSpan(originStart []byte, originEnd []byte) (start []byte, end []byte) { 72 start = originStart 73 end = originEnd 74 75 if originStart == nil { 76 start = []byte{} 77 } 78 79 if originEnd == nil { 80 end = UpperBoundKey 81 } 82 return 83 } 84 85 // GetTableSpan returns the span to watch for the specified table 86 func GetTableSpan(tableID int64) Span { 87 sep := byte('_') 88 recordMarker := byte('r') 89 tablePrefix := tablecodec.GenTablePrefix(tableID) 90 var start, end kv.Key 91 // ignore index keys. 92 start = append(tablePrefix, sep, recordMarker) 93 end = append(tablePrefix, sep, recordMarker+1) 94 return Span{ 95 Start: start, 96 End: end, 97 } 98 } 99 100 // GetDDLSpan returns the span to watch for DDL related events 101 func GetDDLSpan() Span { 102 return getMetaListKey("DDLJobList") 103 } 104 105 // GetAddIndexDDLSpan returns the span to watch for Add Index DDL related events 106 func GetAddIndexDDLSpan() Span { 107 return getMetaListKey("DDLJobAddIdxList") 108 } 109 110 func getMetaListKey(key string) Span { 111 metaPrefix := []byte("m") 112 metaKey := []byte(key) 113 listData := 'l' 114 start := make([]byte, 0, len(metaPrefix)+len(metaKey)+8) 115 start = append(start, metaPrefix...) 116 start = codec.EncodeBytes(start, metaKey) 117 start = codec.EncodeUint(start, uint64(listData)) 118 end := make([]byte, len(start)) 119 copy(end, start) 120 end[len(end)-1]++ 121 return Span{ 122 Start: start, 123 End: end, 124 } 125 } 126 127 // KeyInSpans check if k in the range of spans. 128 func KeyInSpans(k []byte, spans []ComparableSpan) bool { 129 for _, span := range spans { 130 if KeyInSpan(k, span) { 131 return true 132 } 133 } 134 135 return false 136 } 137 138 // KeyInSpan check if k in the span range. 139 func KeyInSpan(k []byte, span ComparableSpan) bool { 140 if StartCompare(k, span.Start) >= 0 && 141 EndCompare(k, span.End) < 0 { 142 return true 143 } 144 145 return false 146 } 147 148 // StartCompare compares two start keys. 149 // Nil means Negative infinity 150 // The result will be 0 if lhs==rhs, -1 if lhs < rhs, and +1 if lhs > rhs 151 func StartCompare(lhs []byte, rhs []byte) int { 152 if lhs == nil && rhs == nil { 153 return 0 154 } 155 156 if lhs == nil { 157 return -1 158 } 159 160 if rhs == nil { 161 return 1 162 } 163 164 return bytes.Compare(lhs, rhs) 165 } 166 167 // EndCompare compares two end keys. 168 // Nil means Positive infinity 169 // The result will be 0 if lhs==rhs, -1 if lhs < rhs, and +1 if lhs > rhs 170 func EndCompare(lhs []byte, rhs []byte) int { 171 if lhs == nil && rhs == nil { 172 return 0 173 } 174 175 if lhs == nil { 176 return 1 177 } 178 179 if rhs == nil { 180 return -1 181 } 182 183 return bytes.Compare(lhs, rhs) 184 } 185 186 // Intersect return the intersect part of lhs and rhs span. 187 // Return error if there's no intersect part 188 func Intersect(lhs ComparableSpan, rhs ComparableSpan) (span ComparableSpan, err error) { 189 if lhs.Start != nil && EndCompare(lhs.Start, rhs.End) >= 0 || 190 rhs.Start != nil && EndCompare(rhs.Start, lhs.End) >= 0 { 191 return ComparableSpan{}, cerror.ErrIntersectNoOverlap.GenWithStackByArgs(lhs, rhs) 192 } 193 194 start := lhs.Start 195 196 if StartCompare(rhs.Start, start) > 0 { 197 start = rhs.Start 198 } 199 200 end := lhs.End 201 202 if EndCompare(rhs.End, end) < 0 { 203 end = rhs.End 204 } 205 206 return ComparableSpan{Start: start, End: end}, nil 207 } 208 209 // IsSubSpan returns true if the sub span is parents spans 210 func IsSubSpan(sub ComparableSpan, parents ...ComparableSpan) bool { 211 if bytes.Compare(sub.Start, sub.End) >= 0 { 212 log.Panic("the sub span is invalid", zap.Reflect("sub span", sub)) 213 } 214 for _, parent := range parents { 215 if StartCompare(parent.Start, sub.Start) <= 0 && 216 EndCompare(sub.End, parent.End) <= 0 { 217 return true 218 } 219 } 220 return false 221 } 222 223 // ToComparableSpan returns a memcomparable span 224 func ToComparableSpan(span Span) ComparableSpan { 225 return ComparableSpan{ 226 Start: codec.EncodeBytes(nil, span.Start), 227 End: codec.EncodeBytes(nil, span.End), 228 } 229 } 230 231 // ToComparableKey returns a memcomparable key. 232 func ToComparableKey(key []byte) []byte { 233 return codec.EncodeBytes(nil, key) 234 }