github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/edge/edge.go (about)

     1  package edge
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"net/http"
     7  	"os"
     8  	"os/signal"
     9  	"runtime/debug"
    10  	"time"
    11  
    12  	"go.opentelemetry.io/otel/codes"
    13  
    14  	"github.com/ronaksoft/rony"
    15  	"github.com/ronaksoft/rony/errors"
    16  	"github.com/ronaksoft/rony/internal/metrics"
    17  	"github.com/ronaksoft/rony/internal/msg"
    18  	"github.com/ronaksoft/rony/log"
    19  	"github.com/ronaksoft/rony/pools"
    20  	"github.com/ronaksoft/rony/registry"
    21  	"github.com/ronaksoft/rony/tools"
    22  	"go.opentelemetry.io/otel/propagation"
    23  	semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
    24  	"go.opentelemetry.io/otel/trace"
    25  	"go.uber.org/zap"
    26  )
    27  
    28  /*
    29     Creation Time: 2020 - Feb - 21
    30     Created by:  (ehsan)
    31     Maintainers:
    32        1.  Ehsan N. Moosa (E2)
    33     Auditor: Ehsan N. Moosa (E2)
    34     Copyright Ronak Software Group 2020
    35  */
    36  
    37  type MessageKind byte
    38  
    39  const (
    40  	_ MessageKind = iota
    41  	GatewayMessage
    42  	TunnelMessage
    43  )
    44  
    45  var (
    46  	messageKindNames = map[MessageKind]string{
    47  		GatewayMessage: "GatewayMessage",
    48  		TunnelMessage:  "TunnelMessage",
    49  	}
    50  )
    51  
    52  func (c MessageKind) String() string {
    53  	return messageKindNames[c]
    54  }
    55  
    56  // Server represents Edge serve. Edge server sticks all other parts of the system together.
    57  type Server struct {
    58  	// General
    59  	name     string
    60  	serverID []byte
    61  	logger   log.Logger
    62  
    63  	// Handlers
    64  	preHandlers  []Handler
    65  	handlers     map[uint64]*HandlerOption
    66  	postHandlers []Handler
    67  
    68  	// Edge components
    69  	router     rony.Router
    70  	cluster    rony.Cluster
    71  	tunnel     rony.Tunnel
    72  	gateway    rony.Gateway
    73  	dispatcher Dispatcher
    74  	restMux    *restMux
    75  
    76  	// Tracing
    77  	tracer     trace.Tracer
    78  	propagator propagation.TraceContext
    79  }
    80  
    81  func NewServer(serverID string, opts ...Option) *Server {
    82  	// Initialize metrics
    83  	metrics.Init(map[string]string{
    84  		"ServerID": serverID,
    85  	})
    86  
    87  	edgeServer := &Server{
    88  		handlers:   make(map[uint64]*HandlerOption),
    89  		serverID:   []byte(serverID),
    90  		dispatcher: &DefaultDispatcher{},
    91  		logger:     log.With("EDGE"),
    92  	}
    93  
    94  	for _, opt := range opts {
    95  		opt(edgeServer)
    96  	}
    97  
    98  	// register builtin rony handlers
    99  	builtin := newBuiltin(edgeServer)
   100  	edgeServer.SetHandler(NewHandlerOptions().SetConstructor(rony.C_GetNodes).Append(builtin.getNodes))
   101  	edgeServer.SetHandler(NewHandlerOptions().SetConstructor(rony.C_GetAllNodes).Append(builtin.getAllNodes))
   102  	edgeServer.SetHandler(NewHandlerOptions().SetConstructor(rony.C_Ping).Append(builtin.ping))
   103  
   104  	return edgeServer
   105  }
   106  
   107  // GetServerID return this server id, which MUST be unique in the cluster otherwise
   108  // the behaviour is unknown.
   109  func (edge *Server) GetServerID() string {
   110  	return string(edge.serverID)
   111  }
   112  
   113  // SetGlobalPreHandlers set the handler which will be called before executing any request.
   114  // These pre handlers are like middlewares which will be automatically triggered for each request.
   115  // If you want to set pre handler for specific request then you must use SetHandlers,
   116  // PrependHandlers or AppendHandlers
   117  func (edge *Server) SetGlobalPreHandlers(handlers ...Handler) {
   118  	edge.preHandlers = handlers
   119  }
   120  
   121  // SetGlobalPostHandlers set the handler which will be called after executing any request.
   122  // These pre handlers are like middlewares which will be automatically triggered for each request.
   123  // If you want to set post handler for specific request then you must use SetHandlers,
   124  // PrependHandlers or AppendHandlers
   125  func (edge *Server) SetGlobalPostHandlers(handlers ...Handler) {
   126  	edge.postHandlers = handlers
   127  }
   128  
   129  // SetHandler set the handlers for the constructor.
   130  func (edge *Server) SetHandler(ho *HandlerOption) {
   131  	for c := range ho.constructors {
   132  		edge.handlers[c] = ho
   133  	}
   134  }
   135  
   136  // GetHandler returns the handlers of the constructor
   137  func (edge *Server) GetHandler(constructor uint64) *HandlerOption {
   138  	return edge.handlers[constructor]
   139  }
   140  
   141  // SetRestProxy set a REST wrapper to expose RPCs in REST (Representational State Transfer) format
   142  func (edge *Server) SetRestProxy(method string, path string, p RestProxy) {
   143  	if edge.restMux == nil {
   144  		edge.restMux = &restMux{
   145  			routes: map[string]*trie{},
   146  		}
   147  	}
   148  	edge.restMux.Set(method, path, p)
   149  }
   150  
   151  // SetCustomDispatcher replace the default dispatcher with your custom dispatcher. Usually you don't need to
   152  // use custom dispatcher, but in some rare cases you can implement your own custom dispatcher
   153  func (edge *Server) SetCustomDispatcher(d Dispatcher) {
   154  	edge.dispatcher = d
   155  }
   156  
   157  // Cluster returns a reference to the underlying cluster of the Edge server
   158  func (edge *Server) Cluster() rony.Cluster {
   159  	return edge.cluster
   160  }
   161  
   162  // Gateway returns a reference to the underlying gateway of the Edge server
   163  func (edge *Server) Gateway() rony.Gateway {
   164  	return edge.gateway
   165  }
   166  
   167  // Tunnel returns a reference to the underlying tunnel of the Edge server
   168  func (edge *Server) Tunnel() rony.Tunnel {
   169  	return edge.tunnel
   170  }
   171  
   172  func (edge *Server) execute(dispatchCtx *DispatchCtx) (err error) {
   173  	waitGroup := pools.AcquireWaitGroup()
   174  	switch dispatchCtx.req.GetConstructor() {
   175  	case rony.C_MessageContainer:
   176  		x := &rony.MessageContainer{}
   177  		err = x.Unmarshal(dispatchCtx.req.Message)
   178  		if err != nil {
   179  			return
   180  		}
   181  		xLen := len(x.Envelopes)
   182  		for i := 0; i < xLen; i++ {
   183  			ctx := acquireRequestCtx(dispatchCtx, x.SyncRun)
   184  			waitGroup.Add(1)
   185  			go func(ctx *RequestCtx, idx int) {
   186  				edge.executeFunc(ctx, x.Envelopes[idx])
   187  				if x.SyncRun {
   188  					select {
   189  					case ctx.nextChan <- struct{}{}:
   190  					default:
   191  					}
   192  				}
   193  				waitGroup.Done()
   194  				releaseRequestCtx(ctx)
   195  			}(ctx, i)
   196  
   197  			if x.SyncRun {
   198  				// wait until we allowed to go to next
   199  				<-ctx.nextChan
   200  			}
   201  		}
   202  	default:
   203  		ctx := acquireRequestCtx(dispatchCtx, false)
   204  		edge.executeFunc(ctx, dispatchCtx.req)
   205  		releaseRequestCtx(ctx)
   206  	}
   207  	waitGroup.Wait()
   208  	pools.ReleaseWaitGroup(waitGroup)
   209  
   210  	return nil
   211  }
   212  func (edge *Server) executeFunc(requestCtx *RequestCtx, in *rony.MessageEnvelope) {
   213  	defer edge.recoverPanic(requestCtx, in)
   214  
   215  	startTime := tools.CPUTicks()
   216  
   217  	// Set the context request
   218  	requestCtx.reqID = in.RequestID
   219  
   220  	ho, ok := edge.handlers[in.GetConstructor()]
   221  	if !ok {
   222  		requestCtx.PushError(errors.ErrInvalidHandler)
   223  
   224  		return
   225  	}
   226  
   227  	if edge.tracer != nil {
   228  		switch in.Constructor {
   229  		case rony.C_Ping, rony.C_GetAllNodes, rony.C_GetNodes:
   230  		default:
   231  			requestCtx.ctx = edge.propagator.Extract(requestCtx.ctx, in.Carrier())
   232  			var span trace.Span
   233  			requestCtx.ctx, span = edge.tracer.
   234  				Start(
   235  					requestCtx.ctx,
   236  					fmt.Sprintf("rpc.%s/%s", ho.serviceName, ho.methodName),
   237  					trace.WithAttributes(
   238  						semconv.RPCServiceKey.String(ho.serviceName),
   239  						semconv.RPCMethodKey.String(ho.methodName),
   240  					),
   241  					trace.WithSpanKind(trace.SpanKindServer),
   242  				)
   243  			defer span.End()
   244  		}
   245  	}
   246  
   247  	// Run the handler
   248  	if !ho.builtin {
   249  		for idx := range edge.preHandlers {
   250  			edge.preHandlers[idx](requestCtx, in)
   251  			if requestCtx.stop {
   252  				break
   253  			}
   254  		}
   255  	}
   256  	if !requestCtx.stop {
   257  		for idx := range ho.handlers {
   258  			ho.handlers[idx](requestCtx, in)
   259  			if requestCtx.stop {
   260  				break
   261  			}
   262  		}
   263  	}
   264  	if !ho.builtin {
   265  		for idx := range edge.postHandlers {
   266  			edge.postHandlers[idx](requestCtx, in)
   267  		}
   268  	}
   269  	if !requestCtx.stop {
   270  		requestCtx.StopExecution()
   271  	}
   272  
   273  	if ce := edge.logger.Check(log.DebugLevel, "Request Executed"); ce != nil {
   274  		ce.Write(
   275  			zap.String("ServerID", edge.GetServerID()),
   276  			zap.String("Kind", requestCtx.Kind().String()),
   277  			zap.Uint64("ReqID", in.GetRequestID()),
   278  			zap.String("C", registry.C(in.GetConstructor())),
   279  			zap.Duration("T", time.Duration(tools.CPUTicks()-startTime)),
   280  		)
   281  	}
   282  
   283  	metrics.AddCounterVec(metrics.CntRPC, 1, registry.C(in.Constructor))
   284  
   285  	if requestCtx.err == nil {
   286  		requestCtx.Span().SetStatus(codes.Ok, "")
   287  	} else {
   288  		requestCtx.Span().SetStatus(codes.Error, requestCtx.err.Error())
   289  	}
   290  
   291  	switch requestCtx.Kind() {
   292  	case GatewayMessage:
   293  		metrics.ObserveHistogram(
   294  			metrics.HistGatewayRequestTime,
   295  			float64(time.Duration(tools.CPUTicks()-startTime)/time.Millisecond),
   296  		)
   297  	case TunnelMessage:
   298  		metrics.ObserveHistogram(
   299  			metrics.HistTunnelRequestTime,
   300  			float64(time.Duration(tools.CPUTicks()-startTime)/time.Millisecond),
   301  		)
   302  	}
   303  }
   304  func (edge *Server) recoverPanic(ctx *RequestCtx, in *rony.MessageEnvelope) {
   305  	if r := recover(); r != nil {
   306  		edge.logger.Error("Panic Recovered",
   307  			zap.String("C", registry.C(in.Constructor)),
   308  			zap.Uint64("ReqID", in.RequestID),
   309  			zap.Uint64("ConnID", ctx.ConnID()),
   310  			zap.Any("Error", r),
   311  		)
   312  		edge.logger.Error("Panic Stack Trace", zap.ByteString("Stack", debug.Stack()))
   313  		ctx.PushError(errors.ErrInternalServer)
   314  	}
   315  }
   316  
   317  func (edge *Server) onGatewayMessage(conn rony.Conn, streamID int64, data []byte) {
   318  	// Fill dispatch context with data. We use the GatewayDispatcher or consume data directly based on the
   319  	// byPassDispatcher argument
   320  	dispatchCtx := acquireDispatchCtx(edge, conn, streamID, edge.serverID, GatewayMessage)
   321  	defer releaseDispatchCtx(dispatchCtx)
   322  
   323  	// if it is REST API then we take a different approach.
   324  	if !conn.Persistent() && edge.restMux != nil {
   325  		if rc, ok := conn.(rony.RestConn); ok {
   326  			path, p := edge.restMux.Search(rc)
   327  			if p != nil {
   328  				if edge.tracer != nil {
   329  					var span trace.Span
   330  					dispatchCtx.ctx = edge.propagator.Extract(dispatchCtx.ctx, &carrier{c: rc})
   331  					dispatchCtx.ctx, span = edge.tracer.
   332  						Start(
   333  							dispatchCtx.ctx,
   334  							fmt.Sprintf("%s %s", rc.Method(), path),
   335  							trace.WithAttributes(
   336  								semconv.HTTPMethodKey.String(rc.Method()),
   337  							),
   338  							trace.WithSpanKind(trace.SpanKindServer),
   339  						)
   340  					defer span.End()
   341  				}
   342  
   343  				edge.onGatewayRest(dispatchCtx, rc, p)
   344  
   345  				return
   346  			}
   347  		}
   348  	}
   349  
   350  	err := edge.dispatcher.Decode(data, dispatchCtx.req)
   351  	if err != nil {
   352  		return
   353  	}
   354  
   355  	err = edge.execute(dispatchCtx)
   356  	if err != nil {
   357  		edge.onError(dispatchCtx, errors.ErrInternalServer)
   358  	} else {
   359  		edge.dispatcher.Done(dispatchCtx)
   360  	}
   361  }
   362  func (edge *Server) onGatewayRest(ctx *DispatchCtx, conn rony.RestConn, proxy RestProxy) {
   363  	// apply the transformation on the client message before execute it
   364  	err := proxy.ClientMessage(conn, ctx)
   365  	if err != nil {
   366  		switch err := err.(type) {
   367  		case *rony.Error:
   368  			conn.WriteStatus(errors.Code(err.Code).HttpStatus())
   369  			b, _ := err.MarshalJSON()
   370  			_ = conn.WriteBinary(0, b)
   371  		default:
   372  			conn.WriteStatus(http.StatusInternalServerError)
   373  			b, _ := errors.New(errors.Internal, err.Error()).MarshalJSON()
   374  			_ = conn.WriteBinary(0, b)
   375  		}
   376  
   377  		return
   378  	}
   379  
   380  	err = edge.execute(ctx)
   381  	if err != nil {
   382  		switch err := err.(type) {
   383  		case *rony.Error:
   384  			conn.WriteStatus(errors.Code(err.Code).HttpStatus())
   385  			b, _ := err.MarshalJSON()
   386  			_ = conn.WriteBinary(0, b)
   387  		default:
   388  			conn.WriteStatus(http.StatusInternalServerError)
   389  			b, _ := errors.New(errors.Internal, err.Error()).MarshalJSON()
   390  			_ = conn.WriteBinary(0, b)
   391  		}
   392  
   393  		return
   394  	}
   395  
   396  	// apply the transformation on the server message before sending it to the client
   397  	err = proxy.ServerMessage(conn, ctx)
   398  	if err != nil {
   399  		switch err := err.(type) {
   400  		case *rony.Error:
   401  			conn.WriteStatus(errors.Code(err.Code).HttpStatus())
   402  			b, _ := err.MarshalJSON()
   403  			_ = conn.WriteBinary(0, b)
   404  		default:
   405  			conn.WriteStatus(http.StatusInternalServerError)
   406  			b, _ := errors.New(errors.Internal, err.Error()).MarshalJSON()
   407  			_ = conn.WriteBinary(0, b)
   408  		}
   409  	}
   410  }
   411  func (edge *Server) onGatewayConnect(conn rony.Conn, kvs ...*rony.KeyValue) {
   412  	edge.dispatcher.OnOpen(conn, kvs...)
   413  }
   414  func (edge *Server) onGatewayClose(conn rony.Conn) {
   415  	edge.dispatcher.OnClose(conn)
   416  }
   417  func (edge *Server) onTunnelMessage(conn rony.Conn, tm *msg.TunnelMessage) {
   418  	// Fill the dispatch context envelope from the received tunnel message
   419  	dispatchCtx := acquireDispatchCtx(edge, conn, 0, tm.SenderID, TunnelMessage)
   420  	tm.Envelope.DeepCopy(dispatchCtx.req)
   421  
   422  	if err := edge.execute(dispatchCtx); err != nil {
   423  		edge.onError(dispatchCtx, errors.ErrInternalServer)
   424  	} else {
   425  		edge.onTunnelDone(dispatchCtx)
   426  	}
   427  
   428  	// Release the dispatch context
   429  	releaseDispatchCtx(dispatchCtx)
   430  }
   431  func (edge *Server) onTunnelDone(ctx *DispatchCtx) {
   432  	tm := msg.PoolTunnelMessage.Get()
   433  	defer msg.PoolTunnelMessage.Put(tm)
   434  	switch ctx.BufferSize() {
   435  	case 0:
   436  		return
   437  	case 1:
   438  		tm.SenderReplicaSet = edge.cluster.ReplicaSet()
   439  		tm.SenderID = edge.serverID
   440  		ctx.BufferPop(func(envelope *rony.MessageEnvelope) {
   441  			envelope.DeepCopy(tm.Envelope)
   442  			buf := pools.Buffer.FromProto(tm)
   443  			_ = ctx.Conn().WriteBinary(ctx.streamID, *buf.Bytes())
   444  			pools.Buffer.Put(buf)
   445  		})
   446  	default:
   447  		// TODO:: implement it
   448  		panic("not implemented, handle multiple tunnel message")
   449  	}
   450  }
   451  func (edge *Server) onError(ctx *DispatchCtx, err *rony.Error) {
   452  	envelope := rony.PoolMessageEnvelope.Get()
   453  	err.ToEnvelope(envelope)
   454  	switch ctx.kind {
   455  	case GatewayMessage:
   456  		_ = edge.dispatcher.Encode(ctx.conn, ctx.streamID, envelope)
   457  		rony.PoolMessageEnvelope.Put(envelope)
   458  	case TunnelMessage:
   459  		ctx.BufferPush(envelope)
   460  	}
   461  }
   462  
   463  // StartCluster is non-blocking function which runs the cluster component of the Edge server.
   464  func (edge *Server) StartCluster() (err error) {
   465  	if edge.cluster == nil {
   466  		edge.logger.Info("Cluster is NOT set",
   467  			zap.ByteString("ServerID", edge.serverID),
   468  		)
   469  
   470  		return errors.ErrClusterNotSet
   471  	}
   472  
   473  	err = edge.cluster.Start()
   474  	if err != nil {
   475  		return
   476  	}
   477  
   478  	edge.logger.Info("Cluster Started",
   479  		zap.ByteString("ServerID", edge.serverID),
   480  		zap.String("Cluster", edge.cluster.Addr()),
   481  		zap.Uint64("ReplicaSet", edge.cluster.ReplicaSet()),
   482  	)
   483  
   484  	return
   485  }
   486  
   487  // StartGateway is non-blocking function runs the gateway in background, so we can accept clients requests
   488  func (edge *Server) StartGateway() error {
   489  	if edge.gateway == nil {
   490  		edge.logger.Info("Gateway is NOT set",
   491  			zap.ByteString("ServerID", edge.serverID),
   492  		)
   493  
   494  		return errors.ErrGatewayNotSet
   495  	}
   496  	edge.gateway.Start()
   497  
   498  	edge.logger.Info("Gateway Started",
   499  		zap.ByteString("ServerID", edge.serverID),
   500  		zap.String("Protocol", edge.gateway.Protocol().String()),
   501  		zap.Strings("Addr", edge.gateway.Addr()),
   502  	)
   503  
   504  	if edge.cluster != nil {
   505  		return errors.WrapText("cluster:")(edge.cluster.SetGatewayAddrs(edge.gateway.Addr()))
   506  	}
   507  
   508  	return nil
   509  }
   510  
   511  // StartTunnel is non-blocking function runs the gateway in background, so we can accept other servers requests
   512  func (edge *Server) StartTunnel() error {
   513  	if edge.tunnel == nil {
   514  		edge.logger.Info("Tunnel is NOT set",
   515  			zap.ByteString("ServerID", edge.serverID),
   516  		)
   517  
   518  		return errors.ErrTunnelNotSet
   519  	}
   520  	edge.tunnel.Start()
   521  
   522  	edge.logger.Info("Tunnel Started",
   523  		zap.ByteString("ServerID", edge.serverID),
   524  		zap.Strings("Addr", edge.tunnel.Addr()),
   525  	)
   526  
   527  	if edge.cluster != nil {
   528  		return edge.cluster.SetTunnelAddrs(edge.tunnel.Addr())
   529  	}
   530  
   531  	return nil
   532  }
   533  
   534  // Start is a helper function which tries to start all three parts of the edge server
   535  // This function does not return any error, if you need to make sure all the parts are started with
   536  // no error, then you must start each section separately. i.e. use StartGateway, StartCluster and StartTunnel
   537  // functions.
   538  func (edge *Server) Start() {
   539  	if err := edge.StartCluster(); err != nil && err != errors.ErrClusterNotSet {
   540  		panic(err)
   541  	}
   542  	if err := edge.StartGateway(); err != nil && err != errors.ErrGatewayNotSet {
   543  		panic(err)
   544  	}
   545  	if err := edge.StartTunnel(); err != nil && err != errors.ErrTunnelNotSet {
   546  		panic(err)
   547  	}
   548  }
   549  
   550  // Shutdown gracefully shutdown the services
   551  func (edge *Server) Shutdown() {
   552  	// First shutdown gateway to not accept any more request
   553  	if edge.gateway != nil {
   554  		edge.gateway.Shutdown()
   555  	}
   556  
   557  	// Shutdown the cluster
   558  	if edge.cluster != nil {
   559  		edge.cluster.Shutdown()
   560  	}
   561  
   562  	// Shutdown the tunnel
   563  	if edge.tunnel != nil {
   564  		edge.tunnel.Shutdown()
   565  	}
   566  
   567  	edge.logger.Info("Server Shutdown!", zap.ByteString("ID", edge.serverID))
   568  }
   569  
   570  // ShutdownWithSignal blocks until any of the signals has been called
   571  func (edge *Server) ShutdownWithSignal(signals ...os.Signal) error {
   572  	edge.WaitForSignal(signals...)
   573  	if edge.cluster != nil {
   574  		if err := edge.cluster.Leave(); err != nil {
   575  			return err
   576  		}
   577  	}
   578  	edge.Shutdown()
   579  
   580  	return nil
   581  }
   582  
   583  func (edge *Server) WaitForSignal(signals ...os.Signal) {
   584  	ch := make(chan os.Signal, 1)
   585  	signal.Notify(ch, signals...)
   586  
   587  	// Wait for signal
   588  	<-ch
   589  }
   590  
   591  // GetGatewayConn return the gateway connection identified by connID or returns nil if not found.
   592  func (edge *Server) GetGatewayConn(connID uint64) rony.Conn {
   593  	if edge.gateway == nil {
   594  		return nil
   595  	}
   596  
   597  	conn := edge.gateway.GetConn(connID)
   598  	if conn == nil {
   599  		return nil
   600  	}
   601  
   602  	return conn
   603  }
   604  
   605  // TunnelRequest sends and receives a request through the Tunnel interface of the receiver Edge node.
   606  func (edge *Server) TunnelRequest(replicaSet uint64, req, res *rony.MessageEnvelope) error {
   607  	return edge.TryTunnelRequest(1, 0, replicaSet, req, res)
   608  }
   609  
   610  func (edge *Server) TryTunnelRequest(
   611  	attempts int, retryWait time.Duration, replicaSet uint64,
   612  	req, res *rony.MessageEnvelope,
   613  ) error {
   614  	if edge.tunnel == nil {
   615  		return errors.ErrTunnelNotSet
   616  	}
   617  	startTime := tools.CPUTicks()
   618  	err := tools.Try(attempts, retryWait, func() error {
   619  		target := edge.getReplicaMember(replicaSet)
   620  		if target == nil {
   621  			return errors.ErrMemberNotFound
   622  		}
   623  
   624  		return edge.sendRemoteCommand(target, req, res)
   625  	})
   626  	metrics.ObserveHistogram(
   627  		metrics.HistTunnelRoundTripTime,
   628  		float64(time.Duration(tools.CPUTicks()-startTime)/time.Millisecond),
   629  	)
   630  
   631  	return err
   632  }
   633  func (edge *Server) getReplicaMember(replicaSet uint64) (target rony.ClusterMember) {
   634  	members := edge.cluster.MembersByReplicaSet(replicaSet)
   635  	if len(members) == 0 {
   636  		return nil
   637  	}
   638  	for idx := range members {
   639  		target = members[idx]
   640  
   641  		break
   642  	}
   643  
   644  	return
   645  }
   646  func (edge *Server) sendRemoteCommand(target rony.ClusterMember, req, res *rony.MessageEnvelope) error {
   647  	conn, err := target.Dial()
   648  	if err != nil {
   649  		return err
   650  	}
   651  
   652  	// Get a rony.TunnelMessage from pool and put it back into the pool when we are done
   653  	tmOut := msg.PoolTunnelMessage.Get()
   654  	defer msg.PoolTunnelMessage.Put(tmOut)
   655  	tmIn := msg.PoolTunnelMessage.Get()
   656  	defer msg.PoolTunnelMessage.Put(tmIn)
   657  	tmOut.Fill(edge.serverID, edge.cluster.ReplicaSet(), req)
   658  
   659  	// Marshal and send over the wire
   660  	buf := pools.Buffer.FromProto(tmOut)
   661  	_, err = conn.Write(*buf.Bytes())
   662  	pools.Buffer.Put(buf)
   663  	if err != nil {
   664  		return err
   665  	}
   666  
   667  	// Wait for response and unmarshal it
   668  	buf = pools.Buffer.GetLen(4096)
   669  	_ = conn.SetReadDeadline(time.Now().Add(time.Second * 3))
   670  	n, err := bufio.NewReader(conn).Read(*buf.Bytes())
   671  	if err != nil || n == 0 {
   672  		return err
   673  	}
   674  	err = tmIn.Unmarshal((*buf.Bytes())[:n])
   675  	if err != nil {
   676  		return err
   677  	}
   678  	pools.Buffer.Put(buf)
   679  
   680  	// deep copy
   681  	tmIn.Envelope.DeepCopy(res)
   682  
   683  	return nil
   684  }
   685  
   686  type carrier struct {
   687  	c rony.RestConn
   688  }
   689  
   690  func (c *carrier) Get(key string) string {
   691  	v, _ := c.c.Get(tools.ToCamel(key)).(string)
   692  
   693  	return v
   694  }
   695  
   696  func (c *carrier) Set(key string, value string) {
   697  	c.c.Set(key, value)
   698  }
   699  
   700  func (c *carrier) Keys() []string {
   701  	var keys []string
   702  	c.c.Walk(func(k string, v interface{}) bool {
   703  		keys = append(keys, k)
   704  
   705  		return true
   706  	})
   707  
   708  	return keys
   709  }