Skip to content

Commit ca417b3

Browse files
committed
util: add FibHash function
This adds a FibHash function that implements a "fibonacci hash." This is a simple multiplicative hash that we use occasionally for testing Pebble and would like to use for similar purposes in CockroachDB as well. We also add Max and Min functions that take an iter.Seq. Epic: none Release note: None
1 parent de3fb16 commit ca417b3

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

pkg/util/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ go_test(
4646
srcs = [
4747
"every_n_test.go",
4848
"fast_int_map_test.go",
49+
"hash_test.go",
4950
"slices_test.go",
5051
"smalltrace_test.go",
5152
"strings_test.go",

pkg/util/hash.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,12 @@ func (f *FNV64) Add(c uint64) {
5656
func (f *FNV64) Sum() uint64 {
5757
return f.sum
5858
}
59+
60+
// Fibonacci Hash is a multiplicative hash that maps the given `v` into 2^bits
61+
// values.
62+
//
63+
// Reference:
64+
// - https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
65+
func FibHash(v uint64, bits int) uint64 {
66+
return (v * 11400714819323198485) >> (64 - bits)
67+
}

pkg/util/hash_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2016 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package util
7+
8+
import (
9+
"testing"
10+
"unsafe"
11+
12+
"github.com/cockroachdb/cockroach/pkg/util/randutil"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestFibHash(t *testing.T) {
17+
rng, _ := randutil.NewTestRand()
18+
counts := make(map[uint64]int)
19+
for range 1000 {
20+
h := FibHash(rng.Uint64(), 3)
21+
counts[h]++
22+
}
23+
24+
// Let's test using a ptr value. We use this slice to keep the pointers alive
25+
// so that we don't just get the same pointer each time.
26+
vs := make([]*int, 0, 1000)
27+
for range 1000 {
28+
v := new(int)
29+
vs = append(vs, v)
30+
h := FibHash(uint64(uintptr(unsafe.Pointer(v))), 3)
31+
counts[h]++
32+
}
33+
require.Equal(t, 1000, len(vs))
34+
// We can only make some weak assertions about the distribution here.
35+
for k, v := range counts {
36+
require.True(t, k < 8)
37+
perfectDistributionCount := 2000 / 8
38+
require.Less(t, v, perfectDistributionCount*2)
39+
}
40+
}

0 commit comments

Comments
 (0)