[Libguestfs] [PATCH libnbd] info: Add --map --totals sub-mode to display summary of map
Eric Blake
eblake at redhat.com
Mon Jun 28 17:05:03 UTC 2021
On Sat, Jun 26, 2021 at 05:19:47PM +0100, Richard W.M. Jones wrote:
> This is similar to "qemu-img measure". Some examples:
>
> $ nbdkit -r file fedora-33.img --run 'nbdinfo --map --totals $uri'
> 1226113024 19.0 0 data
> 5216337920 81.0 3 hole,zero
Is it worth a human-legible header line? Or maybe a % character in
the second column?
>
> $ nbdkit -r file fedora-33.img --run 'nbdinfo --map --totals --json $uri | jq'
> [
> {
> "size": 1226113024,
> "percent": 19.0318,
> "type": 0,
> "description": "data"
> },
> {
> "size": 5216337920,
> "percent": 80.9682,
> "type": 3,
> "description": "hole,zero"
> }
> ]
Output looks nice.
>
> $ nbdkit sparse-random 6G --run 'nbdinfo --map --totals $uri'
> 941551616 14.6 0 data
> 5500899328 85.4 3 hole,zero
> ---
...
> +++ b/info/info-map-totals-json.sh
> +
> +test $( jq -r '.[0].size' < $out ) -eq 65536
> +test $( jq -r '.[0].percent' < $out ) = "6.25"
> +test $( jq -r '.[0].type' < $out ) -eq 0
> +test $( jq -r '.[0].description' < $out ) = "data"
> +
> +test $( jq -r '.[1].size' < $out ) -eq 983040
> +test $( jq -r '.[1].percent' < $out ) = "93.75"
> +test $( jq -r '.[1].type' < $out ) -eq 3
> +test $( jq -r '.[1].description' < $out ) = "hole,zero"
...
> diff --git a/info/info-map-totals.sh b/info/info-map-totals.sh
> new file mode 100755
> index 0000000..12c1263
> --- /dev/null
> +++ b/info/info-map-totals.sh
> @@ -0,0 +1,43 @@
> +
> +cat $out
> +
> +if [ "$(tr -s ' ' < $out)" != " 65536 6.2 0 data
> + 983040 93.8 3 hole,zero" ]; then
So this is the human-readable counterpart of info-map-totals-json.sh.
I'm trying to figure out why 6.25 rounded down and 93.75 rounded up.
I guess it's related to round-to-even? But it's also fine if the
rounded values don't sum back up to 100%; I don't know if it's worth a
documentation disclaimer.
> +++ b/info/map.c
> +/* --map --totals suboption */
> +static void
> +print_totals (uint32_vector *entries, int64_t size)
> +{
> + uint32_t type;
> + bool comma = false;
> +
> + if (json_output) fprintf (fp, "[\n");
> +
> + /* In the outer loop assume we have already printed all entries with
> + * entry type < type. Count all instances of type and at the same
> + * time find the next type that exists > type.
> + */
> + type = 0;
> + for (;;) {
> + uint64_t next_type = (uint64_t)UINT32_MAX + 1;
> + uint64_t c = 0;
> + size_t i;
> +
> + for (i = 0; i < entries->size; i += 2) {
> + uint32_t t = entries->ptr[i+1];
> +
> + if (t == type)
> + c += entries->ptr[i];
> + else if (type < t && t < next_type)
> + next_type = t;
> + }
I see what you mean about a malicious server being able to force us to
do a LOT of work, but I think this is fine for a first cut (we can
worry about rewriting it to do a single pass utilizing a hash table if
it proves to be noticeable in practice).
> +++ b/info/nbdinfo.pod
> @@ -8,7 +8,7 @@ nbdinfo - display information and metadata about NBD servers and exports
>
> nbdinfo --size [--json] NBD-URI
>
> - nbdinfo --map [--json] NBD-URI
> + nbdinfo --map [--totals] [--json] NBD-URI
>
> nbdinfo -L|--list [--json] NBD-URI
>
> @@ -119,6 +119,35 @@ other maps too:
> For more information on NBD maps, see I<Metadata querying> in the NBD
> protocol.
>
> +=head2 Map totals
> +
> +Using S<I<--map --totals>> performs the same operation as I<--map> but
> +displays a summary of the total size of each type of allocation, in
> +bytes and as a percentage (of the virtual size of the export). This
> +is useful for estimating how much real storage is used on the server,
> +or might be required when copying a sparse image with L<nbdcopy(1)>.
> +
> +In the example below, half (50.0%) of the disk is allocated data and
> +half is unallocated:
> +
> + $ nbdinfo --map --totals nbd://localhost/
> + 1048576 50.0 0 data
> + 1048576 50.0 3 hole,zero
> +
> +The fields are: total size in bytes, percentage of the virtual size,
> +type, description (optional).
> +
> +You can also get the same information in parseable form using I<--json>:
> +
> + $ nbdinfo --map --totals --json nbd://localhost/
> + [{ "size": 1048576, "percent": 50,
> + "type": 0, "description": "data" },
> + { "size": 1048576, "percent": 50,
> + "type": 3, "description": "hole,zero" }]
> +
> +As with the I<--map> option, by default this shows the
> +C<"base:allocation"> map, but you can show the summary for other maps.
I'd still like to someday have a mode where we can read all advertised
maps at once, rather than making the command-line user have to
manually invoke nbdinfo once per map spelled by the user, but that can
still go on top of this.
Overall, looks good to me!
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
More information about the Libguestfs
mailing list