aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/page/bufpage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/page/bufpage.c')
-rw-r--r--src/backend/storage/page/bufpage.c112
1 files changed, 94 insertions, 18 deletions
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index 3ce2f04bd8e..b382e4d0240 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -8,12 +8,13 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.73 2007/09/12 22:10:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.74 2007/09/20 17:56:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "access/htup.h"
#include "storage/bufpage.h"
@@ -108,6 +109,9 @@ PageHeaderIsValid(PageHeader page)
* If offsetNumber is not valid, then assign one by finding the first
* one that is both unused and deallocated.
*
+ * If is_heap is true, we enforce that there can't be more than
+ * MaxHeapTuplesPerPage line pointers on the page.
+ *
* !!! EREPORT(ERROR) IS DISALLOWED HERE !!!
*/
OffsetNumber
@@ -115,7 +119,8 @@ PageAddItem(Page page,
Item item,
Size size,
OffsetNumber offsetNumber,
- bool overwrite)
+ bool overwrite,
+ bool is_heap)
{
PageHeader phdr = (PageHeader) page;
Size alignedSize;
@@ -200,6 +205,12 @@ PageAddItem(Page page,
return InvalidOffsetNumber;
}
+ if (is_heap && offsetNumber > MaxHeapTuplesPerPage)
+ {
+ elog(WARNING, "can't put more than MaxHeapTuplesPerPage items in a heap page");
+ return InvalidOffsetNumber;
+ }
+
/*
* Compute new lower and upper pointers for page, see if it'll fit.
*
@@ -315,11 +326,10 @@ itemoffcompare(const void *itemidp1, const void *itemidp2)
*
* This routine is usable for heap pages only, but see PageIndexMultiDelete.
*
- * Returns number of unused line pointers on page. If "unused" is not NULL
- * then the unused[] array is filled with indexes of unused line pointers.
+ * As a side effect, the page's PD_HAS_FREE_LINES hint bit is updated.
*/
-int
-PageRepairFragmentation(Page page, OffsetNumber *unused)
+void
+PageRepairFragmentation(Page page)
{
Offset pd_lower = ((PageHeader) page)->pd_lower;
Offset pd_upper = ((PageHeader) page)->pd_upper;
@@ -329,7 +339,7 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
ItemId lp;
int nline,
nstorage,
- nused;
+ nunused;
int i;
Size totallen;
Offset upper;
@@ -352,13 +362,12 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
pd_lower, pd_upper, pd_special)));
nline = PageGetMaxOffsetNumber(page);
- nused = nstorage = 0;
- for (i = 0; i < nline; i++)
+ nunused = nstorage = 0;
+ for (i = FirstOffsetNumber; i <= nline; i++)
{
- lp = PageGetItemId(page, i + 1);
+ lp = PageGetItemId(page, i);
if (ItemIdIsUsed(lp))
{
- nused++;
if (ItemIdHasStorage(lp))
nstorage++;
}
@@ -366,9 +375,7 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
{
/* Unused entries should have lp_len = 0, but make sure */
ItemIdSetUnused(lp);
- /* Report to caller if asked for */
- if (unused)
- unused[i - nused] = (OffsetNumber) i;
+ nunused++;
}
}
@@ -431,18 +438,19 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
}
/* Set hint bit for PageAddItem */
- if (nused < nline)
+ if (nunused > 0)
PageSetHasFreeLinePointers(page);
else
PageClearHasFreeLinePointers(page);
-
- return (nline - nused);
}
/*
* PageGetFreeSpace
* Returns the size of the free (allocatable) space on a page,
* reduced by the space needed for a new line pointer.
+ *
+ * Note: this should usually only be used on index pages. Use
+ * PageGetHeapFreeSpace on heap pages.
*/
Size
PageGetFreeSpace(Page page)
@@ -465,7 +473,8 @@ PageGetFreeSpace(Page page)
/*
* PageGetExactFreeSpace
- * Returns the size of the free (allocatable) space on a page.
+ * Returns the size of the free (allocatable) space on a page,
+ * without any consideration for adding/removing line pointers.
*/
Size
PageGetExactFreeSpace(Page page)
@@ -484,6 +493,73 @@ PageGetExactFreeSpace(Page page)
/*
+ * PageGetHeapFreeSpace
+ * Returns the size of the free (allocatable) space on a page,
+ * reduced by the space needed for a new line pointer.
+ *
+ * The difference between this and PageGetFreeSpace is that this will return
+ * zero if there are already MaxHeapTuplesPerPage line pointers in the page
+ * and none are free. We use this to enforce that no more than
+ * MaxHeapTuplesPerPage line pointers are created on a heap page. (Although
+ * no more tuples than that could fit anyway, in the presence of redirected
+ * or dead line pointers it'd be possible to have too many line pointers.
+ * To avoid breaking code that assumes MaxHeapTuplesPerPage is a hard limit
+ * on the number of line pointers, we make this extra check.)
+ */
+Size
+PageGetHeapFreeSpace(Page page)
+{
+ Size space;
+
+ space = PageGetFreeSpace(page);
+ if (space > 0)
+ {
+ OffsetNumber offnum, nline;
+
+ /*
+ * Are there already MaxHeapTuplesPerPage line pointers in the page?
+ */
+ nline = PageGetMaxOffsetNumber(page);
+ if (nline >= MaxHeapTuplesPerPage)
+ {
+ if (PageHasFreeLinePointers((PageHeader) page))
+ {
+ /*
+ * Since this is just a hint, we must confirm that there is
+ * indeed a free line pointer
+ */
+ for (offnum = FirstOffsetNumber; offnum <= nline; offnum++)
+ {
+ ItemId lp = PageGetItemId(page, offnum);
+
+ if (!ItemIdIsUsed(lp))
+ break;
+ }
+
+ if (offnum > nline)
+ {
+ /*
+ * The hint is wrong, but we can't clear it here since
+ * we don't have the ability to mark the page dirty.
+ */
+ space = 0;
+ }
+ }
+ else
+ {
+ /*
+ * Although the hint might be wrong, PageAddItem will believe
+ * it anyway, so we must believe it too.
+ */
+ space = 0;
+ }
+ }
+ }
+ return space;
+}
+
+
+/*
* PageIndexTupleDelete
*
* This routine does the work of removing a tuple from an index page.