mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-26 05:27:19 +00:00
26ccde4614
* use lmdb.Append method * linter happiness
310 lines
6.4 KiB
Go
310 lines
6.4 KiB
Go
package ethdb
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"sync"
|
|
|
|
"github.com/ledgerwatch/turbo-geth/common"
|
|
"github.com/ledgerwatch/turbo-geth/ethdb/remote"
|
|
"github.com/ledgerwatch/turbo-geth/log"
|
|
)
|
|
|
|
var (
|
|
remoteTxPool = sync.Pool{New: func() interface{} { return &remoteTx{} }}
|
|
)
|
|
|
|
type remoteOpts struct {
|
|
Remote remote.DbOpts
|
|
}
|
|
|
|
type RemoteKV struct {
|
|
opts remoteOpts
|
|
remote *remote.DB
|
|
log log.Logger
|
|
}
|
|
|
|
type remoteTx struct {
|
|
ctx context.Context
|
|
db *RemoteKV
|
|
|
|
remote *remote.Tx
|
|
}
|
|
|
|
type remoteBucket struct {
|
|
tx *remoteTx
|
|
|
|
nameLen uint
|
|
remote *remote.Bucket
|
|
}
|
|
|
|
type remoteCursor struct {
|
|
ctx context.Context
|
|
bucket remoteBucket
|
|
|
|
remote *remote.Cursor
|
|
|
|
k []byte
|
|
v []byte
|
|
err error
|
|
}
|
|
|
|
type remoteNoValuesCursor struct {
|
|
*remoteCursor
|
|
}
|
|
|
|
func (opts remoteOpts) ReadOnly() remoteOpts {
|
|
return opts
|
|
}
|
|
|
|
func (opts remoteOpts) Path(path string) remoteOpts {
|
|
opts.Remote = opts.Remote.Addr(path)
|
|
return opts
|
|
}
|
|
|
|
// Example test code:
|
|
// writeDb = ethdb.NewMemDatabase().KV()
|
|
// serverIn, clientOut := io.Pipe()
|
|
// clientIn, serverOut := io.Pipe()
|
|
// readDBs = ethdb.NewRemote().InMem(clientIn, clientOut).MustOpen()
|
|
// go func() {
|
|
// if err := remotedbserver.Server(ctx, writeDb, serverIn, serverOut, nil); err != nil {
|
|
// require.NoError(t, err)
|
|
// }
|
|
// }()
|
|
//
|
|
func (opts remoteOpts) InMem(in io.Reader, out io.Writer) remoteOpts {
|
|
opts.Remote.DialFunc = func(ctx context.Context) (io.Reader, io.Writer, io.Closer, error) {
|
|
return in, out, nil, nil
|
|
}
|
|
return opts
|
|
}
|
|
|
|
func (opts remoteOpts) Open() (KV, error) {
|
|
remoteDB, err := remote.Open(opts.Remote)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &RemoteKV{
|
|
opts: opts,
|
|
remote: remoteDB,
|
|
log: log.New("remote_db", opts.Remote.DialAddress),
|
|
}, nil
|
|
}
|
|
|
|
func (opts remoteOpts) MustOpen() KV {
|
|
db, err := opts.Open()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func NewRemote() remoteOpts {
|
|
return remoteOpts{Remote: remote.DefaultOpts}
|
|
}
|
|
|
|
// Close closes BoltKV
|
|
// All transactions must be closed before closing the database.
|
|
func (db *RemoteKV) Close() {
|
|
if db.remote != nil {
|
|
if err := db.remote.Close(); err != nil {
|
|
db.log.Warn("failed to close remote DB", "err", err)
|
|
} else {
|
|
db.log.Info("remote database closed")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (db *RemoteKV) DiskSize(ctx context.Context) (common.StorageSize, error) {
|
|
return db.remote.DiskSize(ctx)
|
|
}
|
|
|
|
func (db *RemoteKV) BucketsStat(ctx context.Context) (map[string]common.StorageBucketWriteStats, error) {
|
|
return db.remote.BucketsStat(ctx)
|
|
}
|
|
|
|
func (db *RemoteKV) IdealBatchSize() int {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (db *RemoteKV) Begin(ctx context.Context, writable bool) (Tx, error) {
|
|
panic("remote db doesn't support managed transactions")
|
|
}
|
|
|
|
func (db *RemoteKV) View(ctx context.Context, f func(tx Tx) error) (err error) {
|
|
t := remoteTxPool.Get().(*remoteTx)
|
|
defer remoteTxPool.Put(t)
|
|
t.ctx = ctx
|
|
t.db = db
|
|
return db.remote.View(ctx, func(tx *remote.Tx) error {
|
|
t.remote = tx
|
|
return f(t)
|
|
})
|
|
}
|
|
|
|
func (db *RemoteKV) Update(ctx context.Context, f func(tx Tx) error) (err error) {
|
|
return fmt.Errorf("remote db provider doesn't support .Update method")
|
|
}
|
|
|
|
func (tx *remoteTx) Commit(ctx context.Context) error {
|
|
panic("remote db is read-only")
|
|
}
|
|
|
|
func (tx *remoteTx) Rollback() error {
|
|
panic("remote db is read-only")
|
|
}
|
|
|
|
func (tx *remoteTx) Bucket(name []byte) Bucket {
|
|
b := remoteBucket{tx: tx, nameLen: uint(len(name))}
|
|
b.remote = tx.remote.Bucket(name)
|
|
return b
|
|
}
|
|
|
|
func (c *remoteCursor) Prefix(v []byte) Cursor {
|
|
c.remote = c.remote.Prefix(v)
|
|
return c
|
|
}
|
|
|
|
func (c *remoteCursor) MatchBits(n uint) Cursor {
|
|
panic("not implemented yet")
|
|
}
|
|
|
|
func (c *remoteCursor) Prefetch(v uint) Cursor {
|
|
c.remote = c.remote.Prefetch(v)
|
|
return c
|
|
}
|
|
|
|
func (c *remoteCursor) NoValues() NoValuesCursor {
|
|
c.remote = c.remote.NoValues()
|
|
return &remoteNoValuesCursor{remoteCursor: c}
|
|
}
|
|
|
|
func (b remoteBucket) Size() (uint64, error) {
|
|
panic("not implemented")
|
|
}
|
|
|
|
func (b remoteBucket) Clear() error {
|
|
panic("not supporte")
|
|
}
|
|
|
|
func (b remoteBucket) Get(key []byte) (val []byte, err error) {
|
|
val, err = b.remote.Get(key)
|
|
return val, err
|
|
}
|
|
|
|
func (b remoteBucket) Put(key []byte, value []byte) error {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (b remoteBucket) Delete(key []byte) error {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (b remoteBucket) Cursor() Cursor {
|
|
c := &remoteCursor{bucket: b, ctx: b.tx.ctx, remote: b.remote.Cursor()}
|
|
return c
|
|
}
|
|
|
|
func (c *remoteCursor) Put(key []byte, value []byte) error {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (c *remoteCursor) Append(key []byte, value []byte) error {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (c *remoteCursor) Delete(key []byte) error {
|
|
panic("not supported")
|
|
}
|
|
|
|
func (c *remoteCursor) First() ([]byte, []byte, error) {
|
|
c.k, c.v, c.err = c.remote.First()
|
|
if c.err != nil {
|
|
return []byte{}, c.v, c.err // on error key should be != nil
|
|
}
|
|
return c.k, c.v, nil
|
|
}
|
|
|
|
func (c *remoteCursor) Seek(seek []byte) ([]byte, []byte, error) {
|
|
c.k, c.v, c.err = c.remote.Seek(seek)
|
|
if c.err != nil {
|
|
return []byte{}, c.v, c.err
|
|
}
|
|
return c.k, c.v, nil
|
|
}
|
|
|
|
func (c *remoteCursor) SeekTo(seek []byte) ([]byte, []byte, error) {
|
|
c.k, c.v, c.err = c.remote.SeekTo(seek)
|
|
if c.err != nil {
|
|
return []byte{}, c.v, c.err
|
|
}
|
|
return c.k, c.v, nil
|
|
}
|
|
|
|
func (c *remoteCursor) Next() ([]byte, []byte, error) {
|
|
c.k, c.v, c.err = c.remote.Next()
|
|
return c.k, c.v, c.err
|
|
}
|
|
|
|
func (c *remoteCursor) Walk(walker func(k, v []byte) (bool, error)) error {
|
|
for k, v, err := c.First(); k != nil; k, v, err = c.Next() {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ok, err := walker(k, v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *remoteNoValuesCursor) Walk(walker func(k []byte, vSize uint32) (bool, error)) error {
|
|
for k, vSize, err := c.First(); k != nil; k, vSize, err = c.Next() {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ok, err := walker(k, vSize)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *remoteNoValuesCursor) First() ([]byte, uint32, error) {
|
|
var vSize uint32
|
|
c.k, vSize, c.err = c.remote.FirstKey()
|
|
if c.err != nil {
|
|
return []byte{}, vSize, c.err
|
|
}
|
|
return c.k, vSize, nil
|
|
}
|
|
|
|
func (c *remoteNoValuesCursor) Seek(seek []byte) ([]byte, uint32, error) {
|
|
var vSize uint32
|
|
c.k, vSize, c.err = c.remote.SeekKey(seek)
|
|
if c.err != nil {
|
|
return []byte{}, vSize, c.err
|
|
}
|
|
return c.k, vSize, nil
|
|
}
|
|
|
|
func (c *remoteNoValuesCursor) Next() ([]byte, uint32, error) {
|
|
var vSize uint32
|
|
c.k, vSize, c.err = c.remote.NextKey()
|
|
if c.err != nil {
|
|
return []byte{}, vSize, c.err
|
|
}
|
|
return c.k, vSize, nil
|
|
}
|