Skip to content

Commit f02325a

Browse files
committed
Merge branch 'main' into rkuris/s3fifo
2 parents 17071c9 + ebdea71 commit f02325a

File tree

11 files changed

+224
-94
lines changed

11 files changed

+224
-94
lines changed

benchmark/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ If you're looking for detailed logging, there are some command line options to e
169169
cargo run --profile release --bin benchmark -- -l debug -n 10000 single
170170
```
171171

172-
# Using opentelemetry
172+
## Using opentelemetry
173173

174174
To use the opentelemetry server and record timings, just run a docker image that collects the data using:
175175

@@ -178,6 +178,3 @@ docker run -p 127.0.0.1:4318:4318 -p 127.0.0.1:55679:55679 otel/openteleme
178178
```
179179

180180
Then, pass the `-e` option to the benchmark.
181-
```
182-
183-
Then, pass the `-e` option to the benchmark.

firewood/Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ readme = "../README.md"
1818
[dependencies]
1919
aquamarine = "0.6.0"
2020
async-trait = "0.1.77"
21-
storage = { version = "0.0.4", path = "../storage" }
2221
futures = "0.3.30"
2322
hex = "0.4.3"
2423
metrics = "0.24.0"
@@ -29,14 +28,13 @@ thiserror = "2.0.3"
2928
typed-builder = "0.20.0"
3029
bincode = "1.3.3"
3130
integer-encoding = "4.0.0"
32-
io-uring = {version = "0.7", optional = true }
3331
smallvec = "1.6.1"
3432
fastrace = { version = "0.7.4" }
3533

3634
[features]
3735
default = []
3836
nightly = []
39-
iouring = ["io-uring"]
37+
io-uring = ["storage/io-uring"]
4038
logger = ["storage/logger"]
4139
branch_factor_256 = [ "storage/branch_factor_256" ]
4240

@@ -60,3 +58,9 @@ unwrap_used = "warn"
6058
indexing_slicing = "warn"
6159
explicit_deref_methods = "warn"
6260
missing_const_for_fn = "warn"
61+
62+
[target.'cfg(target_os = "linux")'.dependencies]
63+
storage = { version = "0.0.4", path = "../storage", features = ["io-uring"] }
64+
65+
[target.'cfg(not(target_os = "linux"))'.dependencies]
66+
storage = { version = "0.0.4", path = "../storage" }

firewood/src/db.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ impl<'a> api::Proposal for Proposal<'a> {
425425
match Arc::into_inner(self) {
426426
Some(proposal) => {
427427
let mut manager = proposal.db.manager.write().expect("poisoned lock");
428-
Ok(manager.commit(proposal.nodestore.clone())?)
428+
Ok(manager.commit(proposal.nodestore)?)
429429
}
430430
None => Err(api::Error::CannotCommitClonedProposal),
431431
}
@@ -438,7 +438,7 @@ impl Proposal<'_> {
438438
match Arc::into_inner(self) {
439439
Some(proposal) => {
440440
let mut manager = proposal.db.manager.write().expect("poisoned lock");
441-
Ok(manager.commit(proposal.nodestore.clone())?)
441+
Ok(manager.commit(proposal.nodestore)?)
442442
}
443443
None => Err(api::Error::CannotCommitClonedProposal),
444444
}

firewood/src/merkle.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use std::num::NonZeroUsize;
1616
use std::sync::Arc;
1717
use storage::{
1818
BranchNode, Child, Hashable, HashedNodeReader, ImmutableProposal, LeafNode, LinearAddress,
19-
MutableProposal, NibblesIterator, Node, NodeStore, Path, ReadableStorage, TrieHash, TrieReader,
20-
ValueDigest,
19+
MutableProposal, NibblesIterator, Node, NodeStore, Path, ReadableStorage, SharedNode, TrieHash,
20+
TrieReader, ValueDigest,
2121
};
2222

2323
use thiserror::Error;
@@ -93,7 +93,7 @@ fn get_helper<T: TrieReader>(
9393
nodestore: &T,
9494
node: &Node,
9595
key: &[u8],
96-
) -> Result<Option<Arc<Node>>, MerkleError> {
96+
) -> Result<Option<SharedNode>, MerkleError> {
9797
// 4 possibilities for the position of the `key` relative to `node`:
9898
// 1. The node is at `key`
9999
// 2. The key is above the node (i.e. its ancestor)
@@ -111,7 +111,7 @@ fn get_helper<T: TrieReader>(
111111
// Case (2) or (4)
112112
Ok(None)
113113
}
114-
(None, None) => Ok(Some(Arc::new(node.clone()))), // 1. The node is at `key`
114+
(None, None) => Ok(Some(node.clone().into())), // 1. The node is at `key`
115115
(Some((child_index, remaining_key)), None) => {
116116
// 3. The key is below the node (i.e. its descendant)
117117
match node {
@@ -152,7 +152,7 @@ impl<T> From<T> for Merkle<T> {
152152
}
153153

154154
impl<T: TrieReader> Merkle<T> {
155-
pub(crate) fn root(&self) -> Option<Arc<Node>> {
155+
pub(crate) fn root(&self) -> Option<SharedNode> {
156156
self.nodestore.root_node()
157157
}
158158

@@ -161,7 +161,7 @@ impl<T: TrieReader> Merkle<T> {
161161
&self.nodestore
162162
}
163163

164-
fn read_node(&self, addr: LinearAddress) -> Result<Arc<Node>, MerkleError> {
164+
fn read_node(&self, addr: LinearAddress) -> Result<SharedNode, MerkleError> {
165165
self.nodestore.read_node(addr).map_err(Into::into)
166166
}
167167

@@ -335,7 +335,7 @@ impl<T: TrieReader> Merkle<T> {
335335
Ok(node.value().map(|v| v.to_vec().into_boxed_slice()))
336336
}
337337

338-
pub(crate) fn get_node(&self, key: &[u8]) -> Result<Option<Arc<Node>>, MerkleError> {
338+
pub(crate) fn get_node(&self, key: &[u8]) -> Result<Option<SharedNode>, MerkleError> {
339339
let Some(root) = self.root() else {
340340
return Ok(None);
341341
};
@@ -591,16 +591,18 @@ impl<S: ReadableStorage> Merkle<NodeStore<MutableProposal, S>> {
591591
let root = self.nodestore.mut_root();
592592
let Some(root_node) = std::mem::take(root) else {
593593
// The trie is empty. There is nothing to remove.
594-
counter!("firewood.remove", "result" => "nonexistent").increment(1);
594+
counter!("firewood.remove", "prefix" => "false", "result" => "nonexistent")
595+
.increment(1);
595596
return Ok(None);
596597
};
597598

598599
let (root_node, removed_value) = self.remove_helper(root_node, &key)?;
599600
*self.nodestore.mut_root() = root_node;
600601
if removed_value.is_some() {
601-
counter!("firewood.remove", "result" => "success").increment(1);
602+
counter!("firewood.remove", "prefix" => "false", "result" => "success").increment(1);
602603
} else {
603-
counter!("firewood.remove", "result" => "nonexistent").increment(1);
604+
counter!("firewood.remove", "prefix" => "false", "result" => "nonexistent")
605+
.increment(1);
604606
}
605607
Ok(removed_value)
606608
}
@@ -816,11 +818,14 @@ impl<S: ReadableStorage> Merkle<NodeStore<MutableProposal, S>> {
816818
let root = self.nodestore.mut_root();
817819
let Some(root_node) = std::mem::take(root) else {
818820
// The trie is empty. There is nothing to remove.
821+
counter!("firewood.remove", "prefix" => "true", "result" => "nonexistent").increment(1);
819822
return Ok(0);
820823
};
821824

822825
let mut deleted = 0;
823826
let root_node = self.remove_prefix_helper(root_node, &prefix, &mut deleted)?;
827+
counter!("firewood.remove", "prefix" => "true", "result" => "success")
828+
.increment(deleted as u64);
824829
*self.nodestore.mut_root() = root_node;
825830
Ok(deleted)
826831
}

firewood/src/stream.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@ use futures::stream::FusedStream;
88
use futures::{Stream, StreamExt};
99
use std::cmp::Ordering;
1010
use std::iter::once;
11-
use std::sync::Arc;
1211
use std::task::Poll;
13-
use storage::{BranchNode, Child, NibblesIterator, Node, PathIterItem, TrieReader};
12+
use storage::{BranchNode, Child, NibblesIterator, Node, PathIterItem, SharedNode, TrieReader};
1413

1514
/// Represents an ongoing iteration over a node and its children.
1615
enum IterationNode {
1716
/// This node has not been returned yet.
1817
Unvisited {
1918
/// The key (as nibbles) of this node.
2019
key: Key,
21-
node: Arc<Node>,
20+
node: SharedNode,
2221
},
2322
/// This node has been returned. Track which child to visit next.
2423
Visited {
@@ -94,7 +93,7 @@ impl<'a, T: TrieReader> MerkleNodeStream<'a, T> {
9493
}
9594

9695
impl<T: TrieReader> Stream for MerkleNodeStream<'_, T> {
97-
type Item = Result<(Key, Arc<Node>), api::Error>;
96+
type Item = Result<(Key, SharedNode), api::Error>;
9897

9998
fn poll_next(
10099
mut self: std::pin::Pin<&mut Self>,
@@ -141,7 +140,7 @@ impl<T: TrieReader> Stream for MerkleNodeStream<'_, T> {
141140

142141
let child = match child {
143142
Child::AddressWithHash(addr, _) => merkle.read_node(addr)?,
144-
Child::Node(node) => Arc::new(node.clone()),
143+
Child::Node(node) => node.clone().into(),
145144
};
146145

147146
let child_partial_path = child.partial_path().iter().copied();
@@ -251,7 +250,7 @@ fn get_iterator_intial_state<T: TrieReader>(
251250
node = match child {
252251
None => return Ok(NodeStreamState::Iterating { iter_stack }),
253252
Some(Child::AddressWithHash(addr, _)) => merkle.read_node(*addr)?,
254-
Some(Child::Node(node)) => Arc::new((*node).clone()), // TODO can we avoid cloning this?
253+
Some(Child::Node(node)) => (*node).clone().into(), // TODO can we avoid cloning this?
255254
};
256255

257256
matched_key_nibbles.push(next_unmatched_key_nibble);
@@ -374,7 +373,7 @@ enum PathIteratorState<'a> {
374373
/// prefix of the key we're traversing to.
375374
matched_key: Vec<u8>,
376375
unmatched_key: NibblesIterator<'a>,
377-
node: Arc<Node>,
376+
node: SharedNode,
378377
},
379378
Exhausted,
380379
}
@@ -504,7 +503,7 @@ impl<T: TrieReader> Iterator for PathIterator<'_, '_, T> {
504503
matched_key.push(next_unmatched_key_nibble);
505504

506505
let ret = node.clone();
507-
*node = Arc::new(child.clone());
506+
*node = child.clone().into();
508507

509508
Some(Ok(PathIterItem {
510509
key_nibbles: node_key,
@@ -584,6 +583,8 @@ fn key_from_nibble_iter<Iter: Iterator<Item = u8>>(mut nibbles: Iter) -> Key {
584583
#[cfg(test)]
585584
#[allow(clippy::indexing_slicing, clippy::unwrap_used)]
586585
mod tests {
586+
use std::sync::Arc;
587+
587588
use storage::{MemStore, MutableProposal, NodeStore};
588589

589590
use crate::merkle::Merkle;

storage/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ bytemuck = "1.7.0"
2222
bytemuck_derive = "1.7.0"
2323
bitfield = "0.18.1"
2424
fastrace = { version = "0.7.4" }
25-
strum = "0.27.0"
26-
strum_macros = "0.27.0"
25+
io-uring = { version = "0.7.4", optional = true }
26+
triomphe = "0.1.14"
2727
s3-fifo = { git = "https://github.com/rkuris/s3-fifo", branch = "main" }
2828

2929
[dev-dependencies]
@@ -36,6 +36,7 @@ tempfile = "3.12.0"
3636
[features]
3737
logger = ["log"]
3838
branch_factor_256 = []
39+
io-uring = ["dep:io-uring"]
3940

4041
[[bench]]
4142
name = "serializer"

storage/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (C) 2023, Ava Labs, Inc. All rights reserved.
22
// See the file LICENSE.md for licensing terms.
33
#![warn(missing_debug_implementations, rust_2018_idioms, missing_docs)]
4-
#![forbid(unsafe_code)]
4+
#![deny(unsafe_code)]
55

66
//! # storage implements the storage of a [Node] on top of a LinearStore
77
//!
@@ -33,14 +33,16 @@ pub use nodestore::{
3333
pub use linear::filebacked::FileBacked;
3434
pub use linear::memory::MemStore;
3535

36-
use strum_macros::VariantArray;
3736
pub use trie_hash::TrieHash;
3837

38+
/// A shared node, which is just a triophe Arc of a node
39+
pub type SharedNode = triomphe::Arc<Node>;
40+
3941
/// The strategy for caching nodes that are read
4042
/// from the storage layer. Generally, we only want to
4143
/// cache write operations, but for some read-heavy workloads
4244
/// you can enable caching of branch reads or all reads.
43-
#[derive(Clone, Debug, VariantArray)]
45+
#[derive(Clone, Debug)]
4446
pub enum CacheReadStrategy {
4547
/// Only cache writes (no reads will be cached)
4648
WritesOnly,

0 commit comments

Comments
 (0)