github.com/matrixorigin/matrixone@v0.7.0/pkg/common/morpc/backend.go (about)

     1  // Copyright 2021 - 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package morpc
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"runtime"
    21  	"sync"
    22  	"sync/atomic"
    23  	"time"
    24  
    25  	"github.com/fagongzi/goetty/v2"
    26  	"github.com/google/uuid"
    27  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    28  	"github.com/matrixorigin/matrixone/pkg/common/stopper"
    29  	"github.com/matrixorigin/matrixone/pkg/logutil"
    30  	"github.com/matrixorigin/matrixone/pkg/util/errutil"
    31  	"go.uber.org/zap"
    32  )
    33  
    34  var (
    35  	stateRunning = int32(0)
    36  	stateStopped = int32(1)
    37  
    38  	backendClosed  = moerr.NewBackendClosedNoCtx()
    39  	messageSkipped = moerr.NewInvalidStateNoCtx("request is skipped")
    40  )
    41  
    42  // WithBackendLogger set the backend logger
    43  func WithBackendLogger(logger *zap.Logger) BackendOption {
    44  	return func(rb *remoteBackend) {
    45  		rb.logger = logger
    46  	}
    47  }
    48  
    49  // WithBackendBufferSize set the buffer size of the wait send chan.
    50  // Default is 1024.
    51  func WithBackendBufferSize(size int) BackendOption {
    52  	return func(rb *remoteBackend) {
    53  		rb.options.bufferSize = size
    54  	}
    55  }
    56  
    57  // WithBackendBusyBufferSize if len(writeC) >= size, backend is busy.
    58  // Default is 3/4 buffer size.
    59  func WithBackendBusyBufferSize(size int) BackendOption {
    60  	return func(rb *remoteBackend) {
    61  		rb.options.busySize = size
    62  	}
    63  }
    64  
    65  // WithBackendFilter set send fiter func. Input ready to send futures, output
    66  // is really need to be send futures.
    67  func WithBackendFilter(filter func(Message, string) bool) BackendOption {
    68  	return func(rb *remoteBackend) {
    69  		rb.options.filter = filter
    70  	}
    71  }
    72  
    73  // WithBackendBatchSendSize set the maximum number of messages to be sent together
    74  // at each batch. Default is 8.
    75  func WithBackendBatchSendSize(size int) BackendOption {
    76  	return func(rb *remoteBackend) {
    77  		rb.options.batchSendSize = size
    78  	}
    79  }
    80  
    81  // WithBackendConnectTimeout set the timeout for connect to remote. Default 10s.
    82  func WithBackendConnectTimeout(timeout time.Duration) BackendOption {
    83  	return func(rb *remoteBackend) {
    84  		rb.options.connectTimeout = timeout
    85  	}
    86  }
    87  
    88  // WithBackendHasPayloadResponse has payload response means read a response that hold
    89  // a slice of data in the read buffer to avoid data copy.
    90  func WithBackendHasPayloadResponse() BackendOption {
    91  	return func(rb *remoteBackend) {
    92  		rb.options.hasPayloadResponse = true
    93  	}
    94  }
    95  
    96  // WithBackendStreamBufferSize set buffer size for stream receive message chan
    97  func WithBackendStreamBufferSize(value int) BackendOption {
    98  	return func(rb *remoteBackend) {
    99  		rb.options.streamBufferSize = value
   100  	}
   101  }
   102  
   103  // WithBackendGoettyOptions set goetty connection options. e.g. set read/write buffer
   104  // size, adjust net.Conn attribute etc.
   105  func WithBackendGoettyOptions(options ...goetty.Option) BackendOption {
   106  	return func(rb *remoteBackend) {
   107  		rb.options.goettyOptions = options
   108  	}
   109  }
   110  
   111  type remoteBackend struct {
   112  	remote      string
   113  	logger      *zap.Logger
   114  	codec       Codec
   115  	conn        goetty.IOSession
   116  	writeC      chan *Future
   117  	stopWriteC  chan struct{}
   118  	resetConnC  chan struct{}
   119  	stopper     *stopper.Stopper
   120  	readStopper *stopper.Stopper
   121  	closeOnce   sync.Once
   122  
   123  	options struct {
   124  		hasPayloadResponse bool
   125  		goettyOptions      []goetty.Option
   126  		connectTimeout     time.Duration
   127  		bufferSize         int
   128  		busySize           int
   129  		batchSendSize      int
   130  		streamBufferSize   int
   131  		filter             func(msg Message, backendAddr string) bool
   132  	}
   133  
   134  	stateMu struct {
   135  		sync.RWMutex
   136  		state          int32
   137  		readLoopActive bool
   138  		locked         bool
   139  	}
   140  
   141  	mu struct {
   142  		sync.RWMutex
   143  		futures       map[uint64]*Future
   144  		activeStreams map[uint64]*stream
   145  	}
   146  
   147  	atomic struct {
   148  		id             uint64
   149  		lastActiveTime atomic.Value //time.Time
   150  	}
   151  
   152  	pool struct {
   153  		streams *sync.Pool
   154  		futures *sync.Pool
   155  	}
   156  }
   157  
   158  // NewRemoteBackend create a goetty connection based backend. This backend will start 2
   159  // goroutiune, one for read and one for write. If there is a network error in the underlying
   160  // goetty connection, it will automatically retry until the Future times out.
   161  func NewRemoteBackend(
   162  	remote string,
   163  	codec Codec,
   164  	options ...BackendOption) (Backend, error) {
   165  	rb := &remoteBackend{
   166  		stopper:     stopper.NewStopper(fmt.Sprintf("backend-write-%s", remote)),
   167  		readStopper: stopper.NewStopper(fmt.Sprintf("backend-read-%s", remote)),
   168  		remote:      remote,
   169  		codec:       codec,
   170  		resetConnC:  make(chan struct{}),
   171  		stopWriteC:  make(chan struct{}),
   172  	}
   173  
   174  	for _, opt := range options {
   175  		opt(rb)
   176  	}
   177  	rb.adjust()
   178  
   179  	rb.pool.futures = &sync.Pool{
   180  		New: func() interface{} {
   181  			return newFuture(rb.releaseFuture)
   182  		},
   183  	}
   184  	rb.pool.streams = &sync.Pool{
   185  		New: func() any {
   186  			return newStream(make(chan Message, rb.options.streamBufferSize),
   187  				rb.newFuture,
   188  				rb.doSend,
   189  				rb.removeActiveStream,
   190  				rb.active)
   191  		},
   192  	}
   193  	rb.writeC = make(chan *Future, rb.options.bufferSize)
   194  	rb.mu.futures = make(map[uint64]*Future, rb.options.bufferSize)
   195  	rb.mu.activeStreams = make(map[uint64]*stream, rb.options.bufferSize)
   196  	if rb.options.hasPayloadResponse {
   197  		rb.options.goettyOptions = append(rb.options.goettyOptions,
   198  			goetty.WithSessionDisableAutoResetInBuffer())
   199  	}
   200  	rb.conn = goetty.NewIOSession(rb.options.goettyOptions...)
   201  
   202  	if err := rb.resetConn(); err != nil {
   203  		rb.logger.Error("connect to remote failed", zap.Error(err))
   204  		return nil, err
   205  	}
   206  	rb.activeReadLoop(false)
   207  
   208  	if err := rb.stopper.RunTask(rb.writeLoop); err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	rb.active()
   213  	return rb, nil
   214  }
   215  
   216  func (rb *remoteBackend) adjust() {
   217  	if rb.options.bufferSize == 0 {
   218  		rb.options.bufferSize = 1024
   219  	}
   220  	if rb.options.busySize == 0 {
   221  		rb.options.busySize = rb.options.bufferSize * 3 / 4
   222  		if rb.options.busySize == 0 {
   223  			rb.options.busySize = 1
   224  		}
   225  	}
   226  	if rb.options.batchSendSize == 0 {
   227  		rb.options.batchSendSize = 8
   228  	}
   229  	if rb.options.connectTimeout == 0 {
   230  		rb.options.connectTimeout = time.Second * 10
   231  	}
   232  	if rb.options.streamBufferSize == 0 {
   233  		rb.options.streamBufferSize = 16
   234  	}
   235  	if rb.options.filter == nil {
   236  		rb.options.filter = func(Message, string) bool {
   237  			return true
   238  		}
   239  	}
   240  
   241  	rb.logger = logutil.Adjust(rb.logger).With(zap.String("remote", rb.remote),
   242  		zap.String("backend-id", uuid.NewString()))
   243  	rb.options.goettyOptions = append(rb.options.goettyOptions,
   244  		goetty.WithSessionCodec(rb.codec),
   245  		goetty.WithSessionLogger(rb.logger))
   246  }
   247  
   248  func (rb *remoteBackend) Send(ctx context.Context, request Message) (*Future, error) {
   249  	return rb.send(ctx, request, false)
   250  }
   251  
   252  func (rb *remoteBackend) SendInternal(ctx context.Context, request Message) (*Future, error) {
   253  	return rb.send(ctx, request, true)
   254  }
   255  
   256  func (rb *remoteBackend) send(ctx context.Context, request Message, internal bool) (*Future, error) {
   257  	rb.active()
   258  	request.SetID(rb.nextID())
   259  
   260  	f := rb.newFuture()
   261  	f.init(RPCMessage{Ctx: ctx, Message: request, internal: internal})
   262  	rb.addFuture(f)
   263  
   264  	if err := rb.doSend(f); err != nil {
   265  		f.Close()
   266  		return nil, err
   267  	}
   268  	return f, nil
   269  }
   270  
   271  func (rb *remoteBackend) NewStream(unlockAfterClose bool) (Stream, error) {
   272  	rb.active()
   273  	rb.stateMu.RLock()
   274  	defer rb.stateMu.RUnlock()
   275  
   276  	if rb.stateMu.state == stateStopped {
   277  		return nil, moerr.NewBackendClosedNoCtx()
   278  	}
   279  
   280  	rb.mu.Lock()
   281  	defer rb.mu.Unlock()
   282  
   283  	st := rb.acquireStream()
   284  	st.init(rb.nextID(), unlockAfterClose)
   285  	rb.mu.activeStreams[st.ID()] = st
   286  	return st, nil
   287  }
   288  
   289  func (rb *remoteBackend) doSend(f *Future) error {
   290  	if err := rb.codec.Valid(f.send.Message); err != nil {
   291  		return err
   292  	}
   293  
   294  	for {
   295  		rb.stateMu.RLock()
   296  		if rb.stateMu.state == stateStopped {
   297  			rb.stateMu.RUnlock()
   298  			return moerr.NewBackendClosedNoCtx()
   299  		}
   300  
   301  		// The close method need acquire the write lock, so we cannot block at here.
   302  		// The write loop may reset the backend's network link and may not be able to
   303  		// process writeC for a long time, causing the writeC buffer to reach its limit.
   304  		select {
   305  		case rb.writeC <- f:
   306  			rb.stateMu.RUnlock()
   307  			return nil
   308  		case <-f.send.Ctx.Done():
   309  			rb.stateMu.RUnlock()
   310  			return f.send.Ctx.Err()
   311  		default:
   312  			rb.stateMu.RUnlock()
   313  		}
   314  	}
   315  }
   316  
   317  func (rb *remoteBackend) Close() {
   318  	rb.stateMu.Lock()
   319  	if rb.stateMu.state == stateStopped {
   320  		rb.stateMu.Unlock()
   321  		return
   322  	}
   323  	rb.stateMu.state = stateStopped
   324  	rb.stopWriteLoop()
   325  	rb.stateMu.Unlock()
   326  
   327  	rb.stopper.Stop()
   328  	rb.doClose()
   329  }
   330  
   331  func (rb *remoteBackend) Busy() bool {
   332  	return len(rb.writeC) >= rb.options.busySize
   333  }
   334  
   335  func (rb *remoteBackend) LastActiveTime() time.Time {
   336  	return rb.atomic.lastActiveTime.Load().(time.Time)
   337  }
   338  
   339  func (rb *remoteBackend) Lock() {
   340  	rb.stateMu.Lock()
   341  	defer rb.stateMu.Unlock()
   342  	if rb.stateMu.locked {
   343  		panic("backend is already locked")
   344  	}
   345  	rb.stateMu.locked = true
   346  }
   347  
   348  func (rb *remoteBackend) Unlock() {
   349  	rb.stateMu.Lock()
   350  	defer rb.stateMu.Unlock()
   351  	if !rb.stateMu.locked {
   352  		panic("backend is not locked")
   353  	}
   354  	rb.stateMu.locked = false
   355  }
   356  
   357  func (rb *remoteBackend) Locked() bool {
   358  	rb.stateMu.RLock()
   359  	defer rb.stateMu.RUnlock()
   360  	return rb.stateMu.locked
   361  }
   362  
   363  func (rb *remoteBackend) active() {
   364  	now := time.Now()
   365  	rb.atomic.lastActiveTime.Store(now)
   366  }
   367  
   368  func (rb *remoteBackend) inactive() {
   369  	rb.atomic.lastActiveTime.Store(time.Time{})
   370  }
   371  
   372  func (rb *remoteBackend) writeLoop(ctx context.Context) {
   373  	rb.logger.Info("write loop started")
   374  	defer func() {
   375  		rb.readStopper.Stop()
   376  		rb.closeConn(true)
   377  		rb.logger.Info("write loop stopped")
   378  	}()
   379  
   380  	defer func() {
   381  		rb.makeAllWritesDoneWithClosed(ctx)
   382  		close(rb.writeC)
   383  	}()
   384  
   385  	messages := make([]*Future, 0, rb.options.batchSendSize)
   386  	stopped := false
   387  	for {
   388  		messages, stopped = rb.fetch(ctx, messages, rb.options.batchSendSize)
   389  		if len(messages) > 0 {
   390  			written := 0
   391  			writeTimeout := time.Duration(0)
   392  			for _, f := range messages {
   393  				id := f.getSendMessageID()
   394  				if stopped {
   395  					f.messageSended(backendClosed)
   396  					continue
   397  				}
   398  
   399  				if v := rb.doWrite(ctx, id, f); v > 0 {
   400  					writeTimeout += v
   401  					written++
   402  				}
   403  			}
   404  
   405  			if written > 0 {
   406  				if err := rb.conn.Flush(writeTimeout); err != nil {
   407  					for _, f := range messages {
   408  						if rb.options.filter(f.send.Message, rb.remote) {
   409  							id := f.getSendMessageID()
   410  							rb.logger.Error("write request failed",
   411  								zap.Uint64("request-id", id),
   412  								zap.Error(err))
   413  							f.messageSended(err)
   414  						}
   415  					}
   416  				}
   417  			}
   418  
   419  			for _, m := range messages {
   420  				m.messageSended(nil)
   421  			}
   422  		}
   423  		if stopped {
   424  			return
   425  		}
   426  	}
   427  }
   428  
   429  func (rb *remoteBackend) doWrite(ctx context.Context, id uint64, f *Future) time.Duration {
   430  	if !rb.options.filter(f.send.Message, rb.remote) {
   431  		f.messageSended(messageSkipped)
   432  		return 0
   433  	}
   434  	// already timeout in future, and future will get a ctx timeout
   435  	if f.send.Timeout() {
   436  		f.messageSended(f.send.Ctx.Err())
   437  		return 0
   438  	}
   439  
   440  	v, err := f.send.GetTimeoutFromContext()
   441  	if err != nil {
   442  		f.messageSended(err)
   443  		return 0
   444  	}
   445  
   446  	// For PayloadMessage, the internal Codec will write the Payload directly to the underlying socket
   447  	// instead of copying it to the buffer, so the write deadline of the underlying conn needs to be reset
   448  	// here, otherwise an old deadline will be out causing io/timeout.
   449  	conn := rb.conn.RawConn()
   450  	if _, ok := f.send.Message.(PayloadMessage); ok && conn != nil {
   451  		conn.SetWriteDeadline(time.Now().Add(v))
   452  	}
   453  	if ce := rb.logger.Check(zap.DebugLevel, "write request"); ce != nil {
   454  		ce.Write(zap.Uint64("request-id", id),
   455  			zap.String("request", f.send.Message.DebugString()))
   456  	}
   457  	if err := rb.conn.Write(f.send, goetty.WriteOptions{}); err != nil {
   458  		rb.logger.Error("write request failed",
   459  			zap.Uint64("request-id", id),
   460  			zap.Error(err))
   461  		f.messageSended(err)
   462  		return 0
   463  	}
   464  	return v
   465  }
   466  
   467  func (rb *remoteBackend) readLoop(ctx context.Context) {
   468  	rb.logger.Info("read loop started")
   469  	defer rb.logger.Error("read loop stopped")
   470  
   471  	wg := &sync.WaitGroup{}
   472  	var cb func()
   473  	if rb.options.hasPayloadResponse {
   474  		cb = wg.Done
   475  	}
   476  
   477  	for {
   478  		select {
   479  		case <-ctx.Done():
   480  			rb.clean()
   481  			return
   482  		default:
   483  			msg, err := rb.conn.Read(goetty.ReadOptions{})
   484  			if err != nil {
   485  				rb.logger.Error("read from backend failed",
   486  					zap.Error(err))
   487  				rb.inactiveReadLoop()
   488  				rb.cancelActiveStreams()
   489  				rb.scheduleResetConn()
   490  				return
   491  			}
   492  
   493  			rb.active()
   494  
   495  			if rb.options.hasPayloadResponse {
   496  				wg.Add(1)
   497  			}
   498  			resp := msg.(RPCMessage).Message
   499  			rb.requestDone(ctx, resp.GetID(), msg.(RPCMessage), nil, cb)
   500  			if rb.options.hasPayloadResponse {
   501  				wg.Wait()
   502  			}
   503  		}
   504  	}
   505  }
   506  
   507  func (rb *remoteBackend) fetch(ctx context.Context,
   508  	messages []*Future,
   509  	maxFetchCount int) ([]*Future, bool) {
   510  	n := len(messages)
   511  	for i := 0; i < n; i++ {
   512  		messages[i] = nil
   513  	}
   514  	messages = messages[:0]
   515  	select {
   516  	case f := <-rb.writeC:
   517  		messages = append(messages, f)
   518  		n := maxFetchCount - 1
   519  	OUTER:
   520  		for i := 0; i < n; i++ {
   521  			select {
   522  			case f := <-rb.writeC:
   523  				messages = append(messages, f)
   524  			default:
   525  				break OUTER
   526  			}
   527  		}
   528  	case <-rb.resetConnC:
   529  		rb.handleResetConn()
   530  	case <-rb.stopWriteC:
   531  		return messages, true
   532  	}
   533  	return messages, false
   534  }
   535  
   536  func (rb *remoteBackend) makeAllWritesDoneWithClosed(ctx context.Context) {
   537  	for {
   538  		select {
   539  		case m := <-rb.writeC:
   540  			m.messageSended(backendClosed)
   541  		default:
   542  			return
   543  		}
   544  	}
   545  }
   546  
   547  func (rb *remoteBackend) handleResetConn() {
   548  	if err := rb.resetConn(); err != nil {
   549  		rb.logger.Error("fail to reset backend connection",
   550  			zap.Error(err))
   551  		rb.inactive()
   552  	}
   553  }
   554  
   555  func (rb *remoteBackend) doClose() {
   556  	rb.closeOnce.Do(func() {
   557  		close(rb.resetConnC)
   558  		rb.closeConn(false)
   559  	})
   560  }
   561  
   562  func (rb *remoteBackend) clean() {
   563  	rb.mu.Lock()
   564  	defer rb.mu.Unlock()
   565  
   566  	for id := range rb.mu.futures {
   567  		delete(rb.mu.futures, id)
   568  	}
   569  }
   570  
   571  func (rb *remoteBackend) acquireStream() *stream {
   572  	return rb.pool.streams.Get().(*stream)
   573  }
   574  
   575  func (rb *remoteBackend) cancelActiveStreams() {
   576  	rb.mu.Lock()
   577  	defer rb.mu.Unlock()
   578  
   579  	for _, st := range rb.mu.activeStreams {
   580  		st.done(RPCMessage{})
   581  	}
   582  }
   583  
   584  func (rb *remoteBackend) removeActiveStream(s *stream) {
   585  	rb.mu.Lock()
   586  	defer rb.mu.Unlock()
   587  
   588  	delete(rb.mu.activeStreams, s.id)
   589  	delete(rb.mu.futures, s.id)
   590  	if s.unlockAfterClose {
   591  		rb.Unlock()
   592  	}
   593  	rb.pool.streams.Put(s)
   594  }
   595  
   596  func (rb *remoteBackend) stopWriteLoop() {
   597  	rb.closeConn(false)
   598  	close(rb.stopWriteC)
   599  }
   600  
   601  func (rb *remoteBackend) requestDone(ctx context.Context, id uint64, msg RPCMessage, err error, cb func()) {
   602  	response := msg.Message
   603  	if ce := rb.logger.Check(zap.DebugLevel, "read response"); ce != nil {
   604  		debugStr := ""
   605  		if response != nil {
   606  			debugStr = response.DebugString()
   607  		}
   608  		ce.Write(zap.Uint64("request-id", id),
   609  			zap.String("response", debugStr),
   610  			zap.Error(err))
   611  	}
   612  
   613  	rb.mu.Lock()
   614  	if f, ok := rb.mu.futures[id]; ok {
   615  		delete(rb.mu.futures, id)
   616  		rb.mu.Unlock()
   617  		if err == nil {
   618  			f.done(response, cb)
   619  		} else {
   620  			errutil.ReportError(ctx, err)
   621  			f.error(id, err, cb)
   622  		}
   623  	} else if st, ok := rb.mu.activeStreams[id]; ok {
   624  		rb.mu.Unlock()
   625  		if response != nil {
   626  			st.done(msg)
   627  		}
   628  	} else {
   629  		// future has been removed, e.g. it has timed out.
   630  		rb.mu.Unlock()
   631  		if cb != nil {
   632  			cb()
   633  		}
   634  	}
   635  }
   636  
   637  func (rb *remoteBackend) addFuture(f *Future) {
   638  	rb.mu.Lock()
   639  	defer rb.mu.Unlock()
   640  
   641  	f.ref()
   642  	rb.mu.futures[f.getSendMessageID()] = f
   643  }
   644  
   645  func (rb *remoteBackend) releaseFuture(f *Future) {
   646  	rb.mu.Lock()
   647  	defer rb.mu.Unlock()
   648  
   649  	delete(rb.mu.futures, f.getSendMessageID())
   650  	f.reset()
   651  	rb.pool.futures.Put(f)
   652  }
   653  
   654  func (rb *remoteBackend) resetConn() error {
   655  	rb.stateMu.Lock()
   656  	defer rb.stateMu.Unlock()
   657  
   658  	start := time.Now()
   659  	wait := time.Second
   660  	sleep := time.Millisecond * 200
   661  	for {
   662  		if !rb.runningLocked() {
   663  			return moerr.NewBackendClosedNoCtx()
   664  		}
   665  
   666  		rb.logger.Info("start connect to remote")
   667  		rb.closeConn(false)
   668  		err := rb.conn.Connect(rb.remote, rb.options.connectTimeout)
   669  		if err == nil {
   670  			rb.logger.Info("connect to remote succeed")
   671  			rb.activeReadLoop(true)
   672  			return nil
   673  		}
   674  		rb.logger.Error("init remote connection failed, retry later",
   675  			zap.Error(err))
   676  
   677  		duration := time.Duration(0)
   678  		for {
   679  			time.Sleep(sleep)
   680  			duration += sleep
   681  			if time.Since(start) > rb.options.connectTimeout {
   682  				return moerr.NewBackendClosedNoCtx()
   683  			}
   684  			if duration >= wait {
   685  				break
   686  			}
   687  		}
   688  		wait += wait / 2
   689  	}
   690  }
   691  
   692  func (rb *remoteBackend) activeReadLoop(locked bool) {
   693  	if !locked {
   694  		rb.stateMu.Lock()
   695  		defer rb.stateMu.Unlock()
   696  	}
   697  
   698  	if rb.stateMu.readLoopActive {
   699  		return
   700  	}
   701  
   702  	if err := rb.readStopper.RunTask(rb.readLoop); err != nil {
   703  		rb.logger.Error("active read loop failed",
   704  			zap.Error(err))
   705  		return
   706  	}
   707  	rb.stateMu.readLoopActive = true
   708  }
   709  
   710  func (rb *remoteBackend) inactiveReadLoop() {
   711  	rb.stateMu.Lock()
   712  	defer rb.stateMu.Unlock()
   713  
   714  	rb.stateMu.readLoopActive = false
   715  }
   716  
   717  func (rb *remoteBackend) runningLocked() bool {
   718  	return rb.stateMu.state == stateRunning
   719  }
   720  
   721  func (rb *remoteBackend) scheduleResetConn() {
   722  	rb.stateMu.RLock()
   723  	defer rb.stateMu.RUnlock()
   724  
   725  	if !rb.runningLocked() {
   726  		return
   727  	}
   728  
   729  	select {
   730  	case rb.resetConnC <- struct{}{}:
   731  		rb.logger.Debug("schedule reset remote connection")
   732  	case <-time.After(time.Second * 10):
   733  		rb.logger.Fatal("BUG: schedule reset remote connection timeout")
   734  	}
   735  }
   736  
   737  func (rb *remoteBackend) closeConn(close bool) {
   738  	fn := rb.conn.Disconnect
   739  	if close {
   740  		fn = rb.conn.Close
   741  	}
   742  
   743  	if err := fn(); err != nil {
   744  		rb.logger.Error("close remote conn failed",
   745  			zap.Error(err))
   746  	}
   747  }
   748  
   749  func (rb *remoteBackend) newFuture() *Future {
   750  	return rb.pool.futures.Get().(*Future)
   751  }
   752  
   753  func (rb *remoteBackend) nextID() uint64 {
   754  	return atomic.AddUint64(&rb.atomic.id, 1)
   755  }
   756  
   757  type goettyBasedBackendFactory struct {
   758  	codec   Codec
   759  	options []BackendOption
   760  }
   761  
   762  func NewGoettyBasedBackendFactory(codec Codec, options ...BackendOption) BackendFactory {
   763  	return &goettyBasedBackendFactory{
   764  		codec:   codec,
   765  		options: options,
   766  	}
   767  }
   768  
   769  func (bf *goettyBasedBackendFactory) Create(remote string) (Backend, error) {
   770  	return NewRemoteBackend(remote, bf.codec, bf.options...)
   771  }
   772  
   773  type stream struct {
   774  	c                chan Message
   775  	sendFunc         func(*Future) error
   776  	activeFunc       func()
   777  	unregisterFunc   func(*stream)
   778  	newFutureFunc    func() *Future
   779  	unlockAfterClose bool
   780  	ctx              context.Context
   781  	cancel           context.CancelFunc
   782  
   783  	// reset fields
   784  	id                   uint64
   785  	sequence             uint32
   786  	lastReceivedSequence uint32
   787  	mu                   struct {
   788  		sync.RWMutex
   789  		closed bool
   790  	}
   791  }
   792  
   793  func newStream(
   794  	c chan Message,
   795  	acquireFutureFunc func() *Future,
   796  	sendFunc func(*Future) error,
   797  	unregisterFunc func(*stream),
   798  	activeFunc func()) *stream {
   799  	ctx, cancel := context.WithCancel(context.Background())
   800  	s := &stream{
   801  		c:              c,
   802  		ctx:            ctx,
   803  		cancel:         cancel,
   804  		sendFunc:       sendFunc,
   805  		unregisterFunc: unregisterFunc,
   806  		activeFunc:     activeFunc,
   807  		newFutureFunc:  acquireFutureFunc,
   808  	}
   809  	s.setFinalizer()
   810  	return s
   811  }
   812  
   813  func (s *stream) init(id uint64, unlockAfterClose bool) {
   814  	s.id = id
   815  	s.sequence = 0
   816  	s.unlockAfterClose = unlockAfterClose
   817  	s.lastReceivedSequence = 0
   818  	s.mu.closed = false
   819  	for {
   820  		select {
   821  		case <-s.c:
   822  		default:
   823  			return
   824  		}
   825  	}
   826  }
   827  
   828  func (s *stream) setFinalizer() {
   829  	runtime.SetFinalizer(s, func(s *stream) {
   830  		s.destroy()
   831  	})
   832  }
   833  
   834  func (s *stream) destroy() {
   835  	close(s.c)
   836  	s.cancel()
   837  }
   838  
   839  func (s *stream) Send(ctx context.Context, request Message) error {
   840  	if s.id != request.GetID() {
   841  		panic("request.id != stream.id")
   842  	}
   843  	if _, ok := ctx.Deadline(); !ok {
   844  		panic("deadline not set in context")
   845  	}
   846  	s.activeFunc()
   847  
   848  	f := s.newFutureFunc()
   849  	f.ref()
   850  	defer f.Close()
   851  
   852  	s.mu.RLock()
   853  	if s.mu.closed {
   854  		s.mu.RUnlock()
   855  		return moerr.NewStreamClosedNoCtx()
   856  	}
   857  
   858  	err := s.doSendLocked(ctx, f, request)
   859  	// unlock before future.close to avoid deadlock with future.Close
   860  	// 1. current goroutine:        stream.Rlock
   861  	// 2. backend read goroutine:   cancelActiveStream -> backend.Lock
   862  	// 3. backend read goroutine:   cancelActiveStream -> stream.Lock : deadlock here
   863  	// 4. current goroutine:        f.Close -> backend.Lock           : deadlock here
   864  	s.mu.RUnlock()
   865  
   866  	if err != nil {
   867  		return err
   868  	}
   869  	// stream only wait send completed
   870  	return f.waitSendCompleted()
   871  }
   872  
   873  func (s *stream) doSendLocked(
   874  	ctx context.Context,
   875  	f *Future,
   876  	request Message) error {
   877  	s.sequence++
   878  	f.init(RPCMessage{
   879  		Ctx:            ctx,
   880  		Message:        request,
   881  		stream:         true,
   882  		streamSequence: s.sequence,
   883  	})
   884  
   885  	return s.sendFunc(f)
   886  }
   887  
   888  func (s *stream) Receive() (chan Message, error) {
   889  	s.mu.RLock()
   890  	defer s.mu.RUnlock()
   891  	if s.mu.closed {
   892  		return nil, moerr.NewStreamClosedNoCtx()
   893  	}
   894  	return s.c, nil
   895  }
   896  
   897  func (s *stream) Close() error {
   898  	s.mu.Lock()
   899  	defer s.mu.Unlock()
   900  
   901  	if s.mu.closed {
   902  		return nil
   903  	}
   904  
   905  	// the stream is reuseable, so use nil to notify stream is closed
   906  	s.c <- nil
   907  	s.mu.closed = true
   908  	s.unregisterFunc(s)
   909  	return nil
   910  }
   911  
   912  func (s *stream) ID() uint64 {
   913  	return s.id
   914  }
   915  
   916  func (s *stream) done(message RPCMessage) {
   917  	s.mu.Lock()
   918  	defer s.mu.Unlock()
   919  
   920  	if s.mu.closed {
   921  		return
   922  	}
   923  
   924  	response := message.Message
   925  	if response != nil && !message.stream {
   926  		panic("BUG")
   927  	}
   928  	if response != nil &&
   929  		message.streamSequence != s.lastReceivedSequence+1 {
   930  		response = nil
   931  	}
   932  
   933  	s.lastReceivedSequence = message.streamSequence
   934  	s.c <- response
   935  }