PostgreSQL Source Code git master
gistxlog.c File Reference
#include "postgres.h"
#include "access/bufmask.h"
#include "access/gist_private.h"
#include "access/gistxlog.h"
#include "access/transam.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "storage/standby.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gistxlog.c:

Go to the source code of this file.

Functions

static void gistRedoClearFollowRight (XLogReaderState *record, uint8 block_id)
 
static void gistRedoPageUpdateRecord (XLogReaderState *record)
 
static void gistRedoDeleteRecord (XLogReaderState *record)
 
static IndexTupledecodePageSplitRecord (char *begin, int len, int *n)
 
static void gistRedoPageSplitRecord (XLogReaderState *record)
 
static void gistRedoPageDelete (XLogReaderState *record)
 
static void gistRedoPageReuse (XLogReaderState *record)
 
void gist_redo (XLogReaderState *record)
 
void gist_xlog_startup (void)
 
void gist_xlog_cleanup (void)
 
void gist_mask (char *pagedata, BlockNumber blkno)
 
XLogRecPtr gistXLogSplit (bool page_is_leaf, SplitPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
 
XLogRecPtr gistXLogPageDelete (Buffer buffer, FullTransactionId xid, Buffer parentBuffer, OffsetNumber downlinkOffset)
 
XLogRecPtr gistXLogAssignLSN (void)
 
void gistXLogPageReuse (Relation rel, Relation heaprel, BlockNumber blkno, FullTransactionId deleteXid)
 
XLogRecPtr gistXLogUpdate (Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
 
XLogRecPtr gistXLogDelete (Buffer buffer, OffsetNumber *todelete, int ntodelete, TransactionId snapshotConflictHorizon, Relation heaprel)
 

Variables

static MemoryContext opCtx
 

Function Documentation

◆ decodePageSplitRecord()

static IndexTuple * decodePageSplitRecord ( char *  begin,
int  len,
int *  n 
)
static

Definition at line 221 of file gistxlog.c.

222{
223 char *ptr;
224 int i = 0;
225 IndexTuple *tuples;
226
227 /* extract the number of tuples */
228 memcpy(n, begin, sizeof(int));
229 ptr = begin + sizeof(int);
230
231 tuples = palloc(*n * sizeof(IndexTuple));
232
233 for (i = 0; i < *n; i++)
234 {
235 Assert(ptr - begin < len);
236 tuples[i] = (IndexTuple) ptr;
237 ptr += IndexTupleSize((IndexTuple) ptr);
238 }
239 Assert(ptr - begin == len);
240
241 return tuples;
242}
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
IndexTupleData * IndexTuple
Definition: itup.h:53
static Size IndexTupleSize(const IndexTupleData *itup)
Definition: itup.h:71
void * palloc(Size size)
Definition: mcxt.c:1365
const void size_t len

References Assert(), i, IndexTupleSize(), len, and palloc().

Referenced by gistRedoPageSplitRecord().

◆ gist_mask()

void gist_mask ( char *  pagedata,
BlockNumber  blkno 
)

Definition at line 451 of file gistxlog.c.

452{
453 Page page = (Page) pagedata;
454
456
458 mask_unused_space(page);
459
460 /*
461 * NSN is nothing but a special purpose LSN. Hence, mask it for the same
462 * reason as mask_page_lsn_and_checksum.
463 */
465
466 /*
467 * We update F_FOLLOW_RIGHT flag on the left child after writing WAL
468 * record. Hence, mask this flag. See gistplacetopage() for details.
469 */
471
472 if (GistPageIsLeaf(page))
473 {
474 /*
475 * In gist leaf pages, it is possible to modify the LP_FLAGS without
476 * emitting any WAL record. Hence, mask the line pointer flags. See
477 * gistkillitems() for details.
478 */
479 mask_lp_flags(page);
480 }
481
482 /*
483 * During gist redo, we never mark a page as garbage. Hence, mask it to
484 * ignore any differences.
485 */
487}
void mask_lp_flags(Page page)
Definition: bufmask.c:95
void mask_page_lsn_and_checksum(Page page)
Definition: bufmask.c:31
void mask_unused_space(Page page)
Definition: bufmask.c:71
void mask_page_hint_bits(Page page)
Definition: bufmask.c:46
#define MASK_MARKER
Definition: bufmask.h:24
PageData * Page
Definition: bufpage.h:81
uint64_t uint64
Definition: c.h:553
#define GistMarkFollowRight(page)
Definition: gist.h:184
#define GistClearPageHasGarbage(page)
Definition: gist.h:181
#define GistPageIsLeaf(page)
Definition: gist.h:170
#define GistPageSetNSN(page, val)
Definition: gist.h:188

References GistClearPageHasGarbage, GistMarkFollowRight, GistPageIsLeaf, GistPageSetNSN, mask_lp_flags(), MASK_MARKER, mask_page_hint_bits(), mask_page_lsn_and_checksum(), and mask_unused_space().

◆ gist_redo()

void gist_redo ( XLogReaderState record)

Definition at line 395 of file gistxlog.c.

396{
397 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
398 MemoryContext oldCxt;
399
400 /*
401 * GiST indexes do not require any conflict processing. NB: If we ever
402 * implement a similar optimization we have in b-tree, and remove killed
403 * tuples outside VACUUM, we'll need to handle that here.
404 */
405
407 switch (info)
408 {
411 break;
412 case XLOG_GIST_DELETE:
413 gistRedoDeleteRecord(record);
414 break;
416 gistRedoPageReuse(record);
417 break;
420 break;
422 gistRedoPageDelete(record);
423 break;
425 /* nop. See gistGetFakeLSN(). */
426 break;
427 default:
428 elog(PANIC, "gist_redo: unknown op code %u", info);
429 }
430
431 MemoryContextSwitchTo(oldCxt);
433}
uint8_t uint8
Definition: c.h:550
#define PANIC
Definition: elog.h:42
#define elog(elevel,...)
Definition: elog.h:226
static void gistRedoPageReuse(XLogReaderState *record)
Definition: gistxlog.c:374
static void gistRedoPageUpdateRecord(XLogReaderState *record)
Definition: gistxlog.c:70
static void gistRedoPageSplitRecord(XLogReaderState *record)
Definition: gistxlog.c:245
static void gistRedoPageDelete(XLogReaderState *record)
Definition: gistxlog.c:340
static void gistRedoDeleteRecord(XLogReaderState *record)
Definition: gistxlog.c:170
static MemoryContext opCtx
Definition: gistxlog.c:26
#define XLOG_GIST_ASSIGN_LSN
Definition: gistxlog.h:27
#define XLOG_GIST_PAGE_REUSE
Definition: gistxlog.h:22
#define XLOG_GIST_PAGE_DELETE
Definition: gistxlog.h:26
#define XLOG_GIST_DELETE
Definition: gistxlog.h:21
#define XLOG_GIST_PAGE_SPLIT
Definition: gistxlog.h:23
#define XLOG_GIST_PAGE_UPDATE
Definition: gistxlog.h:20
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:409

References elog, gistRedoDeleteRecord(), gistRedoPageDelete(), gistRedoPageReuse(), gistRedoPageSplitRecord(), gistRedoPageUpdateRecord(), MemoryContextReset(), MemoryContextSwitchTo(), opCtx, PANIC, XLOG_GIST_ASSIGN_LSN, XLOG_GIST_DELETE, XLOG_GIST_PAGE_DELETE, XLOG_GIST_PAGE_REUSE, XLOG_GIST_PAGE_SPLIT, XLOG_GIST_PAGE_UPDATE, and XLogRecGetInfo.

◆ gist_xlog_cleanup()

void gist_xlog_cleanup ( void  )

Definition at line 442 of file gistxlog.c.

443{
445}
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469

References MemoryContextDelete(), and opCtx.

◆ gist_xlog_startup()

void gist_xlog_startup ( void  )

Definition at line 436 of file gistxlog.c.

437{
439}
MemoryContext createTempGistContext(void)
Definition: gist.c:128

References createTempGistContext(), and opCtx.

◆ gistRedoClearFollowRight()

static void gistRedoClearFollowRight ( XLogReaderState record,
uint8  block_id 
)
static

Definition at line 40 of file gistxlog.c.

41{
42 XLogRecPtr lsn = record->EndRecPtr;
43 Buffer buffer;
44 Page page;
46
47 /*
48 * Note that we still update the page even if it was restored from a full
49 * page image, because the updated NSN is not included in the image.
50 */
51 action = XLogReadBufferForRedo(record, block_id, &buffer);
53 {
54 page = BufferGetPage(buffer);
55
56 GistPageSetNSN(page, lsn);
58
59 PageSetLSN(page, lsn);
60 MarkBufferDirty(buffer);
61 }
62 if (BufferIsValid(buffer))
63 UnlockReleaseBuffer(buffer);
64}
int Buffer
Definition: buf.h:23
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:5383
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2943
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:436
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:387
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:390
#define GistClearFollowRight(page)
Definition: gist.h:185
XLogRecPtr EndRecPtr
Definition: xlogreader.h:206
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:303
XLogRedoAction
Definition: xlogutils.h:73
@ BLK_RESTORED
Definition: xlogutils.h:76
@ BLK_NEEDS_REDO
Definition: xlogutils.h:74

References generate_unaccent_rules::action, BLK_NEEDS_REDO, BLK_RESTORED, BufferGetPage(), BufferIsValid(), XLogReaderState::EndRecPtr, GistClearFollowRight, GistPageSetNSN, MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), and XLogReadBufferForRedo().

Referenced by gistRedoPageSplitRecord(), and gistRedoPageUpdateRecord().

◆ gistRedoDeleteRecord()

static void gistRedoDeleteRecord ( XLogReaderState record)
static

Definition at line 170 of file gistxlog.c.

171{
172 XLogRecPtr lsn = record->EndRecPtr;
173 gistxlogDelete *xldata = (gistxlogDelete *) XLogRecGetData(record);
174 Buffer buffer;
175 Page page;
176 OffsetNumber *toDelete = xldata->offsets;
177
178 /*
179 * If we have any conflict processing to do, it must happen before we
180 * update the page.
181 *
182 * GiST delete records can conflict with standby queries. You might think
183 * that vacuum records would conflict as well, but we've handled that
184 * already. XLOG_HEAP2_PRUNE_VACUUM_SCAN records provide the highest xid
185 * cleaned by the vacuum of the heap and so we can resolve any conflicts
186 * just once when that arrives. After that we know that no conflicts
187 * exist from individual gist vacuum records on that index.
188 */
189 if (InHotStandby)
190 {
191 RelFileLocator rlocator;
192
193 XLogRecGetBlockTag(record, 0, &rlocator, NULL, NULL);
194
196 xldata->isCatalogRel,
197 rlocator);
198 }
199
200 if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
201 {
202 page = BufferGetPage(buffer);
203
204 PageIndexMultiDelete(page, toDelete, xldata->ntodelete);
205
208
209 PageSetLSN(page, lsn);
210 MarkBufferDirty(buffer);
211 }
212
213 if (BufferIsValid(buffer))
214 UnlockReleaseBuffer(buffer);
215}
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1160
#define GistMarkTuplesDeleted(page)
Definition: gist.h:176
uint16 OffsetNumber
Definition: off.h:24
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:468
bool isCatalogRel
Definition: gistxlog.h:52
TransactionId snapshotConflictHorizon
Definition: gistxlog.h:50
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]
Definition: gistxlog.h:56
uint16 ntodelete
Definition: gistxlog.h:51
void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1991
#define XLogRecGetData(decoder)
Definition: xlogreader.h:414
#define InHotStandby
Definition: xlogutils.h:60

References BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), XLogReaderState::EndRecPtr, GistClearPageHasGarbage, GistMarkTuplesDeleted, InHotStandby, gistxlogDelete::isCatalogRel, MarkBufferDirty(), gistxlogDelete::ntodelete, gistxlogDelete::offsets, PageIndexMultiDelete(), PageSetLSN(), ResolveRecoveryConflictWithSnapshot(), gistxlogDelete::snapshotConflictHorizon, UnlockReleaseBuffer(), XLogReadBufferForRedo(), XLogRecGetBlockTag(), and XLogRecGetData.

Referenced by gist_redo().

◆ gistRedoPageDelete()

static void gistRedoPageDelete ( XLogReaderState record)
static

Definition at line 340 of file gistxlog.c.

341{
342 XLogRecPtr lsn = record->EndRecPtr;
344 Buffer parentBuffer;
345 Buffer leafBuffer;
346
347 if (XLogReadBufferForRedo(record, 0, &leafBuffer) == BLK_NEEDS_REDO)
348 {
349 Page page = BufferGetPage(leafBuffer);
350
351 GistPageSetDeleted(page, xldata->deleteXid);
352
353 PageSetLSN(page, lsn);
354 MarkBufferDirty(leafBuffer);
355 }
356
357 if (XLogReadBufferForRedo(record, 1, &parentBuffer) == BLK_NEEDS_REDO)
358 {
359 Page page = BufferGetPage(parentBuffer);
360
362
363 PageSetLSN(page, lsn);
364 MarkBufferDirty(parentBuffer);
365 }
366
367 if (BufferIsValid(parentBuffer))
368 UnlockReleaseBuffer(parentBuffer);
369 if (BufferIsValid(leafBuffer))
370 UnlockReleaseBuffer(leafBuffer);
371}
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1051
static void GistPageSetDeleted(Page page, FullTransactionId deletexid)
Definition: gist.h:205
FullTransactionId deleteXid
Definition: gistxlog.h:86
OffsetNumber downlinkOffset
Definition: gistxlog.h:87

References BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), gistxlogPageDelete::deleteXid, gistxlogPageDelete::downlinkOffset, XLogReaderState::EndRecPtr, GistPageSetDeleted(), MarkBufferDirty(), PageIndexTupleDelete(), PageSetLSN(), UnlockReleaseBuffer(), XLogReadBufferForRedo(), and XLogRecGetData.

Referenced by gist_redo().

◆ gistRedoPageReuse()

static void gistRedoPageReuse ( XLogReaderState record)
static

Definition at line 374 of file gistxlog.c.

375{
377
378 /*
379 * PAGE_REUSE records exist to provide a conflict point when we reuse
380 * pages in the index via the FSM. That's all they do though.
381 *
382 * snapshotConflictHorizon was the page's deleteXid. The
383 * GlobalVisCheckRemovableFullXid(deleteXid) test in gistPageRecyclable()
384 * conceptually mirrors the PGPROC->xmin > limitXmin test in
385 * GetConflictingVirtualXIDs(). Consequently, one XID value achieves the
386 * same exclusion effect on primary and standby.
387 */
388 if (InHotStandby)
390 xlrec->isCatalogRel,
391 xlrec->locator);
392}
void ResolveRecoveryConflictWithSnapshotFullXid(FullTransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:512
RelFileLocator locator
Definition: gistxlog.h:99
FullTransactionId snapshotConflictHorizon
Definition: gistxlog.h:101

References InHotStandby, gistxlogPageReuse::isCatalogRel, gistxlogPageReuse::locator, ResolveRecoveryConflictWithSnapshotFullXid(), gistxlogPageReuse::snapshotConflictHorizon, and XLogRecGetData.

Referenced by gist_redo().

◆ gistRedoPageSplitRecord()

static void gistRedoPageSplitRecord ( XLogReaderState record)
static

Definition at line 245 of file gistxlog.c.

246{
247 XLogRecPtr lsn = record->EndRecPtr;
249 Buffer firstbuffer = InvalidBuffer;
250 Buffer buffer;
251 Page page;
252 int i;
253 bool isrootsplit = false;
254
255 /*
256 * We must hold lock on the first-listed page throughout the action,
257 * including while updating the left child page (if any). We can unlock
258 * remaining pages in the list as soon as they've been written, because
259 * there is no path for concurrent queries to reach those pages without
260 * first visiting the first-listed page.
261 */
262
263 /* loop around all pages */
264 for (i = 0; i < xldata->npage; i++)
265 {
266 int flags;
267 char *data;
268 Size datalen;
269 int num;
270 BlockNumber blkno;
271 IndexTuple *tuples;
272
273 XLogRecGetBlockTag(record, i + 1, NULL, NULL, &blkno);
274 if (blkno == GIST_ROOT_BLKNO)
275 {
276 Assert(i == 0);
277 isrootsplit = true;
278 }
279
280 buffer = XLogInitBufferForRedo(record, i + 1);
281 page = BufferGetPage(buffer);
282 data = XLogRecGetBlockData(record, i + 1, &datalen);
283
284 tuples = decodePageSplitRecord(data, datalen, &num);
285
286 /* ok, clear buffer */
287 if (xldata->origleaf && blkno != GIST_ROOT_BLKNO)
288 flags = F_LEAF;
289 else
290 flags = 0;
291 GISTInitBuffer(buffer, flags);
292
293 /* and fill it */
294 gistfillbuffer(page, tuples, num, FirstOffsetNumber);
295
296 if (blkno == GIST_ROOT_BLKNO)
297 {
298 GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
299 GistPageSetNSN(page, xldata->orignsn);
301 }
302 else
303 {
304 if (i < xldata->npage - 1)
305 {
306 BlockNumber nextblkno;
307
308 XLogRecGetBlockTag(record, i + 2, NULL, NULL, &nextblkno);
309 GistPageGetOpaque(page)->rightlink = nextblkno;
310 }
311 else
312 GistPageGetOpaque(page)->rightlink = xldata->origrlink;
313 GistPageSetNSN(page, xldata->orignsn);
314 if (i < xldata->npage - 1 && !isrootsplit &&
315 xldata->markfollowright)
317 else
319 }
320
321 PageSetLSN(page, lsn);
322 MarkBufferDirty(buffer);
323
324 if (i == 0)
325 firstbuffer = buffer;
326 else
327 UnlockReleaseBuffer(buffer);
328 }
329
330 /* Fix follow-right data on left child page, if any */
331 if (XLogRecHasBlockRef(record, 0))
332 gistRedoClearFollowRight(record, 0);
333
334 /* Finally, release lock on the first page */
335 UnlockReleaseBuffer(firstbuffer);
336}
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
#define InvalidBuffer
Definition: buf.h:25
size_t Size
Definition: c.h:624
#define F_LEAF
Definition: gist.h:49
#define GistPageGetOpaque(page)
Definition: gist.h:168
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition: gistutil.c:34
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:773
static IndexTuple * decodePageSplitRecord(char *begin, int len, int *n)
Definition: gistxlog.c:221
static void gistRedoClearFollowRight(XLogReaderState *record, uint8 block_id)
Definition: gistxlog.c:40
#define FirstOffsetNumber
Definition: off.h:27
const void * data
GistNSN orignsn
Definition: gistxlog.h:69
BlockNumber origrlink
Definition: gistxlog.h:68
bool markfollowright
Definition: gistxlog.h:73
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2045
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:419
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:315

References Assert(), BufferGetPage(), data, decodePageSplitRecord(), XLogReaderState::EndRecPtr, F_LEAF, FirstOffsetNumber, GIST_ROOT_BLKNO, GistClearFollowRight, gistfillbuffer(), GISTInitBuffer(), GistMarkFollowRight, GistPageGetOpaque, GistPageSetNSN, gistRedoClearFollowRight(), i, InvalidBlockNumber, InvalidBuffer, MarkBufferDirty(), gistxlogPageSplit::markfollowright, gistxlogPageSplit::npage, gistxlogPageSplit::origleaf, gistxlogPageSplit::orignsn, gistxlogPageSplit::origrlink, PageSetLSN(), UnlockReleaseBuffer(), XLogInitBufferForRedo(), XLogRecGetBlockData(), XLogRecGetBlockTag(), XLogRecGetData, and XLogRecHasBlockRef.

Referenced by gist_redo().

◆ gistRedoPageUpdateRecord()

static void gistRedoPageUpdateRecord ( XLogReaderState record)
static

Definition at line 70 of file gistxlog.c.

71{
72 XLogRecPtr lsn = record->EndRecPtr;
74 Buffer buffer;
75 Page page;
76
77 if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
78 {
79 char *begin;
80 char *data;
81 Size datalen;
82 int ninserted PG_USED_FOR_ASSERTS_ONLY = 0;
83
84 data = begin = XLogRecGetBlockData(record, 0, &datalen);
85
86 page = BufferGetPage(buffer);
87
88 if (xldata->ntodelete == 1 && xldata->ntoinsert == 1)
89 {
90 /*
91 * When replacing one tuple with one other tuple, we must use
92 * PageIndexTupleOverwrite for consistency with gistplacetopage.
93 */
94 OffsetNumber offnum = *((OffsetNumber *) data);
95 IndexTuple itup;
96 Size itupsize;
97
98 data += sizeof(OffsetNumber);
99 itup = (IndexTuple) data;
100 itupsize = IndexTupleSize(itup);
101 if (!PageIndexTupleOverwrite(page, offnum, itup, itupsize))
102 elog(ERROR, "failed to add item to GiST index page, size %zu bytes", itupsize);
103 data += itupsize;
104 /* should be nothing left after consuming 1 tuple */
105 Assert(data - begin == datalen);
106 /* update insertion count for assert check below */
107 ninserted++;
108 }
109 else if (xldata->ntodelete > 0)
110 {
111 /* Otherwise, delete old tuples if any */
112 OffsetNumber *todelete = (OffsetNumber *) data;
113
114 data += sizeof(OffsetNumber) * xldata->ntodelete;
115
116 PageIndexMultiDelete(page, todelete, xldata->ntodelete);
117 if (GistPageIsLeaf(page))
119 }
120
121 /* Add new tuples if any */
122 if (data - begin < datalen)
123 {
126
127 while (data - begin < datalen)
128 {
129 IndexTuple itup = (IndexTuple) data;
130 Size sz = IndexTupleSize(itup);
131 OffsetNumber l;
132
133 data += sz;
134
135 l = PageAddItem(page, itup, sz, off, false, false);
136 if (l == InvalidOffsetNumber)
137 elog(ERROR, "failed to add item to GiST index page, size %zu bytes", sz);
138 off++;
139 ninserted++;
140 }
141 }
142
143 /* Check that XLOG record contained expected number of tuples */
144 Assert(ninserted == xldata->ntoinsert);
145
146 PageSetLSN(page, lsn);
147 MarkBufferDirty(buffer);
148 }
149
150 /*
151 * Fix follow-right data on left child page
152 *
153 * This must be done while still holding the lock on the target page. Note
154 * that even if the target page no longer exists, we still attempt to
155 * replay the change on the child page.
156 */
157 if (XLogRecHasBlockRef(record, 1))
158 gistRedoClearFollowRight(record, 1);
159
160 if (BufferIsValid(buffer))
161 UnlockReleaseBuffer(buffer);
162}
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, const void *newtup, Size newsize)
Definition: bufpage.c:1404
static bool PageIsEmpty(const PageData *page)
Definition: bufpage.h:223
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition: bufpage.h:371
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:229
#define ERROR
Definition: elog.h:39
#define InvalidOffsetNumber
Definition: off.h:26
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 ntodelete
Definition: gistxlog.h:37
uint16 ntoinsert
Definition: gistxlog.h:38

References Assert(), BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), data, elog, XLogReaderState::EndRecPtr, ERROR, FirstOffsetNumber, GistMarkTuplesDeleted, GistPageIsLeaf, gistRedoClearFollowRight(), IndexTupleSize(), InvalidOffsetNumber, MarkBufferDirty(), gistxlogPageUpdate::ntodelete, gistxlogPageUpdate::ntoinsert, OffsetNumberNext, PageAddItem, PageGetMaxOffsetNumber(), PageIndexMultiDelete(), PageIndexTupleOverwrite(), PageIsEmpty(), PageSetLSN(), PG_USED_FOR_ASSERTS_ONLY, UnlockReleaseBuffer(), XLogReadBufferForRedo(), XLogRecGetBlockData(), XLogRecGetData, and XLogRecHasBlockRef.

Referenced by gist_redo().

◆ gistXLogAssignLSN()

XLogRecPtr gistXLogAssignLSN ( void  )

Definition at line 574 of file gistxlog.c.

575{
576 int dummy = 0;
577
578 /*
579 * Records other than XLOG_SWITCH must have content. We use an integer 0
580 * to follow the restriction.
581 */
584 XLogRegisterData(&dummy, sizeof(dummy));
585 return XLogInsert(RM_GIST_ID, XLOG_GIST_ASSIGN_LSN);
586}
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:155
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:478
void XLogRegisterData(const void *data, uint32 len)
Definition: xloginsert.c:368
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:460
void XLogBeginInsert(void)
Definition: xloginsert.c:152

