Skip to content
Permalink
Browse files

A new show usage example!

The show usage example was one of the very first examples, showing which
block groups and chunks are present in the filesystem.

Now that we have detailed usage analysis code, let's use it to build a
more sophisticated example showing full-blown usage information.

Here's an example, running it on a small empty RAID5 filesystem with
three block devices.

The "Estimated virtual space left to use for data: 10.74GiB" in here is
what users would like to see in the df output (which lists 21G free
instead).

    -# dd if=/dev/zero of=raid5-1 bs=1 count=0 seek=10G
    -# dd if=/dev/zero of=raid5-2 bs=1 count=0 seek=10G
    -# dd if=/dev/zero of=raid5-3 bs=1 count=0 seek=10G
    -# mkfs.btrfs -f -d raid5 -m raid1 raid5-1 raid5-2 raid5-3
    -# for i in `seq 1 3`; do echo $i; losetup -f raid5-$i; done
    -# mount -o space_cache=v2 /dev/loop0 /mnt/commit_message

    -# ./show_usage.py /mnt/commit_message
    Mixed groups: False
    Target profile for System (chunk tree): RAID1
    Target profile for Metadata: RAID1
    Target profile for Data: RAID5

    Virtual space usage by block group type:
    |
    | type                    total         used
    | ----                    -----         ----
    | Data                  2.00GiB        0.00B
    | System                8.00MiB     16.00KiB
    | Metadata              1.00GiB    128.00KiB

    Total raw filesystem size: 30.00GiB
    Total raw allocated bytes: 5.02GiB
    Allocatable bytes remaining: 29.25GiB
    Unallocatable bytes that can be reclaimed by balancing: 512.00MiB
    Unallocatable bytes because of unbalanced device sizes: 256.00MiB
    Note: Don't worry if the unallocatable amounts are < 1GiB

    Estimated virtual space left to use for metadata: 1.25GiB
    Estimated virtual space left to use for data: 17.74GiB

    Allocated raw disk bytes by chunk type. Parity is a reserved part of the
    allocated bytes, limiting the amount that can be used for data or
    metadata:
    |
    | flags               allocated         used       parity
    | -----               ---------         ----       ------
    | DATA|RAID5            3.00GiB        0.00B      1.00GiB
    | SYSTEM|RAID1         16.00MiB     32.00KiB        0.00B
    | METADATA|RAID1        2.00GiB    256.00KiB        0.00B

    Allocated bytes per device:
    |
    | devid      total size    allocated path
    | -----      ----------    --------- ----
    | 1            10.00GiB      2.00GiB /dev/loop0
    | 2            10.00GiB      1.01GiB /dev/loop1
    | 3            10.00GiB      2.01GiB /dev/loop2

    Allocated bytes per device, split up per chunk type. Parity bytes are
    again
    part of the total amount of allocated bytes.
    |
    | Device ID: 1
    | | flags               allocated       parity
    | | -----               ---------       ------
    | | DATA|RAID5            1.00GiB    341.33MiB
    | | METADATA|RAID1        1.00GiB        0.00B
    |
    | Device ID: 2
    | | flags               allocated       parity
    | | -----               ---------       ------
    | | DATA|RAID5            1.00GiB    341.33MiB
    | | SYSTEM|RAID1          8.00MiB        0.00B
    |
    | Device ID: 3
    | | flags               allocated       parity
    | | -----               ---------       ------
    | | DATA|RAID5            1.00GiB    341.33MiB
    | | SYSTEM|RAID1          8.00MiB        0.00B
    | | METADATA|RAID1        1.00GiB        0.00B

    Unallocatable bytes per device:
    |
    | devid            soft         hard  reclaimable
    | -----            ----         ----  -----------
    | 1               0.00B        0.00B        0.00B
    | 2           768.00MiB        0.00B    768.00MiB
    | 3               0.00B    256.00MiB        0.00B

And yes, fun thing is that after doing a raw btrfs balance start on this
mountpoint, the reclaimable unallocated space will be zero. :-)
  • Loading branch information
knorrie committed Jan 18, 2019
1 parent 7be3dfa commit 41f7f3ca8f32566cf2182949c3724295e3776fc8
Showing with 117 additions and 8 deletions.
  1. +117 −8 examples/show_usage.py
@@ -7,13 +7,122 @@
print("Usage: {} <mountpoint>".format(sys.argv[0]))
sys.exit(1)

fs = btrfs.FileSystem(sys.argv[1])
with btrfs.FileSystem(sys.argv[1]) as fs:
mixed_groups = fs.mixed_groups()
usage = fs.usage()

