Skip to content

Commit e1e70ce

Browse files
committed
feat: defer persist every N commits
1 parent 38c9956 commit e1e70ce

File tree

7 files changed

+341
-47
lines changed

7 files changed

+341
-47
lines changed

ffi/firewood.go

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ var (
6262
// ErrActiveKeepAliveHandles is returned when attempting to close a database with unfreed memory.
6363
ErrActiveKeepAliveHandles = errors.New("cannot close database with active keep-alive handles")
6464

65-
errDBClosed = errors.New("firewood database already closed")
65+
errDBClosed = errors.New("firewood database already closed")
66+
errZeroCommitCount = errors.New("deferred persistence commit count must not be 0")
6667
)
6768

6869
// Database is an FFI wrapper for the Rust Firewood database.
@@ -113,14 +114,18 @@ type config struct {
113114
rootStore bool
114115
// expensiveMetricsEnabled controls whether expensive metrics recording is enabled.
115116
expensiveMetricsEnabled bool
117+
// deferredPersistenceCommitCount determines the maximum number of unpersisted
118+
// revisions that can exist at a given time.
119+
deferredPersistenceCommitCount uint64
116120
}
117121

118122
func defaultConfig() *config {
119123
return &config{
120-
nodeCacheEntries: 1_000_000,
121-
freeListCacheEntries: 1_000_000,
122-
revisions: 100,
123-
readCacheStrategy: OnlyCacheWrites,
124+
nodeCacheEntries: 1_000_000,
125+
freeListCacheEntries: 1_000_000,
126+
revisions: 100,
127+
readCacheStrategy: OnlyCacheWrites,
128+
deferredPersistenceCommitCount: 1,
124129
}
125130
}
126131

@@ -193,6 +198,15 @@ func WithExpensiveMetrics() Option {
193198
}
194199
}
195200

201+
// WithDeferredPersistenceCommitCount sets the maximum number of unpersisted revisions
202+
// that can exist at a time. Note: `commitCount` must be greater than 0.
203+
// Default: 1
204+
func WithDeferredPersistenceCommitCount(commitCount uint64) Option {
205+
return func(c *config) {
206+
c.deferredPersistenceCommitCount = commitCount
207+
}
208+
}
209+
196210
// A CacheStrategy represents the caching strategy used by a [Database].
197211
type CacheStrategy uint8
198212

@@ -245,20 +259,24 @@ func New(dbDir string, nodeHashAlgorithm NodeHashAlgorithm, opts ...Option) (*Da
245259
if conf.freeListCacheEntries < 1 {
246260
return nil, fmt.Errorf("free list cache entries must be >= 1, got %d", conf.freeListCacheEntries)
247261
}
262+
if conf.deferredPersistenceCommitCount == 0 {
263+
return nil, errZeroCommitCount
264+
}
248265

249266
var pinner runtime.Pinner
250267
defer pinner.Unpin()
251268

252269
args := C.struct_DatabaseHandleArgs{
253-
dir: newBorrowedBytes([]byte(dbDir), &pinner),
254-
cache_size: C.size_t(conf.nodeCacheEntries),
255-
free_list_cache_size: C.size_t(conf.freeListCacheEntries),
256-
revisions: C.size_t(conf.revisions),
257-
strategy: C.uint8_t(conf.readCacheStrategy),
258-
truncate: C.bool(conf.truncate),
259-
root_store: C.bool(conf.rootStore),
260-
expensive_metrics: C.bool(conf.expensiveMetricsEnabled),
261-
node_hash_algorithm: C.enum_NodeHashAlgorithm(nodeHashAlgorithm),
270+
dir: newBorrowedBytes([]byte(dbDir), &pinner),
271+
cache_size: C.size_t(conf.nodeCacheEntries),
272+
free_list_cache_size: C.size_t(conf.freeListCacheEntries),
273+
revisions: C.size_t(conf.revisions),
274+
strategy: C.uint8_t(conf.readCacheStrategy),
275+
truncate: C.bool(conf.truncate),
276+
root_store: C.bool(conf.rootStore),
277+
expensive_metrics: C.bool(conf.expensiveMetricsEnabled),
278+
node_hash_algorithm: C.enum_NodeHashAlgorithm(nodeHashAlgorithm),
279+
deferred_persistence_commit_count: C.uint64_t(conf.deferredPersistenceCommitCount),
262280
}
263281

264282
return getDatabaseFromHandleResult(C.fwd_open_db(args))

ffi/firewood.h

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

ffi/src/handle.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (C) 2025, Ava Labs, Inc. All rights reserved.
22
// See the file LICENSE.md for licensing terms.
33

4-
use std::num::NonZeroUsize;
4+
use std::num::{NonZeroU64, NonZeroUsize};
55

66
use firewood::{
77
db::{Db, DbConfig},
@@ -99,6 +99,9 @@ pub struct DatabaseHandleArgs<'a> {
9999
///
100100
/// Opening returns an error if this does not match the compile-time feature.
101101
pub node_hash_algorithm: NodeHashAlgorithm,
102+
103+
/// The maximum number of unpersisted revisions that can exist at a given time.
104+
pub deferred_persistence_commit_count: u64,
102105
}
103106

104107
impl DatabaseHandleArgs<'_> {
@@ -152,12 +155,15 @@ impl DatabaseHandle {
152155
/// If the path is empty, or if the configuration is invalid, this will return an error.
153156
pub fn new(args: DatabaseHandleArgs<'_>) -> Result<Self, api::Error> {
154157
let metrics_context = MetricsContext::new(args.expensive_metrics);
158+
let commit_count = NonZeroU64::new(args.deferred_persistence_commit_count)
159+
.ok_or(api::Error::ZeroCommitCount)?;
155160

156161
let cfg = DbConfig::builder()
157162
.node_hash_algorithm(args.node_hash_algorithm.into())
158163
.truncate(args.truncate)
159164
.manager(args.as_rev_manager_config()?)
160165
.root_store(args.root_store)
166+
.deferred_persistence_commit_count(commit_count)
161167
.build();
162168

163169
let path = args

0 commit comments

Comments
 (0)