mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-09 20:41:20 +00:00
9091ce62bb
* move IdealBatchSize method to Batch object :-) remove cursor.Walk remove kv.IdealBatchSize * remove bolt_db.go file * move method NoValueCursor to tx object
2.8 KiB
2.8 KiB
Target:
To build 1 key-value abstraction on top of LMDB and RemoteDB (our own read-only TCP protocol for key-value databases).
Design principles:
- No internal copies/allocations. It means app must copy keys/values before put to database.
Known problems: mutation.Put does copy internally. - Low-level API: as close to original LMDB as possible.
- Expose concept of transaction - app-level code can .Rollback() or .Commit()
Result interface:
type KV interface {
View(ctx context.Context, f func(tx Tx) error) (err error)
Update(ctx context.Context, f func(tx Tx) error) (err error)
Close() error
Begin(ctx context.Context, parentTx Tx, writable bool) (Tx, error)
}
type Tx interface {
Bucket(name []byte) Bucket
Commit(ctx context.Context) error
Rollback() // doesn't return err to be defer friendly
}
type Bucket interface {
Get(key []byte) (val []byte, err error)
Put(key []byte, value []byte) error
Delete(key []byte) error
Cursor() Cursor
}
type Cursor interface {
Prefix(v []byte) Cursor
Prefetch(v uint) Cursor
NoValues() NoValuesCursor
First() ([]byte, []byte, error)
Seek(seek []byte) ([]byte, []byte, error)
Next() ([]byte, []byte, error)
}
type NoValuesCursor interface {
First() ([]byte, uint32, error)
Seek(seek []byte) ([]byte, uint32, error)
Next() ([]byte, uint32, error)
}
Rationale and Features list:
Buckets concept:
- Bucket is an interface, can’t be nil, can't return error
InMemory and ReadOnly modes:
NewLMDB().InMem().ReadOnly().Open(ctx)
Context:
- For transactions - yes
- For .First() and .Next() methods - no
Cursor/Iterator:
- Cursor is an interface, can’t be nil, can't return error
cursor.Prefix(prefix)
filtering keys by given prefix. RemoteDb - to support server side filtering.cursor.Prefetch(1000)
- useful for Remote- Methods .First, .Next, .Seek - can return error. If err!=nil then key SHOULD be !=nil (can be []byte{} for example). Then looping code will look as:
for k, v, err := c.First(); k != nil; k, v, err = c.Next() {
if err != nil {
return err
}
// logic
}
Concept of Item:
- No Lazy values, but can disable fetching values by:
.Cursor().PrefetchValues(false).FirstKey()
Managed/un-managed transactions
- Tx is an interface
- db.Update, db.View - yes
- db.Batch - no
- all keys and values returned by all method are valid until end of transaction
- transaction object can be used only withing 1 goroutine
Errors:
- Lib-Errors must be properly wrapped to project: for example ethdb.ErrKeyNotFound
i.SeekTo vs i.Rewind: TBD
in-memory LRU cache: TBD
- Reverse Iterator
Not covered by Abstractions:
- DB stats, bucket.Stats(), item.EstimatedSize()
- buckets stats, buckets list
- TTL of keys
- Monotonic int DB.GetSequence
- Nested Buckets
- Backups, tx.WriteTo