func (agent *ActionAgent) allowQueries(tablet *topo.Tablet) error { if agent.DBConfigs == nil { // test instance, do nothing return nil } // if the query service is already running, we're not starting it again if tabletserver.SqlQueryRpcService.GetState() == "SERVING" { return nil } // Update our DB config to match the info we have in the tablet if agent.DBConfigs.App.DbName == "" { agent.DBConfigs.App.DbName = tablet.DbName() } agent.DBConfigs.App.Keyspace = tablet.Keyspace agent.DBConfigs.App.Shard = tablet.Shard qrs, err := agent.createQueryRules(tablet) if err != nil { return err } return tabletserver.AllowQueries(&agent.DBConfigs.App, agent.SchemaOverrides, qrs, agent.Mysqld, false) }
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 = tablet.DbName() } 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, tablet.DbName(), 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 }
// createQueryRules computes the query rules that match the tablet record func (agent *ActionAgent) createQueryRules(tablet *topo.Tablet) (qrs *tabletserver.QueryRules, err error) { qrs = tabletserver.LoadCustomRules() // Keyrange rules if tablet.KeyRange.IsPartial() { log.Infof("Restricting to keyrange: %v", tablet.KeyRange) dml_plans := []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 dml_plans { 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 nil, fmt.Errorf("Unable to add keyspace rule: %v", err) } qrs.Add(qr) } } // Blacklisted tables if len(tablet.BlacklistedTables) > 0 { // tables, first resolve wildcards tables, err := agent.Mysqld.ResolveTables(tablet.DbName(), tablet.BlacklistedTables) if err != nil { return nil, 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) } qrs.Add(qr) } return qrs, nil }
func (agent *ActionAgent) allowQueries(tablet *topo.Tablet) error { // if the query service is already running, we're not starting it again if tabletserver.SqlQueryRpcService.GetState() == "SERVING" { return nil } // Update our DB config to match the info we have in the tablet if agent.DBConfigs.App.DbName == "" { agent.DBConfigs.App.DbName = tablet.DbName() } 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 } // Compute the query rules that match the tablet record qrs := tabletserver.LoadCustomRules() if tablet.KeyRange.IsPartial() { qr := tabletserver.NewQueryRule("enforce keyspace_id range", "keyspace_id_not_in_range", tabletserver.QR_FAIL) qr.AddPlanCond(planbuilder.PLAN_INSERT_PK) err := qr.AddBindVarCond("keyspace_id", true, true, tabletserver.QR_NOTIN, tablet.KeyRange) if err != nil { log.Warningf("Unable to add keyspace rule: %v", err) } else { qrs.Add(qr) } } if len(tablet.BlacklistedTables) > 0 { // tables, first resolve wildcards tables, err := agent.Mysqld.ResolveTables(tablet.DbName(), tablet.BlacklistedTables) if err != nil { log.Warningf("Unable to resolve blacklisted tables: %v", err) } else { 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) } qrs.Add(qr) } } return tabletserver.AllowQueries(&agent.DBConfigs.App, agent.SchemaOverrides, qrs, agent.Mysqld, false) }
// 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 *topo.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 = tablet.DbName() } // 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, key.KeyRangeToProto(tablet.KeyRange), sourceShard, tablet.DbName()) 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() } }
// RefreshMap reads the right data from topo.Server and makes sure // we're playing the right logs. func (blm *BinlogPlayerMap) RefreshMap(tablet topo.Tablet, keyspaceInfo *topo.KeyspaceInfo, shardInfo *topo.ShardInfo) { log.Infof("Refreshing map of binlog players") if keyspaceInfo == nil { log.Warningf("Could not read keyspaceInfo, not changing anything") return } if shardInfo == nil { log.Warningf("Could not read shardInfo, not changing anything") return } blm.mu.Lock() // 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(tablet.Alias.Cell, keyspaceInfo.ShardingColumnType, tablet.KeyRange, sourceShard, tablet.DbName()) 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 { blm.enableSuperToSetTimestamp() } }