func TestSyncRandomLimits(t *testing.T) { tree1 := NewTree() n := 10 var k []byte var v []byte for i := 0; i < n; i++ { k = murmur.HashString(fmt.Sprint(i)) v = []byte(fmt.Sprint(i)) tree1.Put(k, v, 1) } var keys [][]byte tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { keys = append(keys, key) return true }) var fromKey []byte var toKey []byte var tree2 *Tree var tree3 *Tree var s *Sync for fromIndex, _ := range keys { for toIndex, _ := range keys { if fromIndex != toIndex { fromKey = keys[fromIndex] toKey = keys[toIndex] if bytes.Compare(fromKey, toKey) < 0 { tree2 = NewTree() tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { if common.BetweenIE(key, fromKey, toKey) { tree2.Put(key, byteValue, 1) } return true }) tree3 = NewTree() s = NewSync(tree1, tree3).From(fromKey).To(toKey) s.Run() if !tree3.deepEqual(tree2) { t.Errorf("when syncing from %v to %v, %v and %v have hashes\n%v\n%v\nand they should be equal!", common.HexEncode(fromKey), common.HexEncode(toKey), tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) } } } } } }
func (self *Node) migrate() { lastAllowedChange := time.Now().Add(-1 * migrateWaitFactor * syncInterval).UnixNano() if lastAllowedChange > common.Max64(atomic.LoadInt64(&self.lastSync), atomic.LoadInt64(&self.lastReroute), atomic.LoadInt64(&self.lastMigrate)) { var succSize int succ := self.node.GetSuccessor() if err := succ.Call("DHash.Owned", 0, &succSize); err != nil { self.node.RemoveNode(succ) } else { mySize := self.Owned() if mySize > 10 && float64(mySize) > float64(succSize)*migrateHysteresis { wantedDelta := (mySize - succSize) / 2 var existed bool var wantedPos []byte pred := self.node.GetPredecessor() if bytes.Compare(pred.Pos, self.node.GetPosition()) < 1 { if wantedPos, existed = self.tree.NextMarkerIndex(self.tree.RealSizeBetween(nil, self.node.GetPosition(), true, false) - wantedDelta); !existed { return } } else { ownedAfterNil := self.tree.RealSizeBetween(nil, succ.Pos, true, false) if ownedAfterNil > wantedDelta { if wantedPos, existed = self.tree.NextMarkerIndex(ownedAfterNil - wantedDelta); !existed { return } } else { if wantedPos, existed = self.tree.NextMarkerIndex(self.tree.RealSize() + ownedAfterNil - wantedDelta); !existed { return } } } if common.BetweenIE(wantedPos, self.node.GetPredecessor().Pos, self.node.GetPosition()) { self.changePosition(wantedPos) } } } } }
// GetSuccessorFor will return the successor for the provided key. // If the successor is not this Node, it will assert that the provided key is between the found successor and the predecessor it claims to have. func (self *Node) GetSuccessorFor(key []byte) common.Remote { // Guess according to our route cache predecessor, match, successor := self.ring.Remotes(key) if match != nil { predecessor = match } // If we consider ourselves successors, just return us if successor.Addr != self.GetBroadcastAddr() { // Double check by asking the successor we found what predecessor it has if err := successor.Call("Discord.GetPredecessor", 0, predecessor); err != nil { self.RemoveNode(*successor) return self.GetSuccessorFor(key) } // If the key we are looking for is between them, just return the successor if !common.BetweenIE(key, predecessor.Pos, successor.Pos) { // Otherwise, ask the predecessor we actually found about who is the successor of the key if err := predecessor.Call("Discord.GetSuccessorFor", key, successor); err != nil { self.RemoveNode(*predecessor) return self.GetSuccessorFor(key) } } } return *successor }
// withinLimits will check i the given key is actually between the from and to Nibbles for this Sync. func (self *Sync) withinLimits(key []Nibble) bool { if self.from == nil || self.to == nil { return true } return common.BetweenIE(toBytes(key), toBytes(self.from), toBytes(self.to)) }