References XLOG_GIST_ASSIGN_LSN, XLOG_MARK_UNIMPORTANT, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by gistGetFakeLSN().

◆ gistXLogDelete()

XLogRecPtr gistXLogDelete ( Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
TransactionId  snapshotConflictHorizon,
Relation  heaprel 
)

Definition at line 668 of file gistxlog.c.

670{
671 gistxlogDelete xlrec;
672 XLogRecPtr recptr;
673
675 xlrec.snapshotConflictHorizon = snapshotConflictHorizon;
676 xlrec.ntodelete = ntodelete;
677
680
681 /*
682 * We need the target-offsets array whether or not we store the whole
683 * buffer, to allow us to find the snapshotConflictHorizon on a standby
684 * server.
685 */
686 XLogRegisterData(todelete, ntodelete * sizeof(OffsetNumber));
687
689
690 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_DELETE);
691
692 return recptr;
693}
#define SizeOfGistxlogDelete
Definition: gistxlog.h:59
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:694
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:245
#define REGBUF_STANDARD
Definition: xloginsert.h:35

References gistxlogDelete::isCatalogRel, gistxlogDelete::ntodelete, REGBUF_STANDARD, RelationIsAccessibleInLogicalDecoding, SizeOfGistxlogDelete, gistxlogDelete::snapshotConflictHorizon, XLOG_GIST_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistprunepage().

