PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 223 of file gistxlog.c.

224{
225 char *ptr;
226 int i = 0;
227 IndexTuple *tuples;
228
229 /* extract the number of tuples */
230 memcpy(n, begin, sizeof(int));
231 ptr = begin + sizeof(int);
232
233 tuples = palloc(*n * sizeof(IndexTuple));
234
235 for (i = 0; i < *n; i++)
236 {
237 Assert(ptr - begin < len);
238 tuples[i] = (IndexTuple) ptr;
239 ptr += IndexTupleSize((IndexTuple) ptr);
240 }
241 Assert(ptr - begin == len);
242
243 return tuples;
244}
#define Assert(condition)
Definition: c.h:812
int i
Definition: isn.c:72
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
void * palloc(Size size)
Definition: mcxt.c:1317
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 453 of file gistxlog.c.

454{
455 Page page = (Page) pagedata;
456
458
460 mask_unused_space(page);
461
462 /*
463 * NSN is nothing but a special purpose LSN. Hence, mask it for the same
464 * reason as mask_page_lsn_and_checksum.
465 */
467
468 /*
469 * We update F_FOLLOW_RIGHT flag on the left child after writing WAL
470 * record. Hence, mask this flag. See gistplacetopage() for details.
471 */
473
474 if (GistPageIsLeaf(page))
475 {
476 /*
477 * In gist leaf pages, it is possible to modify the LP_FLAGS without
478 * emitting any WAL record. Hence, mask the line pointer flags. See
479 * gistkillitems() for details.
480 */
481 mask_lp_flags(page);
482 }
483
484 /*
485 * During gist redo, we never mark a page as garbage. Hence, mask it to
486 * ignore any differences.
487 */
489}
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
Pointer Page
Definition: bufpage.h:81
uint64_t uint64
Definition: c.h:486
#define GistMarkFollowRight(page)
Definition: gist.h:183
#define GistClearPageHasGarbage(page)
Definition: gist.h:180
#define GistPageIsLeaf(page)
Definition: gist.h:169
#define GistPageSetNSN(page, val)
Definition: gist.h:187

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 397 of file gistxlog.c.

398{
399 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
400 MemoryContext oldCxt;
401
402 /*
403 * GiST indexes do not require any conflict processing. NB: If we ever
404 * implement a similar optimization we have in b-tree, and remove killed
405 * tuples outside VACUUM, we'll need to handle that here.
406 */
407
409 switch (info)
410 {
413 break;
414 case XLOG_GIST_DELETE:
415 gistRedoDeleteRecord(record);
416 break;
418 gistRedoPageReuse(record);
419 break;
422 break;
424 gistRedoPageDelete(record);
425 break;
427 /* nop. See gistGetFakeLSN(). */
428 break;
429 default:
430 elog(PANIC, "gist_redo: unknown op code %u", info);
431 }
432
433 MemoryContextSwitchTo(oldCxt);
435}
uint8_t uint8
Definition: c.h:483
#define PANIC
Definition: elog.h:42
#define elog(elevel,...)
Definition: elog.h:225
static void gistRedoPageReuse(XLogReaderState *record)
Definition: gistxlog.c:376
static void gistRedoPageUpdateRecord(XLogReaderState *record)
Definition: gistxlog.c:70
static void gistRedoPageSplitRecord(XLogReaderState *record)
Definition: gistxlog.c:247
static void gistRedoPageDelete(XLogReaderState *record)
Definition: gistxlog.c:342
static void gistRedoDeleteRecord(XLogReaderState *record)
Definition: gistxlog.c:172
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:383
MemoryContextSwitchTo(old_ctx)
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410

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 444 of file gistxlog.c.

445{
447}
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

References MemoryContextDelete(), and opCtx.

◆ gist_xlog_startup()

void gist_xlog_startup ( void  )

Definition at line 438 of file gistxlog.c.

439{
441}
MemoryContext createTempGistContext(void)
Definition: gist.c:123

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:4941
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:351
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
#define GistClearFollowRight(page)
Definition: gist.h:184
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:314
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 172 of file gistxlog.c.

173{
174 XLogRecPtr lsn = record->EndRecPtr;
175 gistxlogDelete *xldata = (gistxlogDelete *) XLogRecGetData(record);
176 Buffer buffer;
177 Page page;
178 OffsetNumber *toDelete = xldata->offsets;
179
180 /*
181 * If we have any conflict processing to do, it must happen before we
182 * update the page.
183 *
184 * GiST delete records can conflict with standby queries. You might think
185 * that vacuum records would conflict as well, but we've handled that
186 * already. XLOG_HEAP2_PRUNE_VACUUM_SCAN records provide the highest xid
187 * cleaned by the vacuum of the heap and so we can resolve any conflicts
188 * just once when that arrives. After that we know that no conflicts
189 * exist from individual gist vacuum records on that index.
190 */
191 if (InHotStandby)
192 {
193 RelFileLocator rlocator;
194
195 XLogRecGetBlockTag(record, 0, &rlocator, NULL, NULL);
196
198 xldata->isCatalogRel,
199 rlocator);
200 }
201
202 if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
203 {
204 page = (Page) BufferGetPage(buffer);
205
206 PageIndexMultiDelete(page, toDelete, xldata->ntodelete);
207
210
211 PageSetLSN(page, lsn);
212 MarkBufferDirty(buffer);
213 }
214
215 if (BufferIsValid(buffer))
216 UnlockReleaseBuffer(buffer);
217}
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1150
#define GistMarkTuplesDeleted(page)
Definition: gist.h:175
uint16 OffsetNumber
Definition: off.h:24
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:467
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:1971
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#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 342 of file gistxlog.c.

