Class StreamingWal2JsonMessageDecoder
- java.lang.Object
-
- io.debezium.connector.postgresql.connection.AbstractMessageDecoder
-
- io.debezium.connector.postgresql.connection.wal2json.StreamingWal2JsonMessageDecoder
-
- All Implemented Interfaces:
MessageDecoder
public class StreamingWal2JsonMessageDecoder extends AbstractMessageDecoder
JSON deserialization of a message sent by wal2json logical decoding plugin. The plugin sends all changes in one transaction as a single batch and they are passed to processor one-by-one. The JSON file arrives in chunks of a big JSON file where the chunks are not valid JSON itself.
There are four different chunks that can arrive from the decoder. Beginning of message
{ "xid": 563, "timestamp": "2018-03-20 10:58:43.396355+01", "change": [First change{ "kind": "insert", "schema": "public", "table": "numeric_decimal_table", "columnnames": ["pk", "d", "dzs", "dvs", "d_nn", "n", "nzs", "nvs", "d_int", "dzs_int", "dvs_int", "n_int", "nzs_int", "nvs_int", "d_nan", "dzs_nan", "dvs_nan", "n_nan", "nzs_nan", "nvs_nan"], "columntypes": ["integer", "numeric(3,2)", "numeric(4,0)", "numeric", "numeric(3,2)", "numeric(6,4)", "numeric(4,0)", "numeric", "numeric(3,2)", "numeric(4,0)", "numeric", "numeric(6,4)", "numeric(4,0)", "numeric", "numeric(3,2)", "numeric(4,0)", "numeric", "numeric(6,4)", "numeric(4,0)", "numeric"], "columnoptionals": [false, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true], "columnvalues": [1, 1.10, 10, 10.1111, 3.30, 22.2200, 22, 22.2222, 1.00, 10, 10, 22.0000, 22, 22, null, null, null, null, null, null] }Further changes,{ "kind": "insert", "schema": "public", "table": "numeric_decimal_table", "columnnames": ["pk", "d", "dzs", "dvs", "d_nn", "n", "nzs", "nvs", "d_int", "dzs_int", "dvs_int", "n_int", "nzs_int", "nvs_int", "d_nan", "dzs_nan", "dvs_nan", "n_nan", "nzs_nan", "nvs_nan"], "columntypes": ["integer", "numeric(3,2)", "numeric(4,0)", "numeric", "numeric(3,2)", "numeric(6,4)", "numeric(4,0)", "numeric", "numeric(3,2)", "numeric(4,0)", "numeric", "numeric(6,4)", "numeric(4,0)", "numeric", "numeric(3,2)", "numeric(4,0)", "numeric", "numeric(6,4)", "numeric(4,0)", "numeric"], "columnoptionals": [false, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true], "columnvalues": [1, 1.10, 10, 10.1111, 3.30, 22.2200, 22, 22.2222, 1.00, 10, 10, 22.0000, 22, 22, null, null, null, null, null, null] }End of message] }For parsing purposes it is necessary to add or remove a fragment of JSON to make a well-formatted JSON out of it. The last message is just dropped.
- Author:
- Jiri Pechanec
-
-
Field Summary
Fields Modifier and Type Field Description private static byteCOMMAprivate InstantcommitTimeprivate booleancontainsMetadataprivate static byteCRprivate byte[]currentChunkTo identify if the last current chunk is the last one we can send the current one for processing only after we read the next one or the end of message fragment.private DateTimeFormatdateTimeprivate static byteLEFT_BRACEprivate static org.slf4j.LoggerLOGGERprivate booleanmessageInProgressprivate static byteRIGHT_BRACEprivate static byteRIGHT_BRACKETprivate static byteSPACEprivate static byteTABprivate longtxIdprivate static longUNDEFINED_LONG
-
Constructor Summary
Constructors Constructor Description StreamingWal2JsonMessageDecoder()
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description private voiddoProcessMessage(ReplicationStream.ReplicationMessageProcessor processor, TypeRegistry typeRegistry, byte[] content, boolean lastMessage)private bytegetFirstNonWhiteChar(byte[] array)private bytegetLastNonWhiteChar(byte[] array)private booleanisWhitespace(byte c)protected voidnonInitialChunk(ReplicationStream.ReplicationMessageProcessor processor, TypeRegistry typeRegistry, byte[] content)org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilderoptionsWithMetadata(org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilder builder)Allows MessageDecoder to configure options with which the replication stream is started.org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilderoptionsWithoutMetadata(org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilder builder)Allows MessageDecoder to configure options with which the replication stream is started.protected voidoutOfOrderChunk(byte[] content)This method is called when a database server or Debezium crashes.voidprocessNotEmptyMessage(ByteBuffer buffer, ReplicationStream.ReplicationMessageProcessor processor, TypeRegistry typeRegistry)private voidreplaceFirstNonWhiteChar(byte[] array, byte to)voidsetContainsMetadata(boolean containsMetadata)Signals to this decoder whether messages contain type metadata or not.-
Methods inherited from class io.debezium.connector.postgresql.connection.AbstractMessageDecoder
close, processMessage, shouldMessageBeSkipped
-
-
-
-
Field Detail
-
LOGGER
private static final org.slf4j.Logger LOGGER
-
TAB
private static final byte TAB
- See Also:
- Constant Field Values
-
CR
private static final byte CR
- See Also:
- Constant Field Values
-
SPACE
private static final byte SPACE
- See Also:
- Constant Field Values
-
COMMA
private static final byte COMMA
- See Also:
- Constant Field Values
-
RIGHT_BRACKET
private static final byte RIGHT_BRACKET
- See Also:
- Constant Field Values
-
LEFT_BRACE
private static final byte LEFT_BRACE
- See Also:
- Constant Field Values
-
RIGHT_BRACE
private static final byte RIGHT_BRACE
- See Also:
- Constant Field Values
-
UNDEFINED_LONG
private static final long UNDEFINED_LONG
- See Also:
- Constant Field Values
-
dateTime
private final DateTimeFormat dateTime
-
containsMetadata
private boolean containsMetadata
-
messageInProgress
private boolean messageInProgress
-
currentChunk
private byte[] currentChunk
To identify if the last current chunk is the last one we can send the current one for processing only after we read the next one or the end of message fragment.
-
txId
private long txId
-
commitTime
private Instant commitTime
-
-
Method Detail
-
processNotEmptyMessage
public void processNotEmptyMessage(ByteBuffer buffer, ReplicationStream.ReplicationMessageProcessor processor, TypeRegistry typeRegistry) throws SQLException, InterruptedException
- Specified by:
processNotEmptyMessagein classAbstractMessageDecoder- Throws:
SQLExceptionInterruptedException
-
nonInitialChunk
protected void nonInitialChunk(ReplicationStream.ReplicationMessageProcessor processor, TypeRegistry typeRegistry, byte[] content) throws IOException, SQLException, InterruptedException
-
outOfOrderChunk
protected void outOfOrderChunk(byte[] content)
This method is called when a database server or Debezium crashes. With wal2json streaming mode it can happen that the message preamble is no replayed but the message is streamed form the middle. This issue is very hard to reproduce so a precaution is taken and metadata are filled with synthetic values.The new wal2json format will be resilient to this situation.
- Parameters:
content-
-
getLastNonWhiteChar
private byte getLastNonWhiteChar(byte[] array) throws IllegalArgumentException- Throws:
IllegalArgumentException
-
getFirstNonWhiteChar
private byte getFirstNonWhiteChar(byte[] array) throws IllegalArgumentException- Throws:
IllegalArgumentException
-
replaceFirstNonWhiteChar
private void replaceFirstNonWhiteChar(byte[] array, byte to)
-
isWhitespace
private boolean isWhitespace(byte c)
-
doProcessMessage
private void doProcessMessage(ReplicationStream.ReplicationMessageProcessor processor, TypeRegistry typeRegistry, byte[] content, boolean lastMessage) throws IOException, SQLException, InterruptedException
-
optionsWithMetadata
public org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilder optionsWithMetadata(org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilder builder)
Description copied from interface:MessageDecoderAllows MessageDecoder to configure options with which the replication stream is started. The messages CAN contain type metadata. See PostgreSQL command START_REPLICATION SLOT for more details.- Returns:
- the builder instance
-
optionsWithoutMetadata
public org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilder optionsWithoutMetadata(org.postgresql.replication.fluent.logical.ChainedLogicalStreamBuilder builder)
Description copied from interface:MessageDecoderAllows MessageDecoder to configure options with which the replication stream is started. The messages MUST NOT contain type metadata. See PostgreSQL command START_REPLICATION SLOT for more details.- Returns:
- the builder instance
-
setContainsMetadata
public void setContainsMetadata(boolean containsMetadata)
Description copied from interface:MessageDecoderSignals to this decoder whether messages contain type metadata or not.
-
-