From 262f426997790cca00f0abe61d5fc483aadf9c43 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 13 Apr 2012 08:32:02 -0400 Subject: [PATCH] core: Add --link-cache option to checkout This is a convenient way to have a lookaside directory of hard links, which can greatly speed up checkouts. In the future we probably want to push this down into the repository. --- src/libostree/ostree-repo.c | 38 +++++++++++++++++++++++++++----- src/libostree/ostree-repo.h | 1 + src/ostree/ot-builtin-checkout.c | 16 ++++++++++---- tests/t0000-basic.sh | 10 ++++++++- tests/t0001-archive.sh | 10 ++++++++- 5 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 327f1870..58407826 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -3567,9 +3567,6 @@ checkout_file_from_input (GFile *file, if (mode == OSTREE_REPO_CHECKOUT_MODE_USER) { - if (g_file_info_get_file_type (finfo) == G_FILE_TYPE_SPECIAL) - return TRUE; - temp_info = g_file_info_dup (finfo); g_file_info_set_attribute_uint32 (temp_info, "unix::uid", geteuid ()); @@ -3684,6 +3681,7 @@ static gboolean checkout_one_file (OstreeRepo *self, OstreeRepoCheckoutMode mode, OstreeRepoCheckoutOverwriteMode overwrite_mode, + GFile *link_cache, OstreeRepoFile *src, GFileInfo *file_info, GFile *destination, @@ -3698,18 +3696,28 @@ checkout_one_file (OstreeRepo *self, ot_lobj GInputStream *input = NULL; ot_lvariant GVariant *xattrs = NULL; + /* Hack to avoid trying to create device files as a user */ + if (mode == OSTREE_REPO_CHECKOUT_MODE_USER + && g_file_info_get_file_type (file_info) == G_FILE_TYPE_SPECIAL) + return TRUE; + checksum = ostree_repo_file_get_checksum ((OstreeRepoFile*)src); if (priv->mode == OSTREE_REPO_MODE_BARE && mode == OSTREE_REPO_CHECKOUT_MODE_NONE) { possible_loose_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE); } + else if (link_cache) + { + ot_lfree char *relpath = ostree_get_relative_object_path (checksum, OSTREE_OBJECT_TYPE_FILE); + possible_loose_path = g_file_resolve_relative_path (link_cache, relpath); + } if (possible_loose_path && lstat (ot_gfile_get_path_cached (possible_loose_path), &stbuf) >= 0) { /* If we found one, we can just hardlink */ if (!checkout_file_hardlink (self, mode, overwrite_mode, possible_loose_path, destination, - cancellable, error) < 0) + cancellable, error)) goto out; } else @@ -3720,6 +3728,23 @@ checkout_one_file (OstreeRepo *self, if (!checkout_file_from_input (destination, mode, overwrite_mode, file_info, xattrs, input, cancellable, error)) goto out; + + if (link_cache) + { + ot_lobj GFile *parent; + g_assert (possible_loose_path); + + parent = g_file_get_parent (possible_loose_path); + if (!ot_gfile_ensure_directory (parent, TRUE, error)) + goto out; + + if (link (ot_gfile_get_path_cached (destination), + ot_gfile_get_path_cached (possible_loose_path)) < 0) + { + ot_util_set_error_from_errno (error, errno); + goto out; + } + } } ret = TRUE; @@ -3731,6 +3756,7 @@ gboolean ostree_repo_checkout_tree (OstreeRepo *self, OstreeRepoCheckoutMode mode, OstreeRepoCheckoutOverwriteMode overwrite_mode, + GFile *link_cache, GFile *destination, OstreeRepoFile *source, GFileInfo *source_info, @@ -3778,14 +3804,14 @@ ostree_repo_checkout_tree (OstreeRepo *self, if (type == G_FILE_TYPE_DIRECTORY) { - if (!ostree_repo_checkout_tree (self, mode, overwrite_mode, + if (!ostree_repo_checkout_tree (self, mode, overwrite_mode, link_cache, dest_path, (OstreeRepoFile*)src_child, file_info, cancellable, error)) goto out; } else { - if (!checkout_one_file (self, mode, overwrite_mode, + if (!checkout_one_file (self, mode, overwrite_mode, link_cache, (OstreeRepoFile*)src_child, file_info, dest_path, cancellable, error)) goto out; diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 98ecbc62..9d7e56f1 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -310,6 +310,7 @@ gboolean ostree_repo_checkout_tree (OstreeRepo *self, OstreeRepoCheckoutMode mode, OstreeRepoCheckoutOverwriteMode overwrite_mode, + GFile *link_cache, GFile *destination, OstreeRepoFile *source, GFileInfo *source_info, diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index 437d83c4..ce3f49d5 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -29,6 +29,7 @@ #include +static char *opt_link_cache; static gboolean opt_user_mode; static gboolean opt_atomic_retarget; static gboolean opt_no_triggers; @@ -37,6 +38,7 @@ static gboolean opt_union; static gboolean opt_from_stdin; static GOptionEntry options[] = { + { "link-cache", 0, 0, G_OPTION_ARG_STRING, &opt_link_cache, "Use directory as lookaside cache for hard links", NULL }, { "user-mode", 'U', 0, G_OPTION_ARG_NONE, &opt_user_mode, "Do not change file ownership or initialze extended attributes", NULL }, { "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL }, @@ -120,6 +122,7 @@ process_one_checkout (OstreeRepo *repo, const char *resolved_commit, const char *subpath, GFile *target, + GFile *link_cache, GCancellable *cancellable, GError **error) { @@ -145,7 +148,7 @@ process_one_checkout (OstreeRepo *repo, if (!ostree_repo_checkout_tree (repo, opt_user_mode ? OSTREE_REPO_CHECKOUT_MODE_USER : 0, opt_union ? OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES : 0, - target, subtree, file_info, cancellable, error)) + link_cache, target, subtree, file_info, cancellable, error)) goto out; ret = TRUE; @@ -155,6 +158,7 @@ process_one_checkout (OstreeRepo *repo, static gboolean process_many_checkouts (OstreeRepo *repo, + GFile *link_cache, GFile *target, GCancellable *cancellable, GError **error) @@ -194,7 +198,7 @@ process_many_checkouts (OstreeRepo *repo, if (!ostree_repo_resolve_rev (repo, revision, FALSE, &resolved_commit, error)) goto out; - if (!process_one_checkout (repo, resolved_commit, subpath, target, + if (!process_one_checkout (repo, resolved_commit, subpath, target, link_cache, cancellable, error)) goto out; @@ -225,6 +229,7 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error ot_lfree char *resolved_commit = NULL; ot_lfree char *suffixed_destination = NULL; ot_lfree char *tmp_destination = NULL; + ot_lobj GFile *link_cache = NULL; ot_lobj GFileInfo *symlink_file_info = NULL; ot_lobj GFile *checkout_target = NULL; ot_lobj GFile *checkout_target_tmp = NULL; @@ -250,6 +255,9 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error goto out; } + if (opt_link_cache) + link_cache = ot_gfile_new_for_path (opt_link_cache); + if (opt_from_stdin) { if (opt_atomic_retarget) @@ -262,7 +270,7 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error destination = argv[1]; checkout_target = ot_gfile_new_for_path (destination); - if (!process_many_checkouts (repo, checkout_target, cancellable, error)) + if (!process_many_checkouts (repo, link_cache, checkout_target, cancellable, error)) goto out; if (!opt_no_triggers) @@ -321,7 +329,7 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error { if (!process_one_checkout (repo, resolved_commit, opt_subpath, checkout_target_tmp ? checkout_target_tmp : checkout_target, - cancellable, error)) + link_cache, cancellable, error)) goto out; if (!opt_no_triggers) diff --git a/tests/t0000-basic.sh b/tests/t0000-basic.sh index dfdb6a19..253421f1 100755 --- a/tests/t0000-basic.sh +++ b/tests/t0000-basic.sh @@ -19,7 +19,7 @@ set -e -echo "1..29" +echo "1..30" . libtest.sh @@ -211,3 +211,11 @@ $OSTREE checkout --atomic-retarget test2 cd test2 assert_file_has_content ./yet/another/tree/green "leaf" echo "ok checkout short form" + +cd ${test_tmpdir} +rm -rf test2 +mkdir linkcache +$OSTREE checkout --link-cache=linkcache test2 test2-checkout-from-link-cache +cd test2-checkout-from-link-cache +assert_file_has_content ./yet/another/tree/green "leaf" +echo "ok checkout link cache" diff --git a/tests/t0001-archive.sh b/tests/t0001-archive.sh index e7b2a7e0..bdcea5ba 100755 --- a/tests/t0001-archive.sh +++ b/tests/t0001-archive.sh @@ -21,7 +21,7 @@ set -e . libtest.sh -echo '1..18' +echo '1..19' setup_test_repository "archive" echo "ok setup" @@ -96,3 +96,11 @@ echo "ok fsck" cd ${test_tmpdir} $OSTREE checkout test2 checkout-test2-from-unpacked echo "ok checkout union 2" + +cd ${test_tmpdir} +rm -rf test2 +mkdir linkcache +$OSTREE checkout --user-mode --link-cache=linkcache test2 test2 +cd test2 +assert_file_has_content baz/cow moo +echo "ok checkout link cache"