github.com/searKing/golang/go@v1.2.117/container/hashring/hash_algorithm.go (about)

     1  // Copyright 2020 The searKing Author. 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  package hashring
     6  
     7  import (
     8  	"crypto/md5"
     9  	"encoding/binary"
    10  	"hash/crc32"
    11  	"hash/fnv"
    12  )
    13  
    14  // Intents to provide hash for locating a server for a key.
    15  type HashAlgorithm interface {
    16  	// Compute the hash for the given key.
    17  	// @return a positive integer hash
    18  	Hash(k string) []uint32
    19  }
    20  
    21  type HashFunc func(k string) []uint32
    22  
    23  func (f HashFunc) Hash(k string) []uint32 {
    24  	return f(k)
    25  }
    26  
    27  // Known hashing algorithms for locating a server for a key. Note that all hash
    28  // algorithms return 64-bits of hash, but only the lower 32-bits are
    29  // significant. This allows a positive 32-bit number to be returned for all
    30  // cases.
    31  var (
    32  	// CRCHash hash algorithm by crc32.
    33  	CRCHash = HashFunc(crcHash)
    34  	// CRCPerlHash as used by the perl API. This will be more consistent both
    35  	// across multiple API users as well as java versions, but is mostly likely
    36  	// significantly slower.
    37  	CRCPerlHash = HashFunc(crcPerlHash)
    38  	// FNV hashes are designed to be fast while maintaining a low collision rate.
    39  	// The FNV speed allows one to quickly hash lots of data while maintaining a
    40  	// reasonable collision rate.
    41  	//
    42  	// @see <a href="http://www.isthe.com/chongo/tech/comp/fnv/">fnv
    43  	//      comparisons</a>
    44  	// @see <a href="http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash">fnv at
    45  	//      wikipedia</a>
    46  	// 32-bit FNV1.
    47  	FNV132Hash = HashFunc(fnv132Hash)
    48  	// Variation of FNV.
    49  	// 32-bit FNV1a.
    50  	FNV1a32Hash = HashFunc(fnv1a32Hash)
    51  	// 64-bit FNV1.
    52  	FNV164Hash = HashFunc(fnv164Hash)
    53  	// 64-bit FNV1a.
    54  	FNV1a64Hash = HashFunc(fnv1a64Hash)
    55  	// 128-bit FNV1.
    56  	FNV1128Hash = HashFunc(fnv1128Hash)
    57  	// 128-bit FNV1a.
    58  	FNV1a128Hash = HashFunc(fnv1a128Hash)
    59  	// MD5-based hash algorithm used by ketama.
    60  	KetamaHash = HashFunc(ketamaHash)
    61  )
    62  
    63  func crcHash(k string) []uint32 {
    64  	rv := crc32.ChecksumIEEE([]byte(k))
    65  	return []uint32{rv}
    66  }
    67  
    68  func crcPerlHash(k string) []uint32 {
    69  	// return (crc32(shift) >> 16) & 0x7fff;
    70  
    71  	//crc32 := crc32.NewIEEE()
    72  	//crc32.Write([]byte(k))
    73  	//rv := (crc32.Sum32() >> 16) & 0x7fff
    74  	rv := crc32.ChecksumIEEE([]byte(k))
    75  	return []uint32{(rv >> 16) & 0x7fff} // Truncate to 16-bits
    76  }
    77  
    78  // FNV hashes are designed to be fast while maintaining a low collision rate.
    79  // The FNV speed allows one to quickly hash lots of data while maintaining a
    80  // reasonable collision rate.
    81  //
    82  // @see <a href="http://www.isthe.com/chongo/tech/comp/fnv/">fnv
    83  //
    84  //	comparisons</a>
    85  //
    86  // @see <a href="http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash">fnv at
    87  //
    88  //	wikipedia</a>
    89  func fnv164Hash(k string) []uint32 {
    90  	hash := fnv.New64()
    91  	hash.Write([]byte(k))
    92  	rv := hash.Sum64()
    93  	return []uint32{uint32(rv & 0xffffffff)} // Truncate to 32-bits
    94  }
    95  
    96  // Variation of FNV.
    97  func fnv1a64Hash(k string) []uint32 {
    98  	hash := fnv.New64a()
    99  	hash.Write([]byte(k))
   100  	rv := (hash.Sum64() >> 16) & 0x7fff
   101  	return []uint32{uint32(rv & 0xffffffff)} // Truncate to 32-bits
   102  }
   103  
   104  // 32-bit FNV1.
   105  func fnv132Hash(k string) []uint32 {
   106  	hash := fnv.New32()
   107  	hash.Write([]byte(k))
   108  	rv := (hash.Sum32() >> 16) & 0x7fff
   109  	return []uint32{rv & 0xffffffff} // Truncate to 32-bits
   110  }
   111  
   112  // 32-bit FNV1a.
   113  func fnv1a32Hash(k string) []uint32 {
   114  	hash := fnv.New32a()
   115  	hash.Write([]byte(k))
   116  	rv := (hash.Sum32() >> 16) & 0x7fff
   117  	return []uint32{rv & 0xffffffff} // Truncate to 32-bits
   118  }
   119  
   120  // 128-bit FNV1.
   121  func fnv1128Hash(k string) []uint32 {
   122  	hash := fnv.New128()
   123  	hash.Write([]byte(k))
   124  	bKey := hash.Sum(nil)
   125  	rv := binary.LittleEndian.Uint32(bKey)
   126  	return []uint32{rv & 0xffffffff} // Truncate to 32-bits
   127  }
   128  
   129  // 128-bit FNV1a.
   130  func fnv1a128Hash(k string) []uint32 {
   131  	hash := fnv.New128a()
   132  	hash.Write([]byte(k))
   133  	bKey := hash.Sum(nil)
   134  	rv := binary.LittleEndian.Uint32(bKey)
   135  	return []uint32{uint32(rv & 0xffffffff)} // Truncate to 32-bits
   136  }
   137  
   138  // MD5-based hash algorithm used by ketama.
   139  func ketamaHash(k string) []uint32 {
   140  	h := md5.New()
   141  	h.Write([]byte(k))
   142  	digest := h.Sum(nil)
   143  	var rvs []uint32
   144  	// 16B -> [4B, 4B, 4B, 4B]
   145  	for h := 0; h < 4; h++ {
   146  		k := binary.LittleEndian.Uint32(digest[h*4:])
   147  		rvs = append(rvs, k)
   148  	}
   149  	return rvs
   150  }