PostgreSQL Source Code  git master
ginentrypage.c File Reference
#include "postgres.h"
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xloginsert.h"
#include "miscadmin.h"
#include "utils/rel.h"
Include dependency graph for ginentrypage.c:

Go to the source code of this file.

Functions

static void entrySplitPage (GinBtree btree, Buffer origbuf, GinBtreeStack *stack, GinBtreeEntryInsertData *insertData, BlockNumber updateblkno, Page *newlpage, Page *newrpage)
 
IndexTuple GinFormTuple (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
 
ItemPointer ginReadTuple (GinState *ginstate, OffsetNumber attnum, IndexTuple itup, int *nitems)
 
static IndexTuple GinFormInteriorTuple (IndexTuple itup, Page page, BlockNumber childblk)
 
static IndexTuple getRightMostTuple (Page page)
 
static bool entryIsMoveRight (GinBtree btree, Page page)
 
static BlockNumber entryLocateEntry (GinBtree btree, GinBtreeStack *stack)
 
static bool entryLocateLeafEntry (GinBtree btree, GinBtreeStack *stack)
 
static OffsetNumber entryFindChildPtr (GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
 
static BlockNumber entryGetLeftMostPage (GinBtree btree, Page page)
 
static bool entryIsEnoughSpace (GinBtree btree, Buffer buf, OffsetNumber off, GinBtreeEntryInsertData *insertData)
 
static void entryPreparePage (GinBtree btree, Page page, OffsetNumber off, GinBtreeEntryInsertData *insertData, BlockNumber updateblkno)
 
static GinPlaceToPageRC entryBeginPlaceToPage (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
 
static void entryExecPlaceToPage (GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void *ptp_workspace)
 
static void * entryPrepareDownlink (GinBtree btree, Buffer lbuf)
 
void ginEntryFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
void ginPrepareEntryScan (GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
 

Function Documentation

◆ entryBeginPlaceToPage()

static GinPlaceToPageRC entryBeginPlaceToPage ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertPayload,
BlockNumber  updateblkno,
void **  ptp_workspace,
Page newlpage,
Page newrpage 
)
static

Definition at line 528 of file ginentrypage.c.

532 {
533  GinBtreeEntryInsertData *insertData = insertPayload;
534  OffsetNumber off = stack->off;
535 
536  /* If it doesn't fit, deal with split case */
537  if (!entryIsEnoughSpace(btree, buf, off, insertData))
538  {
539  entrySplitPage(btree, buf, stack, insertData, updateblkno,
540  newlpage, newrpage);
541  return GPTP_SPLIT;
542  }
543 
544  /* Else, we're ready to proceed with insertion */
545  return GPTP_INSERT;
546 }
@ GPTP_INSERT
Definition: gin_private.h:145
@ GPTP_SPLIT
Definition: gin_private.h:146
static void entrySplitPage(GinBtree btree, Buffer origbuf, GinBtreeStack *stack, GinBtreeEntryInsertData *insertData, BlockNumber updateblkno, Page *newlpage, Page *newrpage)
Definition: ginentrypage.c:600
static bool entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off, GinBtreeEntryInsertData *insertData)
Definition: ginentrypage.c:460
uint16 OffsetNumber
Definition: off.h:24
static char * buf
Definition: pg_test_fsync.c:67
OffsetNumber off
Definition: gin_private.h:132

References buf, entryIsEnoughSpace(), entrySplitPage(), GPTP_INSERT, GPTP_SPLIT, and GinBtreeStack::off.

Referenced by ginPrepareEntryScan().

◆ entryExecPlaceToPage()

static void entryExecPlaceToPage ( GinBtree  btree,
Buffer  buf,
GinBtreeStack stack,
void *  insertPayload,
BlockNumber  updateblkno,
void *  ptp_workspace 
)
static

Definition at line 555 of file ginentrypage.c.

558 {
559  GinBtreeEntryInsertData *insertData = insertPayload;
560  Page page = BufferGetPage(buf);
561  OffsetNumber off = stack->off;
562  OffsetNumber placed;
563 
564  entryPreparePage(btree, page, off, insertData, updateblkno);
565 
566  placed = PageAddItem(page,
567  (Item) insertData->entry,
568  IndexTupleSize(insertData->entry),
569  off, false, false);
570  if (placed != off)
571  elog(ERROR, "failed to add item to index page in \"%s\"",
573 
574  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
575  {
576  /*
577  * This must be static, because it has to survive until XLogInsert,
578  * and we can't palloc here. Ugly, but the XLogInsert infrastructure
579  * isn't reentrant anyway.
580  */
581  static ginxlogInsertEntry data;
582 
583  data.isDelete = insertData->isDelete;
584  data.offset = off;
585 
586  XLogRegisterBufData(0, (char *) &data,
587  offsetof(ginxlogInsertEntry, tuple));
588  XLogRegisterBufData(0, (char *) insertData->entry,
589  IndexTupleSize(insertData->entry));
590  }
591 }
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
Pointer Page
Definition: bufpage.h:78
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:468
#define ERROR
Definition: elog.h:39
static void entryPreparePage(GinBtree btree, Page page, OffsetNumber off, GinBtreeEntryInsertData *insertData, BlockNumber updateblkno)
Definition: ginentrypage.c:491
Pointer Item
Definition: item.h:17
#define IndexTupleSize(itup)
Definition: itup.h:70
const void * data
#define RelationGetRelationName(relation)
Definition: rel.h:538
#define RelationNeedsWAL(relation)
Definition: rel.h:629
Relation index
Definition: gin_private.h:166
void XLogRegisterBufData(uint8 block_id, char *data, uint32 len)
Definition: xloginsert.c:392

References buf, BufferGetPage(), data, elog(), GinBtreeEntryInsertData::entry, entryPreparePage(), ERROR, GinBtreeData::index, IndexTupleSize, GinBtreeData::isBuild, GinBtreeEntryInsertData::isDelete, GinBtreeStack::off, PageAddItem, RelationGetRelationName, RelationNeedsWAL, and XLogRegisterBufData().

Referenced by ginPrepareEntryScan().

◆ entryFindChildPtr()

static OffsetNumber entryFindChildPtr ( GinBtree  btree,
Page  page,
BlockNumber  blkno,
OffsetNumber  storedOff 
)
static

Definition at line 406 of file ginentrypage.c.

407 {
408  OffsetNumber i,
409  maxoff = PageGetMaxOffsetNumber(page);
410  IndexTuple itup;
411 
412  Assert(!GinPageIsLeaf(page));
413  Assert(!GinPageIsData(page));
414 
415  /* if page isn't changed, we returns storedOff */
416  if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
417  {
418  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, storedOff));
419  if (GinGetDownlink(itup) == blkno)
420  return storedOff;
421 
422  /*
423  * we hope, that needed pointer goes to right. It's true if there
424  * wasn't a deletion
425  */
426  for (i = storedOff + 1; i <= maxoff; i++)
427  {
428  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
429  if (GinGetDownlink(itup) == blkno)
430  return i;
431  }
432  maxoff = storedOff - 1;
433  }
434 
435  /* last chance */
436  for (i = FirstOffsetNumber; i <= maxoff; i++)
437  {
438  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
439  if (GinGetDownlink(itup) == blkno)
440  return i;
441  }
442 
443  return InvalidOffsetNumber;
444 }
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
#define GinGetDownlink(itup)
Definition: ginblock.h:257
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
int i
Definition: isn.c:73
IndexTupleData * IndexTuple
Definition: itup.h:53
Assert(fmt[strlen(fmt) - 1] !='\n')
#define InvalidOffsetNumber
Definition: off.h:26
#define FirstOffsetNumber
Definition: off.h:27

References Assert(), FirstOffsetNumber, GinGetDownlink, GinPageIsData, GinPageIsLeaf, i, InvalidOffsetNumber, PageGetItem(), PageGetItemId(), and PageGetMaxOffsetNumber().

Referenced by ginPrepareEntryScan().

◆ entryGetLeftMostPage()

static BlockNumber entryGetLeftMostPage ( GinBtree  btree,
Page  page 
)
static

Definition at line 447 of file ginentrypage.c.

448 {
449  IndexTuple itup;
450 
451  Assert(!GinPageIsLeaf(page));
452  Assert(!GinPageIsData(page));
454 
455  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
456  return GinGetDownlink(itup);
457 }

References Assert(), FirstOffsetNumber, GinGetDownlink, GinPageIsData, GinPageIsLeaf, PageGetItem(), PageGetItemId(), and PageGetMaxOffsetNumber().

Referenced by ginPrepareEntryScan().

◆ entryIsEnoughSpace()

static bool entryIsEnoughSpace ( GinBtree  btree,
Buffer  buf,
OffsetNumber  off,
GinBtreeEntryInsertData insertData 
)
static

Definition at line 460 of file ginentrypage.c.

462 {
463  Size releasedsz = 0;
464  Size addedsz;
465  Page page = BufferGetPage(buf);
466 
467  Assert(insertData->entry);
468  Assert(!GinPageIsData(page));
469 
470  if (insertData->isDelete)
471  {
472  IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
473 
474  releasedsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
475  }
476 
477  addedsz = MAXALIGN(IndexTupleSize(insertData->entry)) + sizeof(ItemIdData);
478 
479  if (PageGetFreeSpace(page) + releasedsz >= addedsz)
480  return true;
481 
482  return false;
483 }
Size PageGetFreeSpace(Page page)
Definition: bufpage.c:907
#define MAXALIGN(LEN)
Definition: c.h:800
size_t Size
Definition: c.h:594
struct ItemIdData ItemIdData

References Assert(), buf, BufferGetPage(), GinBtreeEntryInsertData::entry, GinPageIsData, IndexTupleSize, GinBtreeEntryInsertData::isDelete, MAXALIGN, PageGetFreeSpace(), PageGetItem(), and PageGetItemId().

Referenced by entryBeginPlaceToPage().

◆ entryIsMoveRight()

static bool entryIsMoveRight ( GinBtree  btree,
Page  page 
)
static

Definition at line 244 of file ginentrypage.c.

245 {
246  IndexTuple itup;
248  Datum key;
249  GinNullCategory category;
250 
251  if (GinPageRightMost(page))
252  return false;
253 
254  itup = getRightMostTuple(page);
255  attnum = gintuple_get_attrnum(btree->ginstate, itup);
256  key = gintuple_get_key(btree->ginstate, itup, &category);
257 
258  if (ginCompareAttEntries(btree->ginstate,
259  btree->entryAttnum, btree->entryKey, btree->entryCategory,
260  attnum, key, category) > 0)
261  return true;
262 
263  return false;
264 }
signed char GinNullCategory
Definition: ginblock.h:206
#define GinPageRightMost(page)
Definition: ginblock.h:129
static IndexTuple getRightMostTuple(Page page)
Definition: ginentrypage.c:236
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:225
int ginCompareAttEntries(GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
Definition: ginutil.c:409
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:258
int16 attnum
Definition: pg_attribute.h:74
uintptr_t Datum
Definition: postgres.h:64
Datum entryKey
Definition: gin_private.h:174
GinState * ginstate
Definition: gin_private.h:168
GinNullCategory entryCategory
Definition: gin_private.h:175
OffsetNumber entryAttnum
Definition: gin_private.h:173

References attnum, GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, getRightMostTuple(), ginCompareAttEntries(), GinPageRightMost, GinBtreeData::ginstate, gintuple_get_attrnum(), gintuple_get_key(), and sort-test::key.

Referenced by ginPrepareEntryScan().

◆ entryLocateEntry()

static BlockNumber entryLocateEntry ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 271 of file ginentrypage.c.

272 {
273  OffsetNumber low,
274  high,
275  maxoff;
276  IndexTuple itup = NULL;
277  int result;
278  Page page = BufferGetPage(stack->buffer);
279 
280  Assert(!GinPageIsLeaf(page));
281  Assert(!GinPageIsData(page));
282 
283  if (btree->fullScan)
284  {
285  stack->off = FirstOffsetNumber;
286  stack->predictNumber *= PageGetMaxOffsetNumber(page);
287  return btree->getLeftMostChild(btree, page);
288  }
289 
290  low = FirstOffsetNumber;
291  maxoff = high = PageGetMaxOffsetNumber(page);
292  Assert(high >= low);
293 
294  high++;
295 
296  while (high > low)
297  {
298  OffsetNumber mid = low + ((high - low) / 2);
299 
300  if (mid == maxoff && GinPageRightMost(page))
301  {
302  /* Right infinity */
303  result = -1;
304  }
305  else
306  {
308  Datum key;
309  GinNullCategory category;
310 
311  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
312  attnum = gintuple_get_attrnum(btree->ginstate, itup);
313  key = gintuple_get_key(btree->ginstate, itup, &category);
314  result = ginCompareAttEntries(btree->ginstate,
315  btree->entryAttnum,
316  btree->entryKey,
317  btree->entryCategory,
318  attnum, key, category);
319  }
320 
321  if (result == 0)
322  {
323  stack->off = mid;
325  return GinGetDownlink(itup);
326  }
327  else if (result > 0)
328  low = mid + 1;
329  else
330  high = mid;
331  }
332 
333  Assert(high >= FirstOffsetNumber && high <= maxoff);
334 
335  stack->off = high;
336  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, high));
338  return GinGetDownlink(itup);
339 }
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:153
uint32 predictNumber
Definition: gin_private.h:135