◆ gistXLogPageDelete()

XLogRecPtr gistXLogPageDelete ( Buffer  buffer,
FullTransactionId  xid,
Buffer  parentBuffer,
OffsetNumber  downlinkOffset 
)

Definition at line 550 of file gistxlog.c.

552{
553 gistxlogPageDelete xlrec;
554 XLogRecPtr recptr;
555
556 xlrec.deleteXid = xid;
557 xlrec.downlinkOffset = downlinkOffset;
558
561
563 XLogRegisterBuffer(1, parentBuffer, REGBUF_STANDARD);
564
565 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_DELETE);
566
567 return recptr;
568}
#define SizeOfGistxlogPageDelete
Definition: gistxlog.h:91

References gistxlogPageDelete::deleteXid, gistxlogPageDelete::downlinkOffset, REGBUF_STANDARD, SizeOfGistxlogPageDelete, XLOG_GIST_PAGE_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistdeletepage().

◆ gistXLogPageReuse()

void gistXLogPageReuse ( Relation  rel,
Relation  heaprel,
BlockNumber  blkno,
FullTransactionId  deleteXid 
)

Definition at line 592 of file gistxlog.c.

594{
595 gistxlogPageReuse xlrec_reuse;
596
597 /*
598 * Note that we don't register the buffer with the record, because this
599 * operation doesn't modify the page. This record only exists to provide a
600 * conflict point for Hot Standby.
601 */
602
603 /* XLOG stuff */
605 xlrec_reuse.locator = rel->rd_locator;
606 xlrec_reuse.block = blkno;
607 xlrec_reuse.snapshotConflictHorizon = deleteXid;
608
611
612 XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_REUSE);
613}
#define SizeOfGistxlogPageReuse
Definition: gistxlog.h:106
RelFileLocator rd_locator
Definition: rel.h:57
BlockNumber block
Definition: gistxlog.h:100

