deltas: Only keep one file open at a time during compilation
Otherwise it's possible for us to exhaust available file descriptors or (on 32 bit) run up against mmap limits. In the rollsum case, we didn't need to hold open the "from" object at all. And in the bsdiff case, we weren't even looking at either of the files until we started processing. Also, while we have the patient open, switch to using O_TMPFILE if available. Closes: #567 Approved by: giuseppe
This commit is contained in:
parent
2b150f52f8
commit
24ac4ff190
|
|
@ -32,6 +32,7 @@
|
||||||
#include "ostree-diff.h"
|
#include "ostree-diff.h"
|
||||||
#include "ostree-rollsum.h"
|
#include "ostree-rollsum.h"
|
||||||
#include "otutil.h"
|
#include "otutil.h"
|
||||||
|
#include "libglnx.h"
|
||||||
#include "ostree-varint.h"
|
#include "ostree-varint.h"
|
||||||
#include "bsdiff/bsdiff.h"
|
#include "bsdiff/bsdiff.h"
|
||||||
|
|
||||||
|
|
@ -413,15 +414,11 @@ process_one_object (OstreeRepo *repo,
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *from_checksum;
|
char *from_checksum;
|
||||||
GBytes *tmp_from;
|
|
||||||
GBytes *tmp_to;
|
|
||||||
} ContentBsdiff;
|
} ContentBsdiff;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *from_checksum;
|
char *from_checksum;
|
||||||
OstreeRollsumMatches *matches;
|
OstreeRollsumMatches *matches;
|
||||||
GBytes *tmp_from;
|
|
||||||
GBytes *tmp_to;
|
|
||||||
} ContentRollsum;
|
} ContentRollsum;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -429,8 +426,6 @@ content_rollsums_free (ContentRollsum *rollsum)
|
||||||
{
|
{
|
||||||
g_free (rollsum->from_checksum);
|
g_free (rollsum->from_checksum);
|
||||||
_ostree_rollsum_matches_free (rollsum->matches);
|
_ostree_rollsum_matches_free (rollsum->matches);
|
||||||
g_clear_pointer (&rollsum->tmp_from, g_bytes_unref);
|
|
||||||
g_clear_pointer (&rollsum->tmp_to, g_bytes_unref);
|
|
||||||
g_free (rollsum);
|
g_free (rollsum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,8 +433,6 @@ static void
|
||||||
content_bsdiffs_free (ContentBsdiff *bsdiff)
|
content_bsdiffs_free (ContentBsdiff *bsdiff)
|
||||||
{
|
{
|
||||||
g_free (bsdiff->from_checksum);
|
g_free (bsdiff->from_checksum);
|
||||||
g_clear_pointer (&bsdiff->tmp_from, g_bytes_unref);
|
|
||||||
g_clear_pointer (&bsdiff->tmp_to, g_bytes_unref);
|
|
||||||
g_free (bsdiff);
|
g_free (bsdiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,50 +443,40 @@ static gboolean
|
||||||
get_unpacked_unlinked_content (OstreeRepo *repo,
|
get_unpacked_unlinked_content (OstreeRepo *repo,
|
||||||
const char *checksum,
|
const char *checksum,
|
||||||
GBytes **out_content,
|
GBytes **out_content,
|
||||||
GFileInfo **out_finfo,
|
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
g_autofree char *tmpname = NULL;
|
||||||
g_autofree char *tmpname = g_strdup ("/var/tmp/tmpostree-deltaobj-XXXXXX");
|
|
||||||
glnx_fd_close int fd = -1;
|
glnx_fd_close int fd = -1;
|
||||||
g_autoptr(GBytes) ret_content = NULL;
|
g_autoptr(GBytes) ret_content = NULL;
|
||||||
g_autoptr(GInputStream) istream = NULL;
|
g_autoptr(GInputStream) istream = NULL;
|
||||||
g_autoptr(GFileInfo) ret_finfo = NULL;
|
|
||||||
g_autoptr(GOutputStream) out = NULL;
|
g_autoptr(GOutputStream) out = NULL;
|
||||||
|
|
||||||
fd = g_mkstemp (tmpname);
|
if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, "/tmp", O_RDWR | O_CLOEXEC,
|
||||||
if (fd == -1)
|
&fd, &tmpname, error))
|
||||||
{
|
return FALSE;
|
||||||
glnx_set_error_from_errno (error);
|
/* We don't need the file name */
|
||||||
goto out;
|
if (tmpname)
|
||||||
}
|
(void) unlinkat (AT_FDCWD, tmpname, 0);
|
||||||
/* Doesn't need a name */
|
|
||||||
(void) unlink (tmpname);
|
|
||||||
|
|
||||||
if (!ostree_repo_load_file (repo, checksum, &istream, &ret_finfo, NULL,
|
if (!ostree_repo_load_file (repo, checksum, &istream, NULL, NULL,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
return FALSE;
|
||||||
|
|
||||||
g_assert (g_file_info_get_file_type (ret_finfo) == G_FILE_TYPE_REGULAR);
|
|
||||||
|
|
||||||
out = g_unix_output_stream_new (fd, FALSE);
|
out = g_unix_output_stream_new (fd, FALSE);
|
||||||
if (g_output_stream_splice (out, istream, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
if (g_output_stream_splice (out, istream, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||||
cancellable, error) < 0)
|
cancellable, error) < 0)
|
||||||
goto out;
|
return FALSE;
|
||||||
|
|
||||||
{ GMappedFile *mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
|
{ g_autoptr(GMappedFile) mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
|
||||||
if (!mfile)
|
if (!mfile)
|
||||||
goto out;
|
return FALSE;
|
||||||
ret_content = g_mapped_file_get_bytes (mfile);
|
ret_content = g_mapped_file_get_bytes (mfile);
|
||||||
g_mapped_file_unref (mfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
if (out_content)
|
if (out_content)
|
||||||
*out_content = g_steal_pointer (&ret_content);
|
*out_content = g_steal_pointer (&ret_content);
|
||||||
out:
|
return TRUE;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
@ -506,22 +489,20 @@ try_content_bsdiff (OstreeRepo *repo,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
g_autoptr(GBytes) tmp_from = NULL;
|
|
||||||
g_autoptr(GBytes) tmp_to = NULL;
|
|
||||||
g_autoptr(GFileInfo) from_finfo = NULL;
|
g_autoptr(GFileInfo) from_finfo = NULL;
|
||||||
g_autoptr(GFileInfo) to_finfo = NULL;
|
g_autoptr(GFileInfo) to_finfo = NULL;
|
||||||
ContentBsdiff *ret_bsdiff = NULL;
|
ContentBsdiff *ret_bsdiff = NULL;
|
||||||
|
|
||||||
*out_bsdiff = NULL;
|
*out_bsdiff = NULL;
|
||||||
|
|
||||||
if (!get_unpacked_unlinked_content (repo, from, &tmp_from, &from_finfo,
|
if (!ostree_repo_load_file (repo, from, NULL, &from_finfo, NULL,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
return FALSE;
|
||||||
if (!get_unpacked_unlinked_content (repo, to, &tmp_to, &to_finfo,
|
if (!ostree_repo_load_file (repo, to, NULL, &to_finfo, NULL,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
return FALSE;
|
||||||
|
|
||||||
if (g_bytes_get_size (tmp_to) + g_bytes_get_size (tmp_from) > max_bsdiff_size_bytes)
|
if (g_file_info_get_size (to_finfo) + g_file_info_get_size (from_finfo) > max_bsdiff_size_bytes)
|
||||||
{
|
{
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -529,8 +510,6 @@ try_content_bsdiff (OstreeRepo *repo,
|
||||||
|
|
||||||
ret_bsdiff = g_new0 (ContentBsdiff, 1);
|
ret_bsdiff = g_new0 (ContentBsdiff, 1);
|
||||||
ret_bsdiff->from_checksum = g_strdup (from);
|
ret_bsdiff->from_checksum = g_strdup (from);
|
||||||
ret_bsdiff->tmp_from = tmp_from; tmp_from = NULL;
|
|
||||||
ret_bsdiff->tmp_to = tmp_to; tmp_to = NULL;
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
if (out_bsdiff)
|
if (out_bsdiff)
|
||||||
|
|
@ -551,8 +530,6 @@ try_content_rollsum (OstreeRepo *repo,
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
g_autoptr(GBytes) tmp_from = NULL;
|
g_autoptr(GBytes) tmp_from = NULL;
|
||||||
g_autoptr(GBytes) tmp_to = NULL;
|
g_autoptr(GBytes) tmp_to = NULL;
|
||||||
g_autoptr(GFileInfo) from_finfo = NULL;
|
|
||||||
g_autoptr(GFileInfo) to_finfo = NULL;
|
|
||||||
OstreeRollsumMatches *matches = NULL;
|
OstreeRollsumMatches *matches = NULL;
|
||||||
ContentRollsum *ret_rollsum = NULL;
|
ContentRollsum *ret_rollsum = NULL;
|
||||||
|
|
||||||
|
|
@ -561,11 +538,9 @@ try_content_rollsum (OstreeRepo *repo,
|
||||||
/* Load the content objects, splice them to uncompressed temporary files that
|
/* Load the content objects, splice them to uncompressed temporary files that
|
||||||
* we can just mmap() and seek around in conveniently.
|
* we can just mmap() and seek around in conveniently.
|
||||||
*/
|
*/
|
||||||
if (!get_unpacked_unlinked_content (repo, from, &tmp_from, &from_finfo,
|
if (!get_unpacked_unlinked_content (repo, from, &tmp_from, cancellable, error))
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
if (!get_unpacked_unlinked_content (repo, to, &tmp_to, &to_finfo,
|
if (!get_unpacked_unlinked_content (repo, to, &tmp_to, cancellable, error))
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
matches = _ostree_compute_rollsum_matches (tmp_from, tmp_to);
|
matches = _ostree_compute_rollsum_matches (tmp_from, tmp_to);
|
||||||
|
|
@ -592,10 +567,8 @@ try_content_rollsum (OstreeRepo *repo,
|
||||||
|
|
||||||
ret_rollsum = g_new0 (ContentRollsum, 1);
|
ret_rollsum = g_new0 (ContentRollsum, 1);
|
||||||
ret_rollsum->from_checksum = g_strdup (from);
|
ret_rollsum->from_checksum = g_strdup (from);
|
||||||
ret_rollsum->matches = matches; matches = NULL;
|
ret_rollsum->matches = g_steal_pointer (&matches);
|
||||||
ret_rollsum->tmp_from = tmp_from; tmp_from = NULL;
|
|
||||||
ret_rollsum->tmp_to = tmp_to; tmp_to = NULL;
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
if (out_rollsum)
|
if (out_rollsum)
|
||||||
*out_rollsum = g_steal_pointer (&ret_rollsum);
|
*out_rollsum = g_steal_pointer (&ret_rollsum);
|
||||||
|
|
@ -651,7 +624,7 @@ process_one_rollsum (OstreeRepo *repo,
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
guint64 content_size;
|
guint64 content_size;
|
||||||
g_autoptr(GInputStream) content_stream = NULL;
|
g_autoptr(GBytes) tmp_to = NULL;
|
||||||
g_autoptr(GFileInfo) content_finfo = NULL;
|
g_autoptr(GFileInfo) content_finfo = NULL;
|
||||||
g_autoptr(GVariant) content_xattrs = NULL;
|
g_autoptr(GVariant) content_xattrs = NULL;
|
||||||
OstreeStaticDeltaPartBuilder *current_part = *current_part_val;
|
OstreeStaticDeltaPartBuilder *current_part = *current_part_val;
|
||||||
|
|
@ -665,9 +638,13 @@ process_one_rollsum (OstreeRepo *repo,
|
||||||
*current_part_val = current_part = allocate_part (builder);
|
*current_part_val = current_part = allocate_part (builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_to_buf = g_bytes_get_data (rollsum->tmp_to, &tmp_to_len);
|
if (!get_unpacked_unlinked_content (repo, to_checksum, &tmp_to,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!ostree_repo_load_file (repo, to_checksum, &content_stream,
|
tmp_to_buf = g_bytes_get_data (tmp_to, &tmp_to_len);
|
||||||
|
|
||||||
|
if (!ostree_repo_load_file (repo, to_checksum, NULL,
|
||||||
&content_finfo, &content_xattrs,
|
&content_finfo, &content_xattrs,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -754,9 +731,6 @@ process_one_rollsum (OstreeRepo *repo,
|
||||||
g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_CLOSE);
|
g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clear_pointer (&rollsum->tmp_from, g_bytes_unref);
|
|
||||||
g_clear_pointer (&rollsum->tmp_to, g_bytes_unref);
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -773,10 +747,11 @@ process_one_bsdiff (OstreeRepo *repo,
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
guint64 content_size;
|
guint64 content_size;
|
||||||
g_autoptr(GInputStream) content_stream = NULL;
|
|
||||||
g_autoptr(GFileInfo) content_finfo = NULL;
|
g_autoptr(GFileInfo) content_finfo = NULL;
|
||||||
g_autoptr(GVariant) content_xattrs = NULL;
|
g_autoptr(GVariant) content_xattrs = NULL;
|
||||||
OstreeStaticDeltaPartBuilder *current_part = *current_part_val;
|
OstreeStaticDeltaPartBuilder *current_part = *current_part_val;
|
||||||
|
g_autoptr(GBytes) tmp_from = NULL;
|
||||||
|
g_autoptr(GBytes) tmp_to = NULL;
|
||||||
const guint8 *tmp_to_buf;
|
const guint8 *tmp_to_buf;
|
||||||
gsize tmp_to_len;
|
gsize tmp_to_len;
|
||||||
const guint8 *tmp_from_buf;
|
const guint8 *tmp_from_buf;
|
||||||
|
|
@ -789,10 +764,17 @@ process_one_bsdiff (OstreeRepo *repo,
|
||||||
*current_part_val = current_part = allocate_part (builder);
|
*current_part_val = current_part = allocate_part (builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_to_buf = g_bytes_get_data (bsdiff_content->tmp_to, &tmp_to_len);
|
if (!get_unpacked_unlinked_content (repo, bsdiff_content->from_checksum, &tmp_from,
|
||||||
tmp_from_buf = g_bytes_get_data (bsdiff_content->tmp_from, &tmp_from_len);
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
if (!get_unpacked_unlinked_content (repo, to_checksum, &tmp_to,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!ostree_repo_load_file (repo, to_checksum, &content_stream,
|
tmp_to_buf = g_bytes_get_data (tmp_to, &tmp_to_len);
|
||||||
|
tmp_from_buf = g_bytes_get_data (tmp_from, &tmp_from_len);
|
||||||
|
|
||||||
|
if (!ostree_repo_load_file (repo, to_checksum, NULL,
|
||||||
&content_finfo, &content_xattrs,
|
&content_finfo, &content_xattrs,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -853,9 +835,6 @@ process_one_bsdiff (OstreeRepo *repo,
|
||||||
|
|
||||||
g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE);
|
g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE);
|
||||||
|
|
||||||
g_clear_pointer (&bsdiff_content->tmp_from, g_bytes_unref);
|
|
||||||
g_clear_pointer (&bsdiff_content->tmp_to, g_bytes_unref);
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue