mirror of
https://github.com/ceph/ceph
synced 2024-12-25 04:43:17 +00:00
8abce157f1
* administrators * allocated * allowed * approximate * authenticate * availability * average * behavior * binaries * bootstrap * bootstrapping * capacity * cephadm * clients * combining * command * committed * comparison * compiled * consequences * continues * convenience * cookie * crypto * dashboard * deduplication * defaults * delivered * deployment * describe * directory * documentation * dynamic * elimination * entries * expectancy * explicit * explicitly * exporter * github * hard * healthcheck * heartbeat * heavily * http * indices * infrastructure * inherit * layout * lexically * likelihood * logarithmic * manually * metadata * minimization * minimize * object * of * operation * opportunities * overwrite * prioritized * recipe * records * requirements * restructured * running * scalability * second * select * significant * specify * subscription * supported * synonym * throttle * unpinning * upgraded * value * version * which * with Plus some line wrapping and additional edits... Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
96 lines
3.0 KiB
ReStructuredText
96 lines
3.0 KiB
ReStructuredText
|
|
Serialization (encode/decode)
|
|
=============================
|
|
|
|
When a structure is sent over the network or written to disk, it is
|
|
encoded into a string of bytes. Serializable structures have
|
|
``encode`` and ``decode`` methods that write and read from ``bufferlist``
|
|
objects representing byte strings.
|
|
|
|
Adding a field to a structure
|
|
-----------------------------
|
|
|
|
You can see examples of this all over the Ceph code, but here's an
|
|
example:
|
|
|
|
.. code-block:: cpp
|
|
|
|
class AcmeClass
|
|
{
|
|
int member1;
|
|
std::string member2;
|
|
|
|
void encode(bufferlist &bl)
|
|
{
|
|
ENCODE_START(1, 1, bl);
|
|
::encode(member1, bl);
|
|
::encode(member2, bl);
|
|
ENCODE_FINISH(bl);
|
|
}
|
|
|
|
void decode(bufferlist::iterator &bl)
|
|
{
|
|
DECODE_START(1, bl);
|
|
::decode(member1, bl);
|
|
::decode(member2, bl);
|
|
DECODE_FINISH(bl);
|
|
}
|
|
};
|
|
|
|
The ``ENCODE_START`` macro writes a header that specifies a *version* and
|
|
a *compat_version* (both initially 1). The message version is incremented
|
|
whenever a change is made to the encoding. The compat_version is incremented
|
|
only if the change will break existing decoders -- decoders are tolerant
|
|
of trailing bytes, so changes that add fields at the end of the structure
|
|
do not require incrementing compat_version.
|
|
|
|
The ``DECODE_START`` macro takes an argument specifying the most recent
|
|
message version that the code can handle. This is compared with the
|
|
compat_version encoded in the message, and if the message is too new then
|
|
an exception will be thrown. Because changes to compat_version are rare,
|
|
this isn't usually something to worry about when adding fields.
|
|
|
|
In practice, changes to encoding usually involve simply adding the desired fields
|
|
at the end of the ``encode`` and ``decode`` functions, and incrementing
|
|
the versions in ``ENCODE_START`` and ``DECODE_START``. For example, here's how
|
|
to add a third field to ``AcmeClass``:
|
|
|
|
.. code-block:: cpp
|
|
|
|
class AcmeClass
|
|
{
|
|
int member1;
|
|
std::string member2;
|
|
std::vector<std::string> member3;
|
|
|
|
void encode(bufferlist &bl)
|
|
{
|
|
ENCODE_START(2, 1, bl);
|
|
::encode(member1, bl);
|
|
::encode(member2, bl);
|
|
::encode(member3, bl);
|
|
ENCODE_FINISH(bl);
|
|
}
|
|
|
|
void decode(bufferlist::iterator &bl)
|
|
{
|
|
DECODE_START(2, bl);
|
|
::decode(member1, bl);
|
|
::decode(member2, bl);
|
|
if (struct_v >= 2) {
|
|
::decode(member3, bl);
|
|
}
|
|
DECODE_FINISH(bl);
|
|
}
|
|
};
|
|
|
|
Note that the compat_version did not change because the encoded message
|
|
will still be decodable by versions of the code that only understand
|
|
version 1 -- they will just ignore the trailing bytes where we encode ``member3``.
|
|
|
|
In the ``decode`` function, decoding the new field is conditional: this is
|
|
because we might still be passed older-versioned messages that do not
|
|
have the field. The ``struct_v`` variable is a local set by the ``DECODE_START``
|
|
macro.
|
|
|