func (agent *ActionAgent) allowQueries(tablet *topo.Tablet, blacklistedTables []string) error { // if the query service is already running, we're not starting it again if agent.QueryServiceControl.IsServing() { return nil } // only for real instances if agent.DBConfigs != nil { // Update our DB config to match the info we have in the tablet if agent.DBConfigs.App.DbName == "" { agent.DBConfigs.App.DbName = topo.TabletDbName(tablet) } agent.DBConfigs.App.Keyspace = tablet.Keyspace agent.DBConfigs.App.Shard = tablet.Shard if tablet.Type != topo.TYPE_MASTER { agent.DBConfigs.App.EnableInvalidator = true } else { agent.DBConfigs.App.EnableInvalidator = false } } err := agent.loadKeyspaceAndBlacklistRules(tablet, blacklistedTables) if err != nil { return err } return agent.QueryServiceControl.AllowQueries(&pb.Target{ Keyspace: tablet.Keyspace, Shard: tablet.Shard, TabletType: topo.TabletTypeToProto(tablet.Type), }, agent.DBConfigs, agent.SchemaOverrides, agent.MysqlDaemon) }
// loadKeyspaceAndBlacklistRules does what the name suggests: // 1. load and build keyrange query rules // 2. load and build blacklist query rules func (agent *ActionAgent) loadKeyspaceAndBlacklistRules(tablet *topo.Tablet, blacklistedTables []string) (err error) { // Keyrange rules keyrangeRules := tabletserver.NewQueryRules() if tablet.KeyRange.IsPartial() { log.Infof("Restricting to keyrange: %v", tablet.KeyRange) dmlPlans := []struct { planID planbuilder.PlanType onAbsent bool }{ {planbuilder.PLAN_INSERT_PK, true}, {planbuilder.PLAN_INSERT_SUBQUERY, true}, {planbuilder.PLAN_PASS_DML, false}, {planbuilder.PLAN_DML_PK, false}, {planbuilder.PLAN_DML_SUBQUERY, false}, } for _, plan := range dmlPlans { qr := tabletserver.NewQueryRule( fmt.Sprintf("enforce keyspace_id range for %v", plan.planID), fmt.Sprintf("keyspace_id_not_in_range_%v", plan.planID), tabletserver.QR_FAIL, ) qr.AddPlanCond(plan.planID) err := qr.AddBindVarCond("keyspace_id", plan.onAbsent, true, tabletserver.QR_NOTIN, tablet.KeyRange) if err != nil { return fmt.Errorf("Unable to add keyspace rule: %v", err) } keyrangeRules.Add(qr) } } // Blacklisted tables blacklistRules := tabletserver.NewQueryRules() if len(blacklistedTables) > 0 { // tables, first resolve wildcards tables, err := mysqlctl.ResolveTables(agent.MysqlDaemon, topo.TabletDbName(tablet), blacklistedTables) if err != nil { return err } log.Infof("Blacklisting tables %v", strings.Join(tables, ", ")) qr := tabletserver.NewQueryRule("enforce blacklisted tables", "blacklisted_table", tabletserver.QR_FAIL_RETRY) for _, t := range tables { qr.AddTableCond(t) } blacklistRules.Add(qr) } // Push all three sets of QueryRules to SqlQueryRpcService loadRuleErr := agent.QueryServiceControl.SetQueryRules(keyrangeQueryRules, keyrangeRules) if loadRuleErr != nil { log.Warningf("Fail to load query rule set %s: %s", keyrangeQueryRules, loadRuleErr) } loadRuleErr = agent.QueryServiceControl.SetQueryRules(blacklistQueryRules, blacklistRules) if loadRuleErr != nil { log.Warningf("Fail to load query rule set %s: %s", blacklistQueryRules, loadRuleErr) } return nil }
// RefreshMap reads the right data from topo.Server and makes sure // we're playing the right logs. func (blm *BinlogPlayerMap) RefreshMap(ctx context.Context, tablet *pb.Tablet, keyspaceInfo *topo.KeyspaceInfo, shardInfo *topo.ShardInfo) { log.Infof("Refreshing map of binlog players") if shardInfo == nil { log.Warningf("Could not read shardInfo, not changing anything") return } if len(shardInfo.SourceShards) > 0 && keyspaceInfo == nil { log.Warningf("Could not read keyspaceInfo, not changing anything") return } blm.mu.Lock() if blm.dbConfig.DbName == "" { blm.dbConfig.DbName = topo.TabletDbName(tablet) } // get the existing sources and build a map of sources to remove toRemove := make(map[uint32]bool) hadPlayers := false for source := range blm.players { toRemove[source] = true hadPlayers = true } // for each source, add it if not there, and delete from toRemove for _, sourceShard := range shardInfo.SourceShards { blm.addPlayer(ctx, tablet.Alias.Cell, keyspaceInfo.ShardingColumnType, tablet.KeyRange, sourceShard, topo.TabletDbName(tablet)) delete(toRemove, sourceShard.Uid) } hasPlayers := len(shardInfo.SourceShards) > 0 // remove all entries from toRemove for source := range toRemove { blm.players[source].Stop() delete(blm.players, source) } blm.mu.Unlock() if hadPlayers && !hasPlayers { // We're done streaming, so turn off special playback settings. blm.mysqld.DisableBinlogPlayback() } }