/* * Handle rmgr XLOG_ID records for DecodeRecordIntoReorderBuffer(). */ static void DecodeXLogOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { SnapBuild *builder = ctx->snapshot_builder; uint8 info = XLogRecGetInfo(buf->record) & ~XLR_INFO_MASK; switch (info) { /* this is also used in END_OF_RECOVERY checkpoints */ case XLOG_CHECKPOINT_SHUTDOWN: case XLOG_END_OF_RECOVERY: SnapBuildSerializationPoint(builder, buf->origptr); break; case XLOG_CHECKPOINT_ONLINE: /* * a RUNNING_XACTS record will have been logged near to this, we * can restart from there. */ break; case XLOG_NOOP: case XLOG_NEXTOID: case XLOG_SWITCH: case XLOG_BACKUP_END: case XLOG_PARAMETER_CHANGE: case XLOG_RESTORE_POINT: case XLOG_FPW_CHANGE: case XLOG_FPI_FOR_HINT: case XLOG_FPI: break; default: elog(ERROR, "unexpected RM_XLOG_ID record type: %u", info); } }
void brin_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; switch (info & XLOG_BRIN_OPMASK) { case XLOG_BRIN_CREATE_INDEX: brin_xlog_createidx(record); break; case XLOG_BRIN_INSERT: brin_xlog_insert(record); break; case XLOG_BRIN_UPDATE: brin_xlog_update(record); break; case XLOG_BRIN_SAMEPAGE_UPDATE: brin_xlog_samepage_update(record); break; case XLOG_BRIN_REVMAP_EXTEND: brin_xlog_revmap_extend(record); break; case XLOG_BRIN_DESUMMARIZE: brin_xlog_desummarize_page(record); break; default: elog(PANIC, "brin_redo: unknown op code %u", info); } }
void gist_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; MemoryContext oldCxt; /* * GiST indexes do not require any conflict processing. NB: If we ever * implement a similar optimization we have in b-tree, and remove killed * tuples outside VACUUM, we'll need to handle that here. */ oldCxt = MemoryContextSwitchTo(opCtx); switch (info) { case XLOG_GIST_PAGE_UPDATE: gistRedoPageUpdateRecord(record); break; case XLOG_GIST_PAGE_SPLIT: gistRedoPageSplitRecord(record); break; case XLOG_GIST_CREATE_INDEX: gistRedoCreateIndex(record); break; default: elog(PANIC, "gist_redo: unknown op code %u", info); } MemoryContextSwitchTo(oldCxt); MemoryContextReset(opCtx); }
void standby_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == XLOG_STANDBY_LOCK) { xl_standby_locks *xlrec = (xl_standby_locks *) rec; int i; for (i = 0; i < xlrec->nlocks; i++) appendStringInfo(buf, "xid %u db %u rel %u ", xlrec->locks[i].xid, xlrec->locks[i].dbOid, xlrec->locks[i].relOid); } else if (info == XLOG_RUNNING_XACTS) { xl_running_xacts *xlrec = (xl_running_xacts *) rec; standby_desc_running_xacts(buf, xlrec); } else if (info == XLOG_INVALIDATIONS) { xl_invalidations *xlrec = (xl_invalidations *) rec; standby_desc_invalidations(buf, xlrec->nmsgs, xlrec->msgs, xlrec->dbId, xlrec->tsId, xlrec->relcacheInitFileInval); } }
/* * Handle rmgr STANDBY_ID records for DecodeRecordIntoReorderBuffer(). */ static void DecodeStandbyOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { SnapBuild *builder = ctx->snapshot_builder; XLogReaderState *r = buf->record; uint8 info = XLogRecGetInfo(r) & ~XLR_INFO_MASK; switch (info) { case XLOG_RUNNING_XACTS: { xl_running_xacts *running = (xl_running_xacts *) XLogRecGetData(r); SnapBuildProcessRunningXacts(builder, buf->origptr, running); /* * Abort all transactions that we keep track of, that are * older than the record's oldestRunningXid. This is the most * convenient spot for doing so since, in contrast to shutdown * or end-of-recovery checkpoints, we have information about * all running transactions which includes prepared ones, * while shutdown checkpoints just know that no non-prepared * transactions are in progress. */ ReorderBufferAbortOld(ctx->reorder, running->oldestRunningXid); } break; case XLOG_STANDBY_LOCK: break; default: elog(ERROR, "unexpected RM_STANDBY_ID record type: %u", info); } }
void multixact_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE || info == XLOG_MULTIXACT_ZERO_MEM_PAGE) { int pageno; memcpy(&pageno, rec, sizeof(int)); appendStringInfo(buf, "%d", pageno); } else if (info == XLOG_MULTIXACT_CREATE_ID) { xl_multixact_create *xlrec = (xl_multixact_create *) rec; int i; appendStringInfo(buf, "%u offset %u nmembers %d: ", xlrec->mid, xlrec->moff, xlrec->nmembers); for (i = 0; i < xlrec->nmembers; i++) out_member(buf, &xlrec->members[i]); } else if (info == XLOG_MULTIXACT_TRUNCATE_ID) { xl_multixact_truncate *xlrec = (xl_multixact_truncate *) rec; appendStringInfo(buf, "offsets [%u, %u), members [%u, %u)", xlrec->startTruncOff, xlrec->endTruncOff, xlrec->startTruncMemb, xlrec->endTruncMemb); } }
void heap2_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; info &= XLOG_HEAP_OPMASK; if (info == XLOG_HEAP2_CLEAN) { xl_heap_clean *xlrec = (xl_heap_clean *) rec; appendStringInfo(buf, "remxid %u", xlrec->latestRemovedXid); } else if (info == XLOG_HEAP2_FREEZE_PAGE) { xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec; appendStringInfo(buf, "cutoff xid %u ntuples %u", xlrec->cutoff_xid, xlrec->ntuples); } else if (info == XLOG_HEAP2_CLEANUP_INFO) { xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec; appendStringInfo(buf, "remxid %u", xlrec->latestRemovedXid); } else if (info == XLOG_HEAP2_VISIBLE) { xl_heap_visible *xlrec = (xl_heap_visible *) rec; appendStringInfo(buf, "cutoff xid %u", xlrec->cutoff_xid); } else if (info == XLOG_HEAP2_MULTI_INSERT) { xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec; appendStringInfo(buf, "%d tuples", xlrec->ntuples); } else if (info == XLOG_HEAP2_LOCK_UPDATED) { xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec; appendStringInfo(buf, "off %u: xmax %u ", xlrec->offnum, xlrec->xmax); out_infobits(buf, xlrec->infobits_set); } else if (info == XLOG_HEAP2_NEW_CID) { xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec; appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u", xlrec->target_node.spcNode, xlrec->target_node.dbNode, xlrec->target_node.relNode, ItemPointerGetBlockNumber(&(xlrec->target_tid)), ItemPointerGetOffsetNumber(&(xlrec->target_tid))); appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u", xlrec->cmin, xlrec->cmax, xlrec->combocid); } }
void heap_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; info &= XLOG_HEAP_OPMASK; if (info == XLOG_HEAP_INSERT) { xl_heap_insert *xlrec = (xl_heap_insert *) rec; appendStringInfo(buf, "off %u", xlrec->offnum); } else if (info == XLOG_HEAP_DELETE) { xl_heap_delete *xlrec = (xl_heap_delete *) rec; appendStringInfo(buf, "off %u ", xlrec->offnum); out_infobits(buf, xlrec->infobits_set); } else if (info == XLOG_HEAP_UPDATE) { xl_heap_update *xlrec = (xl_heap_update *) rec; appendStringInfo(buf, "off %u xmax %u ", xlrec->old_offnum, xlrec->old_xmax); out_infobits(buf, xlrec->old_infobits_set); appendStringInfo(buf, "; new off %u xmax %u", xlrec->new_offnum, xlrec->new_xmax); } else if (info == XLOG_HEAP_HOT_UPDATE) { xl_heap_update *xlrec = (xl_heap_update *) rec; appendStringInfo(buf, "off %u xmax %u ", xlrec->old_offnum, xlrec->old_xmax); out_infobits(buf, xlrec->old_infobits_set); appendStringInfo(buf, "; new off %u xmax %u", xlrec->new_offnum, xlrec->new_xmax); } else if (info == XLOG_HEAP_LOCK) { xl_heap_lock *xlrec = (xl_heap_lock *) rec; appendStringInfo(buf, "off %u: xid %u ", xlrec->offnum, xlrec->locking_xid); out_infobits(buf, xlrec->infobits_set); } else if (info == XLOG_HEAP_INPLACE) { xl_heap_inplace *xlrec = (xl_heap_inplace *) rec; appendStringInfo(buf, "off %u", xlrec->offnum); } }
/* * Redo is basically just noop for logical decoding messages. */ void logicalmsg_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info != XLOG_LOGICAL_MESSAGE) elog(PANIC, "logicalmsg_redo: unknown op code %u", info); /* This is only interesting for logical decoding, see decode.c. */ }
void seq_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; xl_seq_rec *xlrec = (xl_seq_rec *) rec; if (info == XLOG_SEQ_LOG) appendStringInfo(buf, "rel %u/%u/%u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); }
void brin_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; info &= XLOG_BRIN_OPMASK; if (info == XLOG_BRIN_CREATE_INDEX) { xl_brin_createidx *xlrec = (xl_brin_createidx *) rec; appendStringInfo(buf, "v%d pagesPerRange %u", xlrec->version, xlrec->pagesPerRange); } else if (info == XLOG_BRIN_INSERT) { xl_brin_insert *xlrec = (xl_brin_insert *) rec; appendStringInfo(buf, "heapBlk %u pagesPerRange %u offnum %u", xlrec->heapBlk, xlrec->pagesPerRange, xlrec->offnum); } else if (info == XLOG_BRIN_UPDATE) { xl_brin_update *xlrec = (xl_brin_update *) rec; appendStringInfo(buf, "heapBlk %u pagesPerRange %u old offnum %u, new offnum %u", xlrec->insert.heapBlk, xlrec->insert.pagesPerRange, xlrec->oldOffnum, xlrec->insert.offnum); } else if (info == XLOG_BRIN_SAMEPAGE_UPDATE) { xl_brin_samepage_update *xlrec = (xl_brin_samepage_update *) rec; appendStringInfo(buf, "offnum %u", xlrec->offnum); } else if (info == XLOG_BRIN_REVMAP_EXTEND) { xl_brin_revmap_extend *xlrec = (xl_brin_revmap_extend *) rec; appendStringInfo(buf, "targetBlk %u", xlrec->targetBlk); } else if (info == XLOG_BRIN_DESUMMARIZE) { xl_brin_desummarize *xlrec = (xl_brin_desummarize *) rec; appendStringInfo(buf, "pagesPerRange %u, heapBlk %u, page offset %u", xlrec->pagesPerRange, xlrec->heapBlk, xlrec->regOffset); } }
void btree_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; switch (info) { case XLOG_BTREE_INSERT_LEAF: btree_xlog_insert(true, false, record); break; case XLOG_BTREE_INSERT_UPPER: btree_xlog_insert(false, false, record); break; case XLOG_BTREE_INSERT_META: btree_xlog_insert(false, true, record); break; case XLOG_BTREE_SPLIT_L: btree_xlog_split(true, false, record); break; case XLOG_BTREE_SPLIT_R: btree_xlog_split(false, false, record); break; case XLOG_BTREE_SPLIT_L_ROOT: btree_xlog_split(true, true, record); break; case XLOG_BTREE_SPLIT_R_ROOT: btree_xlog_split(false, true, record); break; case XLOG_BTREE_VACUUM: btree_xlog_vacuum(record); break; case XLOG_BTREE_DELETE: btree_xlog_delete(record); break; case XLOG_BTREE_MARK_PAGE_HALFDEAD: btree_xlog_mark_page_halfdead(info, record); break; case XLOG_BTREE_UNLINK_PAGE: case XLOG_BTREE_UNLINK_PAGE_META: btree_xlog_unlink_page(info, record); break; case XLOG_BTREE_NEWROOT: btree_xlog_newroot(record); break; case XLOG_BTREE_REUSE_PAGE: btree_xlog_reuse_page(record); break; default: elog(PANIC, "btree_redo: unknown op code %u", info); } }
void gin_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; MemoryContext oldCtx; /* * GIN indexes do not require any conflict processing. NB: If we ever * implement a similar optimization as we have in b-tree, and remove * killed tuples outside VACUUM, we'll need to handle that here. */ oldCtx = MemoryContextSwitchTo(opCtx); switch (info) { case XLOG_GIN_CREATE_INDEX: ginRedoCreateIndex(record); break; case XLOG_GIN_CREATE_PTREE: ginRedoCreatePTree(record); break; case XLOG_GIN_INSERT: ginRedoInsert(record); break; case XLOG_GIN_SPLIT: ginRedoSplit(record); break; case XLOG_GIN_VACUUM_PAGE: ginRedoVacuumPage(record); break; case XLOG_GIN_VACUUM_DATA_LEAF_PAGE: ginRedoVacuumDataLeafPage(record); break; case XLOG_GIN_DELETE_PAGE: ginRedoDeletePage(record); break; case XLOG_GIN_UPDATE_META_PAGE: ginRedoUpdateMetapage(record); break; case XLOG_GIN_INSERT_LISTPAGE: ginRedoInsertListPage(record); break; case XLOG_GIN_DELETE_LISTPAGE: ginRedoDeleteListPages(record); break; default: elog(PANIC, "gin_redo: unknown op code %u", info); } MemoryContextSwitchTo(oldCtx); MemoryContextReset(opCtx); }
void xact_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == XLOG_XACT_COMMIT_COMPACT) { xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec; xact_desc_commit_compact(buf, xlrec); } else if (info == XLOG_XACT_COMMIT) { xl_xact_commit *xlrec = (xl_xact_commit *) rec; xact_desc_commit(buf, xlrec); } else if (info == XLOG_XACT_ABORT) { xl_xact_abort *xlrec = (xl_xact_abort *) rec; xact_desc_abort(buf, xlrec); } else if (info == XLOG_XACT_COMMIT_PREPARED) { xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec; appendStringInfo(buf, "%u: ", xlrec->xid); xact_desc_commit(buf, &xlrec->crec); } else if (info == XLOG_XACT_ABORT_PREPARED) { xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec; appendStringInfo(buf, "%u: ", xlrec->xid); xact_desc_abort(buf, &xlrec->arec); } else if (info == XLOG_XACT_ASSIGNMENT) { xl_xact_assignment *xlrec = (xl_xact_assignment *) rec; /* * Note that we ignore the WAL record's xid, since we're more * interested in the top-level xid that issued the record and which * xids are being reported here. */ appendStringInfo(buf, "xtop %u: ", xlrec->xtop); xact_desc_assignment(buf, xlrec); } }
/* * Handle rmgr HEAP2_ID records for DecodeRecordIntoReorderBuffer(). */ static void DecodeHeap2Op(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { uint8 info = XLogRecGetInfo(buf->record) & XLOG_HEAP_OPMASK; TransactionId xid = XLogRecGetXid(buf->record); SnapBuild *builder = ctx->snapshot_builder; ReorderBufferProcessXid(ctx->reorder, xid, buf->origptr); /* no point in doing anything yet */ if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT) return; switch (info) { case XLOG_HEAP2_MULTI_INSERT: if (SnapBuildProcessChange(builder, xid, buf->origptr)) DecodeMultiInsert(ctx, buf); break; case XLOG_HEAP2_NEW_CID: { xl_heap_new_cid *xlrec; xlrec = (xl_heap_new_cid *) XLogRecGetData(buf->record); SnapBuildProcessNewCid(builder, xid, buf->origptr, xlrec); break; } case XLOG_HEAP2_REWRITE: /* * Although these records only exist to serve the needs of logical * decoding, all the work happens as part of crash or archive * recovery, so we don't need to do anything here. */ break; /* * Everything else here is just low level physical stuff we're not * interested in. */ case XLOG_HEAP2_FREEZE_PAGE: case XLOG_HEAP2_CLEAN: case XLOG_HEAP2_CLEANUP_INFO: case XLOG_HEAP2_VISIBLE: case XLOG_HEAP2_LOCK_UPDATED: break; default: elog(ERROR, "unexpected RM_HEAP2_ID record type: %u", info); } }
void relmap_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == XLOG_RELMAP_UPDATE) { xl_relmap_update *xlrec = (xl_relmap_update *) rec; appendStringInfo(buf, "database %u tablespace %u size %u", xlrec->dbid, xlrec->tsid, xlrec->nbytes); } }
void hash_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; switch (info) { case XLOG_HASH_INIT_META_PAGE: hash_xlog_init_meta_page(record); break; case XLOG_HASH_INIT_BITMAP_PAGE: hash_xlog_init_bitmap_page(record); break; case XLOG_HASH_INSERT: hash_xlog_insert(record); break; case XLOG_HASH_ADD_OVFL_PAGE: hash_xlog_add_ovfl_page(record); break; case XLOG_HASH_SPLIT_ALLOCATE_PAGE: hash_xlog_split_allocate_page(record); break; case XLOG_HASH_SPLIT_PAGE: hash_xlog_split_page(record); break; case XLOG_HASH_SPLIT_COMPLETE: hash_xlog_split_complete(record); break; case XLOG_HASH_MOVE_PAGE_CONTENTS: hash_xlog_move_page_contents(record); break; case XLOG_HASH_SQUEEZE_PAGE: hash_xlog_squeeze_page(record); break; case XLOG_HASH_DELETE: hash_xlog_delete(record); break; case XLOG_HASH_SPLIT_CLEANUP: hash_xlog_split_cleanup(record); break; case XLOG_HASH_UPDATE_META_PAGE: hash_xlog_update_meta_page(record); break; case XLOG_HASH_VACUUM_ONE_PAGE: hash_xlog_vacuum_one_page(record); break; default: elog(PANIC, "hash_redo: unknown op code %u", info); } }
void clog_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == CLOG_ZEROPAGE || info == CLOG_TRUNCATE) { int pageno; memcpy(&pageno, rec, sizeof(int)); appendStringInfo(buf, "%d", pageno); } }
void commit_ts_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == COMMIT_TS_ZEROPAGE) { int pageno; memcpy(&pageno, rec, sizeof(int)); appendStringInfo(buf, "%d", pageno); } else if (info == COMMIT_TS_TRUNCATE) { int pageno; memcpy(&pageno, rec, sizeof(int)); appendStringInfo(buf, "%d", pageno); } else if (info == COMMIT_TS_SETTS) { xl_commit_ts_set *xlrec = (xl_commit_ts_set *) rec; int nsubxids; appendStringInfo(buf, "set %s/%d for: %u", timestamptz_to_str(xlrec->timestamp), xlrec->nodeid, xlrec->mainxid); nsubxids = ((XLogRecGetDataLen(record) - SizeOfCommitTsSet) / sizeof(TransactionId)); if (nsubxids > 0) { int i; TransactionId *subxids; subxids = palloc(sizeof(TransactionId) * nsubxids); memcpy(subxids, XLogRecGetData(record) + SizeOfCommitTsSet, sizeof(TransactionId) * nsubxids); for (i = 0; i < nsubxids; i++) appendStringInfo(buf, ", %u", subxids[i]); pfree(subxids); } } }
void gist_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; switch (info) { case XLOG_GIST_PAGE_UPDATE: out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec); break; case XLOG_GIST_PAGE_SPLIT: out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec); break; case XLOG_GIST_CREATE_INDEX: break; } }
void tblspc_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == XLOG_TBLSPC_CREATE) { xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec; appendStringInfo(buf, "%u \"%s\"", xlrec->ts_id, xlrec->ts_path); } else if (info == XLOG_TBLSPC_DROP) { xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec; appendStringInfo(buf, "%u", xlrec->ts_id); } }
void spg_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; MemoryContext oldCxt; oldCxt = MemoryContextSwitchTo(opCtx); switch (info) { case XLOG_SPGIST_CREATE_INDEX: spgRedoCreateIndex(record); break; case XLOG_SPGIST_ADD_LEAF: spgRedoAddLeaf(record); break; case XLOG_SPGIST_MOVE_LEAFS: spgRedoMoveLeafs(record); break; case XLOG_SPGIST_ADD_NODE: spgRedoAddNode(record); break; case XLOG_SPGIST_SPLIT_TUPLE: spgRedoSplitTuple(record); break; case XLOG_SPGIST_PICKSPLIT: spgRedoPickSplit(record); break; case XLOG_SPGIST_VACUUM_LEAF: spgRedoVacuumLeaf(record); break; case XLOG_SPGIST_VACUUM_ROOT: spgRedoVacuumRoot(record); break; case XLOG_SPGIST_VACUUM_REDIRECT: spgRedoVacuumRedirect(record); break; default: elog(PANIC, "spg_redo: unknown op code %u", info); } MemoryContextSwitchTo(oldCxt); MemoryContextReset(opCtx); }
/* * Handle rmgr LOGICALMSG_ID records for DecodeRecordIntoReorderBuffer(). */ static void DecodeLogicalMsgOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { SnapBuild *builder = ctx->snapshot_builder; XLogReaderState *r = buf->record; TransactionId xid = XLogRecGetXid(r); uint8 info = XLogRecGetInfo(r) & ~XLR_INFO_MASK; RepOriginId origin_id = XLogRecGetOrigin(r); Snapshot snapshot; xl_logical_message *message; if (info != XLOG_LOGICAL_MESSAGE) elog(ERROR, "unexpected RM_LOGICALMSG_ID record type: %u", info); ReorderBufferProcessXid(ctx->reorder, XLogRecGetXid(r), buf->origptr); /* No point in doing anything yet. */ if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT) return; message = (xl_logical_message *) XLogRecGetData(r); if (message->dbId != ctx->slot->data.database || FilterByOrigin(ctx, origin_id)) return; if (message->transactional && !SnapBuildProcessChange(builder, xid, buf->origptr)) return; else if (!message->transactional && (SnapBuildCurrentState(builder) != SNAPBUILD_CONSISTENT || SnapBuildXactNeedsSkip(builder, buf->origptr))) return; snapshot = SnapBuildGetOrBuildSnapshot(builder, xid); ReorderBufferQueueMessage(ctx->reorder, xid, snapshot, buf->endptr, message->transactional, message->message, /* first part of message is * prefix */ message->message_size, message->message + message->prefix_size); }
/* * RELMAP resource manager's routines */ void relmap_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; /* Backup blocks are not used in relmap records */ Assert(!XLogRecHasAnyBlockRefs(record)); if (info == XLOG_RELMAP_UPDATE) { xl_relmap_update *xlrec = (xl_relmap_update *) XLogRecGetData(record); RelMapFile newmap; char *dbpath; if (xlrec->nbytes != sizeof(RelMapFile)) elog(PANIC, "relmap_redo: wrong size %u in relmap update record", xlrec->nbytes); memcpy(&newmap, xlrec->data, sizeof(newmap)); /* We need to construct the pathname for this database */ dbpath = GetDatabasePath(xlrec->dbid, xlrec->tsid); /* * Write out the new map and send sinval, but of course don't write a * new WAL entry. There's no surrounding transaction to tell to * preserve files, either. * * There shouldn't be anyone else updating relmaps during WAL replay, * so we don't bother to take the RelationMappingLock. We would need * to do so if load_relmap_file needed to interlock against writers. */ write_relmap_file((xlrec->dbid == InvalidOid), &newmap, false, true, false, xlrec->dbid, xlrec->tsid, dbpath); pfree(dbpath); } else elog(PANIC, "relmap_redo: unknown op code %u", info); }
void smgr_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; if (info == XLOG_SMGR_CREATE) { xl_smgr_create *xlrec = (xl_smgr_create *) rec; char *path = relpathperm(xlrec->rnode, xlrec->forkNum); appendStringInfoString(buf, path); pfree(path); } else if (info == XLOG_SMGR_TRUNCATE) { xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec; char *path = relpathperm(xlrec->rnode, MAIN_FORKNUM); appendStringInfo(buf, "%s to %u blocks flags %d", path, xlrec->blkno, xlrec->flags); pfree(path); } }
/* * CommitTS resource manager's routines */ void commit_ts_redo(XLogReaderState *record) { uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; /* Backup blocks are not used in commit_ts records */ Assert(!XLogRecHasAnyBlockRefs(record)); if (info == COMMIT_TS_ZEROPAGE) { int pageno; int slotno; memcpy(&pageno, XLogRecGetData(record), sizeof(int)); LWLockAcquire(CommitTsControlLock, LW_EXCLUSIVE); slotno = ZeroCommitTsPage(pageno, false); SimpleLruWritePage(CommitTsCtl, slotno); Assert(!CommitTsCtl->shared->page_dirty[slotno]); LWLockRelease(CommitTsControlLock); } else if (info == COMMIT_TS_TRUNCATE) { int pageno; memcpy(&pageno, XLogRecGetData(record), sizeof(int)); /* * During XLOG replay, latest_page_number isn't set up yet; insert a * suitable value to bypass the sanity test in SimpleLruTruncate. */ CommitTsCtl->shared->latest_page_number = pageno; SimpleLruTruncate(CommitTsCtl, pageno); } else if (info == COMMIT_TS_SETTS) { xl_commit_ts_set *setts = (xl_commit_ts_set *) XLogRecGetData(record); int nsubxids; TransactionId *subxids; nsubxids = ((XLogRecGetDataLen(record) - SizeOfCommitTsSet) / sizeof(TransactionId)); if (nsubxids > 0) { subxids = palloc(sizeof(TransactionId) * nsubxids); memcpy(subxids, XLogRecGetData(record) + SizeOfCommitTsSet, sizeof(TransactionId) * nsubxids); } else subxids = NULL; TransactionTreeSetCommitTsData(setts->mainxid, nsubxids, subxids, setts->timestamp, setts->nodeid, true); if (subxids) pfree(subxids); } else elog(PANIC, "commit_ts_redo: unknown op code %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; XLogReaderState *r = buf->record; uint8 info = XLogRecGetInfo(r) & ~XLR_INFO_MASK; /* 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: { xl_xact_commit *xlrec; TransactionId *subxacts = NULL; SharedInvalidationMessage *invals = NULL; xlrec = (xl_xact_commit *) XLogRecGetData(r); subxacts = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]); invals = (SharedInvalidationMessage *) &(subxacts[xlrec->nsubxacts]); DecodeCommit(ctx, buf, XLogRecGetXid(r), 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 *) XLogRecGetData(r); 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 *) XLogRecGetData(r); DecodeCommit(ctx, buf, XLogRecGetXid(r), 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 *) XLogRecGetData(r); sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]); DecodeAbort(ctx, buf->origptr, XLogRecGetXid(r), 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 *) XLogRecGetData(r); 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 *) 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); } }
void btree_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; switch (info) { case XLOG_BTREE_INSERT_LEAF: case XLOG_BTREE_INSERT_UPPER: case XLOG_BTREE_INSERT_META: { xl_btree_insert *xlrec = (xl_btree_insert *) rec; appendStringInfo(buf, "off %u", xlrec->offnum); break; } case XLOG_BTREE_SPLIT_L: case XLOG_BTREE_SPLIT_R: { xl_btree_split *xlrec = (xl_btree_split *) rec; appendStringInfo(buf, "level %u, firstright %d", xlrec->level, xlrec->firstright); break; } case XLOG_BTREE_VACUUM: { xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec; appendStringInfo(buf, "lastBlockVacuumed %u", xlrec->lastBlockVacuumed); break; } case XLOG_BTREE_DELETE: { xl_btree_delete *xlrec = (xl_btree_delete *) rec; appendStringInfo(buf, "%d items", xlrec->nitems); break; } case XLOG_BTREE_MARK_PAGE_HALFDEAD: { xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec; appendStringInfo(buf, "topparent %u; leaf %u; left %u; right %u", xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk); break; } case XLOG_BTREE_UNLINK_PAGE_META: case XLOG_BTREE_UNLINK_PAGE: { xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec; appendStringInfo(buf, "left %u; right %u; btpo_xact %u; ", xlrec->leftsib, xlrec->rightsib, xlrec->btpo_xact); appendStringInfo(buf, "leafleft %u; leafright %u; topparent %u", xlrec->leafleftsib, xlrec->leafrightsib, xlrec->topparent); break; } case XLOG_BTREE_NEWROOT: { xl_btree_newroot *xlrec = (xl_btree_newroot *) rec; appendStringInfo(buf, "lev %u", xlrec->level); break; } case XLOG_BTREE_REUSE_PAGE: { xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec; appendStringInfo(buf, "rel %u/%u/%u; latestRemovedXid %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->latestRemovedXid); break; } } }
/* * 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 HEAP_ID records for DecodeRecordIntoReorderBuffer(). */ static void DecodeHeapOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { uint8 info = XLogRecGetInfo(buf->record) & XLOG_HEAP_OPMASK; TransactionId xid = XLogRecGetXid(buf->record); SnapBuild *builder = ctx->snapshot_builder; /* no point in doing anything yet */ if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT) return; switch (info) { case XLOG_HEAP_INSERT: if (SnapBuildProcessChange(builder, xid, buf->origptr)) DecodeInsert(ctx, buf); break; /* * Treat HOT update as normal updates. There is no useful * information in the fact that we could make it a HOT update * locally and the WAL layout is compatible. */ case XLOG_HEAP_HOT_UPDATE: case XLOG_HEAP_UPDATE: if (SnapBuildProcessChange(builder, xid, buf->origptr)) DecodeUpdate(ctx, buf); break; case XLOG_HEAP_DELETE: if (SnapBuildProcessChange(builder, xid, buf->origptr)) DecodeDelete(ctx, buf); break; case XLOG_HEAP_INPLACE: /* * Inplace updates are only ever performed on catalog tuples and * can, per definition, not change tuple visibility. Since we * don't decode catalog tuples, we're not interested in the * record's contents. * * In-place updates can be used either by XID-bearing transactions * (e.g. in CREATE INDEX CONCURRENTLY) or by XID-less * transactions (e.g. VACUUM). In the former case, the commit * record will include cache invalidations, so we mark the * transaction as catalog modifying here. Currently that's * redundant because the commit will do that as well, but once we * support decoding in-progress relations, this will be important. */ if (!TransactionIdIsValid(xid)) break; SnapBuildProcessChange(builder, xid, buf->origptr); ReorderBufferXidSetCatalogChanges(ctx->reorder, xid, buf->origptr); break; case XLOG_HEAP_CONFIRM: if (SnapBuildProcessChange(builder, xid, buf->origptr)) DecodeSpecConfirm(ctx, buf); break; case XLOG_HEAP_LOCK: /* we don't care about row level locks for now */ break; default: elog(ERROR, "unexpected RM_HEAP_ID record type: %u", info); break; } }