References Assert(), attnum, GinBtreeStack::buffer, BufferGetPage(), GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, FirstOffsetNumber, GinBtreeData::fullScan, GinBtreeData::getLeftMostChild, GIN_ROOT_BLKNO, ginCompareAttEntries(), GinGetDownlink, GinPageIsData, GinPageIsLeaf, GinPageRightMost, GinBtreeData::ginstate, gintuple_get_attrnum(), gintuple_get_key(), sort-test::key, GinBtreeStack::off, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), and GinBtreeStack::predictNumber.

Referenced by ginPrepareEntryScan().

◆ entryLocateLeafEntry()

static bool entryLocateLeafEntry ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 347 of file ginentrypage.c.

348 {
349  Page page = BufferGetPage(stack->buffer);
350  OffsetNumber low,
351  high;
352 
353  Assert(GinPageIsLeaf(page));
354  Assert(!GinPageIsData(page));
355 
356  if (btree->fullScan)
357  {
358  stack->off = FirstOffsetNumber;
359  return true;
360  }
361 
362  low = FirstOffsetNumber;
363  high = PageGetMaxOffsetNumber(page);
364 
365  if (high < low)
366  {
367  stack->off = FirstOffsetNumber;
368  return false;
369  }
370 
371  high++;
372 
373  while (high > low)
374  {
375  OffsetNumber mid = low + ((high - low) / 2);
376  IndexTuple itup;
378  Datum key;
379  GinNullCategory category;
380  int result;
381 
382  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
383  attnum = gintuple_get_attrnum(btree->ginstate, itup);
384  key = gintuple_get_key(btree->ginstate, itup, &category);
385  result = ginCompareAttEntries(btree->ginstate,
386  btree->entryAttnum,
387  btree->entryKey,
388  btree->entryCategory,
389  attnum, key, category);
390  if (result == 0)
391  {
392  stack->off = mid;
393  return true;
394  }
395  else if (result > 0)
396  low = mid + 1;
397  else
398  high = mid;
399  }
400 
401  stack->off = high;
402  return false;
403 }

