Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
186 commits
Select commit Hold shift + click to select a range
6261968
feat: initial implementation of ffi iterator
AminR443 Jul 29, 2025
071a5eb
feat: better go interface for iterator, edge case fixes
AminR443 Jul 30, 2025
28bc2a8
style: cargo fmt
AminR443 Jul 30, 2025
9d1ef4b
Merge branch 'main' into amin/ffi-iterator
AminR443 Jul 30, 2025
23f7e6d
fix: tiny issues after merge
AminR443 Jul 30, 2025
3295568
fix: test clippy error, better test case
AminR443 Jul 30, 2025
4029d20
feat: better iterator abstraction in ffi, iter_on_root
AminR443 Aug 1, 2025
96acf50
chore: only include firewood crate changes to make pr smaller
AminR443 Aug 4, 2025
0be5eb0
fix: apply suggestions, add docs, add tests
AminR443 Aug 4, 2025
316f9a3
Merge branch 'main' into amin/ffi-iterator-base
AminR443 Aug 4, 2025
338a4c9
fix: stuff from merge, style
AminR443 Aug 4, 2025
4d08b12
fix: format variable for clippy
AminR443 Aug 4, 2025
3ea4f7f
feat: better abstraction, deduplication in DbViewSyncBytes
AminR443 Aug 4, 2025
7cfa1cf
test: add tests for iterate, fix tiny issues
AminR443 Aug 5, 2025
8ec3991
ci: trigger tests
AminR443 Aug 5, 2025
40671f1
Merge branch 'main' into amin/ffi-iterator-base
AminR443 Aug 5, 2025
bde139e
test: add fuzz test for iterate
AminR443 Aug 6, 2025
b1546f2
Merge branch 'main' into amin/ffi-iterator-base
AminR443 Aug 6, 2025
3f76257
wip: new iterator
AminR443 Aug 12, 2025
74ff74b
feat: merkle_ref for supporting arc in merklenodestream
AminR443 Aug 13, 2025
236a710
merge: needed new parts from ffi-iterator-base
AminR443 Aug 13, 2025
b1586d7
fix: missed stuff, fmt
AminR443 Aug 13, 2025
bce4d7d
feat: all ffi methods initial impl
AminR443 Aug 13, 2025
4c8a2bb
feat: go ffi, tidy rust ffi and use borrowed
AminR443 Aug 13, 2025
10c9551
chore: remove go side for now
AminR443 Aug 14, 2025
a42aae2
feat: iter_on_proposal, code cleanup
AminR443 Aug 14, 2025
b17113e
todo: key value note
AminR443 Aug 14, 2025
7440a5f
feat(async-removal): Phase 1 - lint on `clippy::unused_async`
demosdemon Aug 14, 2025
84ff6ce
feat(async-removal): Phase 2 - make `Proposal` trait sync
demosdemon Aug 14, 2025
6d05477
feat(async-removal): Phase 3 - make `Db` trait sync
demosdemon Aug 14, 2025
cc95f6d
Merge branch 'main' into brandon.leblanc/remove-async-p2
demosdemon Aug 14, 2025
83a3c77
Merge branch 'brandon.leblanc/remove-async-p2' into brandon.leblanc/r…
demosdemon Aug 14, 2025
16fe8be
Merge branch 'main' into amin/ffi-iterator-new
AminR443 Aug 14, 2025
a47843b
Merge branch 'main' into brandon.leblanc/remove-async-p2
demosdemon Aug 18, 2025
e7540bf
Merge branch 'brandon.leblanc/remove-async-p2' into brandon.leblanc/r…
demosdemon Aug 18, 2025
d0d8b2b
Merge branch 'main' into brandon.leblanc/remove-async-p2
demosdemon Aug 19, 2025
f6ca77a
Merge branch 'brandon.leblanc/remove-async-p2' into brandon.leblanc/r…
demosdemon Aug 19, 2025
dd3f3cf
Merge branch 'main' into brandon.leblanc/remove-async-p3
demosdemon Aug 19, 2025
ce44145
Merge branch 'main' into amin/ffi-iterator-new
AminR443 Aug 20, 2025
c1452a3
refactor: better types
AminR443 Aug 20, 2025
eeee17e
Merge branch 'main' into brandon.leblanc/remove-async-p3
demosdemon Aug 20, 2025
f07184e
feat(async-removal): Phase 4 - Make `DbView` synchronous
demosdemon Aug 20, 2025
4d8db9d
missed some
demosdemon Aug 20, 2025
28dc159
fix metrics
demosdemon Aug 20, 2025
e330a0b
fix benchmark again
demosdemon Aug 20, 2025
89c0d9b
make tokio/prometheus optional
demosdemon Aug 20, 2025
43227dc
add grpc-testtool back (even though it's broken)
demosdemon Aug 20, 2025
2e387c2
replace DbViewSyncBytes with ArcDynDbView
demosdemon Aug 20, 2025
64ce27a
comment typo
demosdemon Aug 20, 2025
ae15477
cleanup
demosdemon Aug 20, 2025
56ab74e
remove commented code
demosdemon Aug 20, 2025
87bd241
more cleanup
demosdemon Aug 20, 2025
b1d847a
fix root ethhash
demosdemon Aug 20, 2025
bf766d1
Merge remote-tracking branch 'origin/main' into brandon.leblanc/remov…
demosdemon Aug 20, 2025
c30c847
lifetime label consistency
demosdemon Aug 20, 2025
d27fd65
extension trait
demosdemon Aug 20, 2025
628668d
Merge branch 'main' into brandon.leblanc/remove-async-p4
demosdemon Aug 20, 2025
79815d1
remove needless impls
demosdemon Aug 21, 2025
ad310a2
nit-picky change
demosdemon Aug 21, 2025
468291b
move try_extend into its own module and add test
demosdemon Aug 21, 2025
7b2279f
update test
demosdemon Aug 21, 2025
94d6dec
collapse trait bounds
demosdemon Aug 21, 2025
d034c8a
wip: merge remote-tracking branch 'origin/brandon.leblanc/remove-asyn…
AminR443 Aug 22, 2025
3a0ae2d
feat: OwnedIterView and use new sync api
AminR443 Aug 22, 2025
7dee974
feat(ffi-refactor): replace sequence id with pointer to proposals (8/8)
demosdemon Aug 22, 2025
a5ba724
Merge branch 'amin/ffi-iterator-sync' into amin/ffi-iterator-new
AminR443 Aug 23, 2025
5949620
Merge branch 'main' into amin/ffi-iterator-new
AminR443 Aug 23, 2025
1ee07d9
fix: merge errors
AminR443 Aug 23, 2025
546ffc8
Merge remote-tracking branch 'origin/brandon.leblanc/ffi-refactor' in…
AminR443 Aug 23, 2025
d80c022
feat: iterator with new ffi structure
AminR443 Aug 25, 2025
3f06f81
chore: remove irrelevant comments
AminR443 Aug 25, 2025
8020a02
fix: cargo fmt
AminR443 Aug 25, 2025
247fcad
feat: add docs, cleanup
AminR443 Aug 25, 2025
c8b88e1
fmt: .
AminR443 Aug 25, 2025
3b76b12
feat: squash merge from ffi-iterator-performance, update changes to n…
AminR443 Aug 25, 2025
cac3755
feat: iter on proposal for go, tests, fix latest revision issue
AminR443 Aug 26, 2025
53fb5f4
Merge branch 'main' into brandon.leblanc/ffi-refactor
demosdemon Aug 27, 2025
7efdf98
Merge branch 'main' into brandon.leblanc/ffi-refactor
demosdemon Aug 27, 2025
8efa4bf
fmt: ...
AminR443 Sep 3, 2025
1858a9b
fix: uniform behaviour for empty db (ethhash)
AminR443 Sep 3, 2025
ce94989
fix: golangci-lint issues
AminR443 Sep 3, 2025
1a2a37e
review: apply pr comments
AminR443 Sep 4, 2025
f50427d
feat: better iter interface for views, clean code, better docs
AminR443 Sep 5, 2025
b828883
fix: doc ref
AminR443 Sep 5, 2025
9071f19
Merge remote-tracking branch 'origin/main' into brandon.leblanc/ffi-r…
demosdemon Sep 5, 2025
483538f
use something adding in merge
demosdemon Sep 5, 2025
d8ebb92
Merge remote-tracking branch 'origin/main' into brandon.leblanc/ffi-r…
demosdemon Sep 5, 2025
87515fc
errant change from resolving merge conflicts
demosdemon Sep 5, 2025
6b1e3af
start moving things out of memory.go
demosdemon Sep 5, 2025
8171ef7
fix doc error
demosdemon Sep 5, 2025
fcac3a8
Merge remote-tracking branch 'origin/brandon.leblanc/ffi-refactor' in…
AminR443 Sep 8, 2025
bafc8ad
Merge branch 'amin/ffi-iterator-p1' into amin/ffi-iterator-p2
AminR443 Sep 8, 2025
f15635c
fix: apply first round of suggestions by austin
AminR443 Sep 8, 2025
b3f8654
fix: apply second round of suggestions by austin
AminR443 Sep 8, 2025
e4374f3
feat: drop rust iterator automatically if exhausted
AminR443 Sep 8, 2025
d3e2ac7
Merge branch 'main' into brandon.leblanc/ffi-refactor
demosdemon Sep 8, 2025
c04104b
feat!: rename `Hashable::key`
demosdemon Sep 9, 2025
6792c2f
put back the filtered child_hashes
demosdemon Sep 9, 2025
1d1c29a
comments
demosdemon Sep 9, 2025
1705b44
correct comments on the trait
demosdemon Sep 9, 2025
b7cf054
fix: add suggested changes
AminR443 Sep 9, 2025
acf3e94
feat(proofs)!: add v0 serialization for RangeProofs
demosdemon Sep 10, 2025
eb9e4ec
go fmt
demosdemon Sep 10, 2025
febb68e
update err to match on both ethhash and not
demosdemon Sep 10, 2025
49f9366
ensure partial range proofs generate and serialize
demosdemon Sep 10, 2025
ec8ee02
Merge branch 'main' into brandon.leblanc/ffi-refactor
demosdemon Sep 10, 2025
c3e0da7
feedback updates
demosdemon Sep 10, 2025
9cc3c53
golint
demosdemon Sep 10, 2025
7802d5e
update documentation
demosdemon Sep 10, 2025
40c33cc
make ChildrenMap generic
demosdemon Sep 10, 2025
3629d76
fix docs
demosdemon Sep 10, 2025
ccc5f1c
Merge branch 'brandon.leblanc/hashable-trait-methods' into brandon.le…
demosdemon Sep 10, 2025
d182370
Merge branch 'brandon.leblanc/serialized-range-proofs' into brandon.l…
demosdemon Sep 10, 2025
7aaa681
more tests and document the DOS
demosdemon Sep 10, 2025
6b33cf2
simplify tests
demosdemon Sep 10, 2025
31648d7
consistency
demosdemon Sep 10, 2025
e84ae42
rewrite reader to be easier to read
demosdemon Sep 10, 2025
60b54ae
finish moving things around
demosdemon Sep 10, 2025
f0375c4
fix docs
demosdemon Sep 10, 2025
72a444d
hide ProofType too
demosdemon Sep 10, 2025
4ed5534
Merge branch 'brandon.leblanc/serialized-range-proofs' into brandon.l…
demosdemon Sep 10, 2025
b46ca19
check that the keys drom the dropped proposal are not in the db
demosdemon Sep 10, 2025
7508405
Merge branch 'main' into brandon.leblanc/hashable-trait-methods
demosdemon Sep 15, 2025
21ba3b7
Merge branch 'brandon.leblanc/hashable-trait-methods' into brandon.le…
demosdemon Sep 15, 2025
3669d24
Merge branch 'brandon.leblanc/serialized-range-proofs' into brandon.l…
demosdemon Sep 15, 2025
5e7cca7
fix(range-proofs): serialize range proof key consistently
demosdemon Sep 15, 2025
6a6648d
Merge remote-tracking branch 'origin/main' into brandon.leblanc/seria…
demosdemon Sep 15, 2025
b818975
Merge remote-tracking branch 'origin/main' into brandon.leblanc/fix-l…
demosdemon Sep 15, 2025
7ab26ab
Merge branch 'main' into brandon.leblanc/serialized-range-proofs
demosdemon Sep 15, 2025
6348f89
fix(range-proofs): fix verify of exclusion proofs
demosdemon Sep 15, 2025
4a6a77d
Merge branch 'brandon.leblanc/fix-left-exclusion-proof' into brandon.…
demosdemon Sep 15, 2025
662daa3
Merge branch 'main' into brandon.leblanc/fix-left-exclusion-proof
demosdemon Sep 15, 2025
ff250bc
Merge branch 'brandon.leblanc/fix-left-exclusion-proof' into brandon.…
demosdemon Sep 15, 2025
e57666a
fix for ethhash
demosdemon Sep 15, 2025
e4f8ee8
Merge branch 'brandon.leblanc/fix-left-exclusion-proof' into brandon.…
demosdemon Sep 15, 2025
07bf0d1
Merge branch 'brandon.leblanc/serialized-range-proofs' into brandon.l…
demosdemon Sep 15, 2025
7580057
Merge remote-tracking branch 'origin/brandon.leblanc/fix-verify-exclu…
demosdemon Sep 16, 2025
228b463
Merge remote-tracking branch 'origin/main' into brandon.leblanc/ffi-r…
demosdemon Sep 16, 2025
ec865c8
Merge branch 'main' into brandon.leblanc/ffi-refactor
demosdemon Sep 16, 2025
5266c78
Merge branch 'main' into brandon.leblanc/ffi-refactor
demosdemon Sep 24, 2025
fcc07b8
Merge branch 'main' into brandon.leblanc/ffi-refactor
demosdemon Sep 26, 2025
e818456
wip: step 1, revision ground work
AminR443 Oct 1, 2025
3fbb4ae
docs: add documentation for methods
AminR443 Oct 1, 2025
deced79
feat: impl dbview for revision manager
AminR443 Oct 1, 2025
9ecadd8
docs: add docs
AminR443 Oct 1, 2025
97bc262
feat: hook up go side with the revisions
AminR443 Oct 1, 2025
f175b7a
docs: go
AminR443 Oct 1, 2025
3ba04e5
feat: add free
AminR443 Oct 1, 2025
9220cb7
doc+test: revision
AminR443 Oct 2, 2025
3c351ac
fix: typo
AminR443 Oct 2, 2025
efc7bf0
fmt: ...
AminR443 Oct 2, 2025
8db0b58
fmt: clippy
AminR443 Oct 2, 2025
0a57f71
fmt: ...
AminR443 Oct 2, 2025
29d4ccc
Merge commit 'fcc07b8ba5e0716e3d8892a275010e77daaebbe5' into amin/ffi…
AminR443 Oct 2, 2025
60eb9e7
Merge commit '8df1ccc1464f58839c732b57c6cd703e88137abc' into amin/ffi…
AminR443 Oct 2, 2025
340058d
Merge remote-tracking branch 'origin/main' into amin/ffi-iterator-p1
AminR443 Oct 2, 2025
f1177df
chore: cargo.lock update
AminR443 Oct 2, 2025
1d98216
Merge branch 'amin/ffi-revision' into amin/ffi-iterator-p1
AminR443 Oct 2, 2025
975fe4c
feat: integrate with revision handle
AminR443 Oct 2, 2025
96ce89d
docs: ..
AminR443 Oct 2, 2025
4e1398b
fix: docs issue
AminR443 Oct 2, 2025
332fba7
Merge branch 'amin/ffi-revision' into amin/ffi-iterator-p1
AminR443 Oct 2, 2025
42ef414
fmt: ...
AminR443 Oct 2, 2025
c0c126d
wip: merge p1
AminR443 Oct 2, 2025
b37adaf
feat: make iter go interface compatible with revisions
AminR443 Oct 2, 2025
193563f
review: apply Ron's suggestions
AminR443 Oct 2, 2025
ac53d8d
fix: docs
AminR443 Oct 3, 2025
bda609d
fmt: ...
AminR443 Oct 3, 2025
6ea9dbf
Merge branch 'amin/ffi-iterator-p1' into amin/ffi-iterator-p2
AminR443 Oct 3, 2025
38ce865
fix: make it work with p1 changes
AminR443 Oct 3, 2025
dbcf8cf
test: add revision lifetime showcase
AminR443 Oct 3, 2025
ca451df
test: add revision lifetime showcase/reaping
AminR443 Oct 6, 2025
9a5c66e
feat: brandon's suggestions
AminR443 Oct 6, 2025
15a7b40
Merge branch 'main' into amin/ffi-revision
AminR443 Oct 10, 2025
1902e23
Merge branch 'amin/ffi-revision' into amin/ffi-iterator-p1
AminR443 Oct 10, 2025
24da907
Merge branch 'amin/ffi-iterator-p1' into amin/ffi-iterator-p2
AminR443 Oct 10, 2025
4ec6ad7
clippy: ...
AminR443 Oct 10, 2025
dc6a000
Merge branch 'main' into amin/ffi-revision
AminR443 Oct 10, 2025
101b119
fix: cargo.lock anomaly
AminR443 Oct 10, 2025
be6728b
Merge branch 'main' into amin/ffi-revision
AminR443 Oct 10, 2025
57cb082
docs: clarification
AminR443 Oct 10, 2025
e42f063
Merge branch 'main' into amin/ffi-revision
AminR443 Oct 10, 2025
27a0688
Merge branch 'amin/ffi-revision' into amin/ffi-iterator-p1
AminR443 Oct 10, 2025
91d3882
Merge branch 'main' into amin/ffi-iterator-p1
AminR443 Oct 10, 2025
ab7f1ad
Merge branch 'amin/ffi-iterator-p1' into amin/ffi-iterator-p2
AminR443 Oct 10, 2025
6a7dbcc
Merge branch 'main' into amin/ffi-iterator-p2
AminR443 Oct 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions ffi/firewood.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,17 @@ func (db *Database) Root() ([]byte, error) {
return bytes, err
}

func (db *Database) LatestRevision() (*Revision, error) {
root, err := db.Root()
if err != nil {
return nil, err
}
if bytes.Equal(root, EmptyRoot) {
return nil, errRevisionNotFound
}
return db.Revision(root)
}

// Revision returns a historical revision of the database.
func (db *Database) Revision(root []byte) (*Revision, error) {
if root == nil || len(root) != RootLength {
Expand Down
141 changes: 141 additions & 0 deletions ffi/firewood_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1136,3 +1136,144 @@ func TestGetFromRootParallel(t *testing.T) {
r.NoError(err, "Parallel operation failed")
}
}

func assertIteratorYields(r *require.Assertions, it *Iterator, keys [][]byte, vals [][]byte) {
i := 0
for ; it.Next(); i += 1 {
r.Equal(keys[i], it.Key())
r.Equal(vals[i], it.Value())
}
r.NoError(it.Err())
r.Equal(len(keys), i)
}

// Tests that basic iterator functionality works
func TestIter(t *testing.T) {
r := require.New(t)
db := newTestDatabase(t)

keys, vals := kvForTest(10)
_, err := db.Update(keys, vals)
r.NoError(err)

rev, err := db.LatestRevision()
r.NoError(err)
it, err := rev.Iter(nil)
r.NoError(err)
t.Cleanup(func() {
r.NoError(it.Drop())
r.NoError(rev.Drop())
})

assertIteratorYields(r, it, keys, vals)
}

// Tests that iterators on different roots work fine
func TestIterOnRoot(t *testing.T) {
r := require.New(t)
db := newTestDatabase(t)

// Commit 10 key-value pairs.
keys, vals := kvForTest(20)
keys = keys[:10]
vals1, vals2 := vals[:10], vals[10:]

firstRoot, err := db.Update(keys, vals1)
r.NoError(err)

// we use the same keys, but update the values
secondRoot, err := db.Update(keys, vals2)
r.NoError(err)

r1, err := db.Revision(firstRoot)
r.NoError(err)
h1, err := r1.Iter(nil)
r.NoError(err)
t.Cleanup(func() {
r.NoError(h1.Drop())
r.NoError(r1.Drop())
})

r2, err := db.Revision(secondRoot)
r.NoError(err)
h2, err := r2.Iter(nil)
r.NoError(err)
t.Cleanup(func() {
r.NoError(h2.Drop())
r.NoError(r2.Drop())
})

assertIteratorYields(r, h1, keys, vals1)
assertIteratorYields(r, h2, keys, vals2)
}

// Tests that basic iterator functionality works for proposal
func TestIterOnProposal(t *testing.T) {
r := require.New(t)
db := newTestDatabase(t)

keys, vals := kvForTest(10)
p, err := db.Propose(keys, vals)
r.NoError(err)

it, err := p.Iter(nil)
r.NoError(err)
t.Cleanup(func() {
r.NoError(it.Drop())
})

assertIteratorYields(r, it, keys, vals)
}

// Tests that the iterator still works after proposal is committed
func TestIterAfterProposalCommit(t *testing.T) {
r := require.New(t)
db := newTestDatabase(t)

keys, vals := kvForTest(10)
p, err := db.Propose(keys, vals)
r.NoError(err)

it, err := p.Iter(nil)
r.NoError(err)
t.Cleanup(func() {
r.NoError(it.Drop())
})

err = p.Commit()
r.NoError(err)

// iterate after commit
// because iterator hangs on the nodestore reference of proposal
// the nodestore won't be dropped until we drop the iterator
assertIteratorYields(r, it, keys, vals)
}

// Tests that the iterator on latest revision works properly after a proposal commit
func TestIterUpdate(t *testing.T) {
r := require.New(t)
db := newTestDatabase(t)

keys, vals := kvForTest(10)
_, err := db.Update(keys, vals)
r.NoError(err)

// get an iterator on latest revision
rev, err := db.LatestRevision()
r.NoError(err)
it, err := rev.Iter(nil)
r.NoError(err)
t.Cleanup(func() {
r.NoError(it.Drop())
r.NoError(rev.Drop())
})

// update the database
keys2, vals2 := kvForTest(10)
_, err = db.Update(keys2, vals2)
r.NoError(err)

// iterate after commit
// because iterator is fixed on the revision hash, it should return the initial values
assertIteratorYields(r, it, keys, vals)
}
92 changes: 92 additions & 0 deletions ffi/iterator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (C) 2025, Ava Labs, Inc. All rights reserved.
// See the file LICENSE.md for licensing terms.

package ffi

// #include <stdlib.h>
// #include "firewood.h"
import "C"

import (
"fmt"
"unsafe"
)

type Iterator struct {
// handle is an opaque pointer to the iterator within Firewood. It should be
// passed to the C FFI functions that operate on iterators
//
// It is not safe to call these methods with a nil handle.
handle *C.IteratorHandle

// currentKey is the current key retrieved from the iterator
currentKey []byte
// currentVal is the current value retrieved from the iterator
currentVal []byte
// err is the error from the iterator, if any
err error
}

// Next proceeds to the next item on the iterator, and returns true
// if succeeded and there is a pair available.
// The new pair could be retrieved with Key and Value methods.
func (it *Iterator) Next() bool {
kv, e := getKeyValueFromKeyValueResult(C.fwd_iter_next(it.handle))
it.err = e
if kv == nil || e != nil {
return false
}
k, v, e := kv.Consume()
it.currentKey = k
it.currentVal = v
it.err = e
return e == nil
}

// Key returns the key of the current pair
func (it *Iterator) Key() []byte {
if (it.currentKey == nil && it.currentVal == nil) || it.err != nil {
return nil
}
return it.currentKey
}

// Value returns the value of the current pair
func (it *Iterator) Value() []byte {
if (it.currentKey == nil && it.currentVal == nil) || it.err != nil {
return nil
}
return it.currentVal
}

// Err returns the error if Next failed
func (it *Iterator) Err() error {
return it.err
}

// Drop drops the iterator and releases the resources
func (it *Iterator) Drop() error {
if it.handle != nil {
return getErrorFromVoidResult(C.fwd_free_iterator(it.handle))
}
return nil
}

// getIteratorFromIteratorResult converts a C.IteratorResult to an Iterator or error.
func getIteratorFromIteratorResult(result C.IteratorResult) (*Iterator, error) {
switch result.tag {
case C.IteratorResult_NullHandlePointer:
return nil, errDBClosed
case C.IteratorResult_Ok:
body := (*C.IteratorResult_Ok_Body)(unsafe.Pointer(&result.anon0))
proposal := &Iterator{
handle: body.handle,
}
return proposal, nil
case C.IteratorResult_Err:
err := newOwnedBytes(*(*C.OwnedBytes)(unsafe.Pointer(&result.anon0))).intoError()
return nil, err
default:
return nil, fmt.Errorf("unknown C.IteratorResult tag: %d", result.tag)
}
}
50 changes: 50 additions & 0 deletions ffi/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,56 @@ func getValueFromValueResult(result C.ValueResult) ([]byte, error) {
}
}

type ownedKeyValue struct {
key *ownedBytes
value *ownedBytes
}

func (kv *ownedKeyValue) Consume() ([]byte, []byte, error) {
key := kv.key.CopiedBytes()
if err := kv.key.Free(); err != nil {
return nil, nil, fmt.Errorf("%w: %w", errFreeingValue, err)
}
value := kv.value.CopiedBytes()
if err := kv.value.Free(); err != nil {
return nil, nil, fmt.Errorf("%w: %w", errFreeingValue, err)
}
return key, value, nil
}

// newOwnedKeyValue creates a ownedKeyValue from a C.OwnedKeyValuePair.
//
// The caller is responsible for calling Free() on the returned ownedKeyValue
// when it is no longer needed otherwise memory will leak.
func newOwnedKeyValue(owned C.OwnedKeyValuePair) *ownedKeyValue {
return &ownedKeyValue{
key: newOwnedBytes(owned.key),
value: newOwnedBytes(owned.value),
}
}

// getKeyValueFromKeyValueResult converts a C.KeyValueResult to a key value pair or error.
//
// It returns nil, nil if the result is None.
// It returns a *ownedKeyValue, nil if the result is Some.
// It returns an error if the result is an error.
func getKeyValueFromKeyValueResult(result C.KeyValueResult) (*ownedKeyValue, error) {
switch result.tag {
case C.KeyValueResult_NullHandlePointer:
return nil, errDBClosed
case C.KeyValueResult_None:
return nil, nil
case C.KeyValueResult_Some:
ownedKvp := newOwnedKeyValue(*(*C.OwnedKeyValuePair)(unsafe.Pointer(&result.anon0)))
return ownedKvp, nil
case C.ValueResult_Err:
err := newOwnedBytes(*(*C.OwnedBytes)(unsafe.Pointer(&result.anon0))).intoError()
return nil, err
default:
return nil, fmt.Errorf("unknown C.KeyValueResult tag: %d", result.tag)
}
}

// getDatabaseFromHandleResult converts a C.HandleResult to a Database or error.
//
// If the C.HandleResult is an error, it returns an error instead of a Database.
Expand Down
15 changes: 15 additions & 0 deletions ffi/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ func (p *Proposal) Get(key []byte) ([]byte, error) {
return getValueFromValueResult(C.fwd_get_from_proposal(p.handle, newBorrowedBytes(key, &pinner)))
}

// Iter creates and iterator starting from the provided key on proposal.
// pass empty slice to start from beginning
func (p *Proposal) Iter(key []byte) (*Iterator, error) {
if p.handle == nil {
return nil, errDBClosed
}

var pinner runtime.Pinner
defer pinner.Unpin()

itResult := C.fwd_iter_on_proposal(p.handle, newBorrowedBytes(key, &pinner))

return getIteratorFromIteratorResult(itResult)
}

// Propose creates a new proposal with the given keys and values.
// The proposal is not committed until Commit is called.
func (p *Proposal) Propose(keys, vals [][]byte) (*Proposal, error) {
Expand Down
15 changes: 15 additions & 0 deletions ffi/revision.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ func (r *Revision) Get(key []byte) ([]byte, error) {
))
}

// Iter creates an iterator starting from the provided key on revision.
// pass empty slice to start from beginning
func (r *Revision) Iter(key []byte) (*Iterator, error) {
if r.handle == nil {
return nil, errDroppedRevision
}

var pinner runtime.Pinner
defer pinner.Unpin()

itResult := C.fwd_iter_on_revision(r.handle, newBorrowedBytes(key, &pinner))

return getIteratorFromIteratorResult(itResult)
}

// Drop releases the resources backed by the revision handle.
//
// It is safe to call Drop multiple times; subsequent calls after the first are no-ops.
Expand Down
Loading