github.com/ledgerwatch/erigon-lib@v1.0.0/kv/remotedb/kv_remote.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 remotedb
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/binary"
    23  	"fmt"
    24  	"runtime"
    25  
    26  	"github.com/ledgerwatch/erigon-lib/kv/iter"
    27  	"github.com/ledgerwatch/erigon-lib/kv/order"
    28  	"github.com/ledgerwatch/log/v3"
    29  	"golang.org/x/sync/semaphore"
    30  	"google.golang.org/grpc"
    31  	"google.golang.org/protobuf/types/known/emptypb"
    32  
    33  	"github.com/ledgerwatch/erigon-lib/gointerfaces"
    34  	"github.com/ledgerwatch/erigon-lib/gointerfaces/grpcutil"
    35  	"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
    36  	"github.com/ledgerwatch/erigon-lib/kv"
    37  	"github.com/ledgerwatch/erigon-lib/kv/mdbx"
    38  )
    39  
    40  // generate the messages and services
    41  type remoteOpts struct {
    42  	remoteKV    remote.KVClient
    43  	log         log.Logger
    44  	bucketsCfg  mdbx.TableCfgFunc
    45  	DialAddress string
    46  	version     gointerfaces.Version
    47  }
    48  
    49  var _ kv.TemporalTx = (*tx)(nil)
    50  
    51  type DB struct {
    52  	remoteKV     remote.KVClient
    53  	log          log.Logger
    54  	buckets      kv.TableCfg
    55  	roTxsLimiter *semaphore.Weighted
    56  	opts         remoteOpts
    57  }
    58  
    59  type tx struct {
    60  	stream             remote.KV_TxClient
    61  	ctx                context.Context
    62  	streamCancelFn     context.CancelFunc
    63  	db                 *DB
    64  	statelessCursors   map[string]kv.Cursor
    65  	cursors            []*remoteCursor
    66  	streams            []kv.Closer
    67  	viewID, id         uint64
    68  	streamingRequested bool
    69  }
    70  
    71  type remoteCursor struct {
    72  	ctx        context.Context
    73  	stream     remote.KV_TxClient
    74  	tx         *tx
    75  	bucketName string
    76  	bucketCfg  kv.TableCfgItem
    77  	id         uint32
    78  }
    79  
    80  type remoteCursorDupSort struct {
    81  	*remoteCursor
    82  }
    83  
    84  func (opts remoteOpts) ReadOnly() remoteOpts {
    85  	return opts
    86  }
    87  
    88  func (opts remoteOpts) WithBucketsConfig(f mdbx.TableCfgFunc) remoteOpts {
    89  	opts.bucketsCfg = f
    90  	return opts
    91  }
    92  
    93  func (opts remoteOpts) Open() (*DB, error) {
    94  	targetSemCount := int64(runtime.GOMAXPROCS(-1)) - 1
    95  	if targetSemCount <= 1 {
    96  		targetSemCount = 2
    97  	}
    98  
    99  	db := &DB{
   100  		opts:         opts,
   101  		remoteKV:     opts.remoteKV,
   102  		log:          log.New("remote_db", opts.DialAddress),
   103  		buckets:      kv.TableCfg{},
   104  		roTxsLimiter: semaphore.NewWeighted(targetSemCount), // 1 less than max to allow unlocking
   105  	}
   106  	customBuckets := opts.bucketsCfg(kv.ChaindataTablesCfg)
   107  	for name, cfg := range customBuckets { // copy map to avoid changing global variable
   108  		db.buckets[name] = cfg
   109  	}
   110  
   111  	return db, nil
   112  }
   113  
   114  func (opts remoteOpts) MustOpen() kv.RwDB {
   115  	db, err := opts.Open()
   116  	if err != nil {
   117  		panic(err)
   118  	}
   119  	return db
   120  }
   121  
   122  // NewRemote defines new remove KV connection (without actually opening it)
   123  // version parameters represent the version the KV client is expecting,
   124  // compatibility check will be performed when the KV connection opens
   125  func NewRemote(v gointerfaces.Version, logger log.Logger, remoteKV remote.KVClient) remoteOpts {
   126  	return remoteOpts{bucketsCfg: mdbx.WithChaindataTables, version: v, log: logger, remoteKV: remoteKV}
   127  }
   128  
   129  func (db *DB) PageSize() uint64       { panic("not implemented") }
   130  func (db *DB) ReadOnly() bool         { return true }
   131  func (db *DB) AllTables() kv.TableCfg { return db.buckets }
   132  
   133  func (db *DB) EnsureVersionCompatibility() bool {
   134  	versionReply, err := db.remoteKV.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true))
   135  	if err != nil {
   136  		db.log.Error("getting Version", "error", err)
   137  		return false
   138  	}
   139  	if !gointerfaces.EnsureVersion(db.opts.version, versionReply) {
   140  		db.log.Error("incompatible interface versions", "client", db.opts.version.String(),
   141  			"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
   142  		return false
   143  	}
   144  	db.log.Info("interfaces compatible", "client", db.opts.version.String(),
   145  		"server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch))
   146  	return true
   147  }
   148  
   149  func (db *DB) Close() {}
   150  
   151  func (db *DB) BeginRo(ctx context.Context) (txn kv.Tx, err error) {
   152  	select {
   153  	case <-ctx.Done():
   154  		return nil, ctx.Err()
   155  	default:
   156  	}
   157  
   158  	if semErr := db.roTxsLimiter.Acquire(ctx, 1); semErr != nil {
   159  		return nil, semErr
   160  	}
   161  
   162  	defer func() {
   163  		// ensure we release the semaphore on error
   164  		if txn == nil {
   165  			db.roTxsLimiter.Release(1)
   166  		}
   167  	}()
   168  
   169  	streamCtx, streamCancelFn := context.WithCancel(ctx) // We create child context for the stream so we can cancel it to prevent leak
   170  	stream, err := db.remoteKV.Tx(streamCtx)
   171  	if err != nil {
   172  		streamCancelFn()
   173  		return nil, err
   174  	}
   175  	msg, err := stream.Recv()
   176  	if err != nil {
   177  		streamCancelFn()
   178  		return nil, err
   179  	}
   180  	return &tx{ctx: ctx, db: db, stream: stream, streamCancelFn: streamCancelFn, viewID: msg.ViewId, id: msg.TxId}, nil
   181  }
   182  func (db *DB) BeginTemporalRo(ctx context.Context) (kv.TemporalTx, error) {
   183  	t, err := db.BeginRo(ctx)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	return t.(kv.TemporalTx), nil
   188  }
   189  func (db *DB) BeginRw(ctx context.Context) (kv.RwTx, error) {
   190  	return nil, fmt.Errorf("remote db provider doesn't support .BeginRw method")
   191  }
   192  func (db *DB) BeginRwNosync(ctx context.Context) (kv.RwTx, error) {
   193  	return nil, fmt.Errorf("remote db provider doesn't support .BeginRw method")
   194  }
   195  func (db *DB) BeginTemporalRw(ctx context.Context) (kv.RwTx, error) {
   196  	return nil, fmt.Errorf("remote db provider doesn't support .BeginTemporalRw method")
   197  }
   198  func (db *DB) BeginTemporalRwNosync(ctx context.Context) (kv.RwTx, error) {
   199  	return nil, fmt.Errorf("remote db provider doesn't support .BeginTemporalRwNosync method")
   200  }
   201  
   202  func (db *DB) View(ctx context.Context, f func(tx kv.Tx) error) (err error) {
   203  	tx, err := db.BeginRo(ctx)
   204  	if err != nil {
   205  		return err
   206  	}
   207  	defer tx.Rollback()
   208  	return f(tx)
   209  }
   210  func (db *DB) ViewTemporal(ctx context.Context, f func(tx kv.TemporalTx) error) (err error) {
   211  	tx, err := db.BeginTemporalRo(ctx)
   212  	if err != nil {
   213  		return err
   214  	}
   215  	defer tx.Rollback()
   216  	return f(tx)
   217  }
   218  
   219  func (db *DB) Update(ctx context.Context, f func(tx kv.RwTx) error) (err error) {
   220  	return fmt.Errorf("remote db provider doesn't support .Update method")
   221  }
   222  func (db *DB) UpdateNosync(ctx context.Context, f func(tx kv.RwTx) error) (err error) {
   223  	return fmt.Errorf("remote db provider doesn't support .UpdateNosync method")
   224  }
   225  
   226  func (tx *tx) ViewID() uint64  { return tx.viewID }
   227  func (tx *tx) CollectMetrics() {}
   228  func (tx *tx) IncrementSequence(bucket string, amount uint64) (uint64, error) {
   229  	panic("not implemented yet")
   230  }
   231  func (tx *tx) ReadSequence(bucket string) (uint64, error) {
   232  	panic("not implemented yet")
   233  }
   234  func (tx *tx) Append(bucket string, k, v []byte) error    { panic("no write methods") }
   235  func (tx *tx) AppendDup(bucket string, k, v []byte) error { panic("no write methods") }
   236  
   237  func (tx *tx) Commit() error {
   238  	panic("remote db is read-only")
   239  }
   240  
   241  func (tx *tx) Rollback() {
   242  	// don't close opened cursors - just close stream, server will cleanup everything well
   243  	tx.closeGrpcStream()
   244  	tx.db.roTxsLimiter.Release(1)
   245  	for _, c := range tx.streams {
   246  		c.Close()
   247  	}
   248  }
   249  func (tx *tx) DBSize() (uint64, error) { panic("not implemented") }
   250  
   251  func (tx *tx) statelessCursor(bucket string) (kv.Cursor, error) {
   252  	if tx.statelessCursors == nil {
   253  		tx.statelessCursors = make(map[string]kv.Cursor)
   254  	}
   255  	c, ok := tx.statelessCursors[bucket]
   256  	if !ok {
   257  		var err error
   258  		c, err = tx.Cursor(bucket)
   259  		if err != nil {
   260  			return nil, err
   261  		}
   262  		tx.statelessCursors[bucket] = c
   263  	}
   264  	return c, nil
   265  }
   266  
   267  func (tx *tx) BucketSize(name string) (uint64, error) { panic("not implemented") }
   268  
   269  func (tx *tx) ForEach(bucket string, fromPrefix []byte, walker func(k, v []byte) error) error {
   270  	it, err := tx.Range(bucket, fromPrefix, nil)
   271  	if err != nil {
   272  		return err
   273  	}
   274  	for it.HasNext() {
   275  		k, v, err := it.Next()
   276  		if err != nil {
   277  			return err
   278  		}
   279  		if err := walker(k, v); err != nil {
   280  			return err
   281  		}
   282  	}
   283  	return nil
   284  }
   285  
   286  func (tx *tx) ForPrefix(bucket string, prefix []byte, walker func(k, v []byte) error) error {
   287  	it, err := tx.Prefix(bucket, prefix)
   288  	if err != nil {
   289  		return err
   290  	}
   291  	for it.HasNext() {
   292  		k, v, err := it.Next()
   293  		if err != nil {
   294  			return err
   295  		}
   296  		if err := walker(k, v); err != nil {
   297  			return err
   298  		}
   299  	}
   300  	return nil
   301  }
   302  
   303  // TODO: this must be deprecated
   304  func (tx *tx) ForAmount(bucket string, fromPrefix []byte, amount uint32, walker func(k, v []byte) error) error {
   305  	if amount == 0 {
   306  		return nil
   307  	}
   308  	c, err := tx.Cursor(bucket)
   309  	if err != nil {
   310  		return err
   311  	}
   312  	defer c.Close()
   313  
   314  	for k, v, err := c.Seek(fromPrefix); k != nil && amount > 0; k, v, err = c.Next() {
   315  		if err != nil {
   316  			return err
   317  		}
   318  		if err := walker(k, v); err != nil {
   319  			return err
   320  		}
   321  		amount--
   322  	}
   323  	return nil
   324  }
   325  
   326  func (tx *tx) GetOne(bucket string, k []byte) (val []byte, err error) {
   327  	c, err := tx.statelessCursor(bucket)
   328  	if err != nil {
   329  		return nil, err
   330  	}
   331  	_, val, err = c.SeekExact(k)
   332  	return val, err
   333  }
   334  
   335  func (tx *tx) Has(bucket string, k []byte) (bool, error) {
   336  	c, err := tx.statelessCursor(bucket)
   337  	if err != nil {
   338  		return false, err
   339  	}
   340  	kk, _, err := c.Seek(k)
   341  	if err != nil {
   342  		return false, err
   343  	}
   344  	return bytes.Equal(k, kk), nil
   345  }
   346  
   347  func (c *remoteCursor) SeekExact(k []byte) (key, val []byte, err error) {
   348  	return c.seekExact(k)
   349  }
   350  
   351  func (c *remoteCursor) Prev() ([]byte, []byte, error) {
   352  	return c.prev()
   353  }
   354  
   355  func (tx *tx) Cursor(bucket string) (kv.Cursor, error) {
   356  	b := tx.db.buckets[bucket]
   357  	c := &remoteCursor{tx: tx, ctx: tx.ctx, bucketName: bucket, bucketCfg: b, stream: tx.stream}
   358  	tx.cursors = append(tx.cursors, c)
   359  	if err := c.stream.Send(&remote.Cursor{Op: remote.Op_OPEN, BucketName: c.bucketName}); err != nil {
   360  		return nil, err
   361  	}
   362  	msg, err := c.stream.Recv()
   363  	if err != nil {
   364  		return nil, err
   365  	}
   366  	c.id = msg.CursorId
   367  	return c, nil
   368  }
   369  
   370  func (tx *tx) ListBuckets() ([]string, error) {
   371  	return nil, fmt.Errorf("function ListBuckets is not implemented for remoteTx")
   372  }
   373  
   374  // func (c *remoteCursor) Put(k []byte, v []byte) error            { panic("not supported") }
   375  // func (c *remoteCursor) PutNoOverwrite(k []byte, v []byte) error { panic("not supported") }
   376  // func (c *remoteCursor) Append(k []byte, v []byte) error         { panic("not supported") }
   377  // func (c *remoteCursor) Delete(k []byte) error                   { panic("not supported") }
   378  // func (c *remoteCursor) DeleteCurrent() error                    { panic("not supported") }
   379  func (c *remoteCursor) Count() (uint64, error) {
   380  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_COUNT}); err != nil {
   381  		return 0, err
   382  	}
   383  	pair, err := c.stream.Recv()
   384  	if err != nil {
   385  		return 0, err
   386  	}
   387  	return binary.BigEndian.Uint64(pair.V), nil
   388  
   389  }
   390  
   391  func (c *remoteCursor) first() ([]byte, []byte, error) {
   392  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_FIRST}); err != nil {
   393  		return []byte{}, nil, err
   394  	}
   395  	pair, err := c.stream.Recv()
   396  	if err != nil {
   397  		return []byte{}, nil, err
   398  	}
   399  	return pair.K, pair.V, nil
   400  }
   401  
   402  func (c *remoteCursor) next() ([]byte, []byte, error) {
   403  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_NEXT}); err != nil {
   404  		return []byte{}, nil, err
   405  	}
   406  	pair, err := c.stream.Recv()
   407  	if err != nil {
   408  		return []byte{}, nil, err
   409  	}
   410  	return pair.K, pair.V, nil
   411  }
   412  func (c *remoteCursor) nextDup() ([]byte, []byte, error) {
   413  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_NEXT_DUP}); err != nil {
   414  		return []byte{}, nil, err
   415  	}
   416  	pair, err := c.stream.Recv()
   417  	if err != nil {
   418  		return []byte{}, nil, err
   419  	}
   420  	return pair.K, pair.V, nil
   421  }
   422  func (c *remoteCursor) nextNoDup() ([]byte, []byte, error) {
   423  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_NEXT_NO_DUP}); err != nil {
   424  		return []byte{}, nil, err
   425  	}
   426  	pair, err := c.stream.Recv()
   427  	if err != nil {
   428  		return []byte{}, nil, err
   429  	}
   430  	return pair.K, pair.V, nil
   431  }
   432  func (c *remoteCursor) prev() ([]byte, []byte, error) {
   433  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_PREV}); err != nil {
   434  		return []byte{}, nil, err
   435  	}
   436  	pair, err := c.stream.Recv()
   437  	if err != nil {
   438  		return []byte{}, nil, err
   439  	}
   440  	return pair.K, pair.V, nil
   441  }
   442  func (c *remoteCursor) prevDup() ([]byte, []byte, error) {
   443  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_PREV_DUP}); err != nil {
   444  		return []byte{}, nil, err
   445  	}
   446  	pair, err := c.stream.Recv()
   447  	if err != nil {
   448  		return []byte{}, nil, err
   449  	}
   450  	return pair.K, pair.V, nil
   451  }
   452  func (c *remoteCursor) prevNoDup() ([]byte, []byte, error) {
   453  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_PREV_NO_DUP}); err != nil {
   454  		return []byte{}, nil, err
   455  	}
   456  	pair, err := c.stream.Recv()
   457  	if err != nil {
   458  		return []byte{}, nil, err
   459  	}
   460  	return pair.K, pair.V, nil
   461  }
   462  func (c *remoteCursor) last() ([]byte, []byte, error) {
   463  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_LAST}); err != nil {
   464  		return []byte{}, nil, err
   465  	}
   466  	pair, err := c.stream.Recv()
   467  	if err != nil {
   468  		return []byte{}, nil, err
   469  	}
   470  	return pair.K, pair.V, nil
   471  }
   472  func (c *remoteCursor) setRange(k []byte) ([]byte, []byte, error) {
   473  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_SEEK, K: k}); err != nil {
   474  		return []byte{}, nil, err
   475  	}
   476  	pair, err := c.stream.Recv()
   477  	if err != nil {
   478  		return []byte{}, nil, err
   479  	}
   480  	return pair.K, pair.V, nil
   481  }
   482  func (c *remoteCursor) seekExact(k []byte) ([]byte, []byte, error) {
   483  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_SEEK_EXACT, K: k}); err != nil {
   484  		return []byte{}, nil, err
   485  	}
   486  	pair, err := c.stream.Recv()
   487  	if err != nil {
   488  		return []byte{}, nil, err
   489  	}
   490  	return pair.K, pair.V, nil
   491  }
   492  func (c *remoteCursor) getBothRange(k, v []byte) ([]byte, error) {
   493  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_SEEK_BOTH, K: k, V: v}); err != nil {
   494  		return nil, err
   495  	}
   496  	pair, err := c.stream.Recv()
   497  	if err != nil {
   498  		return nil, err
   499  	}
   500  	return pair.V, nil
   501  }
   502  func (c *remoteCursor) seekBothExact(k, v []byte) ([]byte, []byte, error) {
   503  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_SEEK_BOTH_EXACT, K: k, V: v}); err != nil {
   504  		return []byte{}, nil, err
   505  	}
   506  	pair, err := c.stream.Recv()
   507  	if err != nil {
   508  		return []byte{}, nil, err
   509  	}
   510  	return pair.K, pair.V, nil
   511  }
   512  func (c *remoteCursor) firstDup() ([]byte, error) {
   513  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_FIRST_DUP}); err != nil {
   514  		return nil, err
   515  	}
   516  	pair, err := c.stream.Recv()
   517  	if err != nil {
   518  		return nil, err
   519  	}
   520  	return pair.V, nil
   521  }
   522  func (c *remoteCursor) lastDup() ([]byte, error) {
   523  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_LAST_DUP}); err != nil {
   524  		return nil, err
   525  	}
   526  	pair, err := c.stream.Recv()
   527  	if err != nil {
   528  		return nil, err
   529  	}
   530  	return pair.V, nil
   531  }
   532  func (c *remoteCursor) getCurrent() ([]byte, []byte, error) {
   533  	if err := c.stream.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_CURRENT}); err != nil {
   534  		return []byte{}, nil, err
   535  	}
   536  	pair, err := c.stream.Recv()
   537  	if err != nil {
   538  		return []byte{}, nil, err
   539  	}
   540  	return pair.K, pair.V, nil
   541  }
   542  
   543  func (c *remoteCursor) Current() ([]byte, []byte, error) {
   544  	return c.getCurrent()
   545  }
   546  
   547  // Seek - doesn't start streaming (because much of code does only several .Seek calls without reading sequence of data)
   548  // .Next() - does request streaming (if configured by user)
   549  func (c *remoteCursor) Seek(seek []byte) ([]byte, []byte, error) {
   550  	return c.setRange(seek)
   551  }
   552  
   553  func (c *remoteCursor) First() ([]byte, []byte, error) {
   554  	return c.first()
   555  }
   556  
   557  // Next - returns next data element from server, request streaming (if configured by user)
   558  func (c *remoteCursor) Next() ([]byte, []byte, error) {
   559  	return c.next()
   560  }
   561  
   562  func (c *remoteCursor) Last() ([]byte, []byte, error) {
   563  	return c.last()
   564  }
   565  
   566  func (tx *tx) closeGrpcStream() {
   567  	if tx.stream == nil {
   568  		return
   569  	}
   570  	defer tx.streamCancelFn() // hard cancel stream if graceful wasn't successful
   571  
   572  	if tx.streamingRequested {
   573  		// if streaming is in progress, can't use `CloseSend` - because
   574  		// server will not read it right not - it busy with streaming data
   575  		// TODO: set flag 'tx.streamingRequested' to false when got terminator from server (nil key or os.EOF)
   576  		tx.streamCancelFn()
   577  	} else {
   578  		// try graceful close stream
   579  		err := tx.stream.CloseSend()
   580  		if err != nil {
   581  			doLog := !grpcutil.IsEndOfStream(err)
   582  			if doLog {
   583  				log.Warn("couldn't send msg CloseSend to server", "err", err)
   584  			}
   585  		} else {
   586  			_, err = tx.stream.Recv()
   587  			if err != nil {
   588  				doLog := !grpcutil.IsEndOfStream(err)
   589  				if doLog {
   590  					log.Warn("received unexpected error from server after CloseSend", "err", err)
   591  				}
   592  			}
   593  		}
   594  	}
   595  	tx.stream = nil
   596  	tx.streamingRequested = false
   597  }
   598  
   599  func (c *remoteCursor) Close() {
   600  	if c.stream == nil {
   601  		return
   602  	}
   603  	st := c.stream
   604  	c.stream = nil
   605  	if err := st.Send(&remote.Cursor{Cursor: c.id, Op: remote.Op_CLOSE}); err == nil {
   606  		_, _ = st.Recv()
   607  	}
   608  }
   609  
   610  func (tx *tx) CursorDupSort(bucket string) (kv.CursorDupSort, error) {
   611  	b := tx.db.buckets[bucket]
   612  	c := &remoteCursor{tx: tx, ctx: tx.ctx, bucketName: bucket, bucketCfg: b, stream: tx.stream}
   613  	tx.cursors = append(tx.cursors, c)
   614  	if err := c.stream.Send(&remote.Cursor{Op: remote.Op_OPEN_DUP_SORT, BucketName: c.bucketName}); err != nil {
   615  		return nil, err
   616  	}
   617  	msg, err := c.stream.Recv()
   618  	if err != nil {
   619  		return nil, err
   620  	}
   621  	c.id = msg.CursorId
   622  	return &remoteCursorDupSort{remoteCursor: c}, nil
   623  }
   624  
   625  func (c *remoteCursorDupSort) SeekBothExact(k, v []byte) ([]byte, []byte, error) {
   626  	return c.seekBothExact(k, v)
   627  }
   628  
   629  func (c *remoteCursorDupSort) SeekBothRange(k, v []byte) ([]byte, error) {
   630  	return c.getBothRange(k, v)
   631  }
   632  
   633  func (c *remoteCursorDupSort) DeleteExact(k1, k2 []byte) error    { panic("not supported") }
   634  func (c *remoteCursorDupSort) AppendDup(k []byte, v []byte) error { panic("not supported") }
   635  func (c *remoteCursorDupSort) PutNoDupData(k, v []byte) error     { panic("not supported") }
   636  func (c *remoteCursorDupSort) DeleteCurrentDuplicates() error     { panic("not supported") }
   637  func (c *remoteCursorDupSort) CountDuplicates() (uint64, error)   { panic("not supported") }
   638  
   639  func (c *remoteCursorDupSort) FirstDup() ([]byte, error)          { return c.firstDup() }
   640  func (c *remoteCursorDupSort) NextDup() ([]byte, []byte, error)   { return c.nextDup() }
   641  func (c *remoteCursorDupSort) NextNoDup() ([]byte, []byte, error) { return c.nextNoDup() }
   642  func (c *remoteCursorDupSort) PrevDup() ([]byte, []byte, error)   { return c.prevDup() }
   643  func (c *remoteCursorDupSort) PrevNoDup() ([]byte, []byte, error) { return c.prevNoDup() }
   644  func (c *remoteCursorDupSort) LastDup() ([]byte, error)           { return c.lastDup() }
   645  
   646  // Temporal Methods
   647  func (tx *tx) DomainGetAsOf(name kv.Domain, k, k2 []byte, ts uint64) (v []byte, ok bool, err error) {
   648  	reply, err := tx.db.remoteKV.DomainGet(tx.ctx, &remote.DomainGetReq{TxId: tx.id, Table: string(name), K: k, K2: k2, Ts: ts})
   649  	if err != nil {
   650  		return nil, false, err
   651  	}
   652  	return reply.V, reply.Ok, nil
   653  }
   654  
   655  func (tx *tx) DomainGet(name kv.Domain, k, k2 []byte) (v []byte, ok bool, err error) {
   656  	reply, err := tx.db.remoteKV.DomainGet(tx.ctx, &remote.DomainGetReq{TxId: tx.id, Table: string(name), K: k, K2: k2, Latest: true})
   657  	if err != nil {
   658  		return nil, false, err
   659  	}
   660  	return reply.V, reply.Ok, nil
   661  }
   662  
   663  func (tx *tx) DomainRange(name kv.Domain, fromKey, toKey []byte, ts uint64, asc order.By, limit int) (it iter.KV, err error) {
   664  	return iter.PaginateKV(func(pageToken string) (keys, vals [][]byte, nextPageToken string, err error) {
   665  		reply, err := tx.db.remoteKV.DomainRange(tx.ctx, &remote.DomainRangeReq{TxId: tx.id, Table: string(name), FromKey: fromKey, ToKey: toKey, Ts: ts, OrderAscend: bool(asc), Limit: int64(limit)})
   666  		if err != nil {
   667  			return nil, nil, "", err
   668  		}
   669  		return reply.Keys, reply.Values, reply.NextPageToken, nil
   670  	}), nil
   671  }
   672  func (tx *tx) HistoryGet(name kv.History, k []byte, ts uint64) (v []byte, ok bool, err error) {
   673  	reply, err := tx.db.remoteKV.HistoryGet(tx.ctx, &remote.HistoryGetReq{TxId: tx.id, Table: string(name), K: k, Ts: ts})
   674  	if err != nil {
   675  		return nil, false, err
   676  	}
   677  	return reply.V, reply.Ok, nil
   678  }
   679  func (tx *tx) HistoryRange(name kv.History, fromTs, toTs int, asc order.By, limit int) (it iter.KV, err error) {
   680  	return iter.PaginateKV(func(pageToken string) (keys, vals [][]byte, nextPageToken string, err error) {
   681  		reply, err := tx.db.remoteKV.HistoryRange(tx.ctx, &remote.HistoryRangeReq{TxId: tx.id, Table: string(name), FromTs: int64(fromTs), ToTs: int64(toTs), OrderAscend: bool(asc), Limit: int64(limit)})
   682  		if err != nil {
   683  			return nil, nil, "", err
   684  		}
   685  		return reply.Keys, reply.Values, reply.NextPageToken, nil
   686  	}), nil
   687  }
   688  
   689  func (tx *tx) IndexRange(name kv.InvertedIdx, k []byte, fromTs, toTs int, asc order.By, limit int) (timestamps iter.U64, err error) {
   690  	return iter.PaginateU64(func(pageToken string) (arr []uint64, nextPageToken string, err error) {
   691  		req := &remote.IndexRangeReq{TxId: tx.id, Table: string(name), K: k, FromTs: int64(fromTs), ToTs: int64(toTs), OrderAscend: bool(asc), Limit: int64(limit)}
   692  		reply, err := tx.db.remoteKV.IndexRange(tx.ctx, req)
   693  		if err != nil {
   694  			return nil, "", err
   695  		}
   696  		return reply.Timestamps, reply.NextPageToken, nil
   697  	}), nil
   698  }
   699  
   700  func (tx *tx) Prefix(table string, prefix []byte) (iter.KV, error) {
   701  	nextPrefix, ok := kv.NextSubtree(prefix)
   702  	if !ok {
   703  		return tx.Range(table, prefix, nil)
   704  	}
   705  	return tx.Range(table, prefix, nextPrefix)
   706  }
   707  
   708  func (tx *tx) rangeOrderLimit(table string, fromPrefix, toPrefix []byte, asc order.By, limit int) (iter.KV, error) {
   709  	return iter.PaginateKV(func(pageToken string) (keys [][]byte, values [][]byte, nextPageToken string, err error) {
   710  		req := &remote.RangeReq{TxId: tx.id, Table: table, FromPrefix: fromPrefix, ToPrefix: toPrefix, OrderAscend: bool(asc), Limit: int64(limit)}
   711  		reply, err := tx.db.remoteKV.Range(tx.ctx, req)
   712  		if err != nil {
   713  			return nil, nil, "", err
   714  		}
   715  		return reply.Keys, reply.Values, reply.NextPageToken, nil
   716  	}), nil
   717  }
   718  func (tx *tx) Range(table string, fromPrefix, toPrefix []byte) (iter.KV, error) {
   719  	return tx.rangeOrderLimit(table, fromPrefix, toPrefix, order.Asc, -1)
   720  }
   721  func (tx *tx) RangeAscend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) {
   722  	return tx.rangeOrderLimit(table, fromPrefix, toPrefix, order.Asc, limit)
   723  }
   724  func (tx *tx) RangeDescend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) {
   725  	return tx.rangeOrderLimit(table, fromPrefix, toPrefix, order.Desc, limit)
   726  }
   727  func (tx *tx) RangeDupSort(table string, key []byte, fromPrefix, toPrefix []byte, asc order.By, limit int) (iter.KV, error) {
   728  	panic("not implemented yet")
   729  }