| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * spgxlog.h |
| 4 | * xlog declarations for SP-GiST access method. |
| 5 | * |
| 6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 7 | * Portions Copyright (c) 1994, Regents of the University of California |
| 8 | * |
| 9 | * src/include/access/spgxlog.h |
| 10 | * |
| 11 | *------------------------------------------------------------------------- |
| 12 | */ |
| 13 | #ifndef SPGXLOG_H |
| 14 | #define SPGXLOG_H |
| 15 | |
| 16 | #include "access/xlogreader.h" |
| 17 | #include "lib/stringinfo.h" |
| 18 | #include "storage/off.h" |
| 19 | |
| 20 | /* XLOG record types for SPGiST */ |
| 21 | /* #define XLOG_SPGIST_CREATE_INDEX 0x00 */ /* not used anymore */ |
| 22 | #define XLOG_SPGIST_ADD_LEAF 0x10 |
| 23 | #define XLOG_SPGIST_MOVE_LEAFS 0x20 |
| 24 | #define XLOG_SPGIST_ADD_NODE 0x30 |
| 25 | #define XLOG_SPGIST_SPLIT_TUPLE 0x40 |
| 26 | #define XLOG_SPGIST_PICKSPLIT 0x50 |
| 27 | #define XLOG_SPGIST_VACUUM_LEAF 0x60 |
| 28 | #define XLOG_SPGIST_VACUUM_ROOT 0x70 |
| 29 | #define XLOG_SPGIST_VACUUM_REDIRECT 0x80 |
| 30 | |
| 31 | /* |
| 32 | * Some redo functions need an SpGistState, although only a few of its fields |
| 33 | * need to be valid. spgxlogState carries the required info in xlog records. |
| 34 | * (See fillFakeState in spgxlog.c for more comments.) |
| 35 | */ |
| 36 | typedef struct spgxlogState |
| 37 | { |
| 38 | TransactionId myXid; |
| 39 | bool isBuild; |
| 40 | } spgxlogState; |
| 41 | |
| 42 | /* |
| 43 | * Backup Blk 0: destination page for leaf tuple |
| 44 | * Backup Blk 1: parent page (if any) |
| 45 | */ |
| 46 | typedef struct spgxlogAddLeaf |
| 47 | { |
| 48 | bool newPage; /* init dest page? */ |
| 49 | bool storesNulls; /* page is in the nulls tree? */ |
| 50 | OffsetNumber offnumLeaf; /* offset where leaf tuple gets placed */ |
| 51 | OffsetNumber offnumHeadLeaf; /* offset of head tuple in chain, if any */ |
| 52 | |
| 53 | OffsetNumber offnumParent; /* where the parent downlink is, if any */ |
| 54 | uint16 nodeI; |
| 55 | |
| 56 | /* new leaf tuple follows (unaligned!) */ |
| 57 | } spgxlogAddLeaf; |
| 58 | |
| 59 | /* |
| 60 | * Backup Blk 0: source leaf page |
| 61 | * Backup Blk 1: destination leaf page |
| 62 | * Backup Blk 2: parent page |
| 63 | */ |
| 64 | typedef struct spgxlogMoveLeafs |
| 65 | { |
| 66 | uint16 nMoves; /* number of tuples moved from source page */ |
| 67 | bool newPage; /* init dest page? */ |
| 68 | bool replaceDead; /* are we replacing a DEAD source tuple? */ |
| 69 | bool storesNulls; /* pages are in the nulls tree? */ |
| 70 | |
| 71 | /* where the parent downlink is */ |
| 72 | OffsetNumber offnumParent; |
| 73 | uint16 nodeI; |
| 74 | |
| 75 | spgxlogState stateSrc; |
| 76 | |
| 77 | /*---------- |
| 78 | * data follows: |
| 79 | * array of deleted tuple numbers, length nMoves |
| 80 | * array of inserted tuple numbers, length nMoves + 1 or 1 |
| 81 | * list of leaf tuples, length nMoves + 1 or 1 (unaligned!) |
| 82 | * |
| 83 | * Note: if replaceDead is true then there is only one inserted tuple |
| 84 | * number and only one leaf tuple in the data, because we are not copying |
| 85 | * the dead tuple from the source |
| 86 | *---------- |
| 87 | */ |
| 88 | OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; |
| 89 | } spgxlogMoveLeafs; |
| 90 | |
| 91 | #define SizeOfSpgxlogMoveLeafs offsetof(spgxlogMoveLeafs, offsets) |
| 92 | |
| 93 | /* |
| 94 | * Backup Blk 0: original page |
| 95 | * Backup Blk 1: where new tuple goes, if not same place |
| 96 | * Backup Blk 2: where parent downlink is, if updated and different from |
| 97 | * the old and new |
| 98 | */ |
| 99 | typedef struct spgxlogAddNode |
| 100 | { |
| 101 | /* |
| 102 | * Offset of the original inner tuple, in the original page (on backup |
| 103 | * block 0). |
| 104 | */ |
| 105 | OffsetNumber offnum; |
| 106 | |
| 107 | /* |
| 108 | * Offset of the new tuple, on the new page (on backup block 1). Invalid, |
| 109 | * if we overwrote the old tuple in the original page). |
| 110 | */ |
| 111 | OffsetNumber offnumNew; |
| 112 | bool newPage; /* init new page? */ |
| 113 | |
| 114 | /*---- |
| 115 | * Where is the parent downlink? parentBlk indicates which page it's on, |
| 116 | * and offnumParent is the offset within the page. The possible values for |
| 117 | * parentBlk are: |
| 118 | * |
| 119 | * 0: parent == original page |
| 120 | * 1: parent == new page |
| 121 | * 2: parent == different page (blk ref 2) |
| 122 | * -1: parent not updated |
| 123 | *---- |
| 124 | */ |
| 125 | int8 parentBlk; |
| 126 | OffsetNumber offnumParent; /* offset within the parent page */ |
| 127 | |
| 128 | uint16 nodeI; |
| 129 | |
| 130 | spgxlogState stateSrc; |
| 131 | |
| 132 | /* |
| 133 | * updated inner tuple follows (unaligned!) |
| 134 | */ |
| 135 | } spgxlogAddNode; |
| 136 | |
| 137 | /* |
| 138 | * Backup Blk 0: where the prefix tuple goes |
| 139 | * Backup Blk 1: where the postfix tuple goes (if different page) |
| 140 | */ |
| 141 | typedef struct spgxlogSplitTuple |
| 142 | { |
| 143 | /* where the prefix tuple goes */ |
| 144 | OffsetNumber offnumPrefix; |
| 145 | |
| 146 | /* where the postfix tuple goes */ |
| 147 | OffsetNumber offnumPostfix; |
| 148 | bool newPage; /* need to init that page? */ |
| 149 | bool postfixBlkSame; /* was postfix tuple put on same page as |
| 150 | * prefix? */ |
| 151 | |
| 152 | /* |
| 153 | * new prefix inner tuple follows, then new postfix inner tuple (both are |
| 154 | * unaligned!) |
| 155 | */ |
| 156 | } spgxlogSplitTuple; |
| 157 | |
| 158 | /* |
| 159 | * Buffer references in the rdata array are: |
| 160 | * Backup Blk 0: Src page (only if not root) |
| 161 | * Backup Blk 1: Dest page (if used) |
| 162 | * Backup Blk 2: Inner page |
| 163 | * Backup Blk 3: Parent page (if any, and different from Inner) |
| 164 | */ |
| 165 | typedef struct spgxlogPickSplit |
| 166 | { |
| 167 | bool isRootSplit; |
| 168 | |
| 169 | uint16 nDelete; /* n to delete from Src */ |
| 170 | uint16 nInsert; /* n to insert on Src and/or Dest */ |
| 171 | bool initSrc; /* re-init the Src page? */ |
| 172 | bool initDest; /* re-init the Dest page? */ |
| 173 | |
| 174 | /* where to put new inner tuple */ |
| 175 | OffsetNumber offnumInner; |
| 176 | bool initInner; /* re-init the Inner page? */ |
| 177 | |
| 178 | bool storesNulls; /* pages are in the nulls tree? */ |
| 179 | |
| 180 | /* where the parent downlink is, if any */ |
| 181 | bool innerIsParent; /* is parent the same as inner page? */ |
| 182 | OffsetNumber offnumParent; |
| 183 | uint16 nodeI; |
| 184 | |
| 185 | spgxlogState stateSrc; |
| 186 | |
| 187 | /*---------- |
| 188 | * data follows: |
| 189 | * array of deleted tuple numbers, length nDelete |
| 190 | * array of inserted tuple numbers, length nInsert |
| 191 | * array of page selector bytes for inserted tuples, length nInsert |
| 192 | * new inner tuple (unaligned!) |
| 193 | * list of leaf tuples, length nInsert (unaligned!) |
| 194 | *---------- |
| 195 | */ |
| 196 | OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; |
| 197 | } spgxlogPickSplit; |
| 198 | |
| 199 | #define SizeOfSpgxlogPickSplit offsetof(spgxlogPickSplit, offsets) |
| 200 | |
| 201 | typedef struct spgxlogVacuumLeaf |
| 202 | { |
| 203 | uint16 nDead; /* number of tuples to become DEAD */ |
| 204 | uint16 nPlaceholder; /* number of tuples to become PLACEHOLDER */ |
| 205 | uint16 nMove; /* number of tuples to move */ |
| 206 | uint16 nChain; /* number of tuples to re-chain */ |
| 207 | |
| 208 | spgxlogState stateSrc; |
| 209 | |
| 210 | /*---------- |
| 211 | * data follows: |
| 212 | * tuple numbers to become DEAD |
| 213 | * tuple numbers to become PLACEHOLDER |
| 214 | * tuple numbers to move from (and replace with PLACEHOLDER) |
| 215 | * tuple numbers to move to (replacing what is there) |
| 216 | * tuple numbers to update nextOffset links of |
| 217 | * tuple numbers to insert in nextOffset links |
| 218 | *---------- |
| 219 | */ |
| 220 | OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; |
| 221 | } spgxlogVacuumLeaf; |
| 222 | |
| 223 | #define SizeOfSpgxlogVacuumLeaf offsetof(spgxlogVacuumLeaf, offsets) |
| 224 | |
| 225 | typedef struct spgxlogVacuumRoot |
| 226 | { |
| 227 | /* vacuum a root page when it is also a leaf */ |
| 228 | uint16 nDelete; /* number of tuples to delete */ |
| 229 | |
| 230 | spgxlogState stateSrc; |
| 231 | |
| 232 | /* offsets of tuples to delete follow */ |
| 233 | OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; |
| 234 | } spgxlogVacuumRoot; |
| 235 | |
| 236 | #define SizeOfSpgxlogVacuumRoot offsetof(spgxlogVacuumRoot, offsets) |
| 237 | |
| 238 | typedef struct spgxlogVacuumRedirect |
| 239 | { |
| 240 | uint16 nToPlaceholder; /* number of redirects to make placeholders */ |
| 241 | OffsetNumber firstPlaceholder; /* first placeholder tuple to remove */ |
| 242 | TransactionId newestRedirectXid; /* newest XID of removed redirects */ |
| 243 | |
| 244 | /* offsets of redirect tuples to make placeholders follow */ |
| 245 | OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; |
| 246 | } spgxlogVacuumRedirect; |
| 247 | |
| 248 | #define SizeOfSpgxlogVacuumRedirect offsetof(spgxlogVacuumRedirect, offsets) |
| 249 | |
| 250 | extern void spg_redo(XLogReaderState *record); |
| 251 | extern void spg_desc(StringInfo buf, XLogReaderState *record); |
| 252 | extern const char *spg_identify(uint8 info); |
| 253 | extern void spg_xlog_startup(void); |
| 254 | extern void spg_xlog_cleanup(void); |
| 255 | extern void spg_mask(char *pagedata, BlockNumber blkno); |
| 256 | |
| 257 | #endif /* SPGXLOG_H */ |
| 258 | |