}
if (!_ostree_static_delta_part_execute (self, objects, part, skip_validation,
+ FALSE, NULL,
cancellable, error))
{
g_prefix_error (error, "Executing delta part %i: ", i);
return ret;
}
+/*
+ * Displaying static delta parts
+ */
+
+static gboolean
+show_one_part (OstreeRepo *self,
+ const char *from,
+ const char *to,
+ GVariant *meta_entries,
+ guint i,
+ guint64 *total_size_ref,
+ guint64 *total_usize_ref,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ guint32 version;
+ guint64 size, usize;
+ g_autoptr(GVariant) objects = NULL;
+ g_autoptr(GInputStream) part_in = NULL;
+ g_autoptr(GVariant) part = NULL;
+ g_autofree char *part_path = _ostree_get_relative_static_delta_part_path (from, to, i);
+ gint part_fd = -1;
+
+ g_variant_get_child (meta_entries, i, "(u@aytt@ay)", &version, NULL, &size, &usize, &objects);
+ *total_size_ref += size;
+ *total_usize_ref += usize;
+ g_print ("PartMeta%u: nobjects=%u size=%" G_GUINT64_FORMAT " usize=%" G_GUINT64_FORMAT "\n",
+ i, (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN), size, usize);
+
+ part_fd = openat (self->repo_dir_fd, part_path, O_RDONLY | O_CLOEXEC);
+ if (part_fd < 0)
+ {
+ glnx_set_error_from_errno (error);
+ goto out;
+ }
+
+ part_in = g_unix_input_stream_new (part_fd, FALSE);
+
+ if (!_ostree_static_delta_part_open (part_in, NULL,
+ OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM,
+ NULL,
+ &part,
+ cancellable, error))
+ goto out;
+
+ { g_autoptr(GVariant) modes = NULL;
+ g_autoptr(GVariant) xattrs = NULL;
+ g_autoptr(GVariant) blob = NULL;
+ g_autoptr(GVariant) ops = NULL;
+ OstreeDeltaExecuteStats stats = { { 0, }, };
+
+ g_variant_get (part, "(@a(uuu)@aa(ayay)@ay@ay)",
+ &modes, &xattrs, &blob, &ops);
+
+ g_print ("PartPayload%u: nmodes=%" G_GUINT64_FORMAT
+ " nxattrs=%" G_GUINT64_FORMAT
+ " blobsize=%" G_GUINT64_FORMAT
+ " opsize=%" G_GUINT64_FORMAT
+ "\n",
+ i,
+ g_variant_n_children (modes),
+ g_variant_n_children (xattrs),
+ g_variant_n_children (blob),
+ g_variant_n_children (ops));
+
+ if (!_ostree_static_delta_part_execute (self, objects,
+ part, TRUE, TRUE,
+ &stats, cancellable, error))
+ goto out;
+
+ { const guint *n_ops = stats.n_ops_executed;
+ g_print ("PartPayloadOps%u: openspliceclose=%u open=%u write=%u setread=%u "
+ "unsetread=%u close=%u bspatch=%u\n",
+ i, n_ops[0], n_ops[1], n_ops[2], n_ops[3], n_ops[4], n_ops[5], n_ops[6]);
+ }
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
gboolean
_ostree_repo_static_delta_dump (OstreeRepo *self,
const char *delta_id,
for (i = 0; i < n_parts; i++)
{
- guint32 version;
- guint64 size, usize;
- g_autoptr(GVariant) objects = NULL;
- g_variant_get_child (meta_entries, i, "(u@aytt@ay)", &version, NULL, &size, &usize, &objects);
- total_size += size;
- total_usize += usize;
- g_print ("Part%u: nobjects=%u size=%" G_GUINT64_FORMAT " usize=%" G_GUINT64_FORMAT "\n",
- i, (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN), size, usize);
+ if (!show_one_part (self, from, to, meta_entries, i,
+ &total_size, &total_usize,
+ cancellable, error))
+ goto out;
}
}
OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED = (1 << 1)
} OstreeStaticDeltaOpenFlags;
+typedef enum {
+ OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE = 'S',
+ OSTREE_STATIC_DELTA_OP_OPEN = 'o',
+ OSTREE_STATIC_DELTA_OP_WRITE = 'w',
+ OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE = 'r',
+ OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE = 'R',
+ OSTREE_STATIC_DELTA_OP_CLOSE = 'c',
+ OSTREE_STATIC_DELTA_OP_BSPATCH = 'B'
+} OstreeStaticDeltaOpCode;
+#define OSTREE_STATIC_DELTA_N_OPS 7
+
gboolean
_ostree_static_delta_part_open (GInputStream *part_in,
GBytes *inline_part_bytes,
GCancellable *cancellable,
GError **error);
+typedef struct {
+ guint n_ops_executed[OSTREE_STATIC_DELTA_N_OPS];
+} OstreeDeltaExecuteStats;
+
gboolean _ostree_static_delta_part_execute (OstreeRepo *repo,
GVariant *header,
GVariant *part_payload,
gboolean trusted,
+ gboolean stats_only,
+ OstreeDeltaExecuteStats *stats,
GCancellable *cancellable,
GError **error);
GAsyncResult *result,
GError **error);
-typedef enum {
- OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE = 'S',
- OSTREE_STATIC_DELTA_OP_OPEN = 'o',
- OSTREE_STATIC_DELTA_OP_WRITE = 'w',
- OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE = 'r',
- OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE = 'R',
- OSTREE_STATIC_DELTA_OP_CLOSE = 'c',
- OSTREE_STATIC_DELTA_OP_BSPATCH = 'B'
-} OstreeStaticDeltaOpCode;
-
gboolean
_ostree_static_delta_parse_checksum_array (GVariant *array,
guint8 **out_checksums_array,
typedef struct {
gboolean trusted;
+ gboolean stats_only;
OstreeRepo *repo;
guint checksum_index;
const guint8 *checksums;
return ret;
}
+static guint
+delta_opcode_index (OstreeStaticDeltaOpCode op)
+{
+ switch (op)
+ {
+ case OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE:
+ return 0;
+ case OSTREE_STATIC_DELTA_OP_OPEN:
+ return 1;
+ case OSTREE_STATIC_DELTA_OP_WRITE:
+ return 2;
+ case OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE:
+ return 3;
+ case OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE:
+ return 4;
+ case OSTREE_STATIC_DELTA_OP_CLOSE:
+ return 5;
+ case OSTREE_STATIC_DELTA_OP_BSPATCH:
+ return 6;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
gboolean
_ostree_static_delta_part_execute (OstreeRepo *repo,
GVariant *objects,
GVariant *part,
gboolean trusted,
+ gboolean stats_only,
+ OstreeDeltaExecuteStats *stats,
GCancellable *cancellable,
GError **error)
{
state->repo = repo;
state->async_error = error;
state->trusted = trusted;
+ state->stats_only = stats_only;
if (!_ostree_static_delta_parse_checksum_array (objects,
&checksums_data,
}
n_executed++;
+ if (stats)
+ stats->n_ops_executed[delta_opcode_index(opcode)]++;
}
if (state->caught_error)
data->header,
data->part,
data->trusted,
+ FALSE, NULL,
cancellable, &error))
g_simple_async_result_take_error (res, error);
}
if (!read_varuint64 (state, &length, error))
goto out;
+ if (state->stats_only)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
if (!state->have_obj)
{
input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error);
goto out;
if (!validate_ofs (state, offset, length, error))
goto out;
+
+ if (state->stats_only)
+ {
+ ret = TRUE;
+ goto out;
+ }
metadata = g_variant_new_from_data (ostree_metadata_variant_type (state->output_objtype),
state->payload_data + offset, length, TRUE, NULL, NULL);
if (!validate_ofs (state, content_offset, state->content_size, error))
goto out;
+ if (state->stats_only)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
/* Fast path for regular files to bare repositories */
if (S_ISREG (state->mode) &&
(repo->mode == OSTREE_REPO_MODE_BARE ||
ret = TRUE;
out:
+ if (state->stats_only)
+ (void) dispatch_close (repo, state, cancellable, NULL);
if (!ret)
g_prefix_error (error, "opcode open-splice-and-close: ");
return ret;
g_assert (state->output_target == NULL);
/* FIXME - lift this restriction */
- g_assert (repo->mode == OSTREE_REPO_MODE_BARE ||
- repo->mode == OSTREE_REPO_MODE_BARE_USER);
+ if (!state->stats_only)
+ {
+ g_assert (repo->mode == OSTREE_REPO_MODE_BARE ||
+ repo->mode == OSTREE_REPO_MODE_BARE_USER);
+ }
if (!open_output_target (state, cancellable, error))
goto out;
if (!read_varuint64 (state, &state->content_size, error))
goto out;
+ if (state->stats_only)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
if (state->trusted)
{
if (!_ostree_repo_open_trusted_content_bare (repo, state->checksum,
if (!read_varuint64 (state, &content_offset, error))
goto out;
+ if (state->stats_only)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
if (!state->have_obj)
{
if (state->read_source_fd != -1)
if (!validate_ofs (state, source_offset, 32, error))
goto out;
+ if (state->stats_only)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
g_free (state->read_source_object);
state->read_source_object = ostree_checksum_from_bytes (state->payload_data + source_offset);
{
gboolean ret = FALSE;
+ if (state->stats_only)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
if (state->read_source_fd)
{
(void) close (state->read_source_fd);
g_clear_pointer (&state->read_source_object, g_free);
ret = TRUE;
- /* out: */
+ out:
if (!ret)
g_prefix_error (error, "opcode unset-read-source: ");
return ret;