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.
This commit is contained in:
parent
ef7bedc04e
commit
262f426997
|
|
@ -3567,9 +3567,6 @@ checkout_file_from_input (GFile *file,
|
||||||
|
|
||||||
if (mode == OSTREE_REPO_CHECKOUT_MODE_USER)
|
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);
|
temp_info = g_file_info_dup (finfo);
|
||||||
|
|
||||||
g_file_info_set_attribute_uint32 (temp_info, "unix::uid", geteuid ());
|
g_file_info_set_attribute_uint32 (temp_info, "unix::uid", geteuid ());
|
||||||
|
|
@ -3684,6 +3681,7 @@ static gboolean
|
||||||
checkout_one_file (OstreeRepo *self,
|
checkout_one_file (OstreeRepo *self,
|
||||||
OstreeRepoCheckoutMode mode,
|
OstreeRepoCheckoutMode mode,
|
||||||
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
||||||
|
GFile *link_cache,
|
||||||
OstreeRepoFile *src,
|
OstreeRepoFile *src,
|
||||||
GFileInfo *file_info,
|
GFileInfo *file_info,
|
||||||
GFile *destination,
|
GFile *destination,
|
||||||
|
|
@ -3698,18 +3696,28 @@ checkout_one_file (OstreeRepo *self,
|
||||||
ot_lobj GInputStream *input = NULL;
|
ot_lobj GInputStream *input = NULL;
|
||||||
ot_lvariant GVariant *xattrs = 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);
|
checksum = ostree_repo_file_get_checksum ((OstreeRepoFile*)src);
|
||||||
|
|
||||||
if (priv->mode == OSTREE_REPO_MODE_BARE && mode == OSTREE_REPO_CHECKOUT_MODE_NONE)
|
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);
|
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 (possible_loose_path && lstat (ot_gfile_get_path_cached (possible_loose_path), &stbuf) >= 0)
|
||||||
{
|
{
|
||||||
/* If we found one, we can just hardlink */
|
/* If we found one, we can just hardlink */
|
||||||
if (!checkout_file_hardlink (self, mode, overwrite_mode, possible_loose_path, destination,
|
if (!checkout_file_hardlink (self, mode, overwrite_mode, possible_loose_path, destination,
|
||||||
cancellable, error) < 0)
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -3720,6 +3728,23 @@ checkout_one_file (OstreeRepo *self,
|
||||||
if (!checkout_file_from_input (destination, mode, overwrite_mode, file_info, xattrs,
|
if (!checkout_file_from_input (destination, mode, overwrite_mode, file_info, xattrs,
|
||||||
input, cancellable, error))
|
input, cancellable, error))
|
||||||
goto out;
|
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;
|
ret = TRUE;
|
||||||
|
|
@ -3731,6 +3756,7 @@ gboolean
|
||||||
ostree_repo_checkout_tree (OstreeRepo *self,
|
ostree_repo_checkout_tree (OstreeRepo *self,
|
||||||
OstreeRepoCheckoutMode mode,
|
OstreeRepoCheckoutMode mode,
|
||||||
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
||||||
|
GFile *link_cache,
|
||||||
GFile *destination,
|
GFile *destination,
|
||||||
OstreeRepoFile *source,
|
OstreeRepoFile *source,
|
||||||
GFileInfo *source_info,
|
GFileInfo *source_info,
|
||||||
|
|
@ -3778,14 +3804,14 @@ ostree_repo_checkout_tree (OstreeRepo *self,
|
||||||
|
|
||||||
if (type == G_FILE_TYPE_DIRECTORY)
|
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,
|
dest_path, (OstreeRepoFile*)src_child, file_info,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!checkout_one_file (self, mode, overwrite_mode,
|
if (!checkout_one_file (self, mode, overwrite_mode, link_cache,
|
||||||
(OstreeRepoFile*)src_child, file_info,
|
(OstreeRepoFile*)src_child, file_info,
|
||||||
dest_path, cancellable, error))
|
dest_path, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,7 @@ gboolean
|
||||||
ostree_repo_checkout_tree (OstreeRepo *self,
|
ostree_repo_checkout_tree (OstreeRepo *self,
|
||||||
OstreeRepoCheckoutMode mode,
|
OstreeRepoCheckoutMode mode,
|
||||||
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
||||||
|
GFile *link_cache,
|
||||||
GFile *destination,
|
GFile *destination,
|
||||||
OstreeRepoFile *source,
|
OstreeRepoFile *source,
|
||||||
GFileInfo *source_info,
|
GFileInfo *source_info,
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
static char *opt_link_cache;
|
||||||
static gboolean opt_user_mode;
|
static gboolean opt_user_mode;
|
||||||
static gboolean opt_atomic_retarget;
|
static gboolean opt_atomic_retarget;
|
||||||
static gboolean opt_no_triggers;
|
static gboolean opt_no_triggers;
|
||||||
|
|
@ -37,6 +38,7 @@ static gboolean opt_union;
|
||||||
static gboolean opt_from_stdin;
|
static gboolean opt_from_stdin;
|
||||||
|
|
||||||
static GOptionEntry options[] = {
|
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 },
|
{ "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" },
|
{ "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 },
|
{ "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 *resolved_commit,
|
||||||
const char *subpath,
|
const char *subpath,
|
||||||
GFile *target,
|
GFile *target,
|
||||||
|
GFile *link_cache,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
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,
|
if (!ostree_repo_checkout_tree (repo, opt_user_mode ? OSTREE_REPO_CHECKOUT_MODE_USER : 0,
|
||||||
opt_union ? OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES : 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;
|
goto out;
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
@ -155,6 +158,7 @@ process_one_checkout (OstreeRepo *repo,
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
process_many_checkouts (OstreeRepo *repo,
|
process_many_checkouts (OstreeRepo *repo,
|
||||||
|
GFile *link_cache,
|
||||||
GFile *target,
|
GFile *target,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
|
|
@ -194,7 +198,7 @@ process_many_checkouts (OstreeRepo *repo,
|
||||||
if (!ostree_repo_resolve_rev (repo, revision, FALSE, &resolved_commit, error))
|
if (!ostree_repo_resolve_rev (repo, revision, FALSE, &resolved_commit, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!process_one_checkout (repo, resolved_commit, subpath, target,
|
if (!process_one_checkout (repo, resolved_commit, subpath, target, link_cache,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
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 *resolved_commit = NULL;
|
||||||
ot_lfree char *suffixed_destination = NULL;
|
ot_lfree char *suffixed_destination = NULL;
|
||||||
ot_lfree char *tmp_destination = NULL;
|
ot_lfree char *tmp_destination = NULL;
|
||||||
|
ot_lobj GFile *link_cache = NULL;
|
||||||
ot_lobj GFileInfo *symlink_file_info = NULL;
|
ot_lobj GFileInfo *symlink_file_info = NULL;
|
||||||
ot_lobj GFile *checkout_target = NULL;
|
ot_lobj GFile *checkout_target = NULL;
|
||||||
ot_lobj GFile *checkout_target_tmp = 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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt_link_cache)
|
||||||
|
link_cache = ot_gfile_new_for_path (opt_link_cache);
|
||||||
|
|
||||||
if (opt_from_stdin)
|
if (opt_from_stdin)
|
||||||
{
|
{
|
||||||
if (opt_atomic_retarget)
|
if (opt_atomic_retarget)
|
||||||
|
|
@ -262,7 +270,7 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error
|
||||||
destination = argv[1];
|
destination = argv[1];
|
||||||
checkout_target = ot_gfile_new_for_path (destination);
|
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;
|
goto out;
|
||||||
|
|
||||||
if (!opt_no_triggers)
|
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,
|
if (!process_one_checkout (repo, resolved_commit, opt_subpath,
|
||||||
checkout_target_tmp ? checkout_target_tmp : checkout_target,
|
checkout_target_tmp ? checkout_target_tmp : checkout_target,
|
||||||
cancellable, error))
|
link_cache, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!opt_no_triggers)
|
if (!opt_no_triggers)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "1..29"
|
echo "1..30"
|
||||||
|
|
||||||
. libtest.sh
|
. libtest.sh
|
||||||
|
|
||||||
|
|
@ -211,3 +211,11 @@ $OSTREE checkout --atomic-retarget test2
|
||||||
cd test2
|
cd test2
|
||||||
assert_file_has_content ./yet/another/tree/green "leaf"
|
assert_file_has_content ./yet/another/tree/green "leaf"
|
||||||
echo "ok checkout short form"
|
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"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ set -e
|
||||||
|
|
||||||
. libtest.sh
|
. libtest.sh
|
||||||
|
|
||||||
echo '1..18'
|
echo '1..19'
|
||||||
|
|
||||||
setup_test_repository "archive"
|
setup_test_repository "archive"
|
||||||
echo "ok setup"
|
echo "ok setup"
|
||||||
|
|
@ -96,3 +96,11 @@ echo "ok fsck"
|
||||||
cd ${test_tmpdir}
|
cd ${test_tmpdir}
|
||||||
$OSTREE checkout test2 checkout-test2-from-unpacked
|
$OSTREE checkout test2 checkout-test2-from-unpacked
|
||||||
echo "ok checkout union 2"
|
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"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue