/* * Places keys to page and fills WAL record. In case leaf page and * build mode puts all ItemPointers to page. * * If none of the keys fit, returns false without modifying the page. * * On insertion to an internal node, in addition to inserting the given item, * the downlink of the existing item at 'off' is updated to point to * 'updateblkno'. */ static bool dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, void *insertdata, BlockNumber updateblkno, XLogRecData **prdata) { Page page = BufferGetPage(buf); /* these must be static so they can be returned to caller */ static XLogRecData rdata[2]; /* quick exit if it doesn't fit */ if (!dataIsEnoughSpace(btree, buf, off, insertdata)) return false; *prdata = rdata; Assert(GinPageIsData(page)); /* Update existing downlink to point to next page (on internal page) */ if (!GinPageIsLeaf(page)) { PostingItem *pitem = GinDataPageGetPostingItem(page, off); PostingItemSetBlockNumber(pitem, updateblkno); } if (GinPageIsLeaf(page)) { GinBtreeDataLeafInsertData *items = insertdata; static ginxlogInsertDataLeaf data; uint32 savedPos = items->curitem; if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff) { /* usually, create index... */ while (items->curitem < items->nitem) { GinDataPageAddItemPointer(page, items->items + items->curitem, off); off++; items->curitem++; } data.nitem = items->curitem - savedPos; } else { GinDataPageAddItemPointer(page, items->items + items->curitem, off); items->curitem++; data.nitem = 1; } rdata[0].buffer = buf; rdata[0].buffer_std = false; rdata[0].data = (char *) &data; rdata[0].len = offsetof(ginxlogInsertDataLeaf, items); rdata[0].next = &rdata[1]; rdata[1].buffer = buf; rdata[1].buffer_std = false; rdata[1].data = (char *) &items->items[savedPos]; rdata[1].len = sizeof(ItemPointerData) * data.nitem; rdata[1].next = NULL; } else { PostingItem *pitem = insertdata; GinDataPageAddPostingItem(page, pitem, off); rdata[0].buffer = buf; rdata[0].buffer_std = false; rdata[0].data = (char *) pitem; rdata[0].len = sizeof(PostingItem); rdata[0].next = NULL; } return true; }
/* * Places keys to page and fills WAL record. In case leaf page and * build mode puts all ItemPointers to page. */ static void dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) { Page page = BufferGetPage(buf); int sizeofitem = GinSizeOfDataPageItem(page); int cnt = 0; /* these must be static so they can be returned to caller */ static XLogRecData rdata[3]; static ginxlogInsert data; *prdata = rdata; Assert(GinPageIsData(page)); data.updateBlkno = dataPrepareData(btree, page, off); data.node = btree->index->rd_node; data.blkno = BufferGetBlockNumber(buf); data.offset = off; data.nitem = 1; data.isDelete = FALSE; data.isData = TRUE; data.isLeaf = GinPageIsLeaf(page) ? TRUE : FALSE; /* * Prevent full page write if child's split occurs. That is needed to * remove incomplete splits while replaying WAL * * data.updateBlkno contains new block number (of newly created right * page) for recently splited page. */ if (data.updateBlkno == InvalidBlockNumber) { rdata[0].buffer = buf; rdata[0].buffer_std = FALSE; rdata[0].data = NULL; rdata[0].len = 0; rdata[0].next = &rdata[1]; cnt++; } rdata[cnt].buffer = InvalidBuffer; rdata[cnt].data = (char *) &data; rdata[cnt].len = sizeof(ginxlogInsert); rdata[cnt].next = &rdata[cnt + 1]; cnt++; rdata[cnt].buffer = InvalidBuffer; rdata[cnt].data = (GinPageIsLeaf(page)) ? ((char *) (btree->items + btree->curitem)) : ((char *) &(btree->pitem)); rdata[cnt].len = sizeofitem; rdata[cnt].next = NULL; if (GinPageIsLeaf(page)) { if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff) { /* usually, create index... */ uint32 savedPos = btree->curitem; while (btree->curitem < btree->nitem) { GinDataPageAddItemPointer(page, btree->items + btree->curitem, off); off++; btree->curitem++; } data.nitem = btree->curitem - savedPos; rdata[cnt].len = sizeofitem * data.nitem; } else { GinDataPageAddItemPointer(page, btree->items + btree->curitem, off); btree->curitem++; } } else GinDataPageAddPostingItem(page, &(btree->pitem), off); }