diff --git a/README.md b/README.md index 91645cb..3865b47 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ func main() { Includes a helper function for using a `string` as key instead of an `uint64`. This requires a hasher that computes the string into a format accepted by `Hash()`. Such a hasher that uses [CRC-64 (ECMA)](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) is also included for convenience. ```go -h := jump.HashString("127.0.0.1", 8, jump.CRC64) // h = 7 +h := jump.HashString("127.0.0.1", 8, jump.NewCRC64()) // h = 7 ``` In reality though you probably want to use a `Hasher` so you won't have to repeat the bucket size and which key hasher used. It also uses more convenient types, like `int` instead of `int32`. ```go -hasher := jump.New(8, jump.CRC64) +hasher := jump.New(8, jump.NewCRC64()) h := hasher.Hash("127.0.0.1") // h = 7 ``` diff --git a/doc.go b/doc.go index c05a27e..53464ac 100644 --- a/doc.go +++ b/doc.go @@ -1,4 +1,6 @@ /* +Package jump implements the "jump consistent hash" algorithm. + Example h := jump.Hash(256, 1024) // h = 520 diff --git a/jump.go b/jump.go index 3ff3b0c..3fe1a29 100644 --- a/jump.go +++ b/jump.go @@ -77,12 +77,19 @@ func (h *Hasher) Hash(key string) int { var ( // CRC32 uses the 32-bit Cyclic Redundancy Check (CRC-32) with the IEEE // polynomial. - CRC32 hash.Hash64 = &crc32Hasher{crc32.NewIEEE()} + NewCRC32 func() hash.Hash64 = func() hash.Hash64 { return &crc32Hasher{crc32.NewIEEE()} } // CRC64 uses the 64-bit Cyclic Redundancy Check (CRC-64) with the ECMA // polynomial. - CRC64 hash.Hash64 = crc64.New(crc64.MakeTable(crc64.ECMA)) + NewCRC64 func() hash.Hash64 = func() hash.Hash64 { return crc64.New(crc64.MakeTable(crc64.ECMA)) } // FNV1 uses the non-cryptographic hash function FNV-1. - FNV1 hash.Hash64 = fnv.New64() + NewFNV1 func() hash.Hash64 = func() hash.Hash64 { return fnv.New64() } // FNV1a uses the non-cryptographic hash function FNV-1a. + NewFNV1a func() hash.Hash64 = func() hash.Hash64 { return fnv.New64a() } + + // These are deprecated because they're not safe for concurrent use. Please + // use the New* functions instead. + CRC32 hash.Hash64 = &crc32Hasher{crc32.NewIEEE()} + CRC64 hash.Hash64 = crc64.New(crc64.MakeTable(crc64.ECMA)) + FNV1 hash.Hash64 = fnv.New64() FNV1a hash.Hash64 = fnv.New64a() ) diff --git a/jump_test.go b/jump_test.go index b92a90b..14cdebd 100644 --- a/jump_test.go +++ b/jump_test.go @@ -35,19 +35,19 @@ func TestJumpHash(t *testing.T) { var jumpStringTestVectors = []struct { key string buckets int32 - hasher hash.Hash64 + hasher func() hash.Hash64 expected int32 }{ - {"localhost", 10, CRC32, 9}, - {"ёлка", 10, CRC64, 6}, - {"ветер", 10, FNV1, 3}, - {"中国", 10, FNV1a, 5}, - {"日本", 10, CRC64, 6}, + {"localhost", 10, NewCRC32, 9}, + {"ёлка", 10, NewCRC64, 6}, + {"ветер", 10, NewFNV1, 3}, + {"中国", 10, NewFNV1a, 5}, + {"日本", 10, NewCRC64, 6}, } func TestJumpHashString(t *testing.T) { for _, v := range jumpStringTestVectors { - h := HashString(v.key, v.buckets, v.hasher) + h := HashString(v.key, v.buckets, v.hasher()) if h != v.expected { t.Errorf("expected bucket for key=%s to be %d, got %d", strconv.Quote(v.key), v.expected, h) @@ -57,7 +57,7 @@ func TestJumpHashString(t *testing.T) { func TestHasher(t *testing.T) { for _, v := range jumpStringTestVectors { - hasher := New(int(v.buckets), v.hasher) + hasher := New(int(v.buckets), v.hasher()) h := hasher.Hash(v.key) if int32(h) != v.expected { t.Errorf("expected bucket for key=%s to be %d, got %d", @@ -72,7 +72,7 @@ func ExampleHash() { } func ExampleHashString() { - fmt.Print(HashString("127.0.0.1", 8, CRC64)) + fmt.Print(HashString("127.0.0.1", 8, NewCRC64())) // Output: 7 } @@ -85,27 +85,27 @@ func BenchmarkHash(b *testing.B) { func BenchmarkHashStringCRC32(b *testing.B) { s := "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat." for i := 0; i < b.N; i++ { - HashString(s, int32(i), CRC32) + HashString(s, int32(i), NewCRC32()) } } func BenchmarkHashStringCRC64(b *testing.B) { s := "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat." for i := 0; i < b.N; i++ { - HashString(s, int32(i), CRC64) + HashString(s, int32(i), NewCRC64()) } } func BenchmarkHashStringFNV1(b *testing.B) { s := "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat." for i := 0; i < b.N; i++ { - HashString(s, int32(i), FNV1) + HashString(s, int32(i), NewFNV1()) } } func BenchmarkHashStringFNV1a(b *testing.B) { s := "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat." for i := 0; i < b.N; i++ { - HashString(s, int32(i), FNV1a) + HashString(s, int32(i), NewFNV1a()) } }