[ostree] lib: Expand `ostree static-delta show` to show part stats



commit 0481389afd1c2f51c9c137fc27deec54bfb51fc5
Author: Colin Walters <walters verbum org>
Date:   Sat Feb 6 17:04:53 2016 +0100

    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.

 src/libostree/ostree-repo-static-delta-core.c      |   96 ++++++++++++++++++--
 src/libostree/ostree-repo-static-delta-private.h   |   27 ++++--
 .../ostree-repo-static-delta-processing.c          |   84 +++++++++++++++++-
 3 files changed, 186 insertions(+), 21 deletions(-)
---
diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c
index e9d5c15..6369f34 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 55777fc..2da000d 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 74423e7..b44314b 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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]