From 4296d8bd2fa484ad0012dadab8beadb53d6c9297 Mon Sep 17 00:00:00 2001 From: David Gilligan-Cook Date: Thu, 6 Jun 2024 11:30:20 -0700 Subject: [PATCH] Separated digest and encoding usage of legacy_encoding methods into two methods Add digest_encoding method to spfs graph objects. Removed annotation writing from Layer's legacy_encoding, but not its digest_encoding. size_for_legacy_encoding methods remain unchanged. Signed-off-by: David Gilligan-Cook --- crates/spfs/src/graph/entry.rs | 9 +++++++++ crates/spfs/src/graph/layer.rs | 16 +++++++++++++++- crates/spfs/src/graph/manifest.rs | 13 +++++++++++++ crates/spfs/src/graph/object.rs | 6 +++--- crates/spfs/src/graph/platform.rs | 13 +++++++++++++ crates/spfs/src/graph/tree.rs | 12 ++++++++++++ 6 files changed, 65 insertions(+), 4 deletions(-) diff --git a/crates/spfs/src/graph/entry.rs b/crates/spfs/src/graph/entry.rs index 50d4deb91c..ad2ad489ac 100644 --- a/crates/spfs/src/graph/entry.rs +++ b/crates/spfs/src/graph/entry.rs @@ -180,6 +180,15 @@ impl<'buf> encoding::Digestible for Entry<'buf> { } impl<'buf> Entry<'buf> { + pub(super) fn digest_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { + encoding::write_digest(&mut writer, self.object())?; + self.kind().encode(&mut writer)?; + encoding::write_uint64(&mut writer, self.mode() as u64)?; + encoding::write_uint64(&mut writer, self.size_for_legacy_encode())?; + encoding::write_string(writer, self.name())?; + Ok(()) + } + pub(super) fn legacy_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { encoding::write_digest(&mut writer, self.object())?; self.kind().encode(&mut writer)?; diff --git a/crates/spfs/src/graph/layer.rs b/crates/spfs/src/graph/layer.rs index 3bab7a068d..177b3cc68c 100644 --- a/crates/spfs/src/graph/layer.rs +++ b/crates/spfs/src/graph/layer.rs @@ -119,7 +119,8 @@ impl Layer { children } - pub(super) fn legacy_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { + pub(super) fn digest_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { + // Includes any annotations regardless of whether EncodingFormat setting let annotations = self.annotations(); let result = if let Some(manifest_digest) = self.manifest() { let manifest_result = @@ -144,6 +145,19 @@ impl Layer { result } + + pub(super) fn legacy_encode(&self, writer: &mut impl std::io::Write) -> Result<()> { + // Legacy encoded layers do not support writing annotations + let result = if let Some(manifest_digest) = self.manifest() { + encoding::write_digest(writer, manifest_digest).map_err(Error::Encoding) + } else { + Err(Error::String( + "Invalid Layer object for legacy encoding, it has no manifest data".to_string(), + )) + }; + + result + } } impl std::hash::Hash for Layer { diff --git a/crates/spfs/src/graph/manifest.rs b/crates/spfs/src/graph/manifest.rs index fa4d518db6..b1d1113705 100644 --- a/crates/spfs/src/graph/manifest.rs +++ b/crates/spfs/src/graph/manifest.rs @@ -119,6 +119,19 @@ impl Manifest { manifest } + pub(super) fn digest_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { + self.root().digest_encode(&mut writer)?; + // this method encodes the root tree first, and does not + // include it in the count of remaining trees since at least + // one root is always required + encoding::write_uint64(&mut writer, self.proto().trees().len() as u64 - 1)?; + // skip the root tree when saving the rest + for tree in self.iter_trees().skip(1) { + tree.digest_encode(writer)?; + } + Ok(()) + } + pub(super) fn legacy_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { self.root().legacy_encode(&mut writer)?; // this method encodes the root tree first, and does not diff --git a/crates/spfs/src/graph/object.rs b/crates/spfs/src/graph/object.rs index c137bc3b3c..5b1f3f9032 100644 --- a/crates/spfs/src/graph/object.rs +++ b/crates/spfs/src/graph/object.rs @@ -219,9 +219,9 @@ impl encoding::Digestible for FlatObject { } } match variant { - Enum::Platform(obj) => obj.legacy_encode(&mut hasher)?, - Enum::Layer(obj) => obj.legacy_encode(&mut hasher)?, - Enum::Manifest(obj) => obj.legacy_encode(&mut hasher)?, + Enum::Platform(obj) => obj.digest_encode(&mut hasher)?, + Enum::Layer(obj) => obj.digest_encode(&mut hasher)?, + Enum::Manifest(obj) => obj.digest_encode(&mut hasher)?, Enum::Blob(_obj) => unreachable!("handled above"), } Ok(hasher.digest()) diff --git a/crates/spfs/src/graph/platform.rs b/crates/spfs/src/graph/platform.rs index f43eb08422..b50fcbcea6 100644 --- a/crates/spfs/src/graph/platform.rs +++ b/crates/spfs/src/graph/platform.rs @@ -55,6 +55,19 @@ impl Platform { self.iter_bottom_up().copied().collect() } + pub(super) fn digest_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { + // use a vec to know the name ahead of time and + // avoid iterating the stack twice + let digests = self.iter_bottom_up().collect::>(); + encoding::write_uint64(&mut writer, digests.len() as u64)?; + // for historical reasons, and to remain backward-compatible, platform + // stacks are stored in reverse (top-down) order + for digest in digests.into_iter().rev() { + encoding::write_digest(&mut writer, digest)?; + } + Ok(()) + } + pub(super) fn legacy_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { // use a vec to know the name ahead of time and // avoid iterating the stack twice diff --git a/crates/spfs/src/graph/tree.rs b/crates/spfs/src/graph/tree.rs index 7d5fc264d5..400daea3c5 100644 --- a/crates/spfs/src/graph/tree.rs +++ b/crates/spfs/src/graph/tree.rs @@ -37,6 +37,18 @@ impl<'buf> Tree<'buf> { self.entries().find(|entry| entry.name() == name.as_ref()) } + pub(super) fn digest_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { + let mut entries: Vec<_> = self.entries().collect(); + encoding::write_uint64(&mut writer, entries.len() as u64)?; + // this is not the default sort mode for entries but + // matches the existing compatible encoding order + entries.sort_unstable_by_key(|e| e.name()); + for entry in entries.into_iter() { + entry.digest_encode(writer)?; + } + Ok(()) + } + pub(super) fn legacy_encode(&self, mut writer: &mut impl std::io::Write) -> Result<()> { let mut entries: Vec<_> = self.entries().collect(); encoding::write_uint64(&mut writer, entries.len() as u64)?;