From 611cb42f74f61fe71238fe6e9b5a7c32efed2966 Mon Sep 17 00:00:00 2001 From: johnbass Date: Fri, 27 Dec 2024 08:00:40 -0800 Subject: [PATCH 1/2] added benchmarks for hash ring creation --- consistent/main_test.go | 43 ++++++++++++++++++++++++++++++ consistent/ring_benchmarks_test.go | 43 ++++++++++++++++++++++++++++++ consistent/ring_test.go | 33 +++++------------------ go.mod | 1 + go.sum | 2 ++ 5 files changed, 95 insertions(+), 27 deletions(-) create mode 100644 consistent/main_test.go create mode 100644 consistent/ring_benchmarks_test.go diff --git a/consistent/main_test.go b/consistent/main_test.go new file mode 100644 index 0000000..1f9974f --- /dev/null +++ b/consistent/main_test.go @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025 Comcast Cable Communications Management, LLC +// SPDX-License-Identifier: Apache-2.0 + +package consistent + +import ( + "fmt" + "math/rand" + "testing" +) + +const ( + // objectSeed is the random number seed we use to create objects to hash + objectSeed int64 = 7245298734452934458 + + // objectCount is the number of random objects we generate for hash inputs + objectCount int = 1000 + + // serviceCount is the number of random service names to generate for hashes + serviceCount int = 100 +) + +// hashObjects contains a standard set of random objects to hash to services. +var hashObjects [objectCount][16]byte + +// services contains a number of service names to use in tests and benchmarks. +var services [serviceCount]string + +func TestMain(m *testing.M) { + random := rand.New( + rand.NewSource(objectSeed), + ) + + for i := range len(hashObjects) { + random.Read(hashObjects[i][:]) + } + + for i := range len(services) { + services[i] = fmt.Sprintf("service-%d.example.net", i) + } + + m.Run() +} diff --git a/consistent/ring_benchmarks_test.go b/consistent/ring_benchmarks_test.go new file mode 100644 index 0000000..6a79d6e --- /dev/null +++ b/consistent/ring_benchmarks_test.go @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025 Comcast Cable Communications Management, LLC +// SPDX-License-Identifier: Apache-2.0 + +package consistent + +import ( + "fmt" + "testing" + + "github.com/billhathaway/consistentHash" +) + +var benchmarkVnodes = []int{50, 100, 200} + +func BenchmarkRingCreation(b *testing.B) { + for _, vnodes := range benchmarkVnodes { + b.Run( + fmt.Sprintf("vnodes-%d", vnodes), + func(b *testing.B) { + for range b.N { + Strings(services[:]...).VNodes(vnodes).Build() + } + }, + ) + } +} + +func BenchmarkConsistentHashCreation(b *testing.B) { + for _, vnodes := range benchmarkVnodes { + b.Run( + fmt.Sprintf("vnodes-%d", vnodes), + func(b *testing.B) { + for range b.N { + ch := consistentHash.New() + ch.SetVnodeCount(vnodes) + for _, service := range services { + ch.Add(service) + } + } + }, + ) + } +} diff --git a/consistent/ring_test.go b/consistent/ring_test.go index 4aa2cc1..a8dcb39 100644 --- a/consistent/ring_test.go +++ b/consistent/ring_test.go @@ -4,7 +4,6 @@ package consistent import ( - "math/rand" "sort" "testing" @@ -12,43 +11,23 @@ import ( "github.com/xmidt-org/medley" ) -const ( - // objectSeed is the random number seed we use to create objects to hash - objectSeed int64 = 7245298734452934458 - - // objectCount is the number of random objects we generate for hash inputs - objectCount int = 1000 -) - type RingSuite struct { suite.Suite - rand *rand.Rand - objects [objectCount][16]byte - originalServices []string original *Ring[string] } func (suite *RingSuite) SetupSuite() { - suite.rand = rand.New( - rand.NewSource(objectSeed), - ) - - for i := 0; i < len(suite.objects); i++ { - suite.rand.Read(suite.objects[i][:]) - } - - suite.originalServices = []string{ - "original1.service.net", "original2.service.net", "original3.service.net", "original4.service.net", - } + // for the unit tests, we don't need all the services + suite.originalServices = services[0:4] suite.original = Strings(suite.originalServices...).Build() suite.Require().NotNil(suite.original) suite.Require().True(sort.IsSorted(suite.original.nodes)) distribution := make(map[string]int) - for _, object := range suite.objects { + for _, object := range hashObjects { result, err := suite.original.Find(object[:]) suite.Require().NoError(err) suite.Require().Contains(suite.originalServices, result) @@ -79,7 +58,7 @@ func (suite *RingSuite) testUpdateEmpty() { suite.True(didUpdate) suite.Empty(updated.nodes) - for _, object := range suite.objects { + for _, object := range hashObjects { result, err := updated.Find(object[:]) suite.Empty(result) suite.ErrorIs(err, medley.ErrNoServices) @@ -91,7 +70,7 @@ func (suite *RingSuite) testUpdatePartial() { updated, didUpdate := suite.update(partial...) suite.True(didUpdate) - for _, object := range suite.objects { + for _, object := range hashObjects { result, err := updated.Find(object[:]) suite.Contains(partial, result) suite.NoError(err) @@ -103,7 +82,7 @@ func (suite *RingSuite) testUpdateAllNew() { updated, didUpdate := suite.update(allNew...) suite.True(didUpdate) - for _, object := range suite.objects { + for _, object := range hashObjects { result, err := updated.Find(object[:]) suite.Contains(allNew, result) suite.NoError(err) diff --git a/go.mod b/go.mod index 2a7aa4c..1e998fb 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( ) require ( + github.com/billhathaway/consistentHash v0.0.0-20140718022140-addea16d2229 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect diff --git a/go.sum b/go.sum index c4aebae..00831e8 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/billhathaway/consistentHash v0.0.0-20140718022140-addea16d2229 h1:w1t+UCLwxXgpUcXAlm3IkvWHGJDfhIyNrzJmCUkJq7s= +github.com/billhathaway/consistentHash v0.0.0-20140718022140-addea16d2229/go.mod h1:YTos5xiYv+RiIsYn3pqdwe5OULySucMqiPes1OgC5pM= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= From 5b13bdbf1d9a3f8ea1a2cbd1673f7b629673a9d6 Mon Sep 17 00:00:00 2001 From: johnbass Date: Fri, 27 Dec 2024 08:05:58 -0800 Subject: [PATCH 2/2] added backwards compatibility test --- consistent/ring_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/consistent/ring_test.go b/consistent/ring_test.go index a8dcb39..e158c37 100644 --- a/consistent/ring_test.go +++ b/consistent/ring_test.go @@ -7,6 +7,7 @@ import ( "sort" "testing" + "github.com/billhathaway/consistentHash" "github.com/stretchr/testify/suite" "github.com/xmidt-org/medley" ) @@ -102,6 +103,30 @@ func (suite *RingSuite) TestUpdate() { suite.Run("NotNeeded", suite.testUpdateNotNeeded) } +func (suite *RingSuite) TestBackwardCompatibility() { + ch := consistentHash.New() + ch.SetVnodeCount(DefaultVNodes) + for _, service := range suite.originalServices { + ch.Add(service) + } + + var ( + oldResult string + newResult string + err error + ) + + for _, object := range hashObjects { + oldResult, err = ch.Get(object[:]) + suite.Require().NoError(err) + + newResult, err = suite.original.Find(object[:]) + suite.Require().NoError(err) + + suite.Equal(oldResult, newResult) + } +} + func TestRing(t *testing.T) { suite.Run(t, new(RingSuite)) }