// Backup wraps RPCAgent.Backup func (tm *TabletManager) Backup(ctx context.Context, args *gorpcproto.BackupArgs, sendReply func(interface{}) error) error { ctx = callinfo.RPCWrapCallInfo(ctx) return tm.agent.RPCWrapLockAction(ctx, actionnode.TabletActionBackup, args, nil, true, func() error { // create a logger, send the result back to the caller logger := logutil.NewChannelLogger(10) wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logger { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying // to send. sendReply(&e) } wg.Done() }() err := tm.agent.Backup(ctx, args.Concurrency, logger) close(logger) wg.Wait() return err }) }
// ExecuteVtctlCommand is the server side method that will execute the query, // and stream the results. func (s *VtctlServer) ExecuteVtctlCommand(context context.Context, query *gorpcproto.ExecuteVtctlCommandArgs, sendReply func(interface{}) error) error { // create a logger, send the result back to the caller logstream := logutil.NewChannelLogger(10) logger := logutil.NewTeeLogger(logstream, logutil.NewConsoleLogger()) // send logs to the caller wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logstream { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying. sendReply(&e) } wg.Done() }() // create the wrangler wr := wrangler.New(logger, s.ts, query.ActionTimeout, query.LockTimeout) // execute the command err := vtctl.RunCommand(wr, query.Args) // close the log channel, and wait for them all to be sent close(logstream) wg.Wait() return err }
func (tm *TabletManager) MultiSnapshot(context *rpcproto.Context, args *actionnode.MultiSnapshotArgs, sendReply func(interface{}) error) error { return tm.agent.RpcWrapLockAction(context, actionnode.TABLET_ACTION_MULTI_SNAPSHOT, args, nil, true, func() error { // create a logger, send the result back to the caller logger := logutil.NewChannelLogger(10) wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logger { ssr := &gorpcproto.MultiSnapshotStreamingReply{ Log: &e, } // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying to send. sendReply(ssr) } wg.Done() }() sr, err := tm.agent.MultiSnapshot(args, logger) close(logger) wg.Wait() if err != nil { return err } ssr := &gorpcproto.MultiSnapshotStreamingReply{ Result: sr, } sendReply(ssr) return nil }) }
// ExecuteVtctlCommand is the server side method that will execute the query, // and stream the results. func (s *VtctlServer) ExecuteVtctlCommand(context context.Context, query *gorpcproto.ExecuteVtctlCommandArgs, sendReply func(interface{}) error) error { // create a logger, send the result back to the caller logger := logutil.NewChannelLogger(10) wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logger { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep logging the lines. if err := sendReply(&e); err != nil { log.Warningf("Cannot send vtctl log line: %v", e) } } wg.Done() }() // create the wrangler wr := wrangler.New(logger, s.ts, query.ActionTimeout, query.LockTimeout) // execute the command, wait for it to finish if required actionPath, err := vtctl.RunCommand(wr, query.Args) if err == nil && actionPath != "" { err = wr.WaitForCompletion(actionPath) } // close the log channel, and wait for them all to be sent close(logger) wg.Wait() return err }
// ExecuteVtctlCommand is part of the pb.VtctlServer interface func (s *VtctlServer) ExecuteVtctlCommand(args *pb.ExecuteVtctlCommandRequest, stream pbs.Vtctl_ExecuteVtctlCommandServer) (err error) { defer servenv.HandlePanic("vtctl", &err) // create a logger, send the result back to the caller logstream := logutil.NewChannelLogger(10) logger := logutil.NewTeeLogger(logstream, logutil.NewConsoleLogger()) // send logs to the caller wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logstream { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying. stream.Send(&pb.ExecuteVtctlCommandResponse{ Event: logutil.LoggerEventToProto(&e), }) } wg.Done() }() // create the wrangler wr := wrangler.New(logger, s.ts, tmclient.NewTabletManagerClient(), time.Duration(args.LockTimeout)) // execute the command err = vtctl.RunCommand(stream.Context(), wr, args.Args) // close the log channel, and wait for them all to be sent close(logstream) wg.Wait() return err }
func (s *server) Backup(request *tabletmanagerdatapb.BackupRequest, stream tabletmanagerservicepb.TabletManager_BackupServer) error { ctx := callinfo.GRPCCallInfo(stream.Context()) return s.agent.RPCWrapLockAction(ctx, actionnode.TabletActionBackup, request, nil, true, func() error { // create a logger, send the result back to the caller logger := logutil.NewChannelLogger(10) wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logger { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying // to send. stream.Send(&tabletmanagerdatapb.BackupResponse{ Event: logutil.LoggerEventToProto(&e), }) } wg.Done() }() err := s.agent.Backup(ctx, int(request.Concurrency), logger) close(logger) wg.Wait() return err }) }
// ExecuteVtworkerCommand is part of the pb.VtworkerServer interface func (s *VtworkerServer) ExecuteVtworkerCommand(args *pb.ExecuteVtworkerCommandRequest, stream pbs.Vtworker_ExecuteVtworkerCommandServer) (err error) { // Please note that this panic handler catches only panics occuring in the code below. // The actual execution of the vtworker command takes place in a new go routine // (started in Instance.setAndStartWorker()) which has its own panic handler. defer servenv.HandlePanic("vtworker", &err) // create a logger, send the result back to the caller logstream := logutil.NewChannelLogger(10) logger := logutil.NewTeeLogger(logstream, logutil.NewMemoryLogger()) // send logs to the caller wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logstream { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying. stream.Send(&pb.ExecuteVtworkerCommandResponse{ Event: &pbl.Event{ Time: &pbl.Time{ Seconds: e.Time.Unix(), Nanoseconds: int32(e.Time.Nanosecond()), }, Level: pbl.Level(e.Level), File: e.File, Line: int64(e.Line), Value: e.Value, }, }) } wg.Done() }() // create the wrangler wr := s.wi.CreateWrangler(logger) // execute the command if len(args.Args) >= 1 && args.Args[0] == "Reset" { err = s.wi.Reset() } else { // Make sure we use the global "err" variable and do not redeclare it in this scope. var worker worker.Worker var done chan struct{} worker, done, err = s.wi.RunCommand(args.Args, wr, false /*runFromCli*/) if err == nil { err = s.wi.WaitForCommand(worker, done) } } // close the log channel, and wait for them all to be sent close(logstream) wg.Wait() return err }
// ExecuteVtworkerCommand is part of the vtworkerdatapb.VtworkerServer interface func (s *VtworkerServer) ExecuteVtworkerCommand(args *vtworkerdatapb.ExecuteVtworkerCommandRequest, stream vtworkerservicepb.Vtworker_ExecuteVtworkerCommandServer) (err error) { // Please note that this panic handler catches only panics occuring in the code below. // The actual execution of the vtworker command takes place in a new go routine // (started in Instance.setAndStartWorker()) which has its own panic handler. defer servenv.HandlePanic("vtworker", &err) // Stream everything back what the Wrangler is logging. logstream := logutil.NewChannelLogger(10) // Let the Wrangler also log everything to the console (and thereby // effectively to a logfile) to make sure that any information or errors // is preserved in the logs in case the RPC or vtworker crashes. logger := logutil.NewTeeLogger(logstream, logutil.NewConsoleLogger()) // send logs to the caller wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logstream { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying. stream.Send(&vtworkerdatapb.ExecuteVtworkerCommandResponse{ Event: e, }) } wg.Done() }() // create the wrangler wr := s.wi.CreateWrangler(logger) // execute the command worker, done, err := s.wi.RunCommand(args.Args, wr, false /*runFromCli*/) if err == nil && worker != nil && done != nil { err = s.wi.WaitForCommand(worker, done) } // close the log channel, and wait for them all to be sent close(logstream) wg.Wait() return err }
func (tm *TabletManager) MultiRestore(context *rpcproto.Context, args *actionnode.MultiRestoreArgs, sendReply func(interface{}) error) error { return tm.agent.RpcWrapLockAction(context, actionnode.TABLET_ACTION_MULTI_RESTORE, args, nil, true, func() error { // create a logger, send the result back to the caller logger := logutil.NewChannelLogger(10) wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logger { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying to send. sendReply(&e) } wg.Done() }() err := tm.agent.MultiRestore(args, logger) close(logger) wg.Wait() return err }) }
// ExecuteVtctlCommand is the server side method that will execute the query, // and stream the results. func (s *VtctlServer) ExecuteVtctlCommand(ctx context.Context, query *gorpcproto.ExecuteVtctlCommandArgs, sendReply func(interface{}) error) (err error) { defer vtctl.HandlePanic(&err) // create a logger, send the result back to the caller logstream := logutil.NewChannelLogger(10) logger := logutil.NewTeeLogger(logstream, logutil.NewConsoleLogger()) // send logs to the caller wg := sync.WaitGroup{} wg.Add(1) go func() { for e := range logstream { // Note we don't interrupt the loop here, as // we still need to flush and finish the // command, even if the channel to the client // has been broken. We'll just keep trying. sendReply(&e) } wg.Done() }() // create the wrangler wr := wrangler.New(logger, s.ts, tmclient.NewTabletManagerClient(), query.LockTimeout) // FIXME(alainjobart) use a single context, copy the source info from it ctx, cancel := context.WithTimeout(context.TODO(), query.ActionTimeout) // execute the command err = vtctl.RunCommand(ctx, wr, query.Args) cancel() // close the log channel, and wait for them all to be sent close(logstream) wg.Wait() return err }