github.com/XiaoMi/Gaea@v1.2.5/proxy/router/shard.go (about)

     1  // Copyright 2012, Google Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Copyright 2016 The kingshard Authors. All rights reserved.
     6  //
     7  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     8  // not use this file except in compliance with the License. You may obtain
     9  // a copy of the License at
    10  //
    11  //     http://www.apache.org/licenses/LICENSE-2.0
    12  //
    13  // Unless required by applicable law or agreed to in writing, software
    14  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    15  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    16  // License for the specific language governing permissions and limitations
    17  // under the License.
    18  
    19  // Copyright 2019 The Gaea Authors. All Rights Reserved.
    20  //
    21  // Licensed under the Apache License, Version 2.0 (the "License");
    22  // you may not use this file except in compliance with the License.
    23  // You may obtain a copy of the License at
    24  //
    25  //     http://www.apache.org/licenses/LICENSE-2.0
    26  //
    27  // Unless required by applicable law or agreed to in writing, software
    28  // distributed under the License is distributed on an "AS IS" BASIS,
    29  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    30  // See the License for the specific language governing permissions and
    31  // limitations under the License.
    32  
    33  package router
    34  
    35  import (
    36  	"bytes"
    37  	"encoding/binary"
    38  	"fmt"
    39  	"hash/crc32"
    40  	"strconv"
    41  	"time"
    42  
    43  	"github.com/XiaoMi/Gaea/core/errors"
    44  	"github.com/XiaoMi/Gaea/util/hack"
    45  )
    46  
    47  /*由分片ID找到分片,可用文件中的函数*/
    48  type KeyError string
    49  
    50  func NewKeyError(format string, args ...interface{}) KeyError {
    51  	return KeyError(fmt.Sprintf(format, args...))
    52  }
    53  
    54  func NewInvalidDateFormatKeyError(key interface{}) KeyError {
    55  	return KeyError(fmt.Sprintf("invalid date format %v", key))
    56  }
    57  
    58  func (ke KeyError) Error() string {
    59  	return string(ke)
    60  }
    61  
    62  func handleError(err *error) {
    63  	if x := recover(); x != nil {
    64  		*err = x.(KeyError)
    65  	}
    66  }
    67  
    68  // Uint64Key is a uint64 that can be converted into a KeyspaceId.
    69  type Uint64Key uint64
    70  
    71  func (i Uint64Key) String() string {
    72  	buf := new(bytes.Buffer)
    73  	binary.Write(buf, binary.BigEndian, uint64(i))
    74  	return buf.String()
    75  }
    76  
    77  // don't use this function like strconv.FormatInt()!!!
    78  func EncodeValue(value interface{}) string {
    79  	switch val := value.(type) {
    80  	case int:
    81  		return Uint64Key(val).String()
    82  	case uint64:
    83  		return Uint64Key(val).String()
    84  	case int64:
    85  		return Uint64Key(val).String()
    86  	case string:
    87  		return val
    88  	case []byte:
    89  		return hack.String(val)
    90  	}
    91  	panic(NewKeyError("Unexpected key variable type %T", value))
    92  }
    93  
    94  func GetString(value interface{}) string {
    95  	switch val := value.(type) {
    96  	case int:
    97  		return strconv.FormatInt(int64(val), 10)
    98  	case int64:
    99  		return strconv.FormatInt(val, 10)
   100  	case uint:
   101  		return strconv.FormatUint(uint64(val), 10)
   102  	case uint64:
   103  		return strconv.FormatUint(val, 10)
   104  	case string:
   105  		return val
   106  	case []byte:
   107  		return hack.String(val)
   108  	default:
   109  		panic(NewKeyError("Unexpected key variable type %T", value))
   110  	}
   111  }
   112  
   113  func HashValue(value interface{}) uint64 {
   114  	switch val := value.(type) {
   115  	case int:
   116  		return uint64(val)
   117  	case uint64:
   118  		return uint64(val)
   119  	case int64:
   120  		return uint64(val)
   121  	case string:
   122  		if v, err := strconv.ParseUint(val, 10, 64); err != nil {
   123  			return uint64(crc32.ChecksumIEEE(hack.Slice(val)))
   124  		} else {
   125  			return uint64(v)
   126  		}
   127  	case []byte:
   128  		return uint64(crc32.ChecksumIEEE(val))
   129  	}
   130  	panic(NewKeyError("Unexpected key variable type %T", value))
   131  }
   132  
   133  func NumValue(value interface{}) int64 {
   134  	switch val := value.(type) {
   135  	case int:
   136  		return int64(val)
   137  	case uint64:
   138  		return int64(val)
   139  	case int64:
   140  		return int64(val)
   141  	case string:
   142  		if v, err := strconv.ParseInt(val, 10, 64); err != nil {
   143  			panic(NewKeyError("invalid num format %v", v))
   144  		} else {
   145  			return v
   146  		}
   147  	case []byte:
   148  		if v, err := strconv.ParseInt(hack.String(val), 10, 64); err != nil {
   149  			panic(NewKeyError("invalid num format %v", v))
   150  		} else {
   151  			return v
   152  		}
   153  	}
   154  	panic(NewKeyError("Unexpected key variable type %T", value))
   155  }
   156  
   157  type Shard interface {
   158  	FindForKey(key interface{}) (int, error)
   159  }
   160  
   161  /*一个范围的分片,例如[start,end)*/
   162  type RangeShard interface {
   163  	Shard
   164  	EqualStart(key interface{}, index int) bool
   165  }
   166  
   167  type HashShard struct {
   168  	ShardNum int
   169  }
   170  
   171  func (s *HashShard) FindForKey(key interface{}) (int, error) {
   172  	h := HashValue(key)
   173  
   174  	return int(h % uint64(s.ShardNum)), nil
   175  }
   176  
   177  type ModShard struct {
   178  	ShardNum int
   179  }
   180  
   181  func (m *ModShard) FindForKey(key interface{}) (int, error) {
   182  	h := hack.Abs(NumValue(key))
   183  	return int(h % int64(m.ShardNum)), nil
   184  }
   185  
   186  type NumRangeShard struct {
   187  	Shards []NumKeyRange
   188  }
   189  
   190  func (s *NumRangeShard) FindForKey(key interface{}) (int, error) {
   191  	v := NumValue(key)
   192  	for i, r := range s.Shards {
   193  		if r.Contains(v) {
   194  			return i, nil
   195  		}
   196  	}
   197  	return -1, errors.ErrKeyOutOfRange
   198  }
   199  
   200  func (s *NumRangeShard) EqualStart(key interface{}, index int) bool {
   201  	v := NumValue(key)
   202  	return s.Shards[index].Start == v
   203  }
   204  
   205  type DateYearShard struct {
   206  }
   207  
   208  func (s *DateYearShard) getNumYear(key interface{}) (int, error) {
   209  	switch val := key.(type) {
   210  	case int:
   211  		tm := time.Unix(int64(val), 0)
   212  		return tm.Year(), nil
   213  	case uint64:
   214  		tm := time.Unix(int64(val), 0)
   215  		return tm.Year(), nil
   216  	case int64:
   217  		tm := time.Unix(val, 0)
   218  		return tm.Year(), nil
   219  	case string:
   220  		if v, err := strconv.Atoi(val[:4]); err != nil {
   221  			return -1, NewInvalidDateFormatKeyError(key)
   222  		} else {
   223  			return v, nil
   224  		}
   225  	}
   226  	return -1, NewKeyError("Unexpected key variable type %T", key)
   227  }
   228  
   229  //the format of date is: YYYY-MM-DD HH:MM:SS,YYYY-MM-DD or unix timestamp(int)
   230  func (s *DateYearShard) FindForKey(key interface{}) (int, error) {
   231  	return s.getNumYear(key)
   232  }
   233  
   234  func (s *DateYearShard) EqualStart(key interface{}, index int) bool {
   235  	numYear, err := s.getNumYear(key)
   236  	if err != nil {
   237  		return false
   238  	}
   239  
   240  	return numYear == index
   241  }
   242  
   243  type DateMonthShard struct {
   244  }
   245  
   246  func (s *DateMonthShard) getNumYearMonth(key interface{}) (int, error) {
   247  	timeFormat := "2006-01-02"
   248  	switch val := key.(type) {
   249  	case int:
   250  		tm := time.Unix(int64(val), 0)
   251  		dateStr := tm.Format(timeFormat)
   252  		s := dateStr[:4] + dateStr[5:7]
   253  		yearMonth, err := strconv.Atoi(s)
   254  		if err != nil {
   255  			return -1, NewInvalidDateFormatKeyError(key)
   256  		}
   257  		return yearMonth, nil
   258  	case uint64:
   259  		tm := time.Unix(int64(val), 0)
   260  		dateStr := tm.Format(timeFormat)
   261  		s := dateStr[:4] + dateStr[5:7]
   262  		yearMonth, err := strconv.Atoi(s)
   263  		if err != nil {
   264  			return -1, NewInvalidDateFormatKeyError(key)
   265  		}
   266  		return yearMonth, nil
   267  	case int64:
   268  		tm := time.Unix(val, 0)
   269  		dateStr := tm.Format(timeFormat)
   270  		s := dateStr[:4] + dateStr[5:7]
   271  		yearMonth, err := strconv.Atoi(s)
   272  		if err != nil {
   273  			return -1, NewInvalidDateFormatKeyError(key)
   274  		}
   275  		return yearMonth, nil
   276  	case string:
   277  		if len(val) < len(timeFormat) {
   278  			return -1, NewInvalidDateFormatKeyError(key)
   279  		}
   280  		s := val[:4] + val[5:7]
   281  		if v, err := strconv.Atoi(s); err != nil {
   282  			return -1, NewInvalidDateFormatKeyError(key)
   283  		} else {
   284  			return v, nil
   285  		}
   286  	}
   287  	return -1, NewKeyError("Unexpected key variable type %T", key)
   288  }
   289  
   290  //the format of date is: YYYY-MM-DD HH:MM:SS,YYYY-MM-DD or unix timestamp(int)
   291  func (s *DateMonthShard) FindForKey(key interface{}) (int, error) {
   292  	return s.getNumYearMonth(key)
   293  }
   294  
   295  func (s *DateMonthShard) EqualStart(key interface{}, index int) bool {
   296  	numYear, err := s.getNumYearMonth(key)
   297  	if err != nil {
   298  		return false
   299  	}
   300  
   301  	return numYear == index
   302  }
   303  
   304  type DateDayShard struct {
   305  }
   306  
   307  func (s *DateDayShard) getNumYearMonthDay(key interface{}) (int, error) {
   308  	timeFormat := "2006-01-02"
   309  	switch val := key.(type) {
   310  	case int:
   311  		tm := time.Unix(int64(val), 0)
   312  		dateStr := tm.Format(timeFormat)
   313  		s := dateStr[:4] + dateStr[5:7] + dateStr[8:10]
   314  		yearMonthDay, err := strconv.Atoi(s)
   315  		if err != nil {
   316  			return -1, NewInvalidDateFormatKeyError(key)
   317  		}
   318  		return yearMonthDay, nil
   319  	case uint64:
   320  		tm := time.Unix(int64(val), 0)
   321  		dateStr := tm.Format(timeFormat)
   322  		s := dateStr[:4] + dateStr[5:7] + dateStr[8:10]
   323  		yearMonthDay, err := strconv.Atoi(s)
   324  		if err != nil {
   325  			return -1, NewInvalidDateFormatKeyError(key)
   326  		}
   327  		return yearMonthDay, nil
   328  	case int64:
   329  		tm := time.Unix(val, 0)
   330  		dateStr := tm.Format(timeFormat)
   331  		s := dateStr[:4] + dateStr[5:7] + dateStr[8:10]
   332  		yearMonthDay, err := strconv.Atoi(s)
   333  		if err != nil {
   334  			return -1, NewInvalidDateFormatKeyError(key)
   335  		}
   336  		return yearMonthDay, nil
   337  	case string:
   338  		if len(val) < len(timeFormat) {
   339  			return -1, NewInvalidDateFormatKeyError(key)
   340  		}
   341  		s := val[:4] + val[5:7] + val[8:10]
   342  		if v, err := strconv.Atoi(s); err != nil {
   343  			return -1, NewInvalidDateFormatKeyError(key)
   344  		} else {
   345  			return v, nil
   346  		}
   347  	}
   348  	return -1, NewKeyError("Unexpected key variable type %T", key)
   349  }
   350  
   351  //the format of date is: YYYY-MM-DD HH:MM:SS,YYYY-MM-DD or unix timestamp(int)
   352  func (s *DateDayShard) FindForKey(key interface{}) (int, error) {
   353  	return s.getNumYearMonthDay(key)
   354  }
   355  
   356  func (s *DateDayShard) EqualStart(key interface{}, index int) bool {
   357  	numYear, err := s.getNumYearMonthDay(key)
   358  	if err != nil {
   359  		return false
   360  	}
   361  
   362  	return numYear == index
   363  }
   364  
   365  type DefaultShard struct {
   366  }
   367  
   368  func (s *DefaultShard) FindForKey(key interface{}) (int, error) {
   369  	return 0, nil
   370  }
   371  
   372  type GlobalTableShard struct {
   373  }
   374  
   375  func (s *GlobalTableShard) FindForKey(key interface{}) (int, error) {
   376  	panic("global table cannot find key")
   377  }
   378  
   379  func NewGlobalTableShard() *GlobalTableShard {
   380  	return &GlobalTableShard{}
   381  }