}
memcpy(ptr, data, sizeof(PostingItem));
- GinPageGetOpaque(page)->maxoff++;
+ maxoff++;
+ GinPageGetOpaque(page)->maxoff = maxoff;
+
+ /*
+ * Also set pd_lower to the end of the posting items, to follow the
+ * "standard" page layout, so that we can squeeze out the unused space
+ * from full-page images.
+ */
+ GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
}
/*
GinDataPageGetPostingItem(page, offset + 1),
sizeof(PostingItem) * (maxoff - offset));
- GinPageGetOpaque(page)->maxoff--;
+ maxoff--;
+ GinPageGetOpaque(page)->maxoff = maxoff;
+
+ GinDataPageSetDataSize(page, maxoff * sizeof(PostingItem));
}
/*
* a single byte, and we can use all the free space on the old page as
* well as the new page. For simplicity, ignore segment overhead etc.
*/
- maxitems = Min(maxitems, freespace + GinDataLeafMaxContentSize);
+ maxitems = Min(maxitems, freespace + GinDataPageMaxDataSize);
}
else
{
int nnewsegments;
nnewsegments = freespace / GinPostingListSegmentMaxSize;
- nnewsegments += GinDataLeafMaxContentSize / GinPostingListSegmentMaxSize;
+ nnewsegments += GinDataPageMaxDataSize / GinPostingListSegmentMaxSize;
maxitems = Min(maxitems, nnewsegments * MinTuplesPerSegment);
}
leaf->lastleft = dlist_prev_node(&leaf->segments, leaf->lastleft);
}
}
- Assert(leaf->lsize <= GinDataLeafMaxContentSize);
- Assert(leaf->rsize <= GinDataLeafMaxContentSize);
+ Assert(leaf->lsize <= GinDataPageMaxDataSize);
+ Assert(leaf->rsize <= GinDataPageMaxDataSize);
/*
* Fetch the max item in the left page's last segment; it becomes the
if (seginfo->seg)
oldsegsize = SizeOfGinPostingList(seginfo->seg);
else
- oldsegsize = GinDataLeafMaxContentSize;
+ oldsegsize = GinDataPageMaxDataSize;
cleaned = ginVacuumItemPointers(gvs,
seginfo->items,
}
}
- Assert(newsize <= GinDataLeafMaxContentSize);
- GinDataLeafPageSetPostingListSize(page, newsize);
+ Assert(newsize <= GinDataPageMaxDataSize);
+ GinDataPageSetDataSize(page, newsize);
}
/*
}
}
Assert(lsize == leaf->lsize);
- GinDataLeafPageSetPostingListSize(lpage, lsize);
+ GinDataPageSetDataSize(lpage, lsize);
*GinDataPageGetRightBound(lpage) = lbound;
/* Copy the segments that go to the right page */
break;
}
Assert(rsize == leaf->rsize);
- GinDataLeafPageSetPostingListSize(rpage, rsize);
+ GinDataPageSetDataSize(rpage, rsize);
*GinDataPageGetRightBound(rpage) = rbound;
/* Create WAL record */
data.newitem = *pitem;
rdata.buffer = buf;
- rdata.buffer_std = false;
+ rdata.buffer_std = TRUE;
rdata.data = (char *) &data;
rdata.len = sizeof(ginxlogInsertDataInternal);
rdata.next = NULL;
Page oldpage = BufferGetPage(origbuf);
OffsetNumber off = stack->off;
int nitems = GinPageGetOpaque(oldpage)->maxoff;
+ int nleftitems;
+ int nrightitems;
Size pageSize = PageGetPageSize(oldpage);
ItemPointerData oldbound = *GinDataPageGetRightBound(oldpage);
ItemPointer bound;
separator = GinNonLeafDataPageGetFreeSpace(rpage) / sizeof(PostingItem);
else
separator = nitems / 2;
+ nleftitems = separator;
+ nrightitems = nitems - separator;
- memcpy(GinDataPageGetPostingItem(lpage, FirstOffsetNumber), allitems, separator * sizeof(PostingItem));
- GinPageGetOpaque(lpage)->maxoff = separator;
+ memcpy(GinDataPageGetPostingItem(lpage, FirstOffsetNumber),
+ allitems,
+ nleftitems * sizeof(PostingItem));
+ GinPageGetOpaque(lpage)->maxoff = nleftitems;
memcpy(GinDataPageGetPostingItem(rpage, FirstOffsetNumber),
- &allitems[separator], (nitems - separator) * sizeof(PostingItem));
- GinPageGetOpaque(rpage)->maxoff = nitems - separator;
+ &allitems[separator],
+ nrightitems * sizeof(PostingItem));
+ GinPageGetOpaque(rpage)->maxoff = nrightitems;
+
+ /*
+ * Also set pd_lower for both pages, like GinDataPageAddPostingItem does.
+ */
+ GinDataPageSetDataSize(lpage, nleftitems * sizeof(PostingItem));
+ GinDataPageSetDataSize(rpage, nrightitems * sizeof(PostingItem));
/* set up right bound for left page */
bound = GinDataPageGetRightBound(lpage);
- *bound = GinDataPageGetPostingItem(lpage,
- GinPageGetOpaque(lpage)->maxoff)->key;
+ *bound = GinDataPageGetPostingItem(lpage, nleftitems)->key;
/* set up right bound for right page */
*GinDataPageGetRightBound(rpage) = oldbound;
* copying to the page. Did we exceed the size that fits on one page?
*/
segsize = SizeOfGinPostingList(seginfo->seg);
- if (pgused + segsize > GinDataLeafMaxContentSize)
+ if (pgused + segsize > GinDataPageMaxDataSize)
{
if (!needsplit)
{
else
leaf->rsize = pgused;
- Assert(leaf->lsize <= GinDataLeafMaxContentSize);
- Assert(leaf->rsize <= GinDataLeafMaxContentSize);
+ Assert(leaf->lsize <= GinDataPageMaxDataSize);
+ Assert(leaf->rsize <= GinDataPageMaxDataSize);
/*
* Make a palloc'd copy of every segment after the first modified one,
GinPostingListSegmentMaxSize,
&npacked);
segsize = SizeOfGinPostingList(segment);
- if (rootsize + segsize > GinDataLeafMaxContentSize)
+ if (rootsize + segsize > GinDataPageMaxDataSize)
break;
memcpy(ptr, segment, segsize);
nrootitems += npacked;
pfree(segment);
}
- GinDataLeafPageSetPostingListSize(tmppage, rootsize);
+ GinDataPageSetDataSize(tmppage, rootsize);
/*
* All set. Get a new physical page, and copy the in-memory page to it.
/* Place page data */
memcpy(GinDataLeafPageGetPostingList(page), ptr, data->size);
- GinDataLeafPageSetPostingListSize(page, data->size);
+ GinDataPageSetDataSize(page, data->size);
PageSetLSN(page, lsn);
totalsize = SizeOfGinPostingList(plist);
memcpy(GinDataLeafPageGetPostingList(page), plist, totalsize);
- GinDataLeafPageSetPostingListSize(page, totalsize);
+ GinDataPageSetDataSize(page, totalsize);
GinPageSetCompressed(page);
GinPageGetOpaque(page)->maxoff = InvalidOffsetNumber;
}
}
totalsize = segmentend - (Pointer) GinDataLeafPageGetPostingList(page);
- GinDataLeafPageSetPostingListSize(page, totalsize);
+ GinDataPageSetDataSize(page, totalsize);
}
static void
Pointer lptr = (Pointer) rdata + sizeof(ginxlogSplitDataLeaf);
Pointer rptr = lptr + data->lsize;
- Assert(data->lsize > 0 && data->lsize <= GinDataLeafMaxContentSize);
- Assert(data->rsize > 0 && data->rsize <= GinDataLeafMaxContentSize);
+ 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);
- GinDataLeafPageSetPostingListSize(lpage, data->lsize);
- GinDataLeafPageSetPostingListSize(rpage, data->rsize);
+ GinDataPageSetDataSize(lpage, data->lsize);
+ GinDataPageSetDataSize(rpage, data->rsize);
*GinDataPageGetRightBound(lpage) = data->lrightbound;
*GinDataPageGetRightBound(rpage) = data->rrightbound;
}
(GinPostingList *) ((PageGetContents(page) + MAXALIGN(sizeof(ItemPointerData))))
#define GinDataLeafPageGetPostingListSize(page) \
(((PageHeader) page)->pd_lower - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(ItemPointerData)))
-#define GinDataLeafPageSetPostingListSize(page, size) \
- { \
- Assert(size <= GinDataLeafMaxContentSize); \
- ((PageHeader) page)->pd_lower = (size) + MAXALIGN(SizeOfPageHeaderData) + MAXALIGN(sizeof(ItemPointerData)); \
- }
#define GinDataLeafPageIsEmpty(page) \
(GinPageIsCompressed(page) ? (GinDataLeafPageGetPostingListSize(page) == 0) : (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber))
#define GinDataPageGetPostingItem(page, i) \
((PostingItem *) (GinDataPageGetData(page) + ((i)-1) * sizeof(PostingItem)))
+/*
+ * Note: there is no GinDataPageGetDataSize macro, because before version
+ * 9.4, we didn't set pd_lower on data pages. There can be pages in the index
+ * that were binary-upgraded from earlier versions and still have an invalid
+ * pd_lower, so we cannot trust it in general. Compressed posting tree leaf
+ * pages are new in 9.4, however, so we can trust them; see
+ * GinDataLeafPageGetPostingListSize.
+ */
+#define GinDataPageSetDataSize(page, size) \
+ { \
+ Assert(size <= GinDataPageMaxDataSize); \
+ ((PageHeader) page)->pd_lower = (size) + MAXALIGN(SizeOfPageHeaderData) + MAXALIGN(sizeof(ItemPointerData)); \
+ }
+
#define GinNonLeafDataPageGetFreeSpace(page) \
- (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \
- - MAXALIGN(sizeof(ItemPointerData)) \
- - GinPageGetOpaque(page)->maxoff * sizeof(PostingItem) \
- - MAXALIGN(sizeof(GinPageOpaqueData)))
+ (GinDataPageMaxDataSize - \
+ GinPageGetOpaque(page)->maxoff * sizeof(PostingItem))
-#define GinDataLeafMaxContentSize \
+#define GinDataPageMaxDataSize \
(BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \
- MAXALIGN(sizeof(ItemPointerData)) \
- MAXALIGN(sizeof(GinPageOpaqueData)))