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

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


  • To: Marcus Granado <marcus.granado@xxxxxxxxxx>, Frediano Ziglio <freddy77@xxxxxxxxx>
  • From: Teddy Astie <teddy.astie@xxxxxxxxxx>
  • Date: Tue, 4 Aug 2026 11:15:02 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=vates.tech header.i="@vates.tech" header.h="From:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:In-Reply-To:References:Feedback-ID"
  • Autocrypt: addr=teddy.astie@xxxxxxxxxx; keydata= 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 x9fhaZEsniw8/bYgC3igkk5YJiOa
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Roger Pau Monne <roger.pau@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx>
  • Delivery-date: Tue, 04 Aug 2026 09:15:20 +0000
  • Feedback-id: default:8631fc262581453bbf619ec5b2062170:Sweego
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Le 03/08/2026 à 19:23, Marcus Granado a écrit :
On Wed, 29 Jul 2026 at 10:14, Frediano Ziglio <freddy77@xxxxxxxxx> wrote:
About compressing all together and considering also the issue of
memory changing while sending I would vote to copy the memory in a
temporary buffer to avoid this. One advantage is that it simplified
the format. The current LZ4 implementation seems to cope with data
changes but nothing guarantees it in the future, the buffer you are
passing is not supposed to change while you compress it.


Agreed. Frediano and I discussed this further, including simplifications on
the compression record for v2 so that the page data compression:
* compresses the whole batch together
* and uses a staged copy for it as you and Teddy suggested (so that we do
not need to worry about mutating buffers affecting LZ4 or other algorithms).

Once there's exactly one compressed blob per record, there's no need for
extra fields to describe the compressed data, as the uncompressed batch
size is known (and bounded by MAX_BATCH_SIZE * page_size), and its
compressed size can be inferred from the size of the emitted compressed
record without a need for an explicit field for clen or a field with the
number of raw compressed blobs. This means the separate PAGE_DATA_LZ4
record type is not needed, and the proposal for v2 compression record could
simplify to reusing PAGE_DATA and spending one octet of its reserved word
as follows:


      0     1     2     3     4     5     6     7 octet
     +-----------------------+-----+-------------------+
     | count (C)             | comp| (reserved)        |
     +-----------------------+-----+-------------------+
     | pfn[0]                                          |
     +-------------------------------------------------+
     ...
     +-------------------------------------------------+
     | pfn[C-1]                                        |
     +-------------------------------------------------+
     | page_data[0..N-1] if comp == 0                  |
     | or page_cdata     if comp != 0                  |
     +-------------------------------------------------+

with two new entries in the field table:

comp        Compression algorithm applied to the page contents. 0
             means none, and the record is exactly as it is today. 1
             means LZ4 block format. Other values are reserved for
             other future formats like ZSTD etc. A comp != 0 can only
             be emitted if 0 < len(page_cdata) < N * page_size. An
             unknown comp must cause the receiver to fail with a
             "Compression algorithm <value> not handled" error.

page_cdata  Present instead of page_data when comp is non-zero. A
             single compressed object holding the concatenation of the
             N page_data entries. The receiver must verify that
             0 < count <= MAX_BATCH_SIZE.


Teddy, I hope this format covers your points: it's no longer LZ4 specific,
the inline clen inconsistency in libxenguest record disappears, it's one
block over an immutable copy of the batch instead of one per page, the
decompressed size is known up front, and the allocation derived from count
is bounded on the receiver.


Looks good to me.


This simplification is also forward-compatible in two different ways: your
64KB chunking for cache locality doesn't depend on the format, as the
staging copy can be done in chunks while still making a single compress
call over the whole batch. And if we find benefits in splitting the payload
into several compressed units, that can be implemented as a new comp value
using a self-delimiting format like zstd or lz4f frames, which report the
consumed bytes without a need to specify clen or extra framing fields at the
record level.


On Wed, 22 Jul 2026 at 20:42, Frediano Ziglio <freddy77@xxxxxxxxx> wrote:
Don't we need to bump the version number while we add a new mandatory record?

I believe we may avoid having to do a version bump if we adopt the property
that 0 < len(page_cdata) < N * page_size when comp != 0, as in this case
the compressed data sent to an old receiver would fail in handle_page_data()
with "PAGE_DATA record wrong size". Bumping the version would make
uncompressed migrations fail if they are sent to old receivers that also
understand uncompressed migration, so avoiding if possible would be good.
The spec says migration tools "shall always save images using version V",
so it doesn't seem like we could bump the version only when compression is on.


Is there no kind of dialog about the supported version?

There is no in-stream negotiation, and this proposal does not add one.
Compression is opt-in at the sender via xl migrate --compress, so an operator
who enables it against an old receiver gets a clean failure rather than
corruption.

Why not extending the generalization compressing all payload of
uncompressed packets (type+body),

A composable wrapper would be a clean generic mechanism, but I think there
are two reasons not to go that way in v2: PAGE_DATA is effectively all of the
stream bytes, so compressing the other record types would not show up in a
measurement. And the no-extra-fields property above depends on PAGE_DATA
specifically: a generic wrapper has no pfn array from where we can derive
the uncompressed size, so it would need explicit algorithm, compressed
size and uncompressed size fields on every record, which re-adds the fields
that this proposal tries to avoid.


Please let me know if the ideas above capture what you had in mind in terms of
suggestions to improve v1.

In particular, I wonder what the maintainers think of the use of one of the
octets of the PAGE_DATA reserved field for the purpose of indicating the data
is compressed, or is it preferable to use a new PAGE_DATA_COMPRESSED (0x13)
type record as a mandatory record so that an old receiver fails more cleanly
when it doesn't understand compression "Mandatory record <name> not handled"
(caused by the specification of mandatory records) instead of with a generic
error "PAGE_DATA record wrong size" (caused by the current safety
implementation that rejects unexpected record sizes)?


The specification says

> Padding and reserved fields are set to zero on save and must be
ignored during restore.

Which is not really going to help if we add a new field that matters on how the content is organized.

To avoid confusion, it may be desirable to add a new type (PAGE_DATA_COMPRESSED), but I'm not fully sold on it.


Marcus



Teddy

Attachment: OpenPGP_0x660FA9D102CBCFD0.asc
Description: OpenPGP public key

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.