/* * Handle rmgr XACT_ID records for DecodeRecordIntoReorderBuffer(). */ static void DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { SnapBuild *builder = ctx->snapshot_builder; ReorderBuffer *reorder = ctx->reorder; XLogReaderState *r = buf->record; uint8 info = XLogRecGetInfo(r) & XLOG_XACT_OPMASK; /* no point in doing anything yet, data could not be decoded anyway */ if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT) return; switch (info) { case XLOG_XACT_COMMIT: case XLOG_XACT_COMMIT_PREPARED: { xl_xact_commit *xlrec; xl_xact_parsed_commit parsed; TransactionId xid; xlrec = (xl_xact_commit *) XLogRecGetData(r); ParseCommitRecord(XLogRecGetInfo(buf->record), xlrec, &parsed); if (!TransactionIdIsValid(parsed.twophase_xid)) xid = XLogRecGetXid(r); else xid = parsed.twophase_xid; DecodeCommit(ctx, buf, &parsed, xid); break; } case XLOG_XACT_ABORT: case XLOG_XACT_ABORT_PREPARED: { xl_xact_abort *xlrec; xl_xact_parsed_abort parsed; TransactionId xid; xlrec = (xl_xact_abort *) XLogRecGetData(r); ParseAbortRecord(XLogRecGetInfo(buf->record), xlrec, &parsed); if (!TransactionIdIsValid(parsed.twophase_xid)) xid = XLogRecGetXid(r); else xid = parsed.twophase_xid; DecodeAbort(ctx, buf, &parsed, xid); break; } case XLOG_XACT_ASSIGNMENT: { xl_xact_assignment *xlrec; int i; TransactionId *sub_xid; xlrec = (xl_xact_assignment *) XLogRecGetData(r); sub_xid = &xlrec->xsub[0]; for (i = 0; i < xlrec->nsubxacts; i++) { ReorderBufferAssignChild(reorder, xlrec->xtop, *(sub_xid++), buf->origptr); } break; } case XLOG_XACT_PREPARE: /* * Currently decoding ignores PREPARE TRANSACTION and will just * decode the transaction when the COMMIT PREPARED is sent or * throw away the transaction's contents when a ROLLBACK PREPARED * is received. In the future we could add code to expose prepared * transactions in the changestream allowing for a kind of * distributed 2PC. */ break; default: elog(ERROR, "unexpected RM_XACT_ID record type: %u", info); } }
/* * Handle rmgr XACT_ID records for DecodeRecordIntoReorderBuffer(). */ static void DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { SnapBuild *builder = ctx->snapshot_builder; ReorderBuffer *reorder = ctx->reorder; XLogRecord *r = &buf->record; uint8 info = r->xl_info & ~XLR_INFO_MASK; /* * No point in doing anything yet, data could not be decoded anyway. It's * ok not to call ReorderBufferProcessXid() in that case, except in the * assignment case there'll not be any later records with the same xid; * and in the assignment case we'll not decode those xacts. */ if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT) return; switch (info) { case XLOG_XACT_COMMIT: { xl_xact_commit *xlrec; TransactionId *subxacts = NULL; SharedInvalidationMessage *invals = NULL; xlrec = (xl_xact_commit *) buf->record_data; subxacts = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]); invals = (SharedInvalidationMessage *) &(subxacts[xlrec->nsubxacts]); DecodeCommit(ctx, buf, r->xl_xid, xlrec->dbId, xlrec->xact_time, xlrec->nsubxacts, subxacts, xlrec->nmsgs, invals); break; } case XLOG_XACT_COMMIT_PREPARED: { xl_xact_commit_prepared *prec; xl_xact_commit *xlrec; TransactionId *subxacts; SharedInvalidationMessage *invals = NULL; /* Prepared commits contain a normal commit record... */ prec = (xl_xact_commit_prepared *) buf->record_data; xlrec = &prec->crec; subxacts = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]); invals = (SharedInvalidationMessage *) &(subxacts[xlrec->nsubxacts]); DecodeCommit(ctx, buf, prec->xid, xlrec->dbId, xlrec->xact_time, xlrec->nsubxacts, subxacts, xlrec->nmsgs, invals); break; } case XLOG_XACT_COMMIT_COMPACT: { xl_xact_commit_compact *xlrec; xlrec = (xl_xact_commit_compact *) buf->record_data; DecodeCommit(ctx, buf, r->xl_xid, InvalidOid, xlrec->xact_time, xlrec->nsubxacts, xlrec->subxacts, 0, NULL); break; } case XLOG_XACT_ABORT: { xl_xact_abort *xlrec; TransactionId *sub_xids; xlrec = (xl_xact_abort *) buf->record_data; sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]); DecodeAbort(ctx, buf->origptr, r->xl_xid, sub_xids, xlrec->nsubxacts); break; } case XLOG_XACT_ABORT_PREPARED: { xl_xact_abort_prepared *prec; xl_xact_abort *xlrec; TransactionId *sub_xids; /* prepared abort contain a normal commit abort... */ prec = (xl_xact_abort_prepared *) buf->record_data; xlrec = &prec->arec; sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]); /* r->xl_xid is committed in a separate record */ DecodeAbort(ctx, buf->origptr, prec->xid, sub_xids, xlrec->nsubxacts); break; } case XLOG_XACT_ASSIGNMENT: { xl_xact_assignment *xlrec; int i; TransactionId *sub_xid; xlrec = (xl_xact_assignment *) buf->record_data; sub_xid = &xlrec->xsub[0]; for (i = 0; i < xlrec->nsubxacts; i++) { ReorderBufferAssignChild(reorder, xlrec->xtop, *(sub_xid++), buf->origptr); } break; } case XLOG_XACT_PREPARE: /* * Currently decoding ignores PREPARE TRANSACTION and will just * decode the transaction when the COMMIT PREPARED is sent or * throw away the transaction's contents when a ROLLBACK PREPARED * is received. In the future we could add code to expose prepared * transactions in the changestream allowing for a kind of * distributed 2PC. */ ReorderBufferProcessXid(reorder, r->xl_xid, buf->origptr); break; default: elog(ERROR, "unexpected RM_XACT_ID record type: %u", info); } }