References Assert(), attnum, GinBtreeStack::buffer, BufferGetPage(), GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, FirstOffsetNumber, GinBtreeData::fullScan, ginCompareAttEntries(), GinPageIsData, GinPageIsLeaf, GinBtreeData::ginstate, gintuple_get_attrnum(), gintuple_get_key(), sort-test::key, GinBtreeStack::off, PageGetItem(), PageGetItemId(), and PageGetMaxOffsetNumber().

Referenced by ginPrepareEntryScan().

◆ entryPrepareDownlink()

static void* entryPrepareDownlink ( GinBtree  btree,
Buffer  lbuf 
)
static

Definition at line 700 of file ginentrypage.c.

701 {
702  GinBtreeEntryInsertData *insertData;
703  Page lpage = BufferGetPage(lbuf);
704  BlockNumber lblkno = BufferGetBlockNumber(lbuf);
705  IndexTuple itup;
706 
707  itup = getRightMostTuple(lpage);
708 
709  insertData = palloc(sizeof(GinBtreeEntryInsertData));
710  insertData->entry = GinFormInteriorTuple(itup, lpage, lblkno);
711  insertData->isDelete = false;
712 
713  return insertData;
714 }
uint32 BlockNumber
Definition: block.h:31
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3290
static IndexTuple GinFormInteriorTuple(IndexTuple itup, Page page, BlockNumber childblk)
Definition: ginentrypage.c:202
void * palloc(Size size)
Definition: mcxt.c:1226