343{
344 XLogRecPtr lsn = record->EndRecPtr;
346 Buffer parentBuffer;
347 Buffer leafBuffer;
348
349 if (XLogReadBufferForRedo(record, 0, &leafBuffer) == BLK_NEEDS_REDO)
350 {
351 Page page = (Page) BufferGetPage(leafBuffer);
352
353 GistPageSetDeleted(page, xldata->deleteXid);
354
355 PageSetLSN(page, lsn);
356 MarkBufferDirty(leafBuffer);
357 }
358
359 if (XLogReadBufferForRedo(record, 1, &parentBuffer) == BLK_NEEDS_REDO)
360 {
361 Page page = (Page) BufferGetPage(parentBuffer);
362
364
365 PageSetLSN(page, lsn);
366 MarkBufferDirty(parentBuffer);
367 }
368
369 if (BufferIsValid(parentBuffer))
370 UnlockReleaseBuffer(parentBuffer);
371 if (BufferIsValid(leafBuffer))
372 UnlockReleaseBuffer(leafBuffer);
373}
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1041
static void GistPageSetDeleted(Page page, FullTransactionId deletexid)
Definition: gist.h:204
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 376 of file gistxlog.c.

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

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

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 = (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, (Item) itup, itupsize))
102 elog(ERROR, "failed to add item to GiST index page, size %d bytes",
103 (int) itupsize);
104 data += itupsize;
105 /* should be nothing left after consuming 1 tuple */
106 Assert(data - begin == datalen);
107 /* update insertion count for assert check below */
108 ninserted++;
109 }
110 else if (xldata->ntodelete > 0)
111 {
112 /* Otherwise, delete old tuples if any */
113 OffsetNumber *todelete = (OffsetNumber *) data;
114
115 data += sizeof(OffsetNumber) * xldata->ntodelete;
116
117 PageIndexMultiDelete(page, todelete, xldata->ntodelete);
118 if (GistPageIsLeaf(page))
120 }
121
122 /* Add new tuples if any */
123 if (data - begin < datalen)
124 {
127
128 while (data - begin < datalen)
129 {
130 IndexTuple itup = (IndexTuple) data;
131 Size sz = IndexTupleSize(itup);
132 OffsetNumber l;
133
134 data += sz;
135
136 l = PageAddItem(page, (Item) itup, sz, off, false, false);
137 if (l == InvalidOffsetNumber)
138 elog(ERROR, "failed to add item to GiST index page, size %d bytes",
139 (int) sz);
140 off++;
141 ninserted++;
142 }
143 }
144
145 /* Check that XLOG record contained expected number of tuples */
146 Assert(ninserted == xldata->ntoinsert);
147
148 PageSetLSN(page, lsn);
149 MarkBufferDirty(buffer);
150 }
151
152 /*
153 * Fix follow-right data on left child page
154 *
155 * This must be done while still holding the lock on the target page. Note
156 * that even if the target page no longer exists, we still attempt to
157 * replay the change on the child page.
158 */
159 if (XLogRecHasBlockRef(record, 1))
160 gistRedoClearFollowRight(record, 1);
161
162 if (BufferIsValid(buffer))
163 UnlockReleaseBuffer(buffer);
164}
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1394
static bool PageIsEmpty(Page page)
Definition: bufpage.h:223
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:201
#define ERROR
Definition: elog.h:39
Pointer Item
Definition: item.h:17
#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 576 of file gistxlog.c.

577{
578 int dummy = 0;
579
580 /*
581 * Records other than XLOG_SWITCH must have content. We use an integer 0
582 * to follow the restriction.
583 */
586 XLogRegisterData((char *) &dummy, sizeof(dummy));
587 return XLogInsert(RM_GIST_ID, XLOG_GIST_ASSIGN_LSN);
588}
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:155
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogBeginInsert(void)
Definition: xloginsert.c:149

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 670 of file gistxlog.c.

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

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 552 of file gistxlog.c.

554{
555 gistxlogPageDelete xlrec;
556 XLogRecPtr recptr;
557
558 xlrec.deleteXid = xid;
559 xlrec.downlinkOffset = downlinkOffset;
560
563
565 XLogRegisterBuffer(1, parentBuffer, REGBUF_STANDARD);
566
567 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_DELETE);
568
569 return recptr;
570}
#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 594 of file gistxlog.c.

596{
597 gistxlogPageReuse xlrec_reuse;
598
599 /*
600 * Note that we don't register the buffer with the record, because this
601 * operation doesn't modify the page. This record only exists to provide a
602 * conflict point for Hot Standby.
603 */
604
605 /* XLOG stuff */
607 xlrec_reuse.locator = rel->rd_locator;
608 xlrec_reuse.block = blkno;
609 xlrec_reuse.snapshotConflictHorizon = deleteXid;
610
612 XLogRegisterData((char *) &xlrec_reuse, SizeOfGistxlogPageReuse);
613
614 XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_REUSE);
615}
#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 495 of file gistxlog.c.

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

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 629 of file gistxlog.c.

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

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().