Re: new database files not compressed

Hamish Moffatt
2020-08-31T08:54:03Z

On 31/8/20 1:47 pm, Zygo Blaxell wrote:
> On Sun, Aug 30, 2020 at 07:35:59PM +1000, Hamish Moffatt wrote:
>> I am trying to store Firebird database files compressed on btrfs. Although I
>> have mounted the file system with -o compress-force, new files created by
>> Firebird are not being compressed according to compsize. If I copy them, or
>> use btrfs filesystem defrag, they compress well.
>>
>> Other files seem to be compressed automatically OK. Why are the Firebird
>> files different?
> If it is writing single 4K blocks with fsync() between writes, or writing
> 4K blocks to discontiguous file offsets, then the extents will be 4K
> and there can be no compression.
>
> Allocation is in 4K blocks (with default mkfs options on popular CPUs).
> To save any space, compression must reduce the size of an extent by at
> least 4K. A 4K extent can't be compressed because even a single bit of
> compressed output would round the extent size back up to 4K, resulting
> in no size reduction on disk.
>
> 8K extents can be compressed if the compression ratio is 50% or higher,
> 12K extents can be compressed if the ratio is at least 33%, 16K extents
> can be compressed if the ratio is at least 25%, and so on. Larger writes
> are better for compression.
>
> Defrag and copies are able to compress because they write contiguously up
> to the maximum compressed extent size of 128K; however, after defrag,
> small random writes will not release the large contiguous extents
> and total space usage reported by compsize can reach over 100% of the
> original uncompressed file size. With nodatacow (and no compression)
> the disk usage of the database remains stable at 100% of the file size.
>
> With defrag and compression the disk usage varies from the best compressed
> size to (size_of_compressed_database + uncompressed_file_size) over time.
> e.g. if you have a 50% compression ratio on a 1MB database then the disk
> usage varies from 512K immediately after defrag to a maximum of 1502K
> in the worst case (out of every 32 blocks, 31 are written in separate
> transactions, which leaves references in the file to all of the compressed
> extents, and adds 31 uncompressed 4K extents for each compressed extent).
> This means that if you want to keep a database compressed with a 4K
> database page size, you have to run defrag frequently.
>
> Another way to get compression is to increase the database page size.
> Sizes up to 128K are useful--128K is the maximum btrfs compressed extent
> size, and increasing the database page size higher will have no further
> compression benefit. Most databases I've encountered max out at 64K
> pages, but even 64K gives some compression.

Understood. Thanks for this explanation.

Perhaps I'm missing something more fundamental, because I don't seem to
get compression even if I create a file full of zeroes with dd;

$ sudo mount -O compress-force=zstd /dev/sdb /mnt/test
$ cd /mnt/test/db
$ dd if=/dev/zero of=zero bs=16k count=1024
1024+0 records in
1024+0 records out
16777216 bytes (17 MB, 16 MiB) copied, 0.0154404 s, 1.1 GB/s
$ sudo compsize zero
Type       Perc     Disk Usage   Uncompressed Referenced
TOTAL      100%       16M          16M          16M
none       100%       16M          16M          16M
$ sudo btrfs fi defrag -czstd zero
$ sudo compsize zero
Type       Perc     Disk Usage   Uncompressed Referenced
TOTAL        3%      512K          16M          16M
zstd         3%      512K          16M          16M

I did trying my Firebird tests with a 16k database page size and didn't
see any compression there either.

Hamish