// maybeAddResolver creates and adds a resolver for the specified // address if one does not already exist. Returns whether a new // resolver was added. The caller must hold the gossip mutex. func (g *Gossip) maybeAddResolver(addr util.UnresolvedAddr) bool { if _, ok := g.resolverAddrs[addr]; !ok { r, err := resolver.NewResolverFromUnresolvedAddr(addr) if err != nil { log.Warningf("bad address %s: %s", addr, err) return false } g.resolvers = append(g.resolvers, r) g.resolverAddrs[addr] = struct{}{} return true } return false }
// updateNodeAddress is a gossip callback which fires with each // update to the node address. This allows us to compute the // total size of the gossip network (for determining max peers // each gossip node is allowed to have), as well as to create // new resolvers for each encountered host and to write the // set of gossip node addresses to persistent storage when it // changes. func (g *Gossip) updateNodeAddress(_ string, content roachpb.Value) { var desc roachpb.NodeDescriptor if err := content.GetProto(&desc); err != nil { log.Error(err) return } g.mu.Lock() defer g.mu.Unlock() // Recompute max peers based on size of network and set the max // sizes for incoming and outgoing node sets. defer func() { maxPeers := g.maxPeers(len(g.nodeDescs)) g.incoming.setMaxSize(maxPeers) g.outgoing.setMaxSize(maxPeers) }() // Skip if the node has already been seen or it's our own address. if _, ok := g.nodeDescs[desc.NodeID]; ok || desc.Address == g.is.NodeAddr { return } g.nodeDescs[desc.NodeID] = &desc // Add this new node to our list of resolvers so we can keep // connecting to gossip if the original resolvers go offline. r, err := resolver.NewResolverFromUnresolvedAddr(desc.Address) if err != nil { log.Warningf("bad address from gossip node %s: %s", desc, err) return } if !g.haveResolver(r) { g.resolvers = append(g.resolvers, r) } // Add new address to bootstrap info and persist if possible. if !g.haveBootstrapAddress(desc.Address) { g.bootstrapInfo.Addresses = append(g.bootstrapInfo.Addresses, desc.Address) if g.storage != nil { // TODO(spencer): need to clean up ancient gossip nodes, which // will otherwise stick around in the bootstrap info forever. if err := g.storage.WriteBootstrapInfo(&g.bootstrapInfo); err != nil { log.Error(err) } } } }
// SetStorage provides an instance of the Storage interface // for reading and writing gossip bootstrap data from persistent // storage. This should be invoked as early in the lifecycle of a // gossip instance as possible, but can be called at any time. func (g *Gossip) SetStorage(storage Storage) error { g.mu.Lock() defer g.mu.Unlock() g.storage = storage // Read the bootstrap info from the persistent store. var storedBI BootstrapInfo err := storage.ReadBootstrapInfo(&storedBI) if err != nil { log.Warningf("failed to read gossip bootstrap info: %s", err) } // Merge the stored bootstrap info addresses with any we've become // aware of through the --join bootstrap hosts we've connected to. if len(g.bootstrapInfo.Addresses) > 0 { existing := map[string]struct{}{} makeKey := func(a util.UnresolvedAddr) string { return fmt.Sprintf("%s,%s", a.Network(), a.String()) } for _, addr := range g.bootstrapInfo.Addresses { existing[makeKey(addr)] = struct{}{} } for _, addr := range storedBI.Addresses { // If the address is new, and isn't our own address, add it. if _, ok := existing[makeKey(addr)]; !ok && addr != g.is.NodeAddr { g.bootstrapInfo.Addresses = append(g.bootstrapInfo.Addresses, addr) } } // Persist merged addresses. if numAddrs := len(g.bootstrapInfo.Addresses); numAddrs > len(storedBI.Addresses) { if err := g.storage.WriteBootstrapInfo(&g.bootstrapInfo); err != nil { log.Error(err) } } } else { g.bootstrapInfo = storedBI } // Cycle through all persisted bootstrap hosts and add resolvers for // any which haven't already been added. newResolverFound := false for _, addr := range g.bootstrapInfo.Addresses { r, err := resolver.NewResolverFromUnresolvedAddr(addr) if err != nil { log.Warningf("bad node address %s: %s", addr, err) continue } if g.haveResolver(r) { continue } // If we find a new resolver, reset the resolver index so that the // next resolver we try is the first of the new resolvers. if !newResolverFound { newResolverFound = true g.resolverIdx = len(g.resolvers) - 1 } g.resolvers = append(g.resolvers, r) } // If a new resolver was found, immediately signal bootstrap. if newResolverFound { if log.V(1) { log.Infof("found new resolvers from storage; signalling bootstrap") } g.signalStalled() } return nil }