References BufferGetBlockNumber(), BufferGetPage(), GinBtreeEntryInsertData::entry, getRightMostTuple(), GinFormInteriorTuple(), GinBtreeEntryInsertData::isDelete, and palloc().

Referenced by ginPrepareEntryScan().

◆ entryPreparePage()

static void entryPreparePage ( GinBtree  btree,
Page  page,
OffsetNumber  off,
GinBtreeEntryInsertData insertData,
BlockNumber  updateblkno 
)
static

Definition at line 491 of file ginentrypage.c.

493 {
494  Assert(insertData->entry);
495  Assert(!GinPageIsData(page));
496 
497  if (insertData->isDelete)
498  {
499  Assert(GinPageIsLeaf(page));
500  PageIndexTupleDelete(page, off);
501  }
502 
503  if (!GinPageIsLeaf(page) && updateblkno != InvalidBlockNumber)
504  {
505  IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
506 
507  GinSetDownlink(itup, updateblkno);
508  }
509 }
#define InvalidBlockNumber
Definition: block.h:33
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1052
#define GinSetDownlink(itup, blkno)
Definition: ginblock.h:258

References Assert(), GinBtreeEntryInsertData::entry, GinPageIsData, GinPageIsLeaf, GinSetDownlink, InvalidBlockNumber, GinBtreeEntryInsertData::isDelete, PageGetItem(), PageGetItemId(), and PageIndexTupleDelete().

