Skip to content

Read/Write order matters

Since SBE does not hold any data about the layout of the buffer and also supports variable length fields, it has to rely on the developer to use it as specified. This means reading and writing the data in the exact field order specified in the XML. If you do not follow this order, you should expect strange read results.

Here's an example showing this in action. This SBE message has two sequence types followed by two string types:

<sbe:message name="SampleCorruption" id="2" description="Corruption sample">
    <field name="sequence1" id="1" type="Sequence"/>
    <field name="sequence2" id="2" type="Sequence"/>
    <data name="data1" id="3" type="varStringEncoding"/>
    <data name="data2" id="4" type="varStringEncoding"/>
</sbe:message>

If we write the strings in an incorrect order, we can see unexpected results. With "foo" being written to data1, we should expect data1 to be "foo" when read.

encoder.wrapAndApplyHeader(directBuffer, 0, messageHeaderEncoder);
encoder.data2("bar");
encoder.data1("foo");
encoder.sequence1(123L);
encoder.sequence2(321L);

If we read it as follows, with an assertion that data1 has the value "foo":

Assertions.assertEquals(123, decoder.sequence1());
Assertions.assertEquals("foo", decoder.data1());
Assertions.assertEquals(321, decoder.sequence2());
Assertions.assertEquals("bar", decoder.data2());

We can see the assertion fail with data1 having the value for data2, "bar".

com.aeroncookbook.sbe.SbeTests > dataCanBeCorrupted() FAILED
    org.opentest4j.AssertionFailedError: expected: <foo> but was: <bar>

See dataCanBeCorrupted and dataCanBeReadCorrectlyWhenWrittenCorrectly in the test provided with the sample project.

Checking read/write order

SBE can generate precedence checks in the flyweights (since version 1.30.0). When enabled at runtime, these checks will throw an exception if a developer has not written/read fields in the correct order.

Continuing the example above, we can see an exception thrown when data2 is written before data1:

java.lang.IllegalStateException: Illegal field access order. Cannot access field "data2" in state: V0_BLOCK. Expected one of these transitions: ["sequence1(?)", "sequence2(?)", "data1(?)"]. Please see the diagram in the Javadoc of the class SampleCorruptionEncoder#CodecStates.

The exception references a diagram in the Javadoc of the generated class, which shows the valid transitions:

/**
 * The states in which an encoder/decoder/codec can live.
 *
 * <p>The state machine diagram below, encoded in the dot language, describes
 * the valid state transitions according to the order in which fields may be
 * accessed safely. Tools such as PlantUML and Graphviz can render it.
 *
 * <pre>{@code
 *   digraph G {
 *       NOT_WRAPPED -> V0_BLOCK [label="  wrap(version=0)  "];
 *       V0_BLOCK -> V0_BLOCK [label="  sequence1(?)  "];
 *       V0_BLOCK -> V0_BLOCK [label="  sequence2(?)  "];
 *       V0_BLOCK -> V0_DATA1_DONE [label="  data1(?)  "];
 *       V0_DATA1_DONE -> V0_DATA2_DONE [label="  data2(?)  "];
 *   }
 * }</pre>
 */
private static class CodecStates
{
    // ...
}

You can drop this dot diagram into a tool like Graphviz or PlantUML to render it:

SBE precedence diagram

Generation of the checks in enabled by setting the sbe.generate.precedence.checks system property to true when running SbeTool.

Execution of the checks, at runtime, is enabled when the sbe.enable.precedence.checks system property is true or when the sbe.enable.precedence.checks property is left unset and the agrona.disable.bounds.checks is not set to true. Running these checks has a significant cost; therefore, you may wish to disable them in production.

See SBE Wiki - Safe Flyweight Usage for more information.