github.com/searKing/golang/go@v1.2.74/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  //      comparisons</a>
    84  // @see <a href="http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash">fnv at
    85  //      wikipedia</a>
    86  func fnv164Hash(k string) []uint32 {
    87  	hash := fnv.New64()
    88  	hash.Write([]byte(k))
    89  	rv := hash.Sum64()
    90  	return []uint32{uint32(rv & 0xffffffff)} // Truncate to 32-bits
    91  }
    92  
    93  // Variation of FNV.
    94  func fnv1a64Hash(k string) []uint32 {
    95  	hash := fnv.New64a()
    96  	hash.Write([]byte(k))
    97  	rv := (hash.Sum64() >> 16) & 0x7fff
    98  	return []uint32{uint32(rv & 0xffffffff)} // Truncate to 32-bits
    99  }
   100  
   101  // 32-bit FNV1.
   102  func fnv132Hash(k string) []uint32 {
   103  	hash := fnv.New32()
   104  	hash.Write([]byte(k))
   105  	rv := (hash.Sum32() >> 16) & 0x7fff
   106  	return []uint32{rv & 0xffffffff} // Truncate to 32-bits
   107  }
   108  
   109  // 32-bit FNV1a.
   110  func fnv1a32Hash(k string) []uint32 {
   111  	hash := fnv.New32a()
   112  	hash.Write([]byte(k))
   113  	rv := (hash.Sum32() >> 16) & 0x7fff
   114  	return []uint32{rv & 0xffffffff} // Truncate to 32-bits
   115  }
   116  
   117  // 128-bit FNV1.
   118  func fnv1128Hash(k string) []uint32 {
   119  	hash := fnv.New128()
   120  	hash.Write([]byte(k))
   121  	bKey := hash.Sum(nil)
   122  	rv := binary.LittleEndian.Uint32(bKey)
   123  	return []uint32{rv & 0xffffffff} // Truncate to 32-bits
   124  }
   125  
   126  // 128-bit FNV1a.
   127  func fnv1a128Hash(k string) []uint32 {
   128  	hash := fnv.New128a()
   129  	hash.Write([]byte(k))
   130  	bKey := hash.Sum(nil)
   131  	rv := binary.LittleEndian.Uint32(bKey)
   132  	return []uint32{uint32(rv & 0xffffffff)} // Truncate to 32-bits
   133  }
   134  
   135  // MD5-based hash algorithm used by ketama.
   136  func ketamaHash(k string) []uint32 {
   137  	h := md5.New()
   138  	h.Write([]byte(k))
   139  	digest := h.Sum(nil)
   140  	var rvs []uint32
   141  	// 16B -> [4B, 4B, 4B, 4B]
   142  	for h := 0; h < 4; h++ {
   143  		k := binary.LittleEndian.Uint32(digest[h*4:])
   144  		rvs = append(rvs, k)
   145  	}
   146  	return rvs
   147  }