Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for verbatims in ketrees #706

Merged
merged 5 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 24 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ description = "Zenoh: Zero Overhead Pub/sub, Store/Query and Compute."
# (https://github.com/rust-lang/cargo/issues/11329)
[workspace.dependencies]
aes = "0.8.2"
ahash = "0.8.7"
anyhow = { version = "1.0.69", default-features = false } # Default features are disabled due to usage in no_std crates
async-executor = "1.5.0"
async-global-executor = "2.3.1"
Expand Down
1 change: 1 addition & 0 deletions commons/zenoh-keyexpr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ hashbrown = { workspace = true }

# NOTE: May cause problems when testing no_std stuff. Check this tool: https://docs.rs/crate/cargo-no-dev-deps/0.1.0
[dev-dependencies]
ahash = { workspace = true }
criterion = { workspace = true }
lazy_static = { workspace = true }
rand = { workspace = true, features = ["default"] }
Expand Down
20 changes: 17 additions & 3 deletions commons/zenoh-keyexpr/benches/keyexpr_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ fn main() {
let mut intersections = Averager::default();
let results = Benchmarker::benchmark(|b| {
let keys = KeySet::generate(total, wildness, no_double_stars);
let mut ketree: KeBoxTree<_> = KeBoxTree::new();
let mut vectree: KeBoxTree<_, bool, VecSetProvider> = KeBoxTree::new();
let mut hashtree: KeBoxTree<_, bool, HashMapProvider> = KeBoxTree::new();
let mut ketree = KeBoxTree::new();
let mut vectree: KeBoxTree<_, bool, VecSetProvider> = KeBoxTree::default();
let mut hashtree: KeBoxTree<_, bool, HashMapProvider> = KeBoxTree::default();
let mut ahashtree: KeBoxTree<_, bool, HashMapProvider<ahash::AHasher>> =
KeBoxTree::default();
let (kearctree, mut token): (KeArcTree<i32>, _) = KeArcTree::new().unwrap();
let mut map = HashMap::new();
for key in keys.iter() {
Expand All @@ -58,13 +60,15 @@ fn main() {
});
b.run_once("vectree_insert", || vectree.insert(key, 0));
b.run_once("hashtree_insert", || hashtree.insert(key, 0));
b.run_once("ahashtree_insert", || ahashtree.insert(key, 0));
b.run_once("hashmap_insert", || map.insert(key.to_owned(), 0));
}
for key in keys.iter() {
b.run_once("ketree_fetch", || ketree.node(key));
b.run_once("kearctree_fetch", || kearctree.node(&token, key));
b.run_once("vectree_fetch", || vectree.node(key));
b.run_once("hashtree_fetch", || hashtree.node(key));
b.run_once("ahashtree_fetch", || ahashtree.node(key));
b.run_once("hashmap_fetch", || map.get(key));
}
for key in keys.iter() {
Expand All @@ -81,6 +85,9 @@ fn main() {
b.run_once("hashtree_intersect", || {
hashtree.intersecting_nodes(key).count()
});
b.run_once("ahashtree_intersect", || {
ahashtree.intersecting_nodes(key).count()
});
b.run_once("hashmap_intersect", || {
map.iter().filter(|(k, _)| key.intersects(k)).count()
});
Expand All @@ -92,6 +99,9 @@ fn main() {
});
b.run_once("vectree_include", || vectree.included_nodes(key).count());
b.run_once("hashtree_include", || hashtree.included_nodes(key).count());
b.run_once("ahashtree_include", || {
ahashtree.included_nodes(key).count()
});
b.run_once("hashmap_include", || {
map.iter().filter(|(k, _)| key.includes(k)).count()
});
Expand All @@ -102,21 +112,25 @@ fn main() {
"kearctree_insert",
"vectree_insert",
"hashtree_insert",
"ahashtree_insert",
"hashmap_insert",
"ketree_fetch",
"kearctree_fetch",
"vectree_fetch",
"hashtree_fetch",
"ahashtree_fetch",
"hashmap_fetch",
"ketree_intersect",
"kearctree_intersect",
"vectree_intersect",
"hashtree_intersect",
"ahashtree_intersect",
"hashmap_intersect",
"ketree_include",
"kearctree_include",
"vectree_include",
"hashtree_include",
"ahashtree_include",
"hashmap_include",
] {
let b = results.benches.get(name).unwrap();
Expand Down
5 changes: 4 additions & 1 deletion commons/zenoh-keyexpr/src/key_expr/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use super::OwnedKeyExpr;

fn random_chunk(rng: &'_ mut impl rand::Rng) -> impl Iterator<Item = u8> + '_ {
let n = rng.gen_range(1..3);
(0..n).map(move |_| rng.sample(rand::distributions::Uniform::from(b'a'..b'c')))
rng.gen_bool(0.05)
.then_some(b'@')
.into_iter()
.chain((0..n).map(move |_| rng.sample(rand::distributions::Uniform::from(b'a'..b'c'))))
}

fn make(ke: &mut Vec<u8>, rng: &mut impl rand::Rng) {
Expand Down
62 changes: 61 additions & 1 deletion commons/zenoh-keyexpr/src/keyexpr_tree/arc_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ fn ketree_borrow_mut<'a, T, Token: TokenTrait>(
/// A shared KeTree.
///
/// The tree and its nodes have shared ownership, while their mutability is managed through the `Token`.
/// The `(node, &token)` tuple implements [`core::ops::Deref`], while `(node, &mut token)` implements [`core::ops::DerefMut`].
///
/// Most of its methods are declared in the [`ITokenKeyExprTree`] trait.
pub struct KeArcTree<
Weight,
Token: TokenTrait = DefaultToken,
Expand All @@ -82,6 +83,14 @@ impl<
> KeArcTree<Weight, DefaultToken, Wildness, Children>
{
/// Constructs the KeArcTree, returning it and its token, unless constructing the Token failed.
///
/// # Type inference papercut
/// Despite some of `KeArcTree`'s generic parameters having default values, those are only taken into
/// account by the compiler when a type is named with some parameters omitted, and not when a type is
/// infered with the same parameters unconstrained.
///
/// The simplest way to resolve this is to eventually assign to tree part of the return value
/// to a variable or field whose type is named `KeArcTree<_>` (the `Weight` parameter can generally be infered).
pub fn new() -> Result<(Self, DefaultToken), <DefaultToken as TokenTrait>::ConstructionError> {
let token = DefaultToken::new()?;
Ok((Self::with_token(&token), token))
Expand Down Expand Up @@ -329,6 +338,57 @@ where
IterOrOption::Opt(self.node_mut(token, key).map(Into::into))
}
}

type IncluderItem = Self::Node;
type Includer = IterOrOption<
TokenPacker<
Includer<
'a,
Children,
Arc<TokenCell<KeArcTreeNode<Weight, Weak<()>, Wildness, Children, Token>, Token>>,
Weight,
>,
&'a Token,
>,
Self::IncluderItem,
>;
fn nodes_including(&'a self, token: &'a Token, key: &'a keyexpr) -> Self::Includer {
let inner = ketree_borrow(&self.inner, token);
if inner.wildness.get() || key.is_wild() {
IterOrOption::Iter(TokenPacker {
iter: Includer::new(&inner.children, key),
token,
})
} else {
IterOrOption::Opt(self.node(token, key))
}
}
type IncluderItemMut = Self::TreeIterItemMut;
type IncluderMut = IterOrOption<
TokenPacker<
Includer<
'a,
Children,
Arc<TokenCell<KeArcTreeNode<Weight, Weak<()>, Wildness, Children, Token>, Token>>,
Weight,
>,
&'a mut Token,
>,
Self::IncluderItemMut,
>;
fn nodes_including_mut(&'a self, token: &'a mut Token, key: &'a keyexpr) -> Self::IncluderMut {
let inner = ketree_borrow(&self.inner, token);
if inner.wildness.get() || key.is_wild() {
unsafe {
IterOrOption::Iter(TokenPacker {
iter: Includer::new(core::mem::transmute(&inner.children), key),
token,
})
}
} else {
IterOrOption::Opt(self.node_mut(token, key).map(Into::into))
}
}
type PruneNode = KeArcTreeNode<Weight, Weak<()>, Wildness, Children, Token>;

fn prune_where<F: FnMut(&mut Self::PruneNode) -> bool>(
Expand Down
48 changes: 38 additions & 10 deletions commons/zenoh-keyexpr/src/keyexpr_tree/box_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use super::impls::KeyedSetProvider;
use super::support::IterOrOption;

/// A fully owned KeTree.
///
/// Note that most of `KeBoxTree`'s methods are declared in the [`IKeyExprTree`] and [`IKeyExprTreeMut`] traits.
#[repr(C)]
pub struct KeBoxTree<
Weight,
Expand All @@ -37,17 +39,13 @@ pub struct KeBoxTree<
wildness: Wildness,
}

impl<
Weight,
Wildness: IWildness,
Children: IChildrenProvider<Box<KeyExprTreeNode<Weight, Wildness, Children>>>,
> KeBoxTree<Weight, Wildness, Children>
impl<Weight> KeBoxTree<Weight, bool, DefaultChildrenProvider>
where
DefaultChildrenProvider:
IChildrenProvider<Box<KeyExprTreeNode<Weight, bool, DefaultChildrenProvider>>>,
{
pub fn new() -> Self {
KeBoxTree {
children: Default::default(),
wildness: Wildness::non_wild(),
}
Default::default()
}
}
impl<
Expand All @@ -57,7 +55,10 @@ impl<
> Default for KeBoxTree<Weight, Wildness, Children>
{
fn default() -> Self {
Self::new()
KeBoxTree {
children: Default::default(),
wildness: Wildness::non_wild(),
}
}
}

Expand Down Expand Up @@ -117,6 +118,20 @@ where
IterOrOption::Opt(node)
}
}

type IncluderItem = <Self::Includer as Iterator>::Item;
type Includer = IterOrOption<
Includer<'a, Children, Box<KeyExprTreeNode<Weight, Wildness, Children>>, Weight>,
&'a Self::Node,
>;
fn nodes_including(&'a self, ke: &'a keyexpr) -> Self::Includer {
if self.wildness.get() || ke.is_wild() {
Includer::new(&self.children, ke).into()
} else {
let node = self.node(ke);
IterOrOption::Opt(node)
}
}
}
impl<
'a,
Expand Down Expand Up @@ -218,6 +233,19 @@ where
IterOrOption::Opt(node)
}
}
type IncluderItemMut = <Self::IncluderMut as Iterator>::Item;
type IncluderMut = IterOrOption<
IncluderMut<'a, Children, Box<KeyExprTreeNode<Weight, Wildness, Children>>, Weight>,
&'a mut Self::Node,
>;
fn nodes_including_mut(&'a mut self, ke: &'a keyexpr) -> Self::IncluderMut {
if self.wildness.get() || ke.is_wild() {
IncluderMut::new(&mut self.children, ke).into()
} else {
let node = self.node_mut(ke);
IterOrOption::Opt(node)
}
}

fn prune_where<F: FnMut(&mut Self::Node) -> bool>(&mut self, mut predicate: F) {
let mut wild = false;
Expand Down
Loading