Referenced by entryExecPlaceToPage(), and entrySplitPage().

◆ entrySplitPage()

static void entrySplitPage ( GinBtree  btree,
Buffer  origbuf,
GinBtreeStack stack,
GinBtreeEntryInsertData insertData,
BlockNumber  updateblkno,
Page newlpage,
Page newrpage 
)
static

Definition at line 600 of file ginentrypage.c.

605 {
606  OffsetNumber off = stack->off;
607  OffsetNumber i,
608  maxoff,
610  Size totalsize = 0;
611  Size lsize = 0,
612  size;
613  char *ptr;
614  IndexTuple itup;
615  Page page;
616  Page lpage = PageGetTempPageCopy(BufferGetPage(origbuf));
617  Page rpage = PageGetTempPageCopy(BufferGetPage(origbuf));
618  Size pageSize = PageGetPageSize(lpage);
619  PGAlignedBlock tupstore[2]; /* could need 2 pages' worth of tuples */
620 
621  entryPreparePage(btree, lpage, off, insertData, updateblkno);
622 
623  /*
624  * First, append all the existing tuples and the new tuple we're inserting
625  * one after another in a temporary workspace.
626  */
627  maxoff = PageGetMaxOffsetNumber(lpage);
628  ptr = tupstore[0].data;
629  for (i = FirstOffsetNumber; i <= maxoff; i++)
630  {
631  if (i == off)
632  {
633  size = MAXALIGN(IndexTupleSize(insertData->entry));
634  memcpy(ptr, insertData->entry, size);
635  ptr += size;
636  totalsize += size + sizeof(ItemIdData);
637  }
638 
639  itup = (IndexTuple) PageGetItem(lpage, PageGetItemId(lpage, i));
640  size = MAXALIGN(IndexTupleSize(itup));
641  memcpy(ptr, itup, size);
642  ptr += size;
643  totalsize += size + sizeof(ItemIdData);
644  }
645 
646  if (off == maxoff + 1)
647  {
648  size = MAXALIGN(IndexTupleSize(insertData->entry));
649  memcpy(ptr, insertData->entry, size);
650  ptr += size;
651  totalsize += size + sizeof(ItemIdData);
652  }
653 
654  /*
655  * Initialize the left and right pages, and copy all the tuples back to
656  * them.
657  */
658  GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
659  GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
660 
661  ptr = tupstore[0].data;
662  maxoff++;
663  lsize = 0;
664 
665  page = lpage;
666  for (i = FirstOffsetNumber; i <= maxoff; i++)
667  {
668  itup = (IndexTuple) ptr;
669 
670  /*
671  * Decide where to split. We try to equalize the pages' total data
672  * size, not number of tuples.
673  */
674  if (lsize > totalsize / 2)
675  {
677  separator = i - 1;
678  page = rpage;
679  }
680  else
681  {
682  lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
683  }
684 
685  if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
686  elog(ERROR, "failed to add item to index page in \"%s\"",
688  ptr += MAXALIGN(IndexTupleSize(itup));
689  }
690 
691  /* return temp pages to caller */
692  *newlpage = lpage;
693  *newrpage = rpage;
694 }
Page PageGetTempPageCopy(Page page)
Definition: bufpage.c:382
static Size PageGetPageSize(Page page)
Definition: bufpage.h:273
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:337
char data[BLCKSZ]
Definition: c.h:1132

References BufferGetPage(), PGAlignedBlock::data, elog(), GinBtreeEntryInsertData::entry, entryPreparePage(), ERROR, FirstOffsetNumber, GinInitPage(), GinPageGetOpaque, i, GinBtreeData::index, IndexTupleSize, InvalidOffsetNumber, MAXALIGN, GinBtreeStack::off, PageAddItem, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PageGetPageSize(), PageGetTempPageCopy(), and RelationGetRelationName.

Referenced by entryBeginPlaceToPage().

◆ getRightMostTuple()

static IndexTuple getRightMostTuple ( Page  page)
static

Definition at line 236 of file ginentrypage.c.

237 {
238  OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
239 
240  return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff));
241 }

