|
| 1 | +The encoders and decoders that SBE generates in Java (and other languages without approximations of session types) require developers to follow a strict contract: |
| 2 | + |
| 3 | +- Developers must encode/decode all repeating groups and variable-length data fields in the order in which they appear in the schema. |
| 4 | +- Developers must explicitly encode/decode/skip all present groups and variable-length data, i.e., no implicit skipping. |
| 5 | +- Developers must call next() before encoding/decoding each repeating group element. |
| 6 | + |
| 7 | +When encoding, failure to follow the contract can produce invalid messages that do not conform to the format described in the associated SBE schema. |
| 8 | + |
| 9 | +When decoding, failure to follow the contract can result in the misinterpretation of valid messages. |
| 10 | + |
| 11 | +### Checking field access order |
| 12 | + |
| 13 | +SBE can generate runtime checks that ensure the correct usage of flyweight encoders/decoders/codecs (w.r.t. field access order) in Java, C++ and C#. |
| 14 | + |
| 15 | +To generate these runtime checks, pass `-Dsbe.generate.access.order.checks=true` when running the SBE tool. |
| 16 | + |
| 17 | +By default, the generated checks are disabled, using conditional compilation, as they have a significant performance overhead. When running our car benchmarks, we see approximately 50% fewer encodes/decodes per second. |
| 18 | +We expect that teams will enable these runtime checks in non-production environments and in their tests. |
| 19 | + |
| 20 | +To enable the runtime checks: |
| 21 | + |
| 22 | +* In Java, set the `sbe.generate.access.order.checks` system property to `true`. |
| 23 | +* In C++, define the `ENABLE_ACCESS_ORDER_CHECKS` symbol when compiling. |
| 24 | +* In C#, define the `ENABLE_ACCESS_ORDER_CHECKS` symbol when building. |
| 25 | + |
| 26 | +### Checking complete encoding |
| 27 | + |
| 28 | +When runtime checks are enabled, in addition to checking fields are encoded/decoded in the correct order, you can also check that you've fully encoded a message. I.e., that you haven't omitted any groups or variable length fields from the end of the message. |
| 29 | +To do so, call the `checkEncodingIsComplete()` method on the flyweight encoder for the message. |
| 30 | + |
| 31 | +### Understanding errors |
| 32 | + |
| 33 | +Once runtime checks are enabled, you may start to see some errors if you have some incorrect (or very unusual) uses of flyweight encoders/decoders/codecs. |
| 34 | + |
| 35 | +For example, if you have a message schema with two variable length fields: |
| 36 | + |
| 37 | +```xml |
| 38 | +<sbe:message name="SendChatMessage" id="99"> |
| 39 | + <field name="chatId" id="1" type="int64"/> |
| 40 | + <data name="subject" id="2" type="varDataEncoding"/> <!-- subject first --> |
| 41 | + <data name="body" id="3" type="varDataEncoding"/> <!-- body second --> |
| 42 | +</sbe:message> |
| 43 | +``` |
| 44 | + |
| 45 | +and you accidentally encode these in a different order to the schema: |
| 46 | + |
| 47 | +```java |
| 48 | +final SendChatMessageEncoder encoder = new SendChatMessageEncoder() |
| 49 | + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); |
| 50 | + |
| 51 | +encoder.chatId(1) |
| 52 | + .body("About 1 ft tall and furry.") // body first |
| 53 | + .subject("Missing cat"); // subject second |
| 54 | +``` |
| 55 | + |
| 56 | +you will an exception like this one at runtime: |
| 57 | + |
| 58 | +``` |
| 59 | +Illegal field access order. |
| 60 | +Cannot access field "body" in state: V0_BLOCK. |
| 61 | +Expected one of these transitions: ["chatId(?)", "subject(?)"]. |
| 62 | +Please see the diagram in the Javadoc of the inner class #CodecStates. |
| 63 | +``` |
| 64 | + |
| 65 | +The exception tells us: |
| 66 | + |
| 67 | +- The current codec state is `V0_BLOCK`. |
| 68 | +- We cannot call `body` when the codec is in this state. |
| 69 | +- But we can call either `chatId` or `subject` in this state. |
| 70 | + |
| 71 | +It also says where we can find more information. The `CodecStates` class documentation holds a dot diagram of the state machine: |
| 72 | + |
| 73 | +```java |
| 74 | + /** |
| 75 | + * The states in which a encoder/decoder/codec can live. |
| 76 | + * |
| 77 | + * <p>The state machine diagram below, encoded in the dot language, describes |
| 78 | + * the valid state transitions according to the order in which fields may be |
| 79 | + * accessed safely. Tools such as PlantUML and Graphviz can render it. |
| 80 | + * |
| 81 | + * <pre>{@code |
| 82 | + * digraph G { |
| 83 | + * NOT_WRAPPED -> V0_BLOCK [label=" wrap(version=0) "]; |
| 84 | + * V0_BLOCK -> V0_BLOCK [label=" chatId(?) "]; |
| 85 | + * V0_BLOCK -> V0_SUBJECT_DONE [label=" subject(?) "]; |
| 86 | + * V0_SUBJECT_DONE -> V0_BODY_DONE [label=" body(?) "]; |
| 87 | + * } |
| 88 | + * }</pre> |
| 89 | + */ |
| 90 | + private static class CodecStates |
| 91 | + { |
| 92 | + // ... |
| 93 | + } |
| 94 | + ``` |
| 95 | + |
| 96 | + We can use a tool, e.g., [PlantText](http://planttext.com), to render the dot diagram and reveal the state machine diagram. |
| 97 | + |
| 98 | +  |
0 commit comments