From 5388d8091ef02cf927478a1492847ae1666040d4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 3 Mar 2022 16:40:45 +0800 Subject: [PATCH] allow writing empty files during checkout but also query the odb (#301) This should tell us how much time it really takes to do the ODB part, and see how much we could save by optimizing disk access, for instance by using an lstat cache. --- etc/check-package-size.sh | 2 +- git-worktree/tests/index/mod.rs | 9 ++++++++- gitoxide-core/src/index/mod.rs | 28 +++++++++++++++++++++++++--- src/plumbing/main.rs | 11 +++++++++-- src/plumbing/options.rs | 4 ++++ 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/etc/check-package-size.sh b/etc/check-package-size.sh index 0b9c48a5f94..1b9dff874ea 100755 --- a/etc/check-package-size.sh +++ b/etc/check-package-size.sh @@ -41,4 +41,4 @@ echo "in root: gitoxide CLI" (enter git-packetline && indent cargo diet -n --package-size-limit 35KB) (enter git-repository && indent cargo diet -n --package-size-limit 80KB) (enter git-transport && indent cargo diet -n --package-size-limit 50KB) -(enter gitoxide-core && indent cargo diet -n --package-size-limit 50KB) +(enter gitoxide-core && indent cargo diet -n --package-size-limit 60KB) diff --git a/git-worktree/tests/index/mod.rs b/git-worktree/tests/index/mod.rs index d365777f332..ce638a3b056 100644 --- a/git-worktree/tests/index/mod.rs +++ b/git-worktree/tests/index/mod.rs @@ -173,7 +173,14 @@ mod checkout { let odb = git_odb::at(git_dir.join("objects"))?; let destination = tempfile::tempdir()?; - let outcome = index::checkout(&mut index)?; + let outcome = index::checkout( + &mut index, + &destination, + move |oid, buf| odb.find_blob(oid, buf).ok(), + &mut progress::Discard, + &mut progress::Discard, + opts, + )?; Ok((source_tree, destination, index, outcome)) } diff --git a/gitoxide-core/src/index/mod.rs b/gitoxide-core/src/index/mod.rs index bd4f946807a..c7ac6291892 100644 --- a/gitoxide-core/src/index/mod.rs +++ b/gitoxide-core/src/index/mod.rs @@ -101,12 +101,23 @@ fn parse_file(index_path: impl AsRef, object_hash: git::hash::Kind) -> any .map_err(Into::into) } +pub mod checkout_exclusive { + pub struct Options { + pub index: super::Options, + /// If true, all files will be written with zero bytes despite having made an ODB lookup. + pub empty_files: bool, + } +} + pub fn checkout_exclusive( index_path: impl AsRef, dest_directory: impl AsRef, repo: Option, mut progress: impl Progress, - Options { object_hash, .. }: Options, + checkout_exclusive::Options { + index: Options { object_hash, .. }, + empty_files, + }: checkout_exclusive::Options, ) -> anyhow::Result<()> { let repo = repo .map(|dir| git_repository::discover(dir).map(|r| r.apply_environment())) @@ -124,7 +135,7 @@ pub fn checkout_exclusive( let mut index = parse_file(index_path, object_hash)?; let mut num_skipped = 0; - let maybe_symlink_mode = if repo.is_some() { + let maybe_symlink_mode = if !empty_files && repo.is_some() { git::index::entry::Mode::DIR } else { git::index::entry::Mode::SYMLINK @@ -161,7 +172,18 @@ pub fn checkout_exclusive( Some(repo) => git::worktree::index::checkout( &mut index, dest_directory, - |oid, buf| repo.objects.find_blob(oid, buf).ok(), + |oid, buf| { + repo.objects.find_blob(oid, buf).ok(); + if empty_files { + // We always want to query the ODB here… + repo.objects.find_blob(oid, buf).ok(); + buf.clear(); + // …but write nothing + Some(git::objs::BlobRef { data: buf }) + } else { + repo.objects.find_blob(oid, buf).ok() + } + }, &mut files, &mut bytes, opts, diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index c2300926628..22346e55660 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -78,7 +78,11 @@ pub fn main() -> Result<()> { index_path, cmd, }) => match cmd { - index::Subcommands::CheckoutExclusive { directory, repository } => prepare_and_run( + index::Subcommands::CheckoutExclusive { + directory, + empty_files, + repository, + } => prepare_and_run( "index-checkout", verbose, progress, @@ -90,7 +94,10 @@ pub fn main() -> Result<()> { directory, repository, progress, - core::index::Options { object_hash, format }, + core::index::checkout_exclusive::Options { + index: core::index::Options { object_hash, format }, + empty_files, + }, ) }, ), diff --git a/src/plumbing/options.rs b/src/plumbing/options.rs index 8d01894c3a1..43fda5ca779 100644 --- a/src/plumbing/options.rs +++ b/src/plumbing/options.rs @@ -373,6 +373,10 @@ pub mod index { /// in the index. Use this measure the impact on extracting objects on overall performance. #[clap(long, short = 'r')] repository: Option, + /// Enable to query the object database yet write only empty files. This is useful to measure the overhead of ODB query + /// compared to writing the bytes to disk. + #[clap(long, short = 'e', requires = "repository")] + empty_files: bool, /// The directory into which to write all index entries. directory: PathBuf, },