// rpcCallTablet wil execute the RPC on the remote server. func (client *GoRPCTabletManagerClient) rpcCallTablet(ctx context.Context, tablet *topo.TabletInfo, name string, args, reply interface{}) error { // create the RPC client, using ctx.Deadline if set, or no timeout. var connectTimeout time.Duration deadline, ok := ctx.Deadline() if ok { connectTimeout = deadline.Sub(time.Now()) if connectTimeout < 0 { return timeoutError{fmt.Errorf("timeout connecting to TabletManager.%v on %v", name, tablet.Alias)} } } rpcClient, err := bsonrpc.DialHTTP("tcp", tablet.Addr(), connectTimeout) if err != nil { return fmt.Errorf("RPC error for %v: %v", tablet.Alias, err.Error()) } defer rpcClient.Close() // use the context Done() channel. Will handle context timeout. call := rpcClient.Go(ctx, "TabletManager."+name, args, reply, nil) select { case <-ctx.Done(): if ctx.Err() == context.DeadlineExceeded { return timeoutError{fmt.Errorf("timeout waiting for TabletManager.%v to %v", name, tablet.Alias)} } return fmt.Errorf("interrupted waiting for TabletManager.%v to %v", name, tablet.Alias) case <-call.Done: if call.Error != nil { return fmt.Errorf("remote error for %v: %v", tablet.Alias, call.Error.Error()) } return nil } }
func (client *GoRpcTabletManagerClient) MultiSnapshot(tablet *topo.TabletInfo, sa *actionnode.MultiSnapshotArgs, waitTime time.Duration) (<-chan *logutil.LoggerEvent, tmclient.MultiSnapshotReplyFunc, error) { rpcClient, err := bsonrpc.DialHTTP("tcp", tablet.Addr(), waitTime, nil) if err != nil { return nil, nil, err } logstream := make(chan *logutil.LoggerEvent, 10) rpcstream := make(chan *gorpcproto.MultiSnapshotStreamingReply, 10) result := &actionnode.MultiSnapshotReply{} c := rpcClient.StreamGo("TabletManager.MultiSnapshot", sa, rpcstream) go func() { for ssr := range rpcstream { if ssr.Log != nil { logstream <- ssr.Log } if ssr.Result != nil { *result = *ssr.Result } } close(logstream) rpcClient.Close() }() return logstream, func() (*actionnode.MultiSnapshotReply, error) { return result, c.Error }, nil }
func (client *GoRpcTabletManagerClient) MultiRestore(tablet *topo.TabletInfo, sa *actionnode.MultiRestoreArgs, waitTime time.Duration) (<-chan *logutil.LoggerEvent, tmclient.ErrFunc, error) { rpcClient, err := bsonrpc.DialHTTP("tcp", tablet.Addr(), waitTime, nil) if err != nil { return nil, nil, err } logstream := make(chan *logutil.LoggerEvent, 10) c := rpcClient.StreamGo("TabletManager.MultiRestore", sa, logstream) return logstream, func() error { rpcClient.Close() return c.Error }, nil }
// Backup is part of the tmclient.TabletManagerClient interface func (client *GoRPCTabletManagerClient) Backup(ctx context.Context, tablet *topo.TabletInfo, concurrency int) (<-chan *logutil.LoggerEvent, tmclient.ErrFunc, error) { var connectTimeout time.Duration deadline, ok := ctx.Deadline() if ok { connectTimeout = deadline.Sub(time.Now()) if connectTimeout < 0 { return nil, nil, timeoutError{fmt.Errorf("timeout connecting to TabletManager.Backup on %v", tablet.Alias)} } } rpcClient, err := bsonrpc.DialHTTP("tcp", tablet.Addr(), connectTimeout) if err != nil { return nil, nil, err } logstream := make(chan *logutil.LoggerEvent, 10) rpcstream := make(chan *logutil.LoggerEvent, 10) c := rpcClient.StreamGo("TabletManager.Backup", &gorpcproto.BackupArgs{ Concurrency: concurrency, }, rpcstream) interrupted := false go func() { for { select { case <-ctx.Done(): // context is done interrupted = true close(logstream) rpcClient.Close() return case ssr, ok := <-rpcstream: if !ok { close(logstream) rpcClient.Close() return } logstream <- ssr } } }() return logstream, func() error { // this is only called after streaming is done if interrupted { return fmt.Errorf("TabletManager.Backup interrupted by context") } return c.Error }, nil }
// HealthStream is part of the tmclient.TabletManagerClient interface func (client *GoRPCTabletManagerClient) HealthStream(ctx context.Context, tablet *topo.TabletInfo) (<-chan *actionnode.HealthStreamReply, tmclient.ErrFunc, error) { var connectTimeout time.Duration deadline, ok := ctx.Deadline() if ok { connectTimeout = deadline.Sub(time.Now()) if connectTimeout < 0 { return nil, nil, timeoutError{fmt.Errorf("timeout connecting to TabletManager.HealthStream on %v", tablet.Alias)} } } rpcClient, err := bsonrpc.DialHTTP("tcp", tablet.Addr(), connectTimeout, nil) if err != nil { return nil, nil, err } logstream := make(chan *actionnode.HealthStreamReply, 10) rpcstream := make(chan *actionnode.HealthStreamReply, 10) c := rpcClient.StreamGo("TabletManager.HealthStream", "", rpcstream) interrupted := false go func() { for { select { case <-ctx.Done(): // context is done interrupted = true close(logstream) rpcClient.Close() return case hsr, ok := <-rpcstream: if !ok { close(logstream) rpcClient.Close() return } logstream <- hsr } } }() return logstream, func() error { // this is only called after streaming is done if interrupted { return fmt.Errorf("TabletManager.HealthStreamReply interrupted by context") } return c.Error }, nil }
func (client *GoRpcTabletManagerConn) rpcCallTablet(tablet *topo.TabletInfo, name string, args, reply interface{}, waitTime time.Duration) error { // create the RPC client, using waitTime as the connect // timeout, and starting the overall timeout as well timer := time.After(waitTime) rpcClient, err := bsonrpc.DialHTTP("tcp", tablet.Addr(), waitTime, nil) if err != nil { return fmt.Errorf("RPC error for %v: %v", tablet.Alias, err.Error()) } defer rpcClient.Close() // do the call in the remaining time call := rpcClient.Go("TabletManager."+name, args, reply, nil) select { case <-timer: return fmt.Errorf("Timeout waiting for TabletManager.%v to %v", name, tablet.Alias) case <-call.Done: if call.Error != nil { return fmt.Errorf("Remote error for %v: %v", tablet.Alias, call.Error.Error()) } else { return nil } } }