// afterAction needs to be run after an action may have changed the current // state of the tablet. func (agent *ActionAgent) afterAction(context string, reloadSchema bool) { log.Infof("Executing post-action change callbacks") // Save the old tablet so callbacks can have a better idea of // the precise nature of the transition. oldTablet := agent.Tablet().Tablet // Actions should have side effects on the tablet, so reload the data. if err := agent.readTablet(); err != nil { log.Warningf("Failed rereading tablet after %v - services may be inconsistent: %v", context, err) } else { if updatedTablet := actor.CheckTabletMysqlPort(agent.TopoServer, agent.Mysqld, agent.Tablet()); updatedTablet != nil { agent.mutex.Lock() agent._tablet = updatedTablet agent.mutex.Unlock() } agent.runChangeCallback(oldTablet, context) } // Maybe invalidate the schema. // This adds a dependency between tabletmanager and tabletserver, // so it's not ideal. But I (alainjobart) think it's better // to have up to date schema in vtocc. if reloadSchema { tabletserver.ReloadSchema() } log.Infof("Done with post-action change callbacks") }
// A non-nil return signals that event processing should stop. func (agent *ActionAgent) dispatchAction(actionPath, data string) error { relog.Info("action dispatch %v", actionPath) actionNode, err := ActionNodeFromJson(data, actionPath) if err != nil { relog.Error("action decode failed: %v %v", actionPath, err) return nil } logfile := flag.Lookup("logfile").Value.String() if !strings.HasPrefix(logfile, "/dev") { logfile = path.Join(path.Dir(logfile), "vtaction.log") } cmd := []string{ agent.vtActionBinFile, "-action", actionNode.Action, "-action-node", actionPath, "-action-guid", actionNode.ActionGuid, "-mycnf-file", agent.MycnfFile, "-logfile", logfile, } cmd = append(cmd, agent.ts.GetSubprocessFlags()...) if agent.DbConfigsFile != "" { cmd = append(cmd, "-db-configs-file", agent.DbConfigsFile) } if agent.DbCredentialsFile != "" { cmd = append(cmd, "-db-credentials-file", agent.DbCredentialsFile) } relog.Info("action launch %v", cmd) vtActionCmd := exec.Command(cmd[0], cmd[1:]...) stdOut, vtActionErr := vtActionCmd.CombinedOutput() if vtActionErr != nil { relog.Error("agent action failed: %v %v\n%s", actionPath, vtActionErr, stdOut) // If the action failed, preserve single execution path semantics. return vtActionErr } relog.Info("agent action completed %v %s", actionPath, stdOut) // Save the old tablet so callbacks can have a better idea of the precise // nature of the transition. oldTablet := agent.Tablet().Tablet // Actions should have side effects on the tablet, so reload the data. if err := agent.readTablet(); err != nil { relog.Warning("failed rereading tablet after action - services may be inconsistent: %v %v", actionPath, err) } else { agent.runChangeCallbacks(oldTablet, actionPath) } // Maybe invalidate the schema. // This adds a dependency between tabletmanager and tabletserver, // so it's not ideal. But I (alainjobart) think it's better // to have up to date schema in vtocc. if actionNode.Action == TABLET_ACTION_APPLY_SCHEMA { tabletserver.ReloadSchema() } return nil }
// ReloadSchema will reload the schema // Should be called under RpcWrapLockAction. func (agent *ActionAgent) ReloadSchema() { if agent.DBConfigs == nil { // we skip this for test instances that can't connect to the DB anyway return } // This adds a dependency between tabletmanager and tabletserver, // so it's not ideal. But I (alainjobart) think it's better // to have up to date schema in vttablet. tabletserver.ReloadSchema() }
// ReloadSchema will reload the schema // Should be called under RpcWrapLockAction. func (agent *ActionAgent) ReloadSchema() { // This adds a dependency between tabletmanager and tabletserver, // so it's not ideal. But I (alainjobart) think it's better // to have up to date schema in vttablet. tabletserver.ReloadSchema() }