diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c index e9d5c15e..6369f34d 100644 --- a/src/libostree/ostree-repo-static-delta-core.c +++ b/src/libostree/ostree-repo-static-delta-core.c @@ -432,6 +432,7 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self, } if (!_ostree_static_delta_part_execute (self, objects, part, skip_validation, + FALSE, NULL, cancellable, error)) { g_prefix_error (error, "Executing delta part %i: ", i); @@ -578,6 +579,89 @@ _ostree_static_delta_part_open (GInputStream *part_in, 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, @@ -641,14 +725,10 @@ _ostree_repo_static_delta_dump (OstreeRepo *self, 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; } } diff --git a/src/libostree/ostree-repo-static-delta-private.h b/src/libostree/ostree-repo-static-delta-private.h index 55777fcd..2da000d6 100644 --- a/src/libostree/ostree-repo-static-delta-private.h +++ b/src/libostree/ostree-repo-static-delta-private.h @@ -109,6 +109,17 @@ typedef enum { 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, @@ -123,10 +134,16 @@ gboolean _ostree_static_delta_dump (OstreeRepo *repo, 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); @@ -142,16 +159,6 @@ gboolean _ostree_static_delta_part_execute_finish (OstreeRepo *repo, 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, diff --git a/src/libostree/ostree-repo-static-delta-processing.c b/src/libostree/ostree-repo-static-delta-processing.c index 74423e7c..b44314b6 100644 --- a/src/libostree/ostree-repo-static-delta-processing.c +++ b/src/libostree/ostree-repo-static-delta-processing.c @@ -40,6 +40,7 @@ G_STATIC_ASSERT (sizeof (guint) >= sizeof (guint32)); typedef struct { gboolean trusted; + gboolean stats_only; OstreeRepo *repo; guint checksum_index; const guint8 *checksums; @@ -149,11 +150,37 @@ open_output_target (StaticDeltaExecutionState *state, 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) { @@ -171,6 +198,7 @@ _ostree_static_delta_part_execute (OstreeRepo *repo, 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, @@ -240,6 +268,8 @@ _ostree_static_delta_part_execute (OstreeRepo *repo, } n_executed++; + if (stats) + stats->n_ops_executed[delta_opcode_index(opcode)]++; } if (state->caught_error) @@ -284,6 +314,7 @@ static_delta_part_execute_thread (GSimpleAsyncResult *res, data->header, data->part, data->trusted, + FALSE, NULL, cancellable, &error)) g_simple_async_result_take_error (res, error); } @@ -419,6 +450,12 @@ dispatch_bspatch (OstreeRepo *repo, 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); @@ -477,6 +514,12 @@ dispatch_open_splice_and_close (OstreeRepo *repo, 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); @@ -520,6 +563,12 @@ dispatch_open_splice_and_close (OstreeRepo *repo, 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 || @@ -611,6 +660,8 @@ dispatch_open_splice_and_close (OstreeRepo *repo, 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; @@ -626,8 +677,11 @@ dispatch_open (OstreeRepo *repo, 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; @@ -638,6 +692,12 @@ dispatch_open (OstreeRepo *repo, 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, @@ -682,6 +742,12 @@ dispatch_write (OstreeRepo *repo, 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) @@ -762,6 +828,12 @@ dispatch_set_read_source (OstreeRepo *repo, 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); @@ -784,6 +856,12 @@ dispatch_unset_read_source (OstreeRepo *repo, { gboolean ret = FALSE; + if (state->stats_only) + { + ret = TRUE; + goto out; + } + if (state->read_source_fd) { (void) close (state->read_source_fd); @@ -793,7 +871,7 @@ dispatch_unset_read_source (OstreeRepo *repo, 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;