/* * Fills new root by right bound values from child. * Also called from ginxlog, should not use btree */ void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage) { PostingItem li, ri; li.key = *GinDataPageGetRightBound(lpage); PostingItemSetBlockNumber(&li, lblkno); GinDataPageAddPostingItem(root, &li, InvalidOffsetNumber); ri.key = *GinDataPageGetRightBound(rpage); PostingItemSetBlockNumber(&ri, rblkno); GinDataPageAddPostingItem(root, &ri, InvalidOffsetNumber); }
static void ginRedoInsertData(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata) { Page page = BufferGetPage(buffer); if (isLeaf) { ginxlogRecompressDataLeaf *data = (ginxlogRecompressDataLeaf *) rdata; Assert(GinPageIsLeaf(page)); ginRedoRecompress(page, data); } else { ginxlogInsertDataInternal *data = (ginxlogInsertDataInternal *) rdata; PostingItem *oldpitem; Assert(!GinPageIsLeaf(page)); /* update link to right page after split */ oldpitem = GinDataPageGetPostingItem(page, data->offset); PostingItemSetBlockNumber(oldpitem, rightblkno); GinDataPageAddPostingItem(page, &data->newitem, data->offset); } }
/* * Fills new root by right bound values from child. * Also called from ginxlog, should not use btree */ void ginDataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) { Page page = BufferGetPage(root), lpage = BufferGetPage(lbuf), rpage = BufferGetPage(rbuf); PostingItem li, ri; li.key = *GinDataPageGetRightBound(lpage); PostingItemSetBlockNumber(&li, BufferGetBlockNumber(lbuf)); GinDataPageAddPostingItem(page, &li, InvalidOffsetNumber); ri.key = *GinDataPageGetRightBound(rpage); PostingItemSetBlockNumber(&ri, BufferGetBlockNumber(rbuf)); GinDataPageAddPostingItem(page, &ri, InvalidOffsetNumber); }
static void ginRedoSplitData(Page lpage, Page rpage, void *rdata) { bool isleaf = GinPageIsLeaf(lpage); if (isleaf) { ginxlogSplitDataLeaf *data = (ginxlogSplitDataLeaf *) rdata; Pointer lptr = (Pointer) rdata + sizeof(ginxlogSplitDataLeaf); Pointer rptr = lptr + data->lsize; Assert(data->lsize > 0 && data->lsize <= GinDataPageMaxDataSize); Assert(data->rsize > 0 && data->rsize <= GinDataPageMaxDataSize); memcpy(GinDataLeafPageGetPostingList(lpage), lptr, data->lsize); memcpy(GinDataLeafPageGetPostingList(rpage), rptr, data->rsize); GinDataPageSetDataSize(lpage, data->lsize); GinDataPageSetDataSize(rpage, data->rsize); *GinDataPageGetRightBound(lpage) = data->lrightbound; *GinDataPageGetRightBound(rpage) = data->rrightbound; } else { ginxlogSplitDataInternal *data = (ginxlogSplitDataInternal *) rdata; PostingItem *items = (PostingItem *) ((char *) rdata + sizeof(ginxlogSplitDataInternal)); OffsetNumber i; OffsetNumber maxoff; for (i = 0; i < data->separator; i++) GinDataPageAddPostingItem(lpage, &items[i], InvalidOffsetNumber); for (i = data->separator; i < data->nitem; i++) GinDataPageAddPostingItem(rpage, &items[i], InvalidOffsetNumber); /* set up right key */ maxoff = GinPageGetOpaque(lpage)->maxoff; *GinDataPageGetRightBound(lpage) = GinDataPageGetPostingItem(lpage, maxoff)->key; *GinDataPageGetRightBound(rpage) = data->rightbound; } }
/* * 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); }