Beispiel #1
0
func (zkts *Server) updateTabletEndpoint(oldValue string, oldStat zk.Stat, addr *topo.VtnsAddr) (newValue string, err error) {
	if oldStat == nil {
		// The incoming object doesn't exist - we haven't been placed in the serving
		// graph yet, so don't update. Assume the next process that rebuilds the graph
		// will get the updated tablet location.
		return "", skipUpdateErr
	}

	var addrs *topo.VtnsAddrs
	if oldValue != "" {
		addrs, err = topo.NewVtnsAddrs(oldValue, oldStat.Version())
		if err != nil {
			return
		}

		foundTablet := false
		for i, entry := range addrs.Entries {
			if entry.Uid == addr.Uid {
				foundTablet = true
				if !topo.VtnsAddrEquality(&entry, addr) {
					addrs.Entries[i] = *addr
				}
				break
			}
		}

		if !foundTablet {
			addrs.Entries = append(addrs.Entries, *addr)
		}
	} else {
		addrs = topo.NewAddrs()
		addrs.Entries = append(addrs.Entries, *addr)
	}
	return jscfg.ToJson(addrs), nil
}
Beispiel #2
0
// Write serving graph data to the cells
func (wr *Wrangler) rebuildShardSrvGraph(shardInfo *topo.ShardInfo, tablets []*topo.TabletInfo, cells []string) error {
	relog.Info("rebuildShardSrvGraph %v/%v", shardInfo.Keyspace(), shardInfo.ShardName())

	// Get all existing db types so they can be removed if nothing
	// had been editted.  This applies to all cells, which can't
	// be determined until you walk through all the tablets.
	//
	// existingDbTypeLocations is a map:
	//   key: {cell,keyspace,shard,tabletType}
	//   value: true
	existingDbTypeLocations := make(map[cellKeyspaceShardType]bool)

	// Update db type addresses in the serving graph
	//
	// locationAddrsMap is a map:
	//   key: {cell,keyspace,shard,tabletType}
	//   value: topo.VtnsAddrs (list of server records)
	locationAddrsMap := make(map[cellKeyspaceShardType]*topo.VtnsAddrs)

	// we keep track of the existingDbTypeLocations we've already looked at
	knownShardLocations := make(map[cellKeyspaceShard]bool)

	for _, tablet := range tablets {
		// only look at tablets in the cells we want to rebuild
		// we also include masters from everywhere, so we can
		// write the right aliases
		if !inCellList(tablet.Tablet.Cell, cells) && tablet.Type != topo.TYPE_MASTER {
			continue
		}

		// this is {cell,keyspace,shard}
		// we'll get the children to find the existing types
		shardLocation := cellKeyspaceShard{tablet.Tablet.Cell, tablet.Tablet.Keyspace, tablet.Shard}
		// only need to do this once per cell
		if !knownShardLocations[shardLocation] {
			tabletTypes, err := wr.ts.GetSrvTabletTypesPerShard(tablet.Tablet.Cell, tablet.Tablet.Keyspace, tablet.Shard)
			if err != nil {
				if err != topo.ErrNoNode {
					return err
				}
			} else {
				for _, tabletType := range tabletTypes {
					existingDbTypeLocations[cellKeyspaceShardType{tablet.Tablet.Cell, tablet.Tablet.Keyspace, tablet.Shard, tabletType}] = true
				}
			}
			knownShardLocations[shardLocation] = true
		}

		// Check IsServingType after we have populated existingDbTypeLocations
		// so we properly prune data if the definition of serving type
		// changes.
		if !tablet.IsServingType() {
			continue
		}

		location := cellKeyspaceShardType{tablet.Tablet.Cell, tablet.Keyspace, tablet.Shard, tablet.Type}
		addrs, ok := locationAddrsMap[location]
		if !ok {
			addrs = topo.NewAddrs()
			locationAddrsMap[location] = addrs
		}

		entry, err := tm.VtnsAddrForTablet(tablet.Tablet)
		if err != nil {
			relog.Warning("VtnsAddrForTablet failed for tablet %v: %v", tablet.Alias(), err)
			continue
		}
		addrs.Entries = append(addrs.Entries, *entry)
	}

	// if there is a master in one cell, put it in all of them
	var masterRecord *topo.VtnsAddrs
	for shardLocation, _ := range knownShardLocations {
		loc := cellKeyspaceShardType{shardLocation.cell, shardLocation.keyspace, shardLocation.shard, topo.TYPE_MASTER}
		if addrs, ok := locationAddrsMap[loc]; ok {
			if masterRecord != nil {
				relog.Warning("Multiple master records in %v", shardLocation)
			} else {
				relog.Info("Found master record in %v", shardLocation)
				masterRecord = addrs
			}
		}
	}
	if masterRecord != nil {
		for shardLocation, _ := range knownShardLocations {
			location := cellKeyspaceShardType{shardLocation.cell, shardLocation.keyspace, shardLocation.shard, topo.TYPE_MASTER}
			if _, ok := locationAddrsMap[location]; !ok {
				relog.Info("Adding remote master record in %v", location)
				locationAddrsMap[location] = masterRecord
			}
		}
	}

	// write all the {cell,keyspace,shard,type}
	// nodes everywhere we want them
	for location, addrs := range locationAddrsMap {
		cell := location.cell
		if !inCellList(cell, cells) {
			continue
		}

		if err := wr.ts.UpdateSrvTabletType(location.cell, location.keyspace, location.shard, location.tabletType, addrs); err != nil {
			return fmt.Errorf("writing endpoints failed: %v", err)
		}
	}

	// Delete any pre-existing paths that were not updated by this process.
	// That's the existingDbTypeLocations - locationAddrsMap
	for dbTypeLocation, _ := range existingDbTypeLocations {
		if _, ok := locationAddrsMap[dbTypeLocation]; !ok {
			cell := dbTypeLocation.cell
			if !inCellList(cell, cells) {
				continue
			}

			relog.Info("removing stale db type from serving graph: %v", dbTypeLocation)
			if err := wr.ts.DeleteSrvTabletType(dbTypeLocation.cell, dbTypeLocation.keyspace, dbTypeLocation.shard, dbTypeLocation.tabletType); err != nil {
				relog.Warning("unable to remove stale db type from serving graph: %v", err)
			}
		}
	}

	// Update per-shard information per cell-specific serving path.
	//
	// srvShardByPath is a map:
	//   key: {cell,keyspace,shard}
	//   value: topo.SrvShard
	// this will fill in the AddrsByType part for each shard
	srvShardByPath := make(map[cellKeyspaceShard]*topo.SrvShard)
	for location, addrs := range locationAddrsMap {
		// location will be {cell,keyspace,shard,type}
		srvShardPath := cellKeyspaceShard{location.cell, location.keyspace, location.shard}
		tabletType := location.tabletType

		srvShard, ok := srvShardByPath[srvShardPath]
		if !ok {
			srvShard = &topo.SrvShard{KeyRange: shardInfo.KeyRange, AddrsByType: make(map[string]topo.VtnsAddrs)}
			srvShardByPath[srvShardPath] = srvShard
		}
		srvShard.AddrsByType[string(tabletType)] = *addrs
	}

	// Save the shard entries
	for srvPath, srvShard := range srvShardByPath {
		if err := wr.ts.UpdateSrvShard(srvPath.cell, srvPath.keyspace, srvPath.shard, srvShard); err != nil {
			return fmt.Errorf("writing serving data failed: %v", err)
		}
	}
	return nil
}