Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Identity carry over part 5 / Multi ring checksum #192

Merged
merged 75 commits into from
Dec 19, 2016
Merged
Show file tree
Hide file tree
Changes from 67 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
8337973
Refactor rbtree val to a comparable key
Nov 24, 2016
0876074
refactor str to a generic value to store in the tree
Nov 24, 2016
1660c01
implement walk function on rbtree for iterating the tree in order
Nov 28, 2016
97741e9
Define membership and let swim implement it.
Nov 24, 2016
03527bc
Use Reachable instead of Pingable
Nov 28, 2016
58a104c
change naming of receiver for Compare to satisfy linter
Nov 29, 2016
4838ed2
add tests for walking the tree.
Nov 29, 2016
f9c9eb7
let search return nil when items are not found
Nov 29, 2016
bf23425
more documentation refactoring.
Nov 29, 2016
20a4910
casing change for replicaPoint
Nov 29, 2016
5e842da
Merge remote-tracking branch 'origin/dev' into feature/rbtree-absraction
Nov 29, 2016
23fca53
Merge branch 'feature/rbtree-absraction' into feature/membership-package
Nov 29, 2016
65e41f9
prepare hashring to work on membership.Member instead of string.
Nov 28, 2016
735ca7f
start with changed set to false
Nov 28, 2016
a1de8bf
Implement identity on swim and ringpop via labels.
Nov 28, 2016
39d2245
expose identity on the Member.
Nov 28, 2016
19ad1a0
Use identity for points in the ring and make sure an updated identity…
Nov 28, 2016
92cde55
Use replica point with more information on it for future.
Nov 28, 2016
6eca742
abstract checksums into multiple named checksums.
Nov 28, 2016
ae69665
Add replica hashring checksummed.
Nov 28, 2016
e99f2d7
Add ring checksummer that is compatible with current released version.
Nov 28, 2016
ef8a2e4
Use tree walker to calculate checksums.
Nov 28, 2016
3c4c437
removed the legacy checksum from the map and call it legacy explicitly.
Nov 28, 2016
b5b7a47
emit named checksum periodically
Nov 28, 2016
3901340
fix low hanging fruits after feedback.
Nov 30, 2016
68566d8
Fix linting issues and non-needed export.
Nov 30, 2016
b204d2b
refactor postLocalUpdate to an updateLocalMember function that takes …
Nov 30, 2016
28c26a5
Add tests for swim memberlist emitting membership events on updates
Nov 30, 2016
7d33825
Revisit the documentation of the Member interface.
Nov 30, 2016
b3a5a9e
Add extra documentation to the Membership Event tests
Nov 30, 2016
dcc597a
Add tests for remote and local Label changes and membership.ChangeEve…
Nov 30, 2016
b2afa96
Merge branch 'feature/membership-package' into feature/extensible-has…
Nov 30, 2016
33b85a2
make tests working.
Dec 1, 2016
8362478
add missing file for tests
Dec 1, 2016
f2b8ff5
inline adding of replica points while adding server
Dec 1, 2016
0295cb9
rearrange imports
Dec 1, 2016
d5b1490
rename addresses to members in test.
Dec 1, 2016
391bf3a
Naming and consolidation.
Dec 1, 2016
43fd997
remove needles AddRemoveMembers function
Dec 1, 2016
4310b0d
add test for ProcessMembershipChanges
Dec 2, 2016
7cf7735
Merge branch 'feature/extensible-hashring' into feature/identity-carr…
Dec 2, 2016
5dec2b3
make tests work after merge
Dec 2, 2016
2ef6d5f
fix issues found by linter.
Dec 2, 2016
1af053a
Merge branch 'feature/identity-carry-over' into feature/ring-multi-ch…
Dec 2, 2016
68f0b86
Add documentation to make 'make lint' happy
Dec 2, 2016
6ad89c0
refactor in hashring
Dec 2, 2016
3f059b6
Add tests
Dec 5, 2016
b3ed09f
Added ServersUpdated to RingChangedEvent
Dec 5, 2016
730abc4
Merge branch 'feature/identity-carry-over' into feature/ring-multi-ch…
Dec 5, 2016
265c6c2
Fixes after merge
Dec 5, 2016
a047ef8
typo’s
Dec 5, 2016
399aa96
also log checksums
Dec 5, 2016
6c030dc
Add checksums to RingChecksumEvent
Dec 5, 2016
938be77
Add checksum tests
Dec 6, 2016
273d946
Add test
Dec 6, 2016
e4926c9
fix import
Dec 6, 2016
49b5026
switch it-test branch
Dec 6, 2016
bfb5e86
Rename walk
Dec 14, 2016
e4d8dd1
Feedback
Dec 14, 2016
3d0d532
feedback
Dec 15, 2016
31e630b
Renamed checksum -> checksummer
Dec 15, 2016
101e4f8
switch it-tests back to master after merg
Dec 15, 2016
fb81d89
Merge branch 'feature/rbtree-absraction' into feature/membership-package
Dec 15, 2016
60515d0
Merge branch 'feature/membership-package' into feature/extensible-has…
Dec 15, 2016
7c85ff4
Merge branch 'feature/extensible-hashring' into feature/identity-carr…
Dec 15, 2016
74de8fe
Merge branch 'feature/identity-carry-over' into feature/ring-multi-ch…
Dec 15, 2016
fac34e4
fix ringpop-common
Dec 15, 2016
a4d8488
rename traverse function
Dec 16, 2016
a0468ac
Merge branch 'feature/rbtree-absraction' into feature/membership-package
Dec 16, 2016
d721c7e
Merge branch 'feature/membership-package' into feature/extensible-has…
Dec 16, 2016
0b6f6e8
Merge branch 'feature/extensible-hashring' into feature/identity-carr…
Dec 16, 2016
3e015c5
Merge branch 'feature/identity-carry-over' into feature/ring-multi-ch…
Dec 16, 2016
c7ef3e7
fix after merge
Dec 16, 2016
44f225e
emit other checksums under different stat-tree
Dec 16, 2016
752d679
Merge remote-tracking branch 'origin/dev' into feature/ring-multi-che…
Dec 19, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,21 @@ func (a *SyncEventEmitter) EmitEvent(event Event) {
// A RingChangedEvent is sent when servers are added and/or removed from the ring
type RingChangedEvent struct {
ServersAdded []string
ServersUpdated []string
ServersRemoved []string
}

// RingChecksumEvent is sent when a server is removed or added and a new checksum
// for the ring is calculated
type RingChecksumEvent struct {
// OldChecksum contains the previous legacy checksum. Note: might be deprecated in the future.
OldChecksum uint32
// NewChecksum contains the new legacy checksum. Note: might be deprecated in the future.
NewChecksum uint32
// OldChecksums contains the map of previous checksums
OldChecksums map[string]uint32
// NewChecksums contains the map with new checksums
NewChecksums map[string]uint32
}

// A LookupEvent is sent when a lookup is performed on the Ringpop's ring
Expand Down
56 changes: 56 additions & 0 deletions hashring/checksummer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package hashring

import (
"bytes"
"sort"
"strconv"
"strings"

"github.com/dgryski/go-farm"
)

// Checksummer computes a checksum for an instance of a HashRing. The
// checksum can be used to compare two rings for equality.
type Checksummer interface {
// Checksum calculates the checksum for the hashring that is passed in.
// Compute will be called while having at least a read-lock on the hashring so
// it is safe to read from the ring, but not safe to change the ring. There
// might be multiple Checksum Computes initiated at the same time, but every
// Checksum will only be called once per hashring at once
Checksum(ring *HashRing) (checksum uint32)
}

type identityChecksummer struct{}

func (i *identityChecksummer) Checksum(ring *HashRing) uint32 {
identitySet := make(map[string]struct{})
ring.tree.root.walk(func(node *redBlackNode) bool {
identitySet[node.key.(replicaPoint).identity] = struct{}{}
return true
})

identities := make([]string, 0, len(identitySet))
for identity := range identitySet {
identities = append(identities, identity)
}

sort.Strings(identities)
bytes := []byte(strings.Join(identities, ";"))
return farm.Fingerprint32(bytes)
}

type replicaPointChecksummer struct{}

func (r *replicaPointChecksummer) Checksum(ring *HashRing) uint32 {
buffer := bytes.Buffer{}

ring.tree.root.walk(func(node *redBlackNode) bool {
buffer.WriteString(strconv.Itoa(node.key.(replicaPoint).hash))
buffer.WriteString("-")
buffer.WriteString(node.value.(string))
buffer.WriteString(";")
return true
})

return farm.Fingerprint32(buffer.Bytes())
}
96 changes: 96 additions & 0 deletions hashring/checksummer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package hashring

import (
"sort"
"strings"
"testing"

"github.com/dgryski/go-farm"
"github.com/stretchr/testify/assert"
)

// addressChecksum implements the now obsolete checksum method that didn't support identities.
// It's moved to this test file to test backwards compatibility of the identityChecksummer
type addressChecksummer struct{}

func (i *addressChecksummer) Checksum(ring *HashRing) uint32 {
addresses := ring.copyServersNoLock()
sort.Strings(addresses)
bytes := []byte(strings.Join(addresses, ";"))
return farm.Fingerprint32(bytes)
}

func TestAddressChecksum_Compute(t *testing.T) {
members := genMembers(1, 1, 10, false)
ring := New(farm.Fingerprint32, 1)
ring.AddMembers(members...)
checksum := &addressChecksummer{}

addresses := make([]string, 0, 10)
for _, members := range members {
addresses = append(addresses, members.GetAddress())
}

sort.Strings(addresses)
bytes := []byte(strings.Join(addresses, ";"))

expected := farm.Fingerprint32(bytes)
actual := checksum.Checksum(ring)

assert.Equal(t, expected, actual)
}

func TestIdentityChecksum_Compute(t *testing.T) {
identityChecksummer := &identityChecksummer{}

ringWithoutIdentities := New(farm.Fingerprint32, 1)
ringWithoutIdentities.AddMembers(genMembers(1, 1, 10, false)...)

legacyChecksum := (&addressChecksummer{}).Checksum(ringWithoutIdentities)
identityChecksum := identityChecksummer.Checksum(ringWithoutIdentities)

assert.Equal(t, legacyChecksum, identityChecksum, "Identity checksum should be the same as legacy on ring without identities")

ringWithIdentities := New(farm.Fingerprint32, 1)
ringWithIdentities.AddMembers(genMembers(1, 1, 10, true)...)

identityChecksum = identityChecksummer.Checksum(ringWithIdentities)

assert.NotEqual(t, legacyChecksum, identityChecksum, "IdentityChecksummer should not match legacy checksummer on ring with identites ")
}

func TestReplicaPointChecksum_Compute(t *testing.T) {
replicaPointChecksummer := &replicaPointChecksummer{}
members := genMembers(1, 1, 10, false)

ring1ReplicaPoint := New(farm.Fingerprint32, 1)
ring1ReplicaPoint.AddMembers(members...)

ring2ReplicaPoints := New(farm.Fingerprint32, 2)
ring2ReplicaPoints.AddMembers(members...)

checksum1ReplicaPoint := replicaPointChecksummer.Checksum(ring1ReplicaPoint)
checksum2ReplicaPoints := replicaPointChecksummer.Checksum(ring2ReplicaPoints)

assert.NotEqual(t, checksum1ReplicaPoint, checksum2ReplicaPoints, "Checksum should not match with different replica point counts")
}
Loading