Skip to content

Commit

Permalink
consistenthash: replace linear search with binary search
Browse files Browse the repository at this point in the history
The binary search quickly out-paces the linear search, even for a small
number of shards and replicas.

benchmark          old ns/op    new ns/op    delta
BenchmarkGet8            122          122   +0.00%
BenchmarkGet32           471          137  -70.91%
BenchmarkGet128         5619          254  -95.48%
BenchmarkGet512        90302          406  -99.55%
  • Loading branch information
dgryski committed Jun 17, 2014
1 parent d781998 commit 89ec054
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
14 changes: 7 additions & 7 deletions consistenthash/consistenthash.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ func (m *Map) Get(key string) string {

hash := int(m.hash([]byte(key)))

// Linear search for appropriate replica.
for _, v := range m.keys {
if v >= hash {
return m.hashMap[v]
}
}
// Binary search for appropriate replica.
idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash })

// Means we have cycled back to the first replica.
return m.hashMap[m.keys[0]]
if idx == len(m.keys) {
idx = 0
}

return m.hashMap[m.keys[idx]]
}
24 changes: 24 additions & 0 deletions consistenthash/consistenthash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package consistenthash

import (
"fmt"
"strconv"
"testing"
)
Expand Down Expand Up @@ -84,3 +85,26 @@ func TestConsistency(t *testing.T) {
}

}

func BenchmarkGet8(b *testing.B) { benchmarkGet(b, 8) }
func BenchmarkGet32(b *testing.B) { benchmarkGet(b, 32) }
func BenchmarkGet128(b *testing.B) { benchmarkGet(b, 128) }
func BenchmarkGet512(b *testing.B) { benchmarkGet(b, 512) }

func benchmarkGet(b *testing.B, shards int) {

hash := New(shards, nil)

var buckets []string
for i := 0; i < shards; i++ {
buckets = append(buckets, fmt.Sprintf("shard-%d", i))
}

hash.Add(buckets...)

b.ResetTimer()

for i := 0; i < b.N; i++ {
hash.Get(buckets[i&(shards-1)])
}
}

0 comments on commit 89ec054

Please sign in to comment.