github.com/XiaoMi/Gaea@v1.2.5/models/shard_rule.go (about) 1 // Copyright 2016 The kingshard Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 // not use this file except in compliance with the License. You may obtain 5 // 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, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations 13 // under the License. 14 15 package models 16 17 import ( 18 "fmt" 19 "strconv" 20 "strings" 21 22 "github.com/XiaoMi/Gaea/core/errors" 23 ) 24 25 var ruleVerifyFuncMapping = map[string]func(shard *Shard) error{ 26 ShardHash: verifyHashRule, 27 ShardMod: verifyModRule, 28 ShardRange: verifyRangeRule, 29 ShardDay: verifyDayRule, 30 ShardMonth: verifyMonthRule, 31 ShardYear: verifyYearRule, 32 ShardMycatMod: verifyMycatModRule, 33 ShardMycatLong: verifyMycatLongRule, 34 ShardMycatString: verifyMycatStringRule, 35 ShardMycatMURMUR: verifyMycatMURMURRule, 36 ShardMycatPaddingMod: verifyMycatPaddingRule, 37 ShardGlobal: verifyGlobalRule, 38 } 39 40 func verifyHashRule(s *Shard) error { 41 if _, err := verifyHashRuleSliceInfos(s.Locations, s.Slices); err != nil { 42 return err 43 } 44 return nil 45 } 46 47 func verifyModRule(s *Shard) error { 48 if _, err := verifyHashRuleSliceInfos(s.Locations, s.Slices); err != nil { 49 return err 50 } 51 return nil 52 } 53 54 func verifyRangeRule(s *Shard) error { 55 tableToSlice, err := verifyHashRuleSliceInfos(s.Locations, s.Slices) 56 if err != nil { 57 return err 58 } 59 60 tableCount, err := ParseNumSharding(s.Locations, s.TableRowLimit) 61 if err != nil { 62 return err 63 } 64 if len(tableCount) != len(tableToSlice) { 65 return fmt.Errorf("range space %d not equal tables %d", tableCount, len(tableToSlice)) 66 } 67 return nil 68 } 69 70 func verifyDayRule(s *Shard) error { 71 if err := verifyDateDayRuleSliceInfos(s.DateRange, s.Slices); err != nil { 72 return err 73 } 74 return nil 75 } 76 77 func verifyMonthRule(s *Shard) error { 78 err := verifyDateMonthRuleSliceInfos(s.DateRange, s.Slices) 79 if err != nil { 80 return err 81 } 82 return nil 83 } 84 85 func verifyYearRule(s *Shard) error { 86 err := verifyDateYearRuleSliceInfos(s.DateRange, s.Slices) 87 if err != nil { 88 return err 89 } 90 return nil 91 } 92 93 func verifyMycatModRule(s *Shard) error { 94 if _, err := verifyMycatHashRuleSliceInfos(s.Locations, s.Slices, s.Databases); err != nil { 95 return err 96 } 97 return nil 98 } 99 100 func verifyMycatLongRule(s *Shard) error { 101 tableToSlice, err := verifyMycatHashRuleSliceInfos(s.Locations, s.Slices, s.Databases) 102 if err != nil { 103 return err 104 } 105 if err := verifyMycatPatitionLongShard(len(tableToSlice), s.PartitionCount, s.PartitionLength); err != nil { 106 return err 107 } 108 return nil 109 } 110 111 func verifyMycatStringRule(s *Shard) error { 112 tableToSlice, err := verifyMycatHashRuleSliceInfos(s.Locations, s.Slices, s.Databases) 113 if err != nil { 114 return err 115 } 116 if err := verifyMycatPartitionStringShard(len(tableToSlice), s.PartitionCount, s.PartitionLength, s.HashSlice); err != nil { 117 return err 118 } 119 return nil 120 } 121 122 func verifyMycatMURMURRule(s *Shard) error { 123 tableToSlice, err := verifyMycatHashRuleSliceInfos(s.Locations, s.Slices, s.Databases) 124 if err != nil { 125 return err 126 } 127 if err := verifyMycatPartitionMurmurHashShard(s.Seed, s.VirtualBucketTimes, len(tableToSlice)); err != nil { 128 return err 129 } 130 return nil 131 } 132 133 func verifyMycatPaddingRule(s *Shard) error { 134 tableToSlice, err := verifyMycatHashRuleSliceInfos(s.Locations, s.Slices, s.Databases) 135 if err != nil { 136 return err 137 } 138 if err := verifyMycatPartitionPaddingModShard(s.PadFrom, s.PadLength, s.ModBegin, s.ModEnd, len(tableToSlice)); err != nil { 139 return err 140 } 141 return nil 142 } 143 144 func verifyGlobalRule(s *Shard) error { 145 if err := verifyGlobalTableRuleSliceInfos(s.Locations, s.Slices, s.Databases); err != nil { 146 return err 147 } 148 return nil 149 } 150 151 func verifyHashRuleSliceInfos(locations []int, slices []string) (map[int]int, error) { 152 var sumTables int 153 tableToSlice := make(map[int]int, 0) 154 155 if len(locations) != len(slices) { 156 return nil, errors.ErrLocationsCount 157 } 158 for i := 0; i < len(locations); i++ { 159 for j := 0; j < locations[i]; j++ { 160 tableToSlice[j+sumTables] = i 161 } 162 sumTables += locations[i] 163 } 164 return tableToSlice, nil 165 } 166 167 func verifyMycatHashRuleSliceInfos(locations []int, slices []string, databases []string) (map[int]int, error) { 168 tableToSlice, err := verifyHashRuleSliceInfos(locations, slices) 169 if err != nil { 170 return nil, err 171 } 172 173 realDatabaseList, err := getRealDatabases(databases) 174 if err != nil { 175 return nil, err 176 } 177 178 if len(tableToSlice) != len(realDatabaseList) { 179 return nil, errors.ErrLocationsCount 180 } 181 182 return tableToSlice, nil 183 } 184 185 func verifyDateDayRuleSliceInfos(dateRange []string, slices []string) error { 186 var subTableIndexs []int 187 if len(dateRange) != len(slices) { 188 return errors.ErrDateRangeCount 189 } 190 for i := 0; i < len(dateRange); i++ { 191 dayNumbers, err := ParseDayRange(dateRange[i]) 192 if err != nil { 193 return err 194 } 195 if len(subTableIndexs) > 0 && dayNumbers[0] <= subTableIndexs[len(subTableIndexs)-1] { 196 return errors.ErrDateRangeOverlap 197 } 198 for _, v := range dayNumbers { 199 subTableIndexs = append(subTableIndexs, v) 200 } 201 } 202 return nil 203 } 204 205 func verifyDateMonthRuleSliceInfos(dateRange []string, slices []string) error { 206 var subTableIndexs []int 207 if len(dateRange) != len(slices) { 208 return errors.ErrDateRangeCount 209 } 210 for i := 0; i < len(dateRange); i++ { 211 monthNumbers, err := ParseMonthRange(dateRange[i]) 212 if err != nil { 213 return err 214 } 215 if len(subTableIndexs) > 0 && monthNumbers[0] <= subTableIndexs[len(subTableIndexs)-1] { 216 return errors.ErrDateRangeOverlap 217 } 218 for _, v := range monthNumbers { 219 subTableIndexs = append(subTableIndexs, v) 220 } 221 } 222 return nil 223 } 224 225 func verifyDateYearRuleSliceInfos(dateRange []string, slices []string) error { 226 var subTableIndexs []int 227 if len(dateRange) != len(slices) { 228 return errors.ErrDateRangeCount 229 } 230 for i := 0; i < len(dateRange); i++ { 231 yearNumbers, err := ParseYearRange(dateRange[i]) 232 if err != nil { 233 return err 234 } 235 if len(subTableIndexs) > 0 && yearNumbers[0] <= subTableIndexs[len(subTableIndexs)-1] { 236 return errors.ErrDateRangeOverlap 237 } 238 for _, v := range yearNumbers { 239 subTableIndexs = append(subTableIndexs, v) 240 } 241 } 242 return nil 243 } 244 245 func verifyGlobalTableRuleSliceInfos(locations []int, slices []string, databases []string) error { 246 tableToSlice, err := verifyHashRuleSliceInfos(locations, slices) 247 if err != nil { 248 return err 249 } 250 251 if len(databases) != 0 { 252 realDatabaseList, err := getRealDatabases(databases) 253 if err != nil { 254 return err 255 } 256 if len(tableToSlice) != len(realDatabaseList) { 257 return errors.ErrLocationsCount 258 } 259 } 260 return nil 261 } 262 263 func includeSlice(slices []string, sliceName string) bool { 264 for _, s := range slices { 265 if s == sliceName { 266 return true 267 } 268 } 269 return false 270 } 271 272 func toIntArray(str string) ([]int, error) { 273 str = strings.Replace(str, " ", "", -1) 274 strList := strings.Split(str, ",") 275 ret := make([]int, 0, len(strList)) 276 for _, s := range strList { 277 num, err := strconv.Atoi(s) 278 if err != nil { 279 return ret, err 280 } 281 ret = append(ret, num) 282 } 283 return ret, nil 284 } 285 286 func verifyMycatPatitionLongShard(shardNum int, partitionCount, partitionLength string) error { 287 countList, err := toIntArray(partitionCount) 288 if err != nil { 289 return err 290 } 291 lengthList, err := toIntArray(partitionLength) 292 if err != nil { 293 return err 294 } 295 296 countSize := len(countList) 297 lengthSize := len(lengthList) 298 if countSize != lengthSize { 299 return fmt.Errorf("error, check your scope & scopeLength definition") 300 } 301 302 segmentLength := 0 303 for i := 0; i < countSize; i++ { 304 segmentLength += countList[i] 305 } 306 if segmentLength != shardNum { 307 return fmt.Errorf("segmentLength is not equal to shardNum") 308 } 309 310 ai := make([]int, segmentLength+1) 311 312 index := 0 313 for i := 0; i < countSize; i++ { 314 for j := 0; j < countList[i]; j++ { 315 ai[index+1] = ai[index] + lengthList[i] 316 index++ 317 } 318 } 319 if ai[len(ai)-1] != PartitionLength { 320 return fmt.Errorf("error, check your partitionScope definition") 321 } 322 return nil 323 } 324 325 func verifyMycatPartitionStringShard(shardNum int, partitionCount, partitionLength string, hashSliceStr string) error { 326 if err := verifyMycatPatitionLongShard(shardNum, partitionCount, partitionLength); err != nil { 327 return err 328 } 329 if err := verifyHashSliceStartEnd(hashSliceStr); err != nil { 330 return err 331 } 332 return nil 333 } 334 335 func verifyHashSliceStartEnd(hashSliceStr string) error { 336 hashSliceStr = strings.TrimSpace(hashSliceStr) 337 strs := strings.Split(hashSliceStr, ":") 338 339 if len(strs) == 1 { 340 _, err := strconv.Atoi(strs[0]) 341 if err != nil { 342 return err 343 } 344 return nil 345 } 346 347 if len(strs) == 2 { 348 if err := verifyHashSliceValue(strs[0]); err != nil { 349 return fmt.Errorf("parse hash slice start error: %v", err) 350 } 351 if err := verifyHashSliceValue(strs[1]); err != nil { 352 return fmt.Errorf("parse hash slice end error: %v", err) 353 } 354 return nil 355 } 356 357 return fmt.Errorf("invalid hash slice str") 358 } 359 360 func verifyHashSliceValue(str string) error { 361 if str == "" { 362 return nil 363 } 364 _, err := strconv.Atoi(str) 365 return err 366 } 367 368 func verifyMycatPartitionMurmurHashShard(seedStr, virtualBucketTimesStr string, count int) error { 369 _, err := strconv.Atoi(seedStr) 370 if err != nil { 371 return err 372 } 373 if virtualBucketTimesStr == "" { 374 virtualBucketTimesStr = "160" 375 } 376 if _, err := strconv.Atoi(virtualBucketTimesStr); err != nil { 377 return err 378 } 379 return nil 380 } 381 382 func verifyMycatPartitionPaddingModShard(padFromStr, padLengthStr, modBeginStr, modEndStr string, mod int) error { 383 padFrom, err := strconv.Atoi(padFromStr) 384 if err != nil { 385 return err 386 } 387 padLength, err := strconv.Atoi(padLengthStr) 388 if err != nil { 389 return err 390 } 391 modBegin, err := strconv.Atoi(modBeginStr) 392 if err != nil { 393 return err 394 } 395 modEnd, err := strconv.Atoi(modEndStr) 396 if err != nil { 397 return err 398 } 399 if padFrom != PaddingModLeftEnd && padFrom != PaddingModRightEnd { 400 return fmt.Errorf("invalid padding mod mode: %d", padFrom) 401 } 402 if mod < PaddingModDefaultMod { 403 return fmt.Errorf("invalid padding mod number: %d", mod) 404 } 405 if modBegin < 0 || modBegin >= modEnd { 406 return fmt.Errorf("invalid padding modBegin or modEnd: %d, %d", modBegin, modEnd) 407 } 408 if padLength <= 0 { 409 return fmt.Errorf("invalid padding mod padLength: %d", padLength) 410 } 411 if padLength < (modEnd - modBegin) { 412 return fmt.Errorf("invalid padding mod, padLength is less than modBegin - modEnd: %d, %d, %d", padLength, modBegin, modEnd) 413 } 414 return nil 415 }