References gistxlogPageReuse::block, gistxlogPageReuse::isCatalogRel, gistxlogPageReuse::locator, RelationData::rd_locator, RelationIsAccessibleInLogicalDecoding, SizeOfGistxlogPageReuse, gistxlogPageReuse::snapshotConflictHorizon, XLOG_GIST_PAGE_REUSE, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by gistNewBuffer().

◆ gistXLogSplit()

XLogRecPtr gistXLogSplit ( bool  page_is_leaf,
SplitPageLayout dist,
BlockNumber  origrlink,
GistNSN  orignsn,
Buffer  leftchildbuf,
bool  markfollowright 
)

Definition at line 493 of file gistxlog.c.

497{
498 gistxlogPageSplit xlrec;
499 SplitPageLayout *ptr;
500 int npage = 0;
501 XLogRecPtr recptr;
502 int i;
503
504 for (ptr = dist; ptr; ptr = ptr->next)
505 npage++;
506
507 xlrec.origrlink = origrlink;
508 xlrec.orignsn = orignsn;
509 xlrec.origleaf = page_is_leaf;
510 xlrec.npage = (uint16) npage;
511 xlrec.markfollowright = markfollowright;
512
514
515 /*
516 * Include a full page image of the child buf. (only necessary if a
517 * checkpoint happened since the child page was split)
518 */
519 if (BufferIsValid(leftchildbuf))
520 XLogRegisterBuffer(0, leftchildbuf, REGBUF_STANDARD);
521
522 /*
523 * NOTE: We register a lot of data. The caller must've called
524 * XLogEnsureRecordSpace() to prepare for that. We cannot do it here,
525 * because we're already in a critical section. If you change the number
526 * of buffer or data registrations here, make sure you modify the
527 * XLogEnsureRecordSpace() calls accordingly!
528 */
529 XLogRegisterData(&xlrec, sizeof(gistxlogPageSplit));
530
531 i = 1;
532 for (ptr = dist; ptr; ptr = ptr->next)
533 {
535 XLogRegisterBufData(i, &(ptr->block.num), sizeof(int));
536 XLogRegisterBufData(i, ptr->list, ptr->lenlist);
537 i++;
538 }
539
540 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT);
541
542 return recptr;
543}
uint16_t uint16
Definition: c.h:551
gistxlogPage block
Definition: gist_private.h:193
struct SplitPageLayout * next
Definition: gist_private.h:200
IndexTupleData * list
Definition: gist_private.h:194
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
Definition: xloginsert.c:409
#define REGBUF_WILL_INIT
Definition: xloginsert.h:34

