// return a few values that need to be refreshed func (zkc *ZkCache) refreshSomeValues(zconn zk.Conn, maxToRefresh int) { // build a list of a few values we want to refresh refreshThreshold := time.Now().Add(-10 * time.Minute) // range will randomize the traversal order, so we will not always try // the same entries in the same order dataEntries := make([]*zkCacheEntry, 0, maxToRefresh) childrenEntries := make([]*zkCacheEntry, 0, maxToRefresh) zkc.mutex.Lock() for _, entry := range zkc.Cache { shouldBeDataRefreshed, shouldBeChildrenRefreshed := entry.checkForRefresh(refreshThreshold) if shouldBeDataRefreshed { dataEntries = append(dataEntries, entry) } if shouldBeChildrenRefreshed { childrenEntries = append(childrenEntries, entry) } // check if we have enough work to do if len(dataEntries) == maxToRefresh || len(childrenEntries) == maxToRefresh { break } } zkc.mutex.Unlock() // now refresh the values for _, entry := range dataEntries { data, stat, watch, err := zconn.GetW(entry.node.Path) if err == nil { zkStat := &zk.ZkStat{} zkStat.FromZookeeperStat(stat) entry.updateData(data, zkStat, watch) } else if zookeeper.IsError(err, zookeeper.ZCLOSING) { // connection is closing, no point in asking for more log.Warningf("failed to refresh cache: %v (and stopping refresh)", err.Error()) return } else { // individual failure log.Warningf("failed to refresh cache: %v", err.Error()) } } for _, entry := range childrenEntries { children, stat, watch, err := zconn.ChildrenW(entry.node.Path) if err == nil { zkStat := &zk.ZkStat{} zkStat.FromZookeeperStat(stat) entry.updateChildren(children, zkStat, watch) } else if zookeeper.IsError(err, zookeeper.ZCLOSING) { // connection is closing, no point in asking for more log.Warningf("failed to refresh cache: %v (and stopping refresh)", err.Error()) return } else { // individual failure log.Warningf("failed to refresh cache: %v", err.Error()) } } }
// ReadAddrs returns a ZknsAddrs record from the given path in Zookeeper. func ReadAddrs(zconn zk.Conn, zkPath string) (*ZknsAddrs, error) { data, stat, err := zconn.Get(zkPath) if err != nil { return nil, err } // There are nodes that will have no data - for instance a subdomain node. if len(data) == 0 { return nil, nil } addrs := new(ZknsAddrs) err = json.Unmarshal([]byte(data), addrs) if err != nil { return nil, err } addrs.version = stat.Version() return addrs, nil }
func (wr *Wrangler) exportVtnsToZkns(zconn zk.Conn, vtnsAddrPath, zknsAddrPath string) ([]string, error) { zknsPaths := make([]string, 0, 32) parts := strings.Split(vtnsAddrPath, "/") if len(parts) != 8 && len(parts) != 9 { return nil, fmt.Errorf("Invalid leaf zk path: %v", vtnsAddrPath) } cell := parts[2] keyspace := parts[5] shard := parts[6] tabletType := topo.TabletType(parts[7]) if tabletType == "action" || tabletType == "actionlog" { return nil, nil } addrs, err := wr.ts.GetEndPoints(cell, keyspace, shard, tabletType) if err != nil { return nil, err } // Write the individual endpoints and compute the SRV entries. vtoccAddrs := LegacyZknsAddrs{make([]string, 0, 8)} defaultAddrs := LegacyZknsAddrs{make([]string, 0, 8)} for i, entry := range addrs.Entries { zknsAddrPath := fmt.Sprintf("%v/%v", zknsAddrPath, i) zknsPaths = append(zknsPaths, zknsAddrPath) zknsAddr := zkns.ZknsAddr{Host: entry.Host, Port: entry.NamedPortMap["_mysql"], NamedPortMap: entry.NamedPortMap} err := WriteAddr(zconn, zknsAddrPath, &zknsAddr) if err != nil { return nil, err } defaultAddrs.Endpoints = append(defaultAddrs.Endpoints, zknsAddrPath) vtoccAddrs.Endpoints = append(vtoccAddrs.Endpoints, zknsAddrPath+":_vtocc") } // Prune any zkns entries that are no longer referenced by the // shard graph. deleteIdx := len(addrs.Entries) for { zknsStaleAddrPath := fmt.Sprintf("%v/%v", zknsAddrPath, deleteIdx) // A "delete" is a write of sorts - just communicate up that nothing // needs to be done to this node. zknsPaths = append(zknsPaths, zknsStaleAddrPath) err := zconn.Delete(zknsStaleAddrPath, -1) if zookeeper.IsError(err, zookeeper.ZNONODE) { break } if err != nil { return nil, err } deleteIdx++ } // Write the VDNS entries for both vtocc and mysql vtoccVdnsPath := fmt.Sprintf("%v/_vtocc.vdns", zknsAddrPath) zknsPaths = append(zknsPaths, vtoccVdnsPath) if err = WriteAddrs(zconn, vtoccVdnsPath, &vtoccAddrs); err != nil { return nil, err } defaultVdnsPath := fmt.Sprintf("%v.vdns", zknsAddrPath) zknsPaths = append(zknsPaths, defaultVdnsPath) if err = WriteAddrs(zconn, defaultVdnsPath, &defaultAddrs); err != nil { return nil, err } return zknsPaths, nil }