References PageGetItem(), PageGetItemId(), and PageGetMaxOffsetNumber().

Referenced by entryIsMoveRight(), entryPrepareDownlink(), and ginEntryFillRoot().

◆ ginEntryFillRoot()

void ginEntryFillRoot ( GinBtree  btree,
Page  root,
BlockNumber  lblkno,
Page  lpage,
BlockNumber  rblkno,
Page  rpage 
)

Definition at line 721 of file ginentrypage.c.

724 {
725  IndexTuple itup;
726 
727  itup = GinFormInteriorTuple(getRightMostTuple(lpage), lpage, lblkno);
728  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
729  elog(ERROR, "failed to add item to index root page");
730  pfree(itup);
731 
732  itup = GinFormInteriorTuple(getRightMostTuple(rpage), rpage, rblkno);
733  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
734  elog(ERROR, "failed to add item to index root page");
735  pfree(itup);
736 }
void pfree(void *pointer)
Definition: mcxt.c:1456

References elog(), ERROR, getRightMostTuple(), GinFormInteriorTuple(), IndexTupleSize, InvalidOffsetNumber, PageAddItem, and pfree().

Referenced by ginPrepareEntryScan().

◆ GinFormInteriorTuple()

static IndexTuple GinFormInteriorTuple ( IndexTuple  itup,
Page  page,
BlockNumber  childblk 
)
static

Definition at line 202 of file ginentrypage.c.

203 {
204  IndexTuple nitup;
205 
206  if (GinPageIsLeaf(page) && !GinIsPostingTree(itup))
207  {
208  /* Tuple contains a posting list, just copy stuff before that */
209  uint32 origsize = GinGetPostingOffset(itup);
210 
211  origsize = MAXALIGN(origsize);
212  nitup = (IndexTuple) palloc(origsize);
213  memcpy(nitup, itup, origsize);
214  /* ... be sure to fix the size header field ... */
215  nitup->t_info &= ~INDEX_SIZE_MASK;
216  nitup->t_info |= origsize;
217  }
218  else
219  {
220  /* Copy the tuple as-is */
221  nitup = (IndexTuple) palloc(IndexTupleSize(itup));
222  memcpy(nitup, itup, IndexTupleSize(itup));
223  }
224 
225  /* Now insert the correct downlink */
226  GinSetDownlink(nitup, childblk);
227 
228  return nitup;
229 }
unsigned int uint32
Definition: c.h:495
#define GinIsPostingTree(itup)
Definition: ginblock.h:231
#define GinGetPostingOffset(itup)
Definition: ginblock.h:236
#define INDEX_SIZE_MASK
Definition: itup.h:65
unsigned short t_info
Definition: itup.h:49

References GinGetPostingOffset, GinIsPostingTree, GinPageIsLeaf, GinSetDownlink, INDEX_SIZE_MASK, IndexTupleSize, MAXALIGN, palloc(), and IndexTupleData::t_info.

Referenced by entryPrepareDownlink(), and ginEntryFillRoot().

◆ GinFormTuple()

IndexTuple GinFormTuple ( GinState ginstate,
OffsetNumber  attnum,
Datum  key,
GinNullCategory  category,
Pointer  data,
Size  dataSize,
int  nipd,
bool  errorTooBig 
)

Definition at line 45 of file ginentrypage.c.

