lib: Expand `ostree static-delta show` to show part stats
Now we display stats on the individual parts, such as the blob size and the number of each type of opcode. Most interesting to me is things like how many bsdiff opcodes there are vs new objects, etc.
This commit is contained in:
parent
56fc249d08
commit
0481389afd
|
|
@ -432,6 +432,7 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_ostree_static_delta_part_execute (self, objects, part, skip_validation,
|
if (!_ostree_static_delta_part_execute (self, objects, part, skip_validation,
|
||||||
|
FALSE, NULL,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "Executing delta part %i: ", i);
|
g_prefix_error (error, "Executing delta part %i: ", i);
|
||||||
|
|
@ -578,6 +579,89 @@ _ostree_static_delta_part_open (GInputStream *part_in,
|
||||||
return ret;
|
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
|
gboolean
|
||||||
_ostree_repo_static_delta_dump (OstreeRepo *self,
|
_ostree_repo_static_delta_dump (OstreeRepo *self,
|
||||||
const char *delta_id,
|
const char *delta_id,
|
||||||
|
|
@ -641,14 +725,10 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
|
||||||
|
|
||||||
for (i = 0; i < n_parts; i++)
|
for (i = 0; i < n_parts; i++)
|
||||||
{
|
{
|
||||||
guint32 version;
|
if (!show_one_part (self, from, to, meta_entries, i,
|
||||||
guint64 size, usize;
|
&total_size, &total_usize,
|
||||||
g_autoptr(GVariant) objects = NULL;
|
cancellable, error))
|
||||||
g_variant_get_child (meta_entries, i, "(u@aytt@ay)", &version, NULL, &size, &usize, &objects);
|
goto out;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,17 @@ typedef enum {
|
||||||
OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED = (1 << 1)
|
OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED = (1 << 1)
|
||||||
} OstreeStaticDeltaOpenFlags;
|
} 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
|
gboolean
|
||||||
_ostree_static_delta_part_open (GInputStream *part_in,
|
_ostree_static_delta_part_open (GInputStream *part_in,
|
||||||
GBytes *inline_part_bytes,
|
GBytes *inline_part_bytes,
|
||||||
|
|
@ -123,10 +134,16 @@ gboolean _ostree_static_delta_dump (OstreeRepo *repo,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint n_ops_executed[OSTREE_STATIC_DELTA_N_OPS];
|
||||||
|
} OstreeDeltaExecuteStats;
|
||||||
|
|
||||||
gboolean _ostree_static_delta_part_execute (OstreeRepo *repo,
|
gboolean _ostree_static_delta_part_execute (OstreeRepo *repo,
|
||||||
GVariant *header,
|
GVariant *header,
|
||||||
GVariant *part_payload,
|
GVariant *part_payload,
|
||||||
gboolean trusted,
|
gboolean trusted,
|
||||||
|
gboolean stats_only,
|
||||||
|
OstreeDeltaExecuteStats *stats,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
|
@ -142,16 +159,6 @@ gboolean _ostree_static_delta_part_execute_finish (OstreeRepo *repo,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
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
|
gboolean
|
||||||
_ostree_static_delta_parse_checksum_array (GVariant *array,
|
_ostree_static_delta_parse_checksum_array (GVariant *array,
|
||||||
guint8 **out_checksums_array,
|
guint8 **out_checksums_array,
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ G_STATIC_ASSERT (sizeof (guint) >= sizeof (guint32));
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gboolean trusted;
|
gboolean trusted;
|
||||||
|
gboolean stats_only;
|
||||||
OstreeRepo *repo;
|
OstreeRepo *repo;
|
||||||
guint checksum_index;
|
guint checksum_index;
|
||||||
const guint8 *checksums;
|
const guint8 *checksums;
|
||||||
|
|
@ -149,11 +150,37 @@ open_output_target (StaticDeltaExecutionState *state,
|
||||||
return ret;
|
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
|
gboolean
|
||||||
_ostree_static_delta_part_execute (OstreeRepo *repo,
|
_ostree_static_delta_part_execute (OstreeRepo *repo,
|
||||||
GVariant *objects,
|
GVariant *objects,
|
||||||
GVariant *part,
|
GVariant *part,
|
||||||
gboolean trusted,
|
gboolean trusted,
|
||||||
|
gboolean stats_only,
|
||||||
|
OstreeDeltaExecuteStats *stats,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
|
|
@ -171,6 +198,7 @@ _ostree_static_delta_part_execute (OstreeRepo *repo,
|
||||||
state->repo = repo;
|
state->repo = repo;
|
||||||
state->async_error = error;
|
state->async_error = error;
|
||||||
state->trusted = trusted;
|
state->trusted = trusted;
|
||||||
|
state->stats_only = stats_only;
|
||||||
|
|
||||||
if (!_ostree_static_delta_parse_checksum_array (objects,
|
if (!_ostree_static_delta_parse_checksum_array (objects,
|
||||||
&checksums_data,
|
&checksums_data,
|
||||||
|
|
@ -240,6 +268,8 @@ _ostree_static_delta_part_execute (OstreeRepo *repo,
|
||||||
}
|
}
|
||||||
|
|
||||||
n_executed++;
|
n_executed++;
|
||||||
|
if (stats)
|
||||||
|
stats->n_ops_executed[delta_opcode_index(opcode)]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->caught_error)
|
if (state->caught_error)
|
||||||
|
|
@ -284,6 +314,7 @@ static_delta_part_execute_thread (GSimpleAsyncResult *res,
|
||||||
data->header,
|
data->header,
|
||||||
data->part,
|
data->part,
|
||||||
data->trusted,
|
data->trusted,
|
||||||
|
FALSE, NULL,
|
||||||
cancellable, &error))
|
cancellable, &error))
|
||||||
g_simple_async_result_take_error (res, error);
|
g_simple_async_result_take_error (res, error);
|
||||||
}
|
}
|
||||||
|
|
@ -419,6 +450,12 @@ dispatch_bspatch (OstreeRepo *repo,
|
||||||
if (!read_varuint64 (state, &length, error))
|
if (!read_varuint64 (state, &length, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (state->stats_only)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (!state->have_obj)
|
if (!state->have_obj)
|
||||||
{
|
{
|
||||||
input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error);
|
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;
|
goto out;
|
||||||
if (!validate_ofs (state, offset, length, error))
|
if (!validate_ofs (state, offset, length, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (state->stats_only)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
metadata = g_variant_new_from_data (ostree_metadata_variant_type (state->output_objtype),
|
metadata = g_variant_new_from_data (ostree_metadata_variant_type (state->output_objtype),
|
||||||
state->payload_data + offset, length, TRUE, NULL, NULL);
|
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))
|
if (!validate_ofs (state, content_offset, state->content_size, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (state->stats_only)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fast path for regular files to bare repositories */
|
/* Fast path for regular files to bare repositories */
|
||||||
if (S_ISREG (state->mode) &&
|
if (S_ISREG (state->mode) &&
|
||||||
(repo->mode == OSTREE_REPO_MODE_BARE ||
|
(repo->mode == OSTREE_REPO_MODE_BARE ||
|
||||||
|
|
@ -611,6 +660,8 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
|
if (state->stats_only)
|
||||||
|
(void) dispatch_close (repo, state, cancellable, NULL);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
g_prefix_error (error, "opcode open-splice-and-close: ");
|
g_prefix_error (error, "opcode open-splice-and-close: ");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -626,8 +677,11 @@ dispatch_open (OstreeRepo *repo,
|
||||||
|
|
||||||
g_assert (state->output_target == NULL);
|
g_assert (state->output_target == NULL);
|
||||||
/* FIXME - lift this restriction */
|
/* FIXME - lift this restriction */
|
||||||
g_assert (repo->mode == OSTREE_REPO_MODE_BARE ||
|
if (!state->stats_only)
|
||||||
repo->mode == OSTREE_REPO_MODE_BARE_USER);
|
{
|
||||||
|
g_assert (repo->mode == OSTREE_REPO_MODE_BARE ||
|
||||||
|
repo->mode == OSTREE_REPO_MODE_BARE_USER);
|
||||||
|
}
|
||||||
|
|
||||||
if (!open_output_target (state, cancellable, error))
|
if (!open_output_target (state, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -638,6 +692,12 @@ dispatch_open (OstreeRepo *repo,
|
||||||
if (!read_varuint64 (state, &state->content_size, error))
|
if (!read_varuint64 (state, &state->content_size, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (state->stats_only)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (state->trusted)
|
if (state->trusted)
|
||||||
{
|
{
|
||||||
if (!_ostree_repo_open_trusted_content_bare (repo, state->checksum,
|
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))
|
if (!read_varuint64 (state, &content_offset, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (state->stats_only)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (!state->have_obj)
|
if (!state->have_obj)
|
||||||
{
|
{
|
||||||
if (state->read_source_fd != -1)
|
if (state->read_source_fd != -1)
|
||||||
|
|
@ -762,6 +828,12 @@ dispatch_set_read_source (OstreeRepo *repo,
|
||||||
if (!validate_ofs (state, source_offset, 32, error))
|
if (!validate_ofs (state, source_offset, 32, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (state->stats_only)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
g_free (state->read_source_object);
|
g_free (state->read_source_object);
|
||||||
state->read_source_object = ostree_checksum_from_bytes (state->payload_data + source_offset);
|
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;
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
if (state->stats_only)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (state->read_source_fd)
|
if (state->read_source_fd)
|
||||||
{
|
{
|
||||||
(void) close (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);
|
g_clear_pointer (&state->read_source_object, g_free);
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
/* out: */
|
out:
|
||||||
if (!ret)
|
if (!ret)
|
||||||
g_prefix_error (error, "opcode unset-read-source: ");
|
g_prefix_error (error, "opcode unset-read-source: ");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue