fix(snix/castore/import): don't allocate parent repeatedly

We use hashbrown directly (instead of through std::collections::HashMap)
so that we can use HashMap::entry_ref, which only allocates if the entry
is not yet occupied.

This implicitly switches our hash to a less long-term DoS-resistant one
(foldhash rather than SipHash), but we don't usually face HashDoS risks
when ingesting archives.

Change-Id: I3e7fc2cd08d96380cd9fd62bfcfe6cd24698bc9a
Reviewed-on: https://cl.snix.dev/c/snix/+/30277
Reviewed-by: Florian Klink <flokli@flokli.de>
Tested-by: besadii
This commit is contained in:
edef 2025-03-24 20:32:12 +00:00 committed by edef .
parent 86456a3334
commit 479e6ad5c6
4 changed files with 8 additions and 2 deletions

1
snix/Cargo.lock generated
View file

@ -4186,6 +4186,7 @@ dependencies = [
"fastcdc", "fastcdc",
"fuse-backend-rs", "fuse-backend-rs",
"futures", "futures",
"hashbrown 0.15.2",
"hex-literal", "hex-literal",
"hyper-util", "hyper-util",
"libc", "libc",

View file

@ -13640,6 +13640,10 @@ rec {
name = "futures"; name = "futures";
packageId = "futures"; packageId = "futures";
} }
{
name = "hashbrown";
packageId = "hashbrown 0.15.2";
}
{ {
name = "hyper-util"; name = "hyper-util";
packageId = "hyper-util"; packageId = "hyper-util";

View file

@ -55,6 +55,7 @@ vmm-sys-util = { workspace = true, optional = true }
virtio-bindings = { workspace = true, optional = true } virtio-bindings = { workspace = true, optional = true }
wu-manber.workspace = true wu-manber.workspace = true
auto_impl = "1.2.0" auto_impl = "1.2.0"
hashbrown = "0.15.2"
[build-dependencies] [build-dependencies]
prost-build.workspace = true prost-build.workspace = true

View file

@ -10,7 +10,7 @@ use crate::{B3Digest, Directory, Node};
use futures::{Stream, StreamExt}; use futures::{Stream, StreamExt};
use tracing::Level; use tracing::Level;
use std::collections::HashMap; use hashbrown::HashMap;
use tracing::instrument; use tracing::instrument;
mod error; mod error;
@ -131,7 +131,7 @@ where
// record node in parent directory, creating a new [Directory] if not there yet. // record node in parent directory, creating a new [Directory] if not there yet.
directories directories
.entry(parent.to_owned()) .entry_ref(parent)
.or_default() .or_default()
.add(name, node) .add(name, node)
.map_err(|e| { .map_err(|e| {