References SplitPageLayout::block, SplitPageLayout::buffer, BufferIsValid(), i, SplitPageLayout::lenlist, SplitPageLayout::list, gistxlogPageSplit::markfollowright, SplitPageLayout::next, gistxlogPageSplit::npage, gistxlogPage::num, gistxlogPageSplit::origleaf, gistxlogPageSplit::orignsn, gistxlogPageSplit::origrlink, REGBUF_STANDARD, REGBUF_WILL_INIT, XLOG_GIST_PAGE_SPLIT, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistplacetopage().

◆ gistXLogUpdate()

XLogRecPtr gistXLogUpdate ( Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
IndexTuple itup,
int  ituplen,
Buffer  leftchildbuf 
)

Definition at line 627 of file gistxlog.c.

631{
632 gistxlogPageUpdate xlrec;
633 int i;
634 XLogRecPtr recptr;
635
636 xlrec.ntodelete = ntodelete;
637 xlrec.ntoinsert = ituplen;
638
640 XLogRegisterData(&xlrec, sizeof(gistxlogPageUpdate));
641
643 XLogRegisterBufData(0, todelete, sizeof(OffsetNumber) * ntodelete);
644
645 /* new tuples */
646 for (i = 0; i < ituplen; i++)
647 XLogRegisterBufData(0, itup[i], IndexTupleSize(itup[i]));
648
649 /*
650 * Include a full page image of the child buf. (only necessary if a
651 * checkpoint happened since the child page was split)
652 */
653 if (BufferIsValid(leftchildbuf))
654 XLogRegisterBuffer(1, leftchildbuf, REGBUF_STANDARD);
655
656 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE);
657
658 return recptr;
659}

References BufferIsValid(), i, IndexTupleSize(), gistxlogPageUpdate::ntodelete, gistxlogPageUpdate::ntoinsert, REGBUF_STANDARD, XLOG_GIST_PAGE_UPDATE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistplacetopage(), and gistvacuumpage().

Variable Documentation

◆ opCtx

MemoryContext opCtx
static

Definition at line 26 of file gistxlog.c.

Referenced by gist_redo(), gist_xlog_cleanup(), and gist_xlog_startup().