Skip to content

Commit aa385c9

Browse files
committed
feat(reconstruction): ffi interface
1 parent 0375ddc commit aa385c9

File tree

16 files changed

+898
-35
lines changed

16 files changed

+898
-35
lines changed

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ benchmark/ # Performance benchmarking suite
5656
## Important Terminology
5757

5858
- **Revision**: Historical point-in-time state of the trie
59-
- **View**: Interface to read from a Revision or Proposal
59+
- **View**: Interface to read from a Revision, Proposal, or Reconstructed view
6060
- **Node**: Portion of a trie that can point to other nodes and/or contain Key/Value pairs
6161
- **Hash/Root Hash**: Merkle hash for a node/root node
6262
- **Proposal**: Consists of base Root Hash and Batch, not yet committed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ as well as carefully managing the free list during the creation and expiration o
4646
- `Revision` - A historical point-in-time state/version of the trie. This
4747
represents the entire trie, including all `Key`/`Value`s at that point
4848
in time, and all `Node`s.
49-
- `View` - This is the interface to read from a `Revision` or a `Proposal`.
49+
- `View` - This is the interface to read from a `Revision`, `Proposal`, or
50+
`Reconstructed` view.
5051
- `Node` - A node is a portion of a trie. A trie consists of nodes that are linked
5152
together. Nodes can point to other nodes and/or contain `Key`/`Value` pairs.
5253
- `Hash` - In this context, this refers to the merkle hash for a specific node.
@@ -72,6 +73,14 @@ as well as carefully managing the free list during the creation and expiration o
7273
- `Proposal` - A proposal consists of a base `Root Hash` and a `Batch`, but is not
7374
yet committed to the trie. In Firewood's most recent API, a `Proposal` is required
7475
to `Commit`.
76+
- `Reconstructed` - A reconstructed view consists of a base historical view and a
77+
`Batch` applied in-memory.
78+
- It is read-only.
79+
- It cannot be committed.
80+
- It differs from a `Proposal` because reconstructed views are not tracked as
81+
uncommitted branches and do not participate in proposal-parent branching.
82+
- `Reconstructible` - Either a `Historical` or `Reconstructed` view, which supports
83+
building new `Reconstructed` views by applying a `Batch`.
7584
- `Commit` - The operation of applying one or more `Proposal`s to the most recent
7685
`Revision`.
7786

ffi/firewood.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ func (db *Database) root() Hash {
384384
}
385385

386386
// LatestRevision returns a [Revision] representing the latest state of the database.
387-
// If the latest revision has root [EmptyRoot], it returns an error. The [Revision] must
388-
// be dropped prior to closing the database.
387+
// If the latest revision has root [EmptyRoot], it returns an error. The
388+
// [Revision] must be released with [Revision.Drop] before closing the database.
389389
//
390390
// This function conflicts with all other calls that access the latest state of the database,
391391
// and will lock for the duration of this function.
@@ -406,8 +406,9 @@ func (db *Database) LatestRevision() (*Revision, error) {
406406
}
407407

