Skip to content

Commit 94ac1f3

Browse files
authored
[Storage] Add inactivity floor to qmdb::keyless Commit operation (#3624)
1 parent 2a7dd42 commit 94ac1f3

17 files changed

Lines changed: 1692 additions & 375 deletions

File tree

examples/sync/src/databases/keyless.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! Keyless database types and helpers for the sync example.
22
//!
33
//! A `keyless` database is append-only: operations are stored by location rather than by key.
4-
//! It supports `Append(value)` and `Commit(metadata)` operations. For sync, the engine targets
5-
//! the Merkle root over all operations, and the client reconstructs the same state by replaying
6-
//! the fetched operations.
4+
//! It supports `Append(value)` and `Commit(metadata, floor)` operations. For sync, the engine
5+
//! targets the Merkle root over all operations, and the client reconstructs the same state by
6+
//! replaying the fetched operations.
77
88
use crate::{Hasher, Key, Value};
99
use commonware_cryptography::{Hasher as CryptoHasher, Sha256};
@@ -28,7 +28,7 @@ use tracing::error;
2828
pub type Database<E> = fixed::Db<mmr::Family, E, Value, Hasher>;
2929

3030
/// Operation type alias.
31-
pub type Operation = fixed::Operation<Value>;
31+
pub type Operation = fixed::Operation<mmr::Family, Value>;
3232

3333
/// Create a database configuration for the keyless variant.
3434
pub fn create_config(context: &(impl BufferPooler + commonware_runtime::Metrics)) -> fixed::Config {
@@ -56,11 +56,23 @@ pub fn create_config(context: &(impl BufferPooler + commonware_runtime::Metrics)
5656
}
5757

5858
/// Create deterministic test operations for demonstration purposes.
59-
/// Generates Append operations and periodic Commit operations.
59+
///
60+
/// Generates Append operations and periodic Commit operations, advancing the inactivity
61+
/// floor at each commit to the *previous* commit's location. This models a realistic
62+
/// application that declares older commits inactive over time (enabling pruning) while
63+
/// always keeping the most recent commit readable.
6064
pub fn create_test_operations(count: usize, seed: u64) -> Vec<Operation> {
6165
let mut operations = Vec::new();
6266
let mut hasher = <Hasher as CryptoHasher>::new();
6367

68+
// The DB's initial commit lands at location 0 before any of these ops are applied.
69+
// `op_count` tracks the total ops that will exist on disk (including this initial commit
70+
// and everything we push below). `prev_commit_loc` tracks the last commit's location
71+
// and is used as the next commit's floor — always <= the next commit's own location, so
72+
// the per-commit floor bound is satisfied.
73+
let mut op_count: u64 = 1;
74+
let mut prev_commit_loc: u64 = 0;
75+
6476
for i in 0..count {
6577
let value = {
6678
hasher.update(&i.to_be_bytes());
@@ -69,14 +81,20 @@ pub fn create_test_operations(count: usize, seed: u64) -> Vec<Operation> {
6981
};
7082

7183
operations.push(Operation::Append(value));
84+
op_count += 1;
7285

7386
if (i + 1) % 10 == 0 {
74-
operations.push(Operation::Commit(None));
87+
operations.push(Operation::Commit(None, Location::new(prev_commit_loc)));
88+
prev_commit_loc = op_count;
89+
op_count += 1;
7590
}
7691
}
7792

78-
// Always end with a commit
79-
operations.push(Operation::Commit(Some(Sha256::fill(1))));
93+
// Always end with a commit, floor set to the previous commit's location.
94+
operations.push(Operation::Commit(
95+
Some(Sha256::fill(1)),
96+
Location::new(prev_commit_loc),
97+
));
8098
operations
8199
}
82100

@@ -107,8 +125,8 @@ where
107125
Operation::Append(value) => {
108126
batch = batch.append(value);
109127
}
110-
Operation::Commit(metadata) => {
111-
let merkleized = batch.merkleize(self, metadata);
128+
Operation::Commit(metadata, floor) => {
129+
let merkleized = batch.merkleize(self, metadata, floor);
112130
self.apply_batch(merkleized).await?;
113131
self.commit().await?;
114132
batch = self.new_batch();
@@ -127,7 +145,7 @@ where
127145
}
128146

129147
async fn sync_boundary(&self) -> Location {
130-
self.sync_boundary().await
148+
self.sync_boundary()
131149
}
132150

133151
async fn historical_proof(
@@ -161,7 +179,7 @@ mod tests {
161179
let ops = <KeylessDb as Syncable>::create_test_operations(5, 12345);
162180
assert_eq!(ops.len(), 6); // 5 operations + 1 commit
163181

164-
if let Operation::Commit(Some(_)) = &ops[5] {
182+
if let Operation::Commit(Some(_), _) = &ops[5] {
165183
// ok
166184
} else {
167185
panic!("last operation should be a commit with metadata");

storage/conformance.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,19 +220,19 @@ hash = "cafbb288de6f8d5c73ddb19df64d2e1429b4f2e273124cb1b20be3026c54d288"
220220

221221
["commonware_storage::qmdb::conformance::KeylessMmbFixedConf"]
222222
n_cases = 200
223-
hash = "41f832011239e8d76ded66ea5e2559a6eaeb6ef65875b9d50db1296a2f26e5f8"
223+
hash = "d9ad4deb528e8bc514d028efa34e9b31b6642584c8a0c0e98c7a6d9b36f355df"
224224

225225
["commonware_storage::qmdb::conformance::KeylessMmbVariableConf"]
226226
n_cases = 200
227-
hash = "ce612a2c4c3c43db5e797cdeff7df04b872660529ccdfb825feb0efcaaf322a3"
227+
hash = "c1f535aaa1a4ff8d8594b70d4d121a2ee48c342a68c8549c4b411d299cfa43dc"
228228

229229
["commonware_storage::qmdb::conformance::KeylessMmrFixedConf"]
230230
n_cases = 200
231-
hash = "79ac92e88026d3d73d1cf37edf85fcd82a5fd6824566b05fe04d0ad1fd7ec9e0"
231+
hash = "49c54ba4ea198f1e5811abfb3a1a077925d1075b006c620cb3e4aa3769c997cb"
232232

233233
["commonware_storage::qmdb::conformance::KeylessMmrVariableConf"]
234234
n_cases = 200
235-
hash = "aa70f866ae6b4104e94c741f46806a430b2ce76e3af5798ba2fb23dff6d1fbd9"
235+
hash = "aee37bfef687a6855e53f2e4a2ef7190cf9d33cdb67b5e177a7f56f7b44e4b9b"
236236

237237
["commonware_storage::qmdb::immutable::operation::fixed::tests::conformance::CodecConformance<FixedOp>"]
238238
n_cases = 65536
@@ -246,13 +246,13 @@ hash = "bdee433c53489ee67a42ad2029081d3f233799bd360d6e5e7f29cbaec87c9064"
246246
n_cases = 65536
247247
hash = "7952a9bb3a9cec87a95af6dd96a5b88b535106f0241770e0bfdb8aeaf9421056"
248248

249-
["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<FixedEncoding<U64>>>"]
249+
["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<mmr::Family,FixedEncoding<U64>>>"]
250250
n_cases = 65536
251-
hash = "c692a20fa40180844888e7a26401f99a45ce3127faeca5f1228a41b454424623"
251+
hash = "1ad07a5388e328474b353c153617b6a8a3a4713a9895f3f505148f919c49b86d"
252252

253-
["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<VariableEncoding<U64>>>"]
253+
["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<mmr::Family,VariableEncoding<U64>>>"]
254254
n_cases = 65536
255-
hash = "b41d6c6ec560bde9caf2e206526864c618a0721af367585a1719617ca7ce9291"
255+
hash = "c6702e8b8d2e96438df00786289df9ee4ec92a767974fa1484766a246ebc71b7"
256256

257257
["commonware_storage::qmdb::sync::target::tests::conformance::CodecConformance<Target<MmrFamily,sha256::Digest>>"]
258258
n_cases = 65536

0 commit comments

Comments
 (0)