diff options
| author | Robert Haas | 2013-12-10 23:33:45 +0000 |
|---|---|---|
| committer | Robert Haas | 2013-12-11 00:01:40 +0000 |
| commit | e55704d8b2fe522fbc9435acbb5bc59033478bd5 (patch) | |
| tree | 720602fc06bf251eb65dd7c4628d047027122ac8 /src/include | |
| parent | 9ec6199d18d6235cc4b4d5e4e8986e73b55b14d8 (diff) | |
Add new wal_level, logical, sufficient for logical decoding.
When wal_level=logical, we'll log columns from the old tuple as
configured by the REPLICA IDENTITY facility added in commit
07cacba983ef79be4a84fcd0e0ca3b5fcb85dd65. This makes it possible
a properly-configured logical replication solution to correctly
follow table updates even if they change the chosen key columns,
or, with REPLICA IDENTITY FULL, even if the table has no key at
all. Note that updates which do not modify the replica identity
column won't log anything extra, making the choice of a good key
(i.e. one that will rarely be changed) important to performance
when wal_level=logical is configured.
Each insert, update, or delete to a catalog table will also log
the CMIN and/or CMAX values of stamped by the current transaction.
This is necessary because logical decoding will require access to
historical snapshots of the catalog in order to decode some data
types, and the CMIN/CMAX values that we may need in order to judge
row visibility may have been overwritten by the time we need them.
Andres Freund, reviewed in various versions by myself, Heikki
Linnakangas, KONDO Mitsumasa, and many others.
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/access/heapam_xlog.h | 70 | ||||
| -rw-r--r-- | src/include/access/xact.h | 1 | ||||
| -rw-r--r-- | src/include/access/xlog.h | 8 | ||||
| -rw-r--r-- | src/include/access/xlog_internal.h | 2 | ||||
| -rw-r--r-- | src/include/utils/rel.h | 24 | ||||
| -rw-r--r-- | src/include/utils/relcache.h | 12 |
6 files changed, 104 insertions, 13 deletions
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h index 63b73d0329..438e79db48 100644 --- a/src/include/access/heapam_xlog.h +++ b/src/include/access/heapam_xlog.h @@ -55,6 +55,22 @@ #define XLOG_HEAP2_VISIBLE 0x40 #define XLOG_HEAP2_MULTI_INSERT 0x50 #define XLOG_HEAP2_LOCK_UPDATED 0x60 +#define XLOG_HEAP2_NEW_CID 0x70 + +/* + * xl_heap_* ->flag values, 8 bits are available. + */ +/* PD_ALL_VISIBLE was cleared */ +#define XLOG_HEAP_ALL_VISIBLE_CLEARED (1<<0) +/* PD_ALL_VISIBLE was cleared in the 2nd page */ +#define XLOG_HEAP_NEW_ALL_VISIBLE_CLEARED (1<<1) +#define XLOG_HEAP_CONTAINS_OLD_TUPLE (1<<2) +#define XLOG_HEAP_CONTAINS_OLD_KEY (1<<3) +#define XLOG_HEAP_CONTAINS_NEW_TUPLE (1<<4) + +/* convenience macro for checking whether any form of old tuple was logged */ +#define XLOG_HEAP_CONTAINS_OLD \ + (XLOG_HEAP_CONTAINS_OLD_TUPLE | XLOG_HEAP_CONTAINS_OLD_KEY) /* * All what we need to find changed tuple @@ -78,10 +94,10 @@ typedef struct xl_heap_delete xl_heaptid target; /* deleted tuple id */ TransactionId xmax; /* xmax of the deleted tuple */ uint8 infobits_set; /* infomask bits */ - bool all_visible_cleared; /* PD_ALL_VISIBLE was cleared */ + uint8 flags; } xl_heap_delete; -#define SizeOfHeapDelete (offsetof(xl_heap_delete, all_visible_cleared) + sizeof(bool)) +#define SizeOfHeapDelete (offsetof(xl_heap_delete, flags) + sizeof(uint8)) /* * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted @@ -100,15 +116,29 @@ typedef struct xl_heap_header #define SizeOfHeapHeader (offsetof(xl_heap_header, t_hoff) + sizeof(uint8)) +/* + * Variant of xl_heap_header that contains the length of the tuple, which is + * useful if the length of the tuple cannot be computed using the overall + * record length. E.g. because there are several tuples inside a single + * record. + */ +typedef struct xl_heap_header_len +{ + uint16 t_len; + xl_heap_header header; +} xl_heap_header_len; + +#define SizeOfHeapHeaderLen (offsetof(xl_heap_header_len, header) + SizeOfHeapHeader) + /* This is what we need to know about insert */ typedef struct xl_heap_insert { xl_heaptid target; /* inserted tuple id */ - bool all_visible_cleared; /* PD_ALL_VISIBLE was cleared */ + uint8 flags; /* xl_heap_header & TUPLE DATA FOLLOWS AT END OF STRUCT */ } xl_heap_insert; -#define SizeOfHeapInsert (offsetof(xl_heap_insert, all_visible_cleared) + sizeof(bool)) +#define SizeOfHeapInsert (offsetof(xl_heap_insert, flags) + sizeof(uint8)) /* * This is what we need to know about a multi-insert. The record consists of @@ -120,7 +150,7 @@ typedef struct xl_heap_multi_insert { RelFileNode node; BlockNumber blkno; - bool all_visible_cleared; + uint8 flags; uint16 ntuples; OffsetNumber offsets[1]; @@ -147,13 +177,12 @@ typedef struct xl_heap_update TransactionId old_xmax; /* xmax of the old tuple */ TransactionId new_xmax; /* xmax of the new tuple */ ItemPointerData newtid; /* new inserted tuple id */ - uint8 old_infobits_set; /* infomask bits to set on old tuple */ - bool all_visible_cleared; /* PD_ALL_VISIBLE was cleared */ - bool new_all_visible_cleared; /* same for the page of newtid */ + uint8 old_infobits_set; /* infomask bits to set on old tuple */ + uint8 flags; /* NEW TUPLE xl_heap_header AND TUPLE DATA FOLLOWS AT END OF STRUCT */ } xl_heap_update; -#define SizeOfHeapUpdate (offsetof(xl_heap_update, new_all_visible_cleared) + sizeof(bool)) +#define SizeOfHeapUpdate (offsetof(xl_heap_update, flags) + sizeof(uint8)) /* * This is what we need to know about vacuum page cleanup/redirect @@ -263,6 +292,29 @@ typedef struct xl_heap_visible #define SizeOfHeapVisible (offsetof(xl_heap_visible, cutoff_xid) + sizeof(TransactionId)) +typedef struct xl_heap_new_cid +{ + /* + * store toplevel xid so we don't have to merge cids from different + * transactions + */ + TransactionId top_xid; + CommandId cmin; + CommandId cmax; + /* + * don't really need the combocid since we have the actual values + * right in this struct, but the padding makes it free and its + * useful for debugging. + */ + CommandId combocid; + /* + * Store the relfilenode/ctid pair to facilitate lookups. + */ + xl_heaptid target; +} xl_heap_new_cid; + +#define SizeOfHeapNewCid (offsetof(xl_heap_new_cid, target) + SizeOfHeapTid) + extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple, TransactionId *latestRemovedXid); diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 1d3e7d8938..9632378865 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -215,6 +215,7 @@ extern TransactionId GetCurrentTransactionId(void); extern TransactionId GetCurrentTransactionIdIfAny(void); extern TransactionId GetStableLatestTransactionId(void); extern SubTransactionId GetCurrentSubTransactionId(void); +extern void MarkCurrentTransactionIdLoggedIfAny(void); extern bool SubTransactionIsActive(SubTransactionId subxid); extern CommandId GetCurrentCommandId(bool used); extern TimestampTz GetCurrentTransactionStartTimestamp(void); diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 002862cca5..7415a261bb 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -197,7 +197,8 @@ typedef enum WalLevel { WAL_LEVEL_MINIMAL = 0, WAL_LEVEL_ARCHIVE, - WAL_LEVEL_HOT_STANDBY + WAL_LEVEL_HOT_STANDBY, + WAL_LEVEL_LOGICAL } WalLevel; extern int wal_level; @@ -210,9 +211,12 @@ extern int wal_level; */ #define XLogIsNeeded() (wal_level >= WAL_LEVEL_ARCHIVE) -/* Do we need to WAL-log information required only for Hot Standby? */ +/* Do we need to WAL-log information required only for Hot Standby and logical replication? */ #define XLogStandbyInfoActive() (wal_level >= WAL_LEVEL_HOT_STANDBY) +/* Do we need to WAL-log information required only for logical replication? */ +#define XLogLogicalInfoActive() (wal_level >= WAL_LEVEL_LOGICAL) + #ifdef WAL_DEBUG extern bool XLOG_DEBUG; #endif diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 9fba8c3db8..64ba55355b 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -55,7 +55,7 @@ typedef struct BkpBlock /* * Each page of XLOG file has a header like this: */ -#define XLOG_PAGE_MAGIC 0xD078 /* can be used as WAL version indicator */ +#define XLOG_PAGE_MAGIC 0xD079 /* can be used as WAL version indicator */ typedef struct XLogPageHeaderData { diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 21d5871454..ad878cf1a2 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -104,6 +104,7 @@ typedef struct RelationData List *rd_indexlist; /* list of OIDs of indexes on relation */ Bitmapset *rd_indexattr; /* identifies columns used in indexes */ Bitmapset *rd_keyattr; /* cols that can be ref'd by foreign keys */ + Bitmapset *rd_idattr; /* included in replica identity index */ Oid rd_oidindex; /* OID of unique index on OID, if any */ LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */ RuleLock *rd_rules; /* rewrite rules */ @@ -453,6 +454,29 @@ typedef struct StdRdOptions */ #define RelationIsPopulated(relation) ((relation)->rd_rel->relispopulated) +/* + * RelationIsAccessibleInLogicalDecoding + * True if we need to log enough information to have access via + * decoding snapshot. + */ +#define RelationIsAccessibleInLogicalDecoding(relation) \ + (XLogLogicalInfoActive() && \ + RelationNeedsWAL(relation) && \ + IsCatalogRelation(relation)) + +/* + * RelationIsLogicallyLogged + * True if we need to log enough information to extract the data from the + * WAL stream. + * + * We don't log information for unlogged tables (since they don't WAL log + * anyway) and for system tables (their content is hard to make sense of, and + * it would complicate decoding slightly for little gain). + */ +#define RelationIsLogicallyLogged(relation) \ + (XLogLogicalInfoActive() && \ + RelationNeedsWAL(relation) && \ + !IsCatalogRelation(relation)) /* routines in utils/cache/relcache.c */ extern void RelationIncrementReferenceCount(Relation rel); diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 8ac2549cb3..d7604ec113 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -41,7 +41,17 @@ extern List *RelationGetIndexList(Relation relation); extern Oid RelationGetOidIndex(Relation relation); extern List *RelationGetIndexExpressions(Relation relation); extern List *RelationGetIndexPredicate(Relation relation); -extern Bitmapset *RelationGetIndexAttrBitmap(Relation relation, bool keyAttrs); + +typedef enum IndexAttrBitmapKind +{ + INDEX_ATTR_BITMAP_ALL, + INDEX_ATTR_BITMAP_KEY, + INDEX_ATTR_BITMAP_IDENTITY_KEY +} IndexAttrBitmapKind; + +extern Bitmapset *RelationGetIndexAttrBitmap(Relation relation, + IndexAttrBitmapKind keyAttrs); + extern void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, |
