Documentation
¶
Overview ¶
Package edb implements a document database on top of a key-value store (in this case, on top of Bolt).
We implement:
1. Tables, collection of arbitrary documents marshaled from the given struct.
2. Indices, allowing quick lookup of table data by custom values.
3. Maps, exposing raw key-value buckets with string keys and untyped values.
4. Singleton Keys, allowing to store a typed value for a given key within a map (say, a “config” value in a “globals” map).
Technical Details ¶
**Buckets.** We rely on scoped namespaces for keys called buckets. Bolt supports them natively. A flat database like Redis could simulate buckets via key prefixes. We use nested buckets in Bolt, but only for conveninece; flat buckets are fine.
**Index ordinal** We assign a unique positive integer ordinal to each index. These values are never reused, even if an index is removed.
**Table states** We store a meta document per table, called “table state”. This document holds the information about which indexes are defined for the table, and assigns a (an ordinal) to each one. Ordinals are never reused as indexes are removed and added.
## Binary encoding
**Key encoding**. Keys are encoded using a _tuple encoding_.
**Value**: value header, then encoded data, then encoded index key records.
**Value header**: 1. Flags (uvarint). 2. Schema version (uvarint). 3. Data size (uvarint). 3. Index size (uvarint).
**Value data**: msgpack of the row struct.
**Index key records** (inside a value) record the keys contributed by this row. If index computation changes in the future, we still need to know which index keys to delete when updating the row, so we store all index keys. Format: 1. Number of entries (uvarint). 2. For each entry: index ordinal (uvarint), key length (uvarint), key bytes.
Index ¶
- Constants
- Variables
- func All[Row any](c Cursor[Row]) []*Row
- func AllKeys[Key any](c RawCursor) []Key
- func AllRawKeys(c RawCursor) [][]byte
- func AllTableRows[Row any](txh Txish) []*Row
- func AllUntypedKeys(c RawCursor) []any
- func CountAll(txh Txish, tbl *Table) int
- func DeleteAll(c RawCursor) int
- func DeleteByKey[Row any](txh Txish, key any) bool
- func DeleteRow[Row any](txh Txish, row *Row) bool
- func Exists[Row any](txh Txish, key any) bool
- func Filter[Row any](c Cursor[Row], f func(*Row) bool) []*Row
- func First[Row any](c Cursor[Row]) *Row
- func Get[Row any](txh Txish, key any) *Row
- func Lookup[Row any](txh Txish, idx *Index, indexKey any) *Row
- func LookupKey[Key any](txh Txish, idx *Index, indexKey any) (Key, bool)
- func Memo[T any](txish Txish, key string, f func() (T, error)) (T, error)
- func Proto[T any]() any
- func Put(txh Txish, rows ...any)
- func Reload[Row any](txh Txish, row *Row) *Row
- func SGet[T any](txh Txish, sk *SKey, v *T) bool
- func SGetRaw(txh Txish, sk *SKey) []byte
- func SPut[T any](txh Txish, sk *SKey, v *T)
- func SPutRaw(txh Txish, sk *SKey, raw []byte)
- func Select[Row any](c Cursor[Row], f func(*Row) bool) *Row
- type Cursor
- func ExactIndexScan[Row any](txh Txish, idx *Index, indexValue any) Cursor[Row]
- func FullIndexScan[Row any](txh Txish, idx *Index) Cursor[Row]
- func FullReverseTableScan[Row any](txh Txish) Cursor[Row]
- func FullTableScan[Row any](txh Txish) Cursor[Row]
- func IndexScan[Row any](txh Txish, idx *Index, opt ScanOptions) Cursor[Row]
- func PrefixIndexScan[Row any](txh Txish, idx *Index, els int, indexValue any) Cursor[Row]
- func TableScan[Row any](txh Txish, opt ScanOptions) Cursor[Row]
- type DB
- type DataError
- type DumpFlags
- type FlatMarshaler
- type FlatMarshallable
- type FlatUnmarshaler
- type Index
- type IndexBuilder
- type IndexRow
- type KVMap
- type Options
- type RawCursor
- type RawIndexCursor
- func (c *RawIndexCursor) Key() any
- func (c *RawIndexCursor) Meta() ValueMeta
- func (c *RawIndexCursor) Next() bool
- func (c *RawIndexCursor) RawKey() []byte
- func (c *RawIndexCursor) Row() (any, ValueMeta)
- func (c *RawIndexCursor) RowVal() (reflect.Value, ValueMeta)
- func (c *RawIndexCursor) Table() *Table
- func (c *RawIndexCursor) Tx() *Tx
- type RawTableCursor
- func (c *RawTableCursor) Key() any
- func (c *RawTableCursor) Meta() ValueMeta
- func (c *RawTableCursor) Next() bool
- func (c *RawTableCursor) RawKey() []byte
- func (c *RawTableCursor) Row() (any, ValueMeta)
- func (c *RawTableCursor) RowVal() (reflect.Value, ValueMeta)
- func (c *RawTableCursor) Table() *Table
- func (c *RawTableCursor) Tx() *Tx
- type SKey
- type ScanMethod
- type ScanOptions
- type Schema
- type Table
- func (tbl *Table) DecodeKeyVal(buf []byte) reflect.Value
- func (tbl *Table) EncodeKey(key any) []byte
- func (tbl *Table) KeyString(key any) string
- func (tbl *Table) KeyType() reflect.Type
- func (tbl *Table) Name() string
- func (tbl *Table) NewRow() any
- func (tbl *Table) NewRowVal() reflect.Value
- func (tbl *Table) ParseKey(s string) (any, error)
- func (tbl *Table) ParseKeyVal(s string) (reflect.Value, error)
- func (tbl *Table) RawKeyString(keyRaw []byte) string
- func (tbl *Table) RowHasZeroKey(row any) bool
- func (tbl *Table) RowKey(row any) any
- func (tbl *Table) RowKeyVal(rowVal reflect.Value) reflect.Value
- func (tbl *Table) RowValHasZeroKey(rowVal reflect.Value) bool
- func (tbl *Table) SetRowKey(row, key any)
- func (tbl *Table) SetRowKeyVal(rowVal, keyVal reflect.Value)
- type TableError
- type TableStats
- type Tx
- func (tx *Tx) Close()
- func (tx *Tx) Commit() error
- func (tx *Tx) CommitDespiteError()
- func (tx *Tx) DB() *DB
- func (tx *Tx) DBTx() *Tx
- func (tx *Tx) DeleteByKey(tbl *Table, key any) bool
- func (tx *Tx) DeleteByKeyRaw(tbl *Table, keyRaw []byte) bool
- func (tx *Tx) DeleteByKeyVal(tbl *Table, keyVal reflect.Value) bool
- func (tx *Tx) Dump(f DumpFlags) string
- func (tx *Tx) Exists(tbl *Table, key any) bool
- func (tx *Tx) Get(tbl *Table, key any) (any, ValueMeta)
- func (tx *Tx) GetByKeyVal(tbl *Table, keyVal reflect.Value) (any, ValueMeta)
- func (tx *Tx) GetMemo(key string) (any, bool)
- func (tx *Tx) GetMeta(tbl *Table, key any) ValueMeta
- func (tx *Tx) GetMetaByKeyVal(tbl *Table, keyVal reflect.Value) ValueMeta
- func (tx *Tx) IndexScan(idx *Index, opt ScanOptions) *RawIndexCursor
- func (tx *Tx) IsWritable() bool
- func (tx *Tx) Lookup(idx *Index, indexKey any) any
- func (tx *Tx) LookupKey(idx *Index, indexKey any) any
- func (tx *Tx) LookupKeyVal(idx *Index, indexKeyVal reflect.Value) reflect.Value
- func (tx *Tx) LookupVal(idx *Index, indexKeyVal reflect.Value) (reflect.Value, ValueMeta)
- func (tx *Tx) Memo(key string, f func() (any, error)) (any, error)
- func (tx *Tx) OnChange(f func(tbl *Table, key any))
- func (tx *Tx) Put(tbl *Table, row any) ValueMeta
- func (tx *Tx) PutVal(tbl *Table, rowVal reflect.Value) ValueMeta
- func (tx *Tx) Reindex(tbl *Table, idx *Index)
- func (tx *Tx) Schema() *Schema
- func (tx *Tx) TableScan(tbl *Table, opt ScanOptions) *RawTableCursor
- func (tx *Tx) TableStats(tbl *Table) TableStats
- func (tx *Tx) UnsafeDeleteByKeyRawSkippingIndex(tbl *Table, keyRaw []byte) bool
- type Txish
- type ValueMeta
Constants ¶
const ( DumpTableHeaders = DumpFlags(1 << iota) DumpRows DumpStats DumpIndices DumpIndexRows DumpAll = DumpFlags(0xFFFFFFFFFFFFFFFF) )
const ( MsgPack encodingMethod = iota JSON )
const ( ScanMethodFull = ScanMethod(iota) ScanMethodExact )
const (
SuppressContentWhenLogging = tableOpt(1)
)
Variables ¶
var Break = errors.New("break")
Functions ¶
func AllRawKeys ¶
func AllTableRows ¶
func AllUntypedKeys ¶
Types ¶
type Cursor ¶
func ExactIndexScan ¶
func FullReverseTableScan ¶ added in v0.1.4
func FullTableScan ¶ added in v0.1.1
func PrefixIndexScan ¶
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
func (*DB) BeginUpdate ¶
func (*DB) Tx ¶
Tx currently implements Check-Mutate phases for writable transactions:
Phase 1, Check: before any modifications are made. Runs inside bdb.Batch. Returning an error won't cause the entire batch to fail.
Phase 2, Mutate: from the first mutation. Runs inside bdb.Batch. The entire transaction will be retried in case of error.
TODO: split Mutate phase into Mutate and Post-Mutate phases:
Phase 1, Check (initial phase): inside bdb.Batch, error does not fail batch.
Phase 2, Mutate (initiated by any mutation call): inside bdb.Batch, error fails batch.
Phase 3, Read (initiated by explicit call like Commit): mutations committed, outside bdb.Batch, a new read-only tx is opened on demand.
Check-Mutate-Read would allow to avoid holding the batch during rendering.
A read-only transaction would be a natural extension of Check-Mutate-Read with Check and Mutate phases skipped.
type FlatMarshaler ¶
type FlatMarshallable ¶
type FlatMarshallable interface { FlatMarshaler FlatUnmarshaler }
type FlatUnmarshaler ¶
type IndexBuilder ¶
type IndexBuilder struct {
// contains filtered or unexported fields
}
type RawIndexCursor ¶
type RawIndexCursor struct {
// contains filtered or unexported fields
}
func (*RawIndexCursor) Key ¶
func (c *RawIndexCursor) Key() any
func (*RawIndexCursor) Meta ¶
func (c *RawIndexCursor) Meta() ValueMeta
func (*RawIndexCursor) Next ¶
func (c *RawIndexCursor) Next() bool
func (*RawIndexCursor) RawKey ¶
func (c *RawIndexCursor) RawKey() []byte
func (*RawIndexCursor) Row ¶
func (c *RawIndexCursor) Row() (any, ValueMeta)
func (*RawIndexCursor) Table ¶
func (c *RawIndexCursor) Table() *Table
func (*RawIndexCursor) Tx ¶
func (c *RawIndexCursor) Tx() *Tx
type RawTableCursor ¶
type RawTableCursor struct {
// contains filtered or unexported fields
}
func (*RawTableCursor) Key ¶
func (c *RawTableCursor) Key() any
func (*RawTableCursor) Meta ¶
func (c *RawTableCursor) Meta() ValueMeta
func (*RawTableCursor) Next ¶
func (c *RawTableCursor) Next() bool
func (*RawTableCursor) RawKey ¶
func (c *RawTableCursor) RawKey() []byte
func (*RawTableCursor) Row ¶
func (c *RawTableCursor) Row() (any, ValueMeta)
func (*RawTableCursor) Table ¶
func (c *RawTableCursor) Table() *Table
func (*RawTableCursor) Tx ¶
func (c *RawTableCursor) Tx() *Tx
type ScanMethod ¶
type ScanMethod int
type ScanOptions ¶
type ScanOptions struct { Reverse bool Method ScanMethod Lower reflect.Value Els int }
func ExactScan ¶
func ExactScan(v any) ScanOptions
func ExactScanVal ¶
func ExactScanVal(val reflect.Value) ScanOptions
func FullScan ¶
func FullScan() ScanOptions
func (ScanOptions) LogString ¶ added in v0.1.2
func (so ScanOptions) LogString() string
func (ScanOptions) Prefix ¶
func (so ScanOptions) Prefix(els int) ScanOptions
func (ScanOptions) Reversed ¶
func (so ScanOptions) Reversed() ScanOptions
type Schema ¶
type Schema struct { Name string // contains filtered or unexported fields }
func (*Schema) TableByRow ¶ added in v0.1.2
func (*Schema) TableByRowType ¶ added in v0.1.2
func (*Schema) TableNamed ¶
type Table ¶
type Table struct {
// contains filtered or unexported fields
}
func (*Table) RawKeyString ¶
func (*Table) RowHasZeroKey ¶ added in v0.1.2
func (*Table) RowValHasZeroKey ¶ added in v0.1.2
func (*Table) SetRowKeyVal ¶
type TableError ¶
func (*TableError) Error ¶
func (e *TableError) Error() string
func (*TableError) Unwrap ¶
func (e *TableError) Unwrap() error
type TableStats ¶
type TableStats struct { Rows int IndexRows int DataSize int DataAlloc int IndexSize int IndexAlloc int }
func (*TableStats) TotalAlloc ¶
func (ts *TableStats) TotalAlloc() int
func (*TableStats) TotalSize ¶
func (ts *TableStats) TotalSize() int
type Tx ¶
type Tx struct {
// contains filtered or unexported fields
}
func (*Tx) CommitDespiteError ¶
func (tx *Tx) CommitDespiteError()
func (*Tx) GetByKeyVal ¶
func (*Tx) GetMetaByKeyVal ¶
func (*Tx) IndexScan ¶
func (tx *Tx) IndexScan(idx *Index, opt ScanOptions) *RawIndexCursor
func (*Tx) IsWritable ¶
func (*Tx) LookupKeyVal ¶
func (*Tx) TableScan ¶
func (tx *Tx) TableScan(tbl *Table, opt ScanOptions) *RawTableCursor
func (*Tx) TableStats ¶
func (tx *Tx) TableStats(tbl *Table) TableStats
Source Files
¶
- byteutil.go
- db.go
- debug.go
- doc.go
- encflat.go
- encindexkeys.go
- encoding.go
- enctuple.go
- encvalue.go
- errors.go
- index.go
- monitoring.go
- opdelete.go
- opget.go
- opimpl.go
- opimpldecode.go
- oplookup.go
- opmaint.go
- opput.go
- ops.go
- opscan.go
- pools.go
- reflect.go
- schema.go
- schemaindex.go
- schemastate.go
- schematable.go
- tx.go
- util.go