408408
// Revision returns a historical revision of the database.
409-
// If the provided root does not exist (or is the [EmptyRoot]), it returns an error.
410-
// The [Revision] must be dropped prior to closing the database.
409+
// If the provided root does not exist (or is the [EmptyRoot]), it returns an
410+
// error. The [Revision] must be released with [Revision.Drop] before closing
411+
// the database.
411412
//
412413
// This function is thread-safe with all other operations.
413414
func (db *Database) Revision(root Hash) (*Revision, error) {
@@ -435,7 +436,7 @@ func (db *Database) Revision(root Hash) (*Revision, error) {
435436
// [context.Context] is cancelled. That is, until all Revisions and Proposals
436437
// created from this Database are either unreachable or one of
437438
// [Proposal.Commit], [Proposal.Drop], or [Revision.Drop] has been called on
438-
// them. Unreachable objects will be automatically dropped before Close returns,
439+
// them. Unreachable objects will be automatically released before Close returns,
439440
// unless an alternate GC finalizer is set on them.
440441
//
441442
// This is safe to call multiple times; subsequent calls after the first will do

ffi/firewood.h

Lines changed: 102 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ffi/iterator.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ import (
2121
//
2222
// An Iterator holds a reference to the underlying view, so it can safely outlive the
2323
// Revision or Proposal it was created from. The underlying state will not be released
24-
// until the Iterator is dropped.
24+
// until the Iterator is released.
2525
//
2626
// Iterator supports two modes of accessing key-value pairs. [Iterator.Next] copies
2727
// the key and value into Go-managed memory. [Iterator.NextBorrowed] returns slices
2828
// that borrow Rust-owned memory, which is faster but the slices are only valid until
29-
// the next call to Next, NextBorrowed, or Drop.
29+
// the next call to Next, NextBorrowed, or [Iterator.Drop].
3030
type Iterator struct {
3131
// handle is an opaque pointer to the iterator within Firewood. It should be
3232
// passed to the C FFI functions that operate on iterators
@@ -47,7 +47,7 @@ type Iterator struct {
4747
currentPair *ownedKeyValue
4848
currentKey []byte
4949
currentValue []byte
50-
// FFI resource for current pair or batch to free on advance or drop
50+
// FFI resource for current pair or batch to free on advance or release
5151
currentResource interface{ free() error }
5252

5353
// err is the error from the iterator, if any
@@ -149,7 +149,7 @@ func (it *Iterator) NextBorrowed() bool {
149149
// If the iterator has not been advanced or is exhausted, it returns nil.
150150
//
151151
// If the iterator was advanced with [Iterator.NextBorrowed], the returned slice
152-
// borrows Rust memory and is only valid until the next advance or drop.
152+
// borrows Rust memory and is only valid until the next advance or release.
153153
func (it *Iterator) Key() []byte {
154154
if it.currentPair == nil || it.err != nil {
155155
return nil
@@ -161,7 +161,7 @@ func (it *Iterator) Key() []byte {
161161
// If the iterator has not been advanced or is exhausted, it returns nil.
162162
//
163163
// If the iterator was advanced with [Iterator.NextBorrowed], the returned slice
164-
// borrows Rust memory and is only valid until the next advance or drop.
164+
// borrows Rust memory and is only valid until the next advance or release.
165165
func (it *Iterator) Value() []byte {
166166
if it.currentPair == nil || it.err != nil {
167167
return nil
@@ -183,7 +183,7 @@ func (it *Iterator) Drop() error {
183183
err := it.freeCurrentAllocation()
184184
if it.handle != nil {
185185
// Always free the iterator even if releasing the current KV/batch failed.
186-
// The iterator holds a NodeStore ref that must be dropped.
186+
// The iterator holds a NodeStore ref that must be released.
187187
err = errors.Join(
188188
err,
189189
getErrorFromVoidResult(C.fwd_free_iterator(it.handle)))

ffi/proposal.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ var errDroppedProposal = errors.New("proposal already dropped")
2121
// Proposals are created via [Database.Propose] or [Proposal.Propose], and must be
2222
// either committed with [Proposal.Commit] or released with [Proposal.Drop].
2323
//
24-
// Proposals must be committed or dropped before the associated database is
25-
// closed. A finalizer is set on each Proposal to ensure that Drop is called
26-
// when the Proposal is garbage collected, but relying on finalizers is not
27-
// recommended. Failing to commit or drop a proposal before the database is
28-
// closed will cause it to block or fail.
24+
// Proposals must be committed or released before the associated database is
25+
// closed. Release is done by calling [Proposal.Drop]. A finalizer is set on
26+
// each Proposal to ensure Drop is called when the Proposal is garbage
27+
// collected, but relying on finalizers is not recommended. Failing to commit
28+
// or release a proposal before the database is closed will cause it to block
29+
// or fail.
2930
//
3031
// All read operations on a Proposal are thread-safe with respect to each other,
3132
// and can be performed regardless of the state of the associated database. However,
@@ -75,7 +76,7 @@ func (p *Proposal) Get(key []byte) ([]byte, error) {
7576
// The Iterator must be released with [Iterator.Drop] when no longer needed,
7677
// otherwise the underlying proposal will never be properly freed.
7778
//
78-
// It returns an error if Drop or Commit has already been called on the Proposal.
79+
// It returns an error if this Proposal has already been committed or released.
7980
func (p *Proposal) Iter(key []byte) (*Iterator, error) {
8081
p.keepAliveHandle.mu.RLock()
8182
defer p.keepAliveHandle.mu.RUnlock()
@@ -94,7 +95,7 @@ func (p *Proposal) Iter(key []byte) (*Iterator, error) {
9495
// Propose is equivalent to [Database.Propose] except that the new proposal is
9596
// based on `p`.
9697
// The returned proposal cannot be committed until the parent proposal `p` has been
97-
// committed. Additionally, it must be committed or dropped before the [Database] is closed.
98+
// committed. Additionally, it must be committed or released before the [Database] is closed.
9899
//
99100
// Use [Put], [Delete], and [PrefixDelete] to create batch operations.
100101
func (p *Proposal) Propose(batch []BatchOp) (*Proposal, error) {
@@ -142,7 +143,7 @@ func (p *Proposal) Commit() error {
142143
// Dump returns a DOT (Graphviz) format representation of the trie structure
143144
// of this proposal for debugging purposes.
144145
//
145-
// Returns errDroppedProposal if Commit or Drop has already been called.
146+
// Returns errDroppedProposal if this Proposal has already been committed or released.
146147
func (p *Proposal) Dump() (string, error) {
147148
p.keepAliveHandle.mu.RLock()
148149
defer p.keepAliveHandle.mu.RUnlock()

0 commit comments

Comments
 (0)