Bladeren bron

ring: addHostIfMissing returns existing host

If the ring already has the host that is being added, return the
existing one and add a method to update the host from another host.
Chris Bannister 10 jaren geleden
bovenliggende
commit
7c6162801e
3 gewijzigde bestanden met toevoegingen van 31 en 14 verwijderingen
  1. 9 5
      events.go
  2. 18 6
      host_source.go
  3. 4 3
      ring.go

+ 9 - 5
events.go

@@ -97,7 +97,7 @@ func (s *Session) handleNodeEvent(frames []frame) {
 		case *topologyChangeEventFrame:
 			event, ok := events[f.host.String()]
 			if !ok {
-				event = &nodeEvent{change: f.change, host: f.host}
+				event = &nodeEvent{change: f.change, host: f.host, port: f.port}
 				events[f.host.String()] = event
 			}
 			event.change = f.change
@@ -105,7 +105,7 @@ func (s *Session) handleNodeEvent(frames []frame) {
 		case *statusChangeEventFrame:
 			event, ok := events[f.host.String()]
 			if !ok {
-				event = &nodeEvent{change: f.change, host: f.host}
+				event = &nodeEvent{change: f.change, host: f.host, port: f.port}
 				events[f.host.String()] = event
 			}
 			event.change = f.change
@@ -169,12 +169,14 @@ func (s *Session) handleNewNode(host net.IP, port int) {
 	}
 
 	// should this handle token moving?
-	if !s.ring.addHostIfMissing(hostInfo) {
-		s.handleNodeUp(host, port)
-		return
+	if existing, ok := s.ring.addHostIfMissing(hostInfo); !ok {
+		log.Printf("already have host=%v existing=%v, updating\n", hostInfo, existing)
+		existing.update(hostInfo)
+		hostInfo = existing
 	}
 
 	s.pool.addHost(hostInfo)
+	s.hostSource.refreshRing()
 }
 
 func (s *Session) handleRemovedNode(ip net.IP, port int) {
@@ -182,6 +184,8 @@ func (s *Session) handleRemovedNode(ip net.IP, port int) {
 	addr := ip.String()
 	s.pool.removeHost(addr)
 	s.ring.removeHost(addr)
+
+	s.hostSource.refreshRing()
 }
 
 func (s *Session) handleNodeUp(ip net.IP, port int) {

+ 18 - 6
host_source.go

@@ -172,6 +172,16 @@ func (h *HostInfo) setTokens(tokens []string) *HostInfo {
 	return h
 }
 
+func (h *HostInfo) update(from *HostInfo) {
+	h.mu.Lock()
+	defer h.mu.Unlock()
+
+	h.tokens = from.tokens
+	h.version = from.version
+	h.hostId = from.hostId
+	h.dataCenter = from.dataCenter
+}
+
 func (h *HostInfo) IsUp() bool {
 	return h.State() == NodeUp
 }
@@ -284,7 +294,6 @@ func (r *ringDescriber) GetHosts() (hosts []*HostInfo, partitioner string, err e
 }
 
 func (r *ringDescriber) matchFilter(host *HostInfo) bool {
-
 	if r.dcFilter != "" && r.dcFilter != host.DataCenter() {
 		return false
 	}
@@ -296,24 +305,27 @@ func (r *ringDescriber) matchFilter(host *HostInfo) bool {
 	return true
 }
 
-func (r *ringDescriber) refreshRing() {
+func (r *ringDescriber) refreshRing() error {
 	// if we have 0 hosts this will return the previous list of hosts to
 	// attempt to reconnect to the cluster otherwise we would never find
 	// downed hosts again, could possibly have an optimisation to only
 	// try to add new hosts if GetHosts didnt error and the hosts didnt change.
 	hosts, partitioner, err := r.GetHosts()
 	if err != nil {
-		log.Println("RingDescriber: unable to get ring topology:", err)
-		return
+		return err
 	}
 
 	// TODO: move this to session
+	// TODO: handle removing hosts here
 	for _, h := range hosts {
-		if r.session.ring.addHostIfMissing(h) {
+		log.Println(h)
+		if host, ok := r.session.ring.addHostIfMissing(h); !ok {
 			r.session.pool.addHost(h)
-			// TODO: trigger OnUp/OnAdd
+		} else {
+			host.update(h)
 		}
 	}
 
 	r.session.pool.SetPartitioner(partitioner)
+	return nil
 }

+ 4 - 3
ring.go

@@ -46,19 +46,20 @@ func (r *ring) addHost(host *HostInfo) bool {
 	return ok
 }
 
-func (r *ring) addHostIfMissing(host *HostInfo) bool {
+func (r *ring) addHostIfMissing(host *HostInfo) (*HostInfo, bool) {
 	r.mu.Lock()
 	if r.hosts == nil {
 		r.hosts = make(map[string]*HostInfo)
 	}
 
 	addr := host.Peer()
-	_, ok := r.hosts[addr]
+	existing, ok := r.hosts[addr]
 	if !ok {
 		r.hosts[addr] = host
+		existing = host
 	}
 	r.mu.Unlock()
-	return ok
+	return existing, ok
 }
 
 func (r *ring) removeHost(addr string) bool {