49 {
50  Datum datums[2];
51  bool isnull[2];
52  IndexTuple itup;
53  uint32 newsize;
54 
55  /* Build the basic tuple: optional column number, plus key datum */
56  if (ginstate->oneCol)
57  {
58  datums[0] = key;
59  isnull[0] = (category != GIN_CAT_NORM_KEY);
60  }
61  else
62  {
63  datums[0] = UInt16GetDatum(attnum);
64  isnull[0] = false;
65  datums[1] = key;
66  isnull[1] = (category != GIN_CAT_NORM_KEY);
67  }
68 
69  itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull);
70 
71  /*
72  * Determine and store offset to the posting list, making sure there is
73  * room for the category byte if needed.
74  *
75  * Note: because index_form_tuple MAXALIGNs the tuple size, there may well
76  * be some wasted pad space. Is it worth recomputing the data length to
77  * prevent that? That would also allow us to Assert that the real data
78  * doesn't overlap the GinNullCategory byte, which this code currently
79  * takes on faith.
80  */
81  newsize = IndexTupleSize(itup);
82 
83  if (IndexTupleHasNulls(itup))
84  {
85  uint32 minsize;
86 
87  Assert(category != GIN_CAT_NORM_KEY);
88  minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory);
89  newsize = Max(newsize, minsize);
90  }
91 
92  newsize = SHORTALIGN(newsize);
93 
94  GinSetPostingOffset(itup, newsize);
95  GinSetNPosting(itup, nipd);
96 
97  /*
98  * Add space needed for posting list, if any. Then check that the tuple
99  * won't be too big to store.
100  */
101  newsize += dataSize;
102 
103  newsize = MAXALIGN(newsize);
104 
105  if (newsize > GinMaxItemSize)
106  {
107  if (errorTooBig)
108  ereport(ERROR,
109  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
110  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
111  (Size) newsize, (Size) GinMaxItemSize,
112  RelationGetRelationName(ginstate->index))));
113  pfree(itup);
114  return NULL;
115  }
116 
117  /*
118  * Resize tuple if needed
119  */
120  if (newsize != IndexTupleSize(itup))
121  {
122  itup = repalloc(itup, newsize);
123 
124  /*
125  * PostgreSQL 9.3 and earlier did not clear this new space, so we
126  * might find uninitialized padding when reading tuples from disk.
127  */
128  memset((char *) itup + IndexTupleSize(itup),
129  0, newsize - IndexTupleSize(itup));
130  /* set new size in tuple header */
131  itup->t_info &= ~INDEX_SIZE_MASK;
132  itup->t_info |= newsize;
133  }
134 
135  /*
136  * Copy in the posting list, if provided
137  */
138  if (data)
139  {
140  char *ptr = GinGetPosting(itup);
141 
142  memcpy(ptr, data, dataSize);
143  }
144 
145  /*
146  * Insert category byte, if needed
147  */
148  if (category != GIN_CAT_NORM_KEY)
149  {
150  Assert(IndexTupleHasNulls(itup));
151  GinSetNullCategory(itup, ginstate, category);
152  }
153  return itup;
154 }
#define Max(x, y)
Definition: c.h:987
#define SHORTALIGN(LEN)
Definition: c.h:796
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereport(elevel,...)
Definition: elog.h:149
#define GinCategoryOffset(itup, ginstate)
Definition: ginblock.h:217
#define GinGetPosting(itup)
Definition: ginblock.h:238
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:208
#define GinSetNPosting(itup, n)
Definition: ginblock.h:229
#define GinSetPostingOffset(itup, n)
Definition: ginblock.h:237
#define GinSetNullCategory(itup, ginstate, c)
Definition: ginblock.h:222
#define GinMaxItemSize
Definition: ginblock.h:248
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:44
#define IndexTupleHasNulls(itup)
Definition: itup.h:71
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1476
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:192
bool oneCol
Definition: gin_private.h:59
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:73
Relation index
Definition: gin_private.h:58

References Assert(), attnum, data, ereport, errcode(), errmsg(), ERROR, GIN_CAT_NORM_KEY, GinCategoryOffset, GinGetPosting, GinMaxItemSize, GinSetNPosting, GinSetNullCategory, GinSetPostingOffset, GinState::index, index_form_tuple(), INDEX_SIZE_MASK, IndexTupleHasNulls, IndexTupleSize, sort-test::key, Max, MAXALIGN, GinState::oneCol, pfree(), RelationGetRelationName, repalloc(), SHORTALIGN, IndexTupleData::t_info, GinState::tupdesc, and UInt16GetDatum().

Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), ginHeapTupleFastCollect(), and ginVacuumEntryPage().

