core: Attempt direct link() and fallback on EEXIST

Rather than always doing:

1) make temporary link
2) unlink() target
3) rename()

Just try making the link, and only do the second two if the file
already exists.  This reduces system call traffic a lot.
This commit is contained in:
Colin Walters 2012-05-24 20:14:51 -04:00
parent f7bbf41132
commit fb71519cd6
1 changed files with 18 additions and 30 deletions

View File

@ -4120,15 +4120,11 @@ checkout_file_hardlink (OstreeRepo *self,
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
ot_lobj GFile *dir = NULL; ot_lobj GFile *dir = NULL;
ot_lobj GFile *temp_file = NULL;
if (overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) < 0)
{
if (errno == EEXIST && overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
{ {
dir = g_file_get_parent (destination);
if (!ostree_create_temp_hardlink (dir, (GFile*)source, NULL, "link",
&temp_file, cancellable, error))
goto out;
/* Idiocy, from man rename(2) /* Idiocy, from man rename(2)
* *
* "If oldpath and newpath are existing hard links referring to * "If oldpath and newpath are existing hard links referring to
@ -4137,20 +4133,14 @@ checkout_file_hardlink (OstreeRepo *self,
* *
* So we can't make this atomic. * So we can't make this atomic.
*/ */
(void) unlink (ot_gfile_get_path_cached (destination)); (void) unlink (ot_gfile_get_path_cached (destination));
if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) < 0)
if (rename (ot_gfile_get_path_cached (temp_file),
ot_gfile_get_path_cached (destination)) < 0)
{ {
ot_util_set_error_from_errno (error, errno); ot_util_set_error_from_errno (error, errno);
goto out; goto out;
} }
g_clear_object (&temp_file);
} }
else else
{
if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) < 0)
{ {
ot_util_set_error_from_errno (error, errno); ot_util_set_error_from_errno (error, errno);
goto out; goto out;
@ -4159,8 +4149,6 @@ checkout_file_hardlink (OstreeRepo *self,
ret = TRUE; ret = TRUE;
out: out:
if (temp_file)
(void) unlink (ot_gfile_get_path_cached (temp_file));
return ret; return ret;
} }