Skip to content
This repository was archived by the owner on Oct 23, 2022. It is now read-only.

Commit aab2e82

Browse files
author
Joonas Koivunen
committed
perf: render Cids to bytes without allocating a Vec
not sure how much sense does this make, given that the byte writing fns might be less inlined. would be nice to have some benchmarks. this also adds a test to verify directory cid when using cidv1 even though it's quite unclear to me if those are allowed in unixfs dirs.
1 parent dfdeaa1 commit aab2e82

File tree

2 files changed

+89
-8
lines changed

2 files changed

+89
-8
lines changed

unixfs/src/dir/builder/buffered.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,44 @@ mod tests {
417417
);
418418
}
419419

420+
#[test]
421+
fn dir_with_cidv1_link() {
422+
// this is `echo '{ "name": "hello" }` | ./ipfs dag put`
423+
let target =
424+
Cid::try_from("bafyreihakpd7te5nbmlhdk5ntvcvhf2hmfgrvcwna2sddq5zz5342mcbli").unwrap();
425+
426+
let mut builder = BufferingTreeBuilder::default();
427+
builder.put_file("a/b", target, 12).unwrap();
428+
429+
let mut full_path = String::new();
430+
let mut buffer = Vec::new();
431+
432+
let iter = builder.build(&mut full_path, &mut buffer);
433+
let mut actual = iter
434+
.map(|res| res.map(|n| (n.path, n.cid, n.block)))
435+
.collect::<Result<Vec<_>, _>>()
436+
.unwrap();
437+
438+
let mut expected = vec![("a", "QmPMDMPG8dbHDC9GuvqWr9pfruLnp4GZCAWrskwCmenVQa")];
439+
440+
// hopefully this way the errors will be easier to hunt down
441+
442+
actual.reverse();
443+
expected.reverse();
444+
445+
while let Some(actual) = actual.pop() {
446+
let expected = expected.pop().expect("size mismatch");
447+
assert_eq!(actual.0, expected.0);
448+
assert_eq!(
449+
actual.1.to_string(),
450+
expected.1,
451+
"{:?}: {:?}",
452+
actual.0,
453+
Hex(&actual.2)
454+
);
455+
}
456+
}
457+
420458
/// Returns a quick and dirty sha2-256 of the given number as a Cidv0
421459
fn some_cid(number: usize) -> Cid {
422460
use multihash::Sha2_256;

unixfs/src/dir/builder/iter.rs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ impl<'a> PostOrderIterator<'a> {
8282
// ones are the tags
8383
1 + sizeof_len(self.0.len())
8484
+ 1
85-
+ sizeof_len(self.1.link.hash().as_bytes().len())
85+
//+ sizeof_len(WriteableCid(&self.1.link).get_size())
86+
+ sizeof_len(self.1.link.to_bytes().len())
8687
+ 1
8788
+ sizeof_varint(self.1.total_size)
8889
}
@@ -91,26 +92,68 @@ impl<'a> PostOrderIterator<'a> {
9192
&self,
9293
w: &mut Writer<W>,
9394
) -> quick_protobuf::Result<()> {
94-
w.write_with_tag(10, |w| w.write_bytes(self.1.link.hash().as_bytes()))?;
95+
// w.write_with_tag(10, |w| w.write_message(&WriteableCid(&self.1.link)))?;
96+
w.write_with_tag(10, |w| w.write_bytes(&self.1.link.to_bytes()))?;
9597
w.write_with_tag(18, |w| w.write_string(self.0.as_str()))?;
9698
w.write_with_tag(24, |w| w.write_uint64(self.1.total_size))?;
9799
Ok(())
98100
}
99101
}
100102

103+
struct WriteableCid<'a>(&'a Cid);
104+
105+
// Cid by default does not have a way to count it's length or just write it out without
106+
// allocating a vector.
107+
impl<'a> MessageWrite for WriteableCid<'a> {
108+
fn get_size(&self) -> usize {
109+
use cid::Version::*;
110+
use quick_protobuf::sizeofs::*;
111+
112+
match self.0.version() {
113+
V0 => self.0.hash().as_bytes().len(),
114+
V1 => {
115+
let version_len = 1;
116+
let codec_len = sizeof_varint(u64::from(self.0.codec()));
117+
let hash_len = self.0.hash().as_bytes().len();
118+
version_len + codec_len + hash_len
119+
}
120+
}
121+
}
122+
123+
fn write_message<W: WriterBackend>(
124+
&self,
125+
w: &mut Writer<W>,
126+
) -> quick_protobuf::Result<()> {
127+
use cid::Version::*;
128+
129+
match self.0.version() {
130+
V0 => {
131+
for b in self.0.hash().as_bytes() {
132+
w.write_u8(*b)?;
133+
}
134+
Ok(())
135+
}
136+
V1 => {
137+
// it is possible that Cidv1 should not be linked to from a unixfs
138+
// directory; at least go-ipfs 0.5 `ipfs files` denies making a cbor link
139+
w.write_u8(1)?;
140+
w.write_varint(u64::from(self.0.codec()))?;
141+
for b in self.0.hash().as_bytes() {
142+
w.write_u8(*b)?;
143+
}
144+
Ok(())
145+
}
146+
}
147+
}
148+
}
149+
101150
impl<'a> MessageWrite for BTreeMappedDir<'a> {
102151
fn get_size(&self) -> usize {
103152
use quick_protobuf::sizeofs::*;
104153

105154
let links = self
106155
.links
107156
.iter()
108-
.inspect(|(_, Leaf { link, .. })| {
109-
assert!(
110-
link.version() == cid::Version::V0,
111-
"size calc is only impl for v0 cids"
112-
)
113-
})
114157
.map(|(k, v)| EntryAsPBLink(k, v))
115158
.map(|link| 1 + sizeof_len(link.get_size()))
116159
.sum::<usize>();

0 commit comments

Comments
 (0)