◆ ginPrepareEntryScan()

void ginPrepareEntryScan ( GinBtree  btree,
OffsetNumber  attnum,
Datum  key,
GinNullCategory  category,
GinState ginstate 
)

Definition at line 745 of file ginentrypage.c.

748 {
749  memset(btree, 0, sizeof(GinBtreeData));
750 
751  btree->index = ginstate->index;
752  btree->rootBlkno = GIN_ROOT_BLKNO;
753  btree->ginstate = ginstate;
754 
757  btree->isMoveRight = entryIsMoveRight;
762  btree->fillRoot = ginEntryFillRoot;
764 
765  btree->isData = false;
766  btree->fullScan = false;
767  btree->isBuild = false;
768 
769  btree->entryAttnum = attnum;
770  btree->entryKey = key;
771  btree->entryCategory = category;
772 }
void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: ginentrypage.c:721
static bool entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:347
static bool entryIsMoveRight(GinBtree btree, Page page)
Definition: ginentrypage.c:244
static BlockNumber entryGetLeftMostPage(GinBtree btree, Page page)
Definition: ginentrypage.c:447
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: ginentrypage.c:700
static OffsetNumber entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: ginentrypage.c:406
static GinPlaceToPageRC entryBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: ginentrypage.c:528
static void entryExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void *ptp_workspace)
Definition: ginentrypage.c:555
static BlockNumber entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:271
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:152
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:160
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:155
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:154
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:159
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:161
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:158
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:162
BlockNumber rootBlkno
Definition: gin_private.h:167

References attnum, GinBtreeData::beginPlaceToPage, GinBtreeData::entryAttnum, entryBeginPlaceToPage(), GinBtreeData::entryCategory, entryExecPlaceToPage(), entryFindChildPtr(), entryGetLeftMostPage(), entryIsMoveRight(), GinBtreeData::entryKey, entryLocateEntry(), entryLocateLeafEntry(), entryPrepareDownlink(), GinBtreeData::execPlaceToPage, GinBtreeData::fillRoot, GinBtreeData::findChildPage, GinBtreeData::findChildPtr, GinBtreeData::findItem, GinBtreeData::fullScan, GinBtreeData::getLeftMostChild, GIN_ROOT_BLKNO, ginEntryFillRoot(), GinBtreeData::ginstate, GinState::index, GinBtreeData::index, GinBtreeData::isBuild, GinBtreeData::isData, GinBtreeData::isMoveRight, sort-test::key, GinBtreeData::prepareDownlink, and GinBtreeData::rootBlkno.

Referenced by ginEntryInsert(), and startScanEntry().

◆ ginReadTuple()

ItemPointer ginReadTuple ( GinState ginstate,
OffsetNumber  attnum,
IndexTuple  itup,
int *  nitems 
)

Definition at line 163 of file ginentrypage.c.

165 {
166  Pointer ptr = GinGetPosting(itup);
167  int nipd = GinGetNPosting(itup);
168  ItemPointer ipd;
169  int ndecoded;
170 
171  if (GinItupIsCompressed(itup))
172  {
173  if (nipd > 0)
174  {
175  ipd = ginPostingListDecode((GinPostingList *) ptr, &ndecoded);
176  if (nipd != ndecoded)
177  elog(ERROR, "number of items mismatch in GIN entry tuple, %d in tuple header, %d decoded",
178  nipd, ndecoded);
179  }
180  else
181  {
182  ipd = palloc(0);
183  }
184  }
185  else
186  {
187  ipd = (ItemPointer) palloc(sizeof(ItemPointerData) * nipd);
188  memcpy(ipd, ptr, sizeof(ItemPointerData) * nipd);
189  }
190  *nitems = nipd;
191  return ipd;
192 }
char * Pointer
Definition: c.h:472
#define GinItupIsCompressed(itup)
Definition: ginblock.h:239
#define GinGetNPosting(itup)
Definition: ginblock.h:228
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
#define nitems(x)
Definition: indent.h:31
ItemPointerData * ItemPointer
Definition: itemptr.h:49

References elog(), ERROR, GinGetNPosting, GinGetPosting, GinItupIsCompressed, ginPostingListDecode(), nitems, and palloc().

Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), and startScanEntry().