Re: [PATCH v1 1/6] tools/migration: introduce PAGE_DATA_LZ4 stream record type

Teddy Astie <[email protected]>
Newsgroups org.xenproject.lists.xen-devel
Message-ID <1784622046.8631fc262581453bbf619ec5b2062170.19f83c35cd4000edb5@vates.tech>
Le 20/07/2026 à 17:51, Marcus Granado a écrit :
> Allocate a new migration stream record type REC_TYPE_PAGE_DATA_LZ4
> (0x00000013) to transmit PAGE_DATA when payload is LZ4-compressed. The
> record use the same xc_sr_rec_page_data_header as REC_TYPE_PAGE_DATA
> but the page data section type changes from page_data to data_lz4.
> 
> Signed-off-by: Marcus Granado <[email protected]>
> ---
>   docs/specs/libxc-migration-stream.pandoc | 71 ++++++++++++++++-
>   tools/libs/guest/xg_sr_common.c          |  4 +
>   tools/libs/guest/xg_sr_stream_format.h   | 13 ++++
>   tools/python/xen/migration/libxc.py      | 90 ++++++++++++++++++++-
>   tools/python/xen/migration/tests.py      | 99 +++++++++++++++++++++++-
>   5 files changed, 271 insertions(+), 6 deletions(-)
> 
> diff --git a/docs/specs/libxc-migration-stream.pandoc b/docs/specs/libxc-migration-stream.pandoc
> index 1319ce1f1e..7469c95139 100644
> --- a/docs/specs/libxc-migration-stream.pandoc
> +++ b/docs/specs/libxc-migration-stream.pandoc

...

> +PAGE_DATA_LZ4
> +-------------
> +
> +A PAGE_DATA_LZ4 record carries exactly the same information as a
> +PAGE_DATA record, but with the page contents LZ4-compressed.  The saver
> +may emit it in place of a PAGE_DATA record when LZ4 compression has been
> +requested.
> +

Would it be preferable to make this structure more generic, i.e 
PAGE_DATA_COMPRESSED, as I'm not sure it's wise to restrict to only LZ4 
(someone may want to add support for e.g zstd or another algorithm 
without having to change the format) ?

> +     0     1     2     3     4     5     6     7 octet
> +    +-----------------------+-------------------------+
> +    | count (C)             | (reserved)              |
> +    +-----------------------+-------------------------+
> +    | pfn[0]                                          |
> +    +-------------------------------------------------+
> +    ...
> +    +-------------------------------------------------+
> +    | pfn[C-1]                                        |
> +    +-----------+-------------------------------------+
> +    | clen[0]   | page_data_lz4[0]...                 |
> +    +-----------+-------------------------------------+
> +    ...
> +    +-----------+-------------------------------------+
> +    | clen[N-1] | page_data_lz4[N-1]...               |
> +    ...
> +    +-------------------------------------------------+
> +
> +--------------------------------------------------------------------
> +Field       Description
> +----------- --------------------------------------------------------
> +count       Number of pages described in this record.
> +
> +pfn         An array of count PFNs and their types, with the same
> +            layout and page types as in a PAGE_DATA record.
> +
> +data_lz4    The compressed page contents, as one sub-block per page
> +            set as present in the pfn array, in pfn-array order (i.e.
> +            N sub-blocks, with N as in a PAGE_DATA record: N <= C).
> +            Each sub-block is a `uint16` little-endian length `clen`
> +            followed by either an LZ4 block or a raw page.  When
> +            `clen > 0`, page_data_lz4 is `clen` octets of a raw LZ4
> +            block (per the LZ4 block format) whose decompressed output
> +            is one page_size page.  When `clen == 0`, page_data_lz4 is
> +            page_size octets of a raw, uncompressed page.
> +            A compressed `clen` is at most page_size - 1, occupying
> +            only the low 12 bits; the top 4 bits are reserved for
> +            future use and must be 0.
> +--------------------------------------------------------------------
> +
> +The `count` (C) and `pfn` fields are identical in meaning and
> +constraints to those of a PAGE_DATA record, and N (the number of
> +present pages, N <= C) is as defined there.  Unlike PAGE_DATA, a
> +PAGE_DATA_LZ4 record always has N >= 1 (at least one sub-block):
> +the saver emits the LZ4 variant only when there is page data to
> +compress, and a restoring side rejects a PAGE_DATA_LZ4 record with
> +N == 0.  When a batch has no present pages (all pfns of invalid
> +types) the saver emits a plain PAGE_DATA record instead.
> +
> +PAGE_DATA_LZ4 is a _mandatory_ record: a restoring side that does not
> +support it must fail the migration.
> +

The inline clen at the beginning of page_data_lz4 feels a bit odd to me, 
or at least, a bit inconsistent with how pfns are arranged. I think 
something like i.e

1. count and (reserved)
2. pfn[0] ... pfn[C-1]
3. clen[0] ... clen[N-1]
4. page_data_lz4[0] ... page_data_lz4[N-1]

would be better.

Though, aside that, I'm not sure having separate compressed block for 
each page is a good idea. Compression is more efficient when processing 
larger blocks, LZ4 documents a 64 KB deduplication window (of the past 
bytes) [1].

In my opinion, it may be preferable to have one large block with all the 
page datas (covering up to MAX_BATCH_SIZE=1024 pages) rather than having 
to uncompress individual blocks. Which in the end would remove the need 
to have individual clen[n].

What do you think ?

[1] 
https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md#compression-techniques
...

> 
> base-commit: a7fd7d4cbd5e793d31d61c25e08526b330edd7f8

Teddy
OpenPGP_0x660FA9D102CBCFD0.asc (application/pgp-keys, 2.4 KB)
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
x9fhaZEsniw8/bYgC3igkk5YJiOa
=lUIA
-----END PGP PUBLIC KEY BLOCK-----
OpenPGP_signature.asc (application/pgp-signature, 665 B)
-----BEGIN PGP SIGNATURE-----

wsD5BAABCAAjFiEEGAIew9LzHY3pdrqtZg+p0QLLz9AFAmpfK90FAwAAAAAACgkQZg+p0QLLz9Aw
Fgv+JRZeDD38rBEGX1m1zYFkbqgIJ3i+dp5yJ8mub1TMtGV4O0DQjPOzKwa8s3jBhz9HbRFts++R
y767hJQc9QkH7PqmVMIUOL0VTR1boSna5gRSqG8VsSen8fTniaSQBobTABjDWEHnqOnNy2d7C/nT
RPdGNRK683G8ON3+XWQkTt2Mu3qTtJk735TRFQgxQIRQrsl5OXdI8NvfsMve5RbJWauFuql37tvu
LCxP3CzmnSVxinlUTTXSIa3qcCj4TH/nJGV+cW9pg3MwJPSbZEsopBHHO+CHhTI+3Rjphkyx3cA3
Px3pWR/E25xg3ymZMrzkXEsiUNGM8/CGlacSF+v0vjEGRiWdspPE/PxSWo4Ma8T9BdGYRglNBIUV
2HDFLmpwXGsoSP0XuQvYG0tg6behDPZe2RmzQGM4lnctPDbOtyqIZb18QUt0T8J7wQTanHgFsqtb
IBUsmnXU50Gpq9l+erVwvrOJv10UL2NTWPOkalEJo/QvfYU56omlrqOuGWxy
=lAnz
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.