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  }