for device in fs.devices():
print(device)
print("Mixed groups: {}".format(mixed_groups))
print("Target profile for System (chunk tree): {}".format(usage.target_profile_system_str))
if not mixed_groups:
print("Target profile for Metadata: {}".format(usage.target_profile_metadata_str))
print("Target profile for Data: {}".format(usage.target_profile_data_str))
else:
print("Target profile for Data+Metadata: {}".format(
usage.target_profile_data_metadata_str))
print()
print("Virtual space usage by block group type:")
print("|")
virtual_block_group_type_usage_table_values = [
('type', 'total', 'used'),
('----', '-----', '----'),
]
for _, virtual_block_group_type_usage in usage.virtual_block_group_type_usage.items():
virtual_block_group_type_usage_table_values.append((
btrfs.utils.space_type_description(virtual_block_group_type_usage.type),
virtual_block_group_type_usage.total_str,
virtual_block_group_type_usage.used_str,
))
for virtual_block_group_type_usage_table_value in virtual_block_group_type_usage_table_values:
print("| {: <16} {: >12} {: >12}".format(*virtual_block_group_type_usage_table_value))
print()

for chunk in fs.chunks():
print(fs.block_group(chunk.vaddr, chunk.length))
print(" " + str(chunk))
for stripe in chunk.stripes:
print(" " + str(stripe))
print("Total raw filesystem size: {}".format(usage.total_str))
print("Total raw allocated bytes: {}".format(usage.allocated_str))
print("Allocatable bytes remaining: {}".format(usage.allocatable_left_str))
print("Unallocatable bytes that can be reclaimed by balancing: {}".format(
usage.unallocatable_reclaimable_str))
print("Unallocatable bytes because of unbalanced device sizes: {}".format(
usage.unallocatable_hard_str))
print()

if not mixed_groups:
print("Estimated virtual space left to use for metadata: {}".format(
usage.free_metadata_str))
print("Estimated virtual space left to use for data: {}".format(usage.free_data_str))
else:
print("Estimated virtual space left to use for metadata and data: {}".format(
usage.free_str))
print()

print("Allocated raw disk bytes by chunk type. Parity is a reserved part of the \n"
"allocated bytes, limiting the amount that can be used for data or metadata:")
print("|")
raw_space_usage_table_values = [
('flags', 'allocated', 'used', 'parity'),
('-----', '---------', '----', '------'),
]
for _, raw_space_usage in usage.raw_space_usage.items():
raw_space_usage_table_values.append((
btrfs.utils.block_group_flags_str(raw_space_usage.flags),
raw_space_usage.allocated_str,
raw_space_usage.used_str,
raw_space_usage.parity_str,
))
for raw_space_usage_table_value in raw_space_usage_table_values:
print("| {: <16} {: >12} {: >12} {: >12}".format(*raw_space_usage_table_value))
print()

print("Allocated bytes per device:")
print("|")
dev_usage_table_values = [
('devid', 'total size', 'allocated', 'path'),
('-----', '----------', '---------', '----'),
]
for devid in sorted(usage.dev_usage.keys()):
dev_usage = usage.dev_usage[devid]
dev_usage_table_values.append((
dev_usage.devid,
dev_usage.total_str,
dev_usage.allocated_str,
btrfs.ioctl.dev_info(fs.fd, devid).path,
))
for dev_usage_table_value in dev_usage_table_values:
print("| {: <8} {: >12} {: >12} {}".format(*dev_usage_table_value))
print()

print("Allocated bytes per device, split up per chunk type. Parity bytes are again\n"
"part of the total amount of allocated bytes.")
for devid in sorted(usage.dev_usage.keys()):
print("|")
print("| Device ID: {}".format(devid))
dev_usage = usage.dev_usage[devid]
dev_space_usage_table_values = [
('flags', 'allocated', 'parity'),
('-----', '---------', '------'),
]
for _, dev_space_usage in dev_usage.dev_space_usage.items():
dev_space_usage_table_values.append((
btrfs.utils.block_group_flags_str(dev_space_usage.flags),
dev_space_usage.allocated_str,
dev_space_usage.parity_str,
))
for dev_space_usage_table_value in dev_space_usage_table_values:
print("| | {: <16} {: >12} {: >12}".format(*dev_space_usage_table_value))
print()

print("Unallocatable bytes per device:")
print("|")
wasted_sizes_table_values = [
('devid', 'soft', 'hard', 'reclaimable'),
('-----', '----', '----', '-----------'),
]
for devid in sorted(usage.dev_usage.keys()):
dev_usage = usage.dev_usage[devid]
wasted_sizes_table_values.append((
devid,
dev_usage.unallocatable_soft_str,
dev_usage.unallocatable_hard_str,
dev_usage.unallocatable_reclaimable_str,
))
for wasted_sizes_table_value in wasted_sizes_table_values:
print("| {: <8} {: >12} {: >12} {: >12}".format(*wasted_sizes_table_value))

0 comments on commit 41f7f3c

Please sign in to comment.
You can’t perform that action at this time.