github.com/ledgerwatch/erigon-lib@v1.0.0/kv/remotedbserver/remotedbserver.go (about)

     1  /*
     2     Copyright 2021 Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package remotedbserver
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"reflect"
    26  	"sync"
    27  	"sync/atomic"
    28  	"time"
    29  
    30  	"github.com/ledgerwatch/log/v3"
    31  	"google.golang.org/protobuf/proto"
    32  	"google.golang.org/protobuf/types/known/emptypb"
    33  
    34  	"github.com/ledgerwatch/erigon-lib/common"
    35  	"github.com/ledgerwatch/erigon-lib/common/dbg"
    36  	"github.com/ledgerwatch/erigon-lib/common/hexutility"
    37  	"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
    38  	"github.com/ledgerwatch/erigon-lib/gointerfaces/types"
    39  	"github.com/ledgerwatch/erigon-lib/kv"
    40  	"github.com/ledgerwatch/erigon-lib/kv/iter"
    41  	"github.com/ledgerwatch/erigon-lib/kv/order"
    42  )
    43  
    44  // MaxTxTTL - kv interface provide high-consistancy guaranties: Serializable Isolations Level https://en.wikipedia.org/wiki/Isolation_(database_systems)
    45  // But it comes with cost: DB will start grow if run too long read transactions (hours)
    46  // We decided limit TTL of transaction to `MaxTxTTL`
    47  //
    48  // It means you sill have `Serializable` if tx living < `MaxTxTTL`
    49  // You start have Read Committed Level if tx living > `MaxTxTTL`
    50  //
    51  // It's done by `renew` method: after `renew` call reader will see all changes committed after last `renew` call.
    52  //
    53  // Erigon has much Historical data - which is immutable: reading of historical data for hours still gives you consistant data.
    54  const MaxTxTTL = 60 * time.Second
    55  
    56  // KvServiceAPIVersion - use it to track changes in API
    57  // 1.1.0 - added pending transactions, add methods eth_getRawTransactionByHash, eth_retRawTransactionByBlockHashAndIndex, eth_retRawTransactionByBlockNumberAndIndex| Yes     |                                            |
    58  // 1.2.0 - Added separated services for mining and txpool methods
    59  // 2.0.0 - Rename all buckets
    60  // 3.0.0 - ??
    61  // 4.0.0 - Server send tx.ViewID() after open tx
    62  // 5.0 - BlockTransaction table now has canonical ids (txs of non-canonical blocks moving to NonCanonicalTransaction table)
    63  // 5.1.0 - Added blockGasLimit to the StateChangeBatch
    64  // 6.0.0 - Blocks now have system-txs - in the begin/end of block
    65  // 6.1.0 - Add methods Range, IndexRange, HistoryGet, HistoryRange
    66  // 6.2.0 - Add HistoryFiles to reply of Snapshots() method
    67  var KvServiceAPIVersion = &types.VersionReply{Major: 6, Minor: 2, Patch: 0}
    68  
    69  type KvServer struct {
    70  	remote.UnimplementedKVServer // must be embedded to have forward compatible implementations.
    71  
    72  	kv                 kv.RoDB
    73  	stateChangeStreams *StateChangePubSub
    74  	blockSnapshots     Snapsthots
    75  	historySnapshots   Snapsthots
    76  	ctx                context.Context
    77  
    78  	//v3 fields
    79  	txIdGen    atomic.Uint64
    80  	txsMapLock *sync.RWMutex
    81  	txs        map[uint64]*threadSafeTx
    82  
    83  	trace     bool
    84  	rangeStep int // make sure `s.with` has limited time
    85  	logger    log.Logger
    86  }
    87  
    88  type threadSafeTx struct {
    89  	kv.Tx
    90  	sync.Mutex
    91  }
    92  
    93  type Snapsthots interface {
    94  	Files() []string
    95  }
    96  
    97  func NewKvServer(ctx context.Context, db kv.RoDB, snapshots Snapsthots, historySnapshots Snapsthots, logger log.Logger) *KvServer {
    98  	return &KvServer{
    99  		trace:     false,
   100  		rangeStep: 1024,
   101  		kv:        db, stateChangeStreams: newStateChangeStreams(), ctx: ctx,
   102  		blockSnapshots: snapshots, historySnapshots: historySnapshots,
   103  		txs: map[uint64]*threadSafeTx{}, txsMapLock: &sync.RWMutex{},
   104  		logger: logger,
   105  	}
   106  }
   107  
   108  // Version returns the service-side interface version number
   109  func (s *KvServer) Version(context.Context, *emptypb.Empty) (*types.VersionReply, error) {
   110  	dbSchemaVersion := &kv.DBSchemaVersion
   111  	if KvServiceAPIVersion.Major > dbSchemaVersion.Major {
   112  		return KvServiceAPIVersion, nil
   113  	}
   114  	if dbSchemaVersion.Major > KvServiceAPIVersion.Major {
   115  		return dbSchemaVersion, nil
   116  	}
   117  	if KvServiceAPIVersion.Minor > dbSchemaVersion.Minor {
   118  		return KvServiceAPIVersion, nil
   119  	}
   120  	if dbSchemaVersion.Minor > KvServiceAPIVersion.Minor {
   121  		return dbSchemaVersion, nil
   122  	}
   123  	return dbSchemaVersion, nil
   124  }
   125  
   126  func (s *KvServer) begin(ctx context.Context) (id uint64, err error) {
   127  	if s.trace {
   128  		s.logger.Info(fmt.Sprintf("[kv_server] begin %d %s\n", id, dbg.Stack()))
   129  	}
   130  	s.txsMapLock.Lock()
   131  	defer s.txsMapLock.Unlock()
   132  	tx, errBegin := s.kv.BeginRo(ctx)
   133  	if errBegin != nil {
   134  		return 0, errBegin
   135  	}
   136  	id = s.txIdGen.Add(1)
   137  	s.txs[id] = &threadSafeTx{Tx: tx}
   138  	return id, nil
   139  }
   140  
   141  // renew - rollback and begin tx without changing it's `id`
   142  func (s *KvServer) renew(ctx context.Context, id uint64) (err error) {
   143  	if s.trace {
   144  		s.logger.Info(fmt.Sprintf("[kv_server] renew %d %s\n", id, dbg.Stack()[:2]))
   145  	}
   146  	s.txsMapLock.Lock()
   147  	defer s.txsMapLock.Unlock()
   148  	tx, ok := s.txs[id]
   149  	if ok {
   150  		tx.Lock()
   151  		defer tx.Unlock()
   152  		tx.Rollback()
   153  	}
   154  	newTx, errBegin := s.kv.BeginRo(ctx)
   155  	if errBegin != nil {
   156  		return fmt.Errorf("kvserver: %w", err)
   157  	}
   158  	s.txs[id] = &threadSafeTx{Tx: newTx}
   159  	return nil
   160  }
   161  
   162  func (s *KvServer) rollback(id uint64) {
   163  	if s.trace {
   164  		s.logger.Info(fmt.Sprintf("[kv_server] rollback %d %s\n", id, dbg.Stack()[:2]))
   165  	}
   166  	s.txsMapLock.Lock()
   167  	defer s.txsMapLock.Unlock()
   168  	tx, ok := s.txs[id]
   169  	if ok {
   170  		tx.Lock()
   171  		defer tx.Unlock()
   172  		tx.Rollback()
   173  		delete(s.txs, id)
   174  	}
   175  }
   176  
   177  // with - provides exclusive access to `tx` object. Use it if you need open Cursor or run another method of `tx` object.
   178  // it's ok to use same `kv.RoTx` from different goroutines, but such use must be guarded by `with` method.
   179  //
   180  //	!Important: client may open multiple Cursors and multiple Streams on same `tx` in same time
   181  //	it means server must do limited amount of work inside `with` method (periodically release `tx` for other streams)
   182  //	long-living server-side streams must read limited-portion of data inside `with`, send this portion to
   183  //	client, portion of data it to client, then read next portion in another `with` call.
   184  //	It will allow cooperative access to `tx` object
   185  func (s *KvServer) with(id uint64, f func(kv.Tx) error) error {
   186  	s.txsMapLock.RLock()
   187  	tx, ok := s.txs[id]
   188  	s.txsMapLock.RUnlock()
   189  	if !ok {
   190  		return fmt.Errorf("txn %d already rollback", id)
   191  	}
   192  
   193  	if s.trace {
   194  		s.logger.Info(fmt.Sprintf("[kv_server] with %d try lock %s\n", id, dbg.Stack()[:2]))
   195  	}
   196  	tx.Lock()
   197  	if s.trace {
   198  		s.logger.Info(fmt.Sprintf("[kv_server] with %d can lock %s\n", id, dbg.Stack()[:2]))
   199  	}
   200  	defer func() {
   201  		tx.Unlock()
   202  		if s.trace {
   203  			s.logger.Info(fmt.Sprintf("[kv_server] with %d unlock %s\n", id, dbg.Stack()[:2]))
   204  		}
   205  	}()
   206  	return f(tx.Tx)
   207  }
   208  
   209  func (s *KvServer) Tx(stream remote.KV_TxServer) error {
   210  	id, errBegin := s.begin(stream.Context())
   211  	if errBegin != nil {
   212  		return fmt.Errorf("server-side error: %w", errBegin)
   213  	}
   214  	defer s.rollback(id)
   215  
   216  	var viewID uint64
   217  	if err := s.with(id, func(tx kv.Tx) error {
   218  		viewID = tx.ViewID()
   219  		return nil
   220  	}); err != nil {
   221  		return fmt.Errorf("kvserver: %w", err)
   222  	}
   223  	if err := stream.Send(&remote.Pair{ViewId: viewID, TxId: id}); err != nil {
   224  		return fmt.Errorf("server-side error: %w", err)
   225  	}
   226  
   227  	var CursorID uint32
   228  	type CursorInfo struct {
   229  		bucket string
   230  		c      kv.Cursor
   231  		k, v   []byte //fields to save current position of cursor - used when Tx reopen
   232  	}
   233  	cursors := map[uint32]*CursorInfo{}
   234  
   235  	txTicker := time.NewTicker(MaxTxTTL)
   236  	defer txTicker.Stop()
   237  
   238  	// send all items to client, if k==nil - still send it to client and break loop
   239  	for {
   240  		in, recvErr := stream.Recv()
   241  		if recvErr != nil {
   242  			if errors.Is(recvErr, io.EOF) { // termination
   243  				return nil
   244  			}
   245  			return fmt.Errorf("server-side error: %w", recvErr)
   246  		}
   247  
   248  		//TODO: protect against client - which doesn't send any requests
   249  		select {
   250  		default:
   251  		case <-txTicker.C:
   252  			for _, c := range cursors { // save positions of cursor, will restore after Tx reopening
   253  				k, v, err := c.c.Current()
   254  				if err != nil {
   255  					return fmt.Errorf("kvserver: %w", err)
   256  				}
   257  				c.k = bytesCopy(k)
   258  				c.v = bytesCopy(v)
   259  			}
   260  
   261  			if err := s.renew(stream.Context(), id); err != nil {
   262  				return err
   263  			}
   264  			if err := s.with(id, func(tx kv.Tx) error {
   265  				for _, c := range cursors { // restore all cursors position
   266  					var err error
   267  					c.c, err = tx.Cursor(c.bucket)
   268  					if err != nil {
   269  						return err
   270  					}
   271  					switch casted := c.c.(type) {
   272  					case kv.CursorDupSort:
   273  						v, err := casted.SeekBothRange(c.k, c.v)
   274  						if err != nil {
   275  							return fmt.Errorf("server-side error: %w", err)
   276  						}
   277  						if v == nil { // it may happen that key where we stopped disappeared after transaction reopen, then just move to next key
   278  							_, _, err = casted.Next()
   279  							if err != nil {
   280  								return fmt.Errorf("server-side error: %w", err)
   281  							}
   282  						}
   283  					case kv.Cursor:
   284  						if _, _, err := c.c.Seek(c.k); err != nil {
   285  							return fmt.Errorf("server-side error: %w", err)
   286  						}
   287  					}
   288  				}
   289  				return nil
   290  			}); err != nil {
   291  				return err
   292  			}
   293  		}
   294  
   295  		var c kv.Cursor
   296  		if in.BucketName == "" {
   297  			cInfo, ok := cursors[in.Cursor]
   298  			if !ok {
   299  				return fmt.Errorf("server-side error: unknown Cursor=%d, Op=%s", in.Cursor, in.Op)
   300  			}
   301  			c = cInfo.c
   302  		}
   303  		switch in.Op {
   304  		case remote.Op_OPEN:
   305  			CursorID++
   306  			var err error
   307  			if err := s.with(id, func(tx kv.Tx) error {
   308  				c, err = tx.Cursor(in.BucketName)
   309  				if err != nil {
   310  					return err
   311  				}
   312  				return nil
   313  			}); err != nil {
   314  				return fmt.Errorf("kvserver: %w", err)
   315  			}
   316  			cursors[CursorID] = &CursorInfo{
   317  				bucket: in.BucketName,
   318  				c:      c,
   319  			}
   320  			if err := stream.Send(&remote.Pair{CursorId: CursorID}); err != nil {
   321  				return fmt.Errorf("kvserver: %w", err)
   322  			}
   323  			continue
   324  		case remote.Op_OPEN_DUP_SORT:
   325  			CursorID++
   326  			var err error
   327  			if err := s.with(id, func(tx kv.Tx) error {
   328  				c, err = tx.CursorDupSort(in.BucketName)
   329  				if err != nil {
   330  					return err
   331  				}
   332  				return nil
   333  			}); err != nil {
   334  				return fmt.Errorf("kvserver: %w", err)
   335  			}
   336  			cursors[CursorID] = &CursorInfo{
   337  				bucket: in.BucketName,
   338  				c:      c,
   339  			}
   340  			if err := stream.Send(&remote.Pair{CursorId: CursorID}); err != nil {
   341  				return fmt.Errorf("server-side error: %w", err)
   342  			}
   343  			continue
   344  		case remote.Op_CLOSE:
   345  			cInfo, ok := cursors[in.Cursor]
   346  			if !ok {
   347  				return fmt.Errorf("server-side error: unknown Cursor=%d, Op=%s", in.Cursor, in.Op)
   348  			}
   349  			cInfo.c.Close()
   350  			delete(cursors, in.Cursor)
   351  			if err := stream.Send(&remote.Pair{}); err != nil {
   352  				return fmt.Errorf("server-side error: %w", err)
   353  			}
   354  			continue
   355  		default:
   356  		}
   357  
   358  		if err := handleOp(c, stream, in); err != nil {
   359  			return fmt.Errorf("server-side error: %w", err)
   360  		}
   361  	}
   362  }
   363  
   364  func handleOp(c kv.Cursor, stream remote.KV_TxServer, in *remote.Cursor) error {
   365  	var k, v []byte
   366  	var err error
   367  	switch in.Op {
   368  	case remote.Op_FIRST:
   369  		k, v, err = c.First()
   370  	case remote.Op_FIRST_DUP:
   371  		v, err = c.(kv.CursorDupSort).FirstDup()
   372  	case remote.Op_SEEK:
   373  		k, v, err = c.Seek(in.K)
   374  	case remote.Op_SEEK_BOTH:
   375  		v, err = c.(kv.CursorDupSort).SeekBothRange(in.K, in.V)
   376  	case remote.Op_CURRENT:
   377  		k, v, err = c.Current()
   378  	case remote.Op_LAST:
   379  		k, v, err = c.Last()
   380  	case remote.Op_LAST_DUP:
   381  		v, err = c.(kv.CursorDupSort).LastDup()
   382  	case remote.Op_NEXT:
   383  		k, v, err = c.Next()
   384  	case remote.Op_NEXT_DUP:
   385  		k, v, err = c.(kv.CursorDupSort).NextDup()
   386  	case remote.Op_NEXT_NO_DUP:
   387  		k, v, err = c.(kv.CursorDupSort).NextNoDup()
   388  	case remote.Op_PREV:
   389  		k, v, err = c.Prev()
   390  	//case remote.Op_PREV_DUP:
   391  	//	k, v, err = c.(ethdb.CursorDupSort).Prev()
   392  	//	if err != nil {
   393  	//		return err
   394  	//	}
   395  	//case remote.Op_PREV_NO_DUP:
   396  	//	k, v, err = c.Prev()
   397  	//	if err != nil {
   398  	//		return err
   399  	//	}
   400  	case remote.Op_SEEK_EXACT:
   401  		k, v, err = c.SeekExact(in.K)
   402  	case remote.Op_SEEK_BOTH_EXACT:
   403  		k, v, err = c.(kv.CursorDupSort).SeekBothExact(in.K, in.V)
   404  	case remote.Op_COUNT:
   405  		cnt, err := c.Count()
   406  		if err != nil {
   407  			return err
   408  		}
   409  		v = hexutility.EncodeTs(cnt)
   410  	default:
   411  		return fmt.Errorf("unknown operation: %s", in.Op)
   412  	}
   413  	if err != nil {
   414  		return err
   415  	}
   416  
   417  	if err := stream.Send(&remote.Pair{K: k, V: v}); err != nil {
   418  		return err
   419  	}
   420  
   421  	return nil
   422  }
   423  
   424  func bytesCopy(b []byte) []byte {
   425  	if b == nil {
   426  		return nil
   427  	}
   428  	copiedBytes := make([]byte, len(b))
   429  	copy(copiedBytes, b)
   430  	return copiedBytes
   431  }
   432  
   433  func (s *KvServer) StateChanges(req *remote.StateChangeRequest, server remote.KV_StateChangesServer) error {
   434  	ch, remove := s.stateChangeStreams.Sub()
   435  	defer remove()
   436  	for {
   437  		select {
   438  		case reply := <-ch:
   439  			if err := server.Send(reply); err != nil {
   440  				return err
   441  			}
   442  		case <-s.ctx.Done():
   443  			return nil
   444  		case <-server.Context().Done():
   445  			return nil
   446  		}
   447  	}
   448  }
   449  
   450  func (s *KvServer) SendStateChanges(ctx context.Context, sc *remote.StateChangeBatch) {
   451  	s.stateChangeStreams.Pub(sc)
   452  }
   453  
   454  func (s *KvServer) Snapshots(ctx context.Context, _ *remote.SnapshotsRequest) (*remote.SnapshotsReply, error) {
   455  	if s.blockSnapshots == nil || reflect.ValueOf(s.blockSnapshots).IsNil() { // nolint
   456  		return &remote.SnapshotsReply{BlocksFiles: []string{}, HistoryFiles: []string{}}, nil
   457  	}
   458  
   459  	return &remote.SnapshotsReply{BlocksFiles: s.blockSnapshots.Files(), HistoryFiles: s.historySnapshots.Files()}, nil
   460  }
   461  
   462  type StateChangePubSub struct {
   463  	chans map[uint]chan *remote.StateChangeBatch
   464  	id    uint
   465  	mu    sync.RWMutex
   466  }
   467  
   468  func newStateChangeStreams() *StateChangePubSub {
   469  	return &StateChangePubSub{}
   470  }
   471  
   472  func (s *StateChangePubSub) Sub() (ch chan *remote.StateChangeBatch, remove func()) {
   473  	s.mu.Lock()
   474  	defer s.mu.Unlock()
   475  	if s.chans == nil {
   476  		s.chans = make(map[uint]chan *remote.StateChangeBatch)
   477  	}
   478  	s.id++
   479  	id := s.id
   480  	ch = make(chan *remote.StateChangeBatch, 8)
   481  	s.chans[id] = ch
   482  	return ch, func() { s.remove(id) }
   483  }
   484  
   485  func (s *StateChangePubSub) Pub(reply *remote.StateChangeBatch) {
   486  	s.mu.RLock()
   487  	defer s.mu.RUnlock()
   488  	for _, ch := range s.chans {
   489  		common.PrioritizedSend(ch, reply)
   490  	}
   491  }
   492  
   493  func (s *StateChangePubSub) Len() int {
   494  	s.mu.RLock()
   495  	defer s.mu.RUnlock()
   496  	return len(s.chans)
   497  }
   498  
   499  func (s *StateChangePubSub) remove(id uint) {
   500  	s.mu.Lock()
   501  	defer s.mu.Unlock()
   502  	ch, ok := s.chans[id]
   503  	if !ok { // double-unsubscribe support
   504  		return
   505  	}
   506  	close(ch)
   507  	delete(s.chans, id)
   508  }
   509  
   510  // Temporal methods
   511  func (s *KvServer) DomainGet(ctx context.Context, req *remote.DomainGetReq) (reply *remote.DomainGetReply, err error) {
   512  	reply = &remote.DomainGetReply{}
   513  	if err := s.with(req.TxId, func(tx kv.Tx) error {
   514  		ttx, ok := tx.(kv.TemporalTx)
   515  		if !ok {
   516  			return fmt.Errorf("server DB doesn't implement kv.Temporal interface")
   517  		}
   518  		if req.Latest {
   519  			reply.V, reply.Ok, err = ttx.DomainGet(kv.Domain(req.Table), req.K, req.K2)
   520  			if err != nil {
   521  				return err
   522  			}
   523  		} else {
   524  			reply.V, reply.Ok, err = ttx.DomainGetAsOf(kv.Domain(req.Table), req.K, req.K2, req.Ts)
   525  			if err != nil {
   526  				return err
   527  			}
   528  		}
   529  		return nil
   530  	}); err != nil {
   531  		return nil, err
   532  	}
   533  	return reply, nil
   534  }
   535  func (s *KvServer) HistoryGet(ctx context.Context, req *remote.HistoryGetReq) (reply *remote.HistoryGetReply, err error) {
   536  	reply = &remote.HistoryGetReply{}
   537  	if err := s.with(req.TxId, func(tx kv.Tx) error {
   538  		ttx, ok := tx.(kv.TemporalTx)
   539  		if !ok {
   540  			return fmt.Errorf("server DB doesn't implement kv.Temporal interface")
   541  		}
   542  		reply.V, reply.Ok, err = ttx.HistoryGet(kv.History(req.Table), req.K, req.Ts)
   543  		if err != nil {
   544  			return err
   545  		}
   546  		return nil
   547  	}); err != nil {
   548  		return nil, err
   549  	}
   550  	return reply, nil
   551  }
   552  
   553  const PageSizeLimit = 4 * 4096
   554  
   555  func (s *KvServer) IndexRange(ctx context.Context, req *remote.IndexRangeReq) (*remote.IndexRangeReply, error) {
   556  	reply := &remote.IndexRangeReply{}
   557  	from, limit := int(req.FromTs), int(req.Limit)
   558  	if req.PageToken != "" {
   559  		var pagination remote.IndexPagination
   560  		if err := unmarshalPagination(req.PageToken, &pagination); err != nil {
   561  			return nil, err
   562  		}
   563  		from, limit = int(pagination.NextTimeStamp), int(pagination.Limit)
   564  	}
   565  	if req.PageSize <= 0 || req.PageSize > PageSizeLimit {
   566  		req.PageSize = PageSizeLimit
   567  	}
   568  
   569  	if err := s.with(req.TxId, func(tx kv.Tx) error {
   570  		ttx, ok := tx.(kv.TemporalTx)
   571  		if !ok {
   572  			return fmt.Errorf("server DB doesn't implement kv.Temporal interface")
   573  		}
   574  		it, err := ttx.IndexRange(kv.InvertedIdx(req.Table), req.K, from, int(req.ToTs), order.By(req.OrderAscend), limit)
   575  		if err != nil {
   576  			return err
   577  		}
   578  		for it.HasNext() {
   579  			v, err := it.Next()
   580  			if err != nil {
   581  				return err
   582  			}
   583  			reply.Timestamps = append(reply.Timestamps, v)
   584  			limit--
   585  		}
   586  		if len(reply.Timestamps) == PageSizeLimit && it.HasNext() {
   587  			next, err := it.Next()
   588  			if err != nil {
   589  				return err
   590  			}
   591  			reply.NextPageToken, err = marshalPagination(&remote.IndexPagination{NextTimeStamp: int64(next), Limit: int64(limit)})
   592  			if err != nil {
   593  				return err
   594  			}
   595  		}
   596  		return nil
   597  	}); err != nil {
   598  		return nil, err
   599  	}
   600  	return reply, nil
   601  }
   602  
   603  func (s *KvServer) Range(ctx context.Context, req *remote.RangeReq) (*remote.Pairs, error) {
   604  	from, limit := req.FromPrefix, int(req.Limit)
   605  	if req.PageToken != "" {
   606  		var pagination remote.ParisPagination
   607  		if err := unmarshalPagination(req.PageToken, &pagination); err != nil {
   608  			return nil, err
   609  		}
   610  		from, limit = pagination.NextKey, int(pagination.Limit)
   611  	}
   612  	if req.PageSize <= 0 || req.PageSize > PageSizeLimit {
   613  		req.PageSize = PageSizeLimit
   614  	}
   615  
   616  	reply := &remote.Pairs{}
   617  	var err error
   618  	if err = s.with(req.TxId, func(tx kv.Tx) error {
   619  		var it iter.KV
   620  		if req.OrderAscend {
   621  			it, err = tx.RangeAscend(req.Table, from, req.ToPrefix, limit)
   622  			if err != nil {
   623  				return err
   624  			}
   625  		} else {
   626  			it, err = tx.RangeDescend(req.Table, from, req.ToPrefix, limit)
   627  			if err != nil {
   628  				return err
   629  			}
   630  		}
   631  		for it.HasNext() {
   632  			k, v, err := it.Next()
   633  			if err != nil {
   634  				return err
   635  			}
   636  			reply.Keys = append(reply.Keys, k)
   637  			reply.Values = append(reply.Values, v)
   638  			limit--
   639  		}
   640  		if len(reply.Keys) == PageSizeLimit && it.HasNext() {
   641  			nextK, _, err := it.Next()
   642  			if err != nil {
   643  				return err
   644  			}
   645  			reply.NextPageToken, err = marshalPagination(&remote.ParisPagination{NextKey: nextK, Limit: int64(limit)})
   646  			if err != nil {
   647  				return err
   648  			}
   649  		}
   650  		return nil
   651  	}); err != nil {
   652  		return nil, err
   653  	}
   654  	return reply, nil
   655  }
   656  
   657  // see: https://cloud.google.com/apis/design/design_patterns
   658  func marshalPagination(m proto.Message) (string, error) {
   659  	pageToken, err := proto.Marshal(m)
   660  	if err != nil {
   661  		return "", err
   662  	}
   663  	return base64.StdEncoding.EncodeToString(pageToken), nil
   664  }
   665  
   666  func unmarshalPagination(pageToken string, m proto.Message) error {
   667  	token, err := base64.StdEncoding.DecodeString(pageToken)
   668  	if err != nil {
   669  		return err
   670  	}
   671  	if err = proto.Unmarshal(token, m); err != nil {
   672  		return err
   673  	}
   674  	return nil
   675  }