I attached second version of space reservation patch. You can see first
version here:
http://archives.postgresql.org/pgsql-hackers/2008-12/msg00886.php
I thought about Heikki'es comments and I removed all catalog changes,
because there are not necessary to be in pg_class. Instead of
pg_preugrade script should create own schema (pg_upgrade) and tables on
its needs.
This patch implement settings like relation options. Tom had objection
about this approach. I can rewrite it and extend pg_class instead.
However before I will do it I would like to know opinion about rest of
the patch.
And last thing is most important. Space reservation MUST TO be implemented if we
want to have 8.4->8.5 upgrade. Else we will be at the begging...
Zdenek
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/common/reloptions.c pgsql_spacereserve/src/backend/access/common/reloptions.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/common/reloptions.c 2009-01-23 14:53:17.553968280 +0100
--- pgsql_spacereserve/src/backend/access/common/reloptions.c 2009-01-23 14:53:17.785452704 +0100
***************
*** 86,91 ****
--- 86,108 ----
},
GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
},
+ {
+ {
+ "rs_perpage",
+ "Page reserved space per page for in-place upgrade in bytes",
+ RELOPT_KIND_ALL
+ },
+ 0, 0, BLCKSZ/4
+ },
+ {
+ {
+ "rs_pertuple",
+ "Page reserved space per tuple for in-place upgrade in bytes",
+ RELOPT_KIND_ALL
+ },
+ 0, 0, BLCKSZ/16
+ },
+
/* list terminator */
{ { NULL } }
};
***************
*** 592,598 ****
/* Build a list of expected options, based on kind */
for (i = 0; relOpts[i]; i++)
! if (relOpts[i]->kind == kind)
numoptions++;
if (numoptions == 0)
--- 609,615 ----
/* Build a list of expected options, based on kind */
for (i = 0; relOpts[i]; i++)
! if (relOpts[i]->kind == kind || relOpts[i]->kind == RELOPT_KIND_ALL)
numoptions++;
if (numoptions == 0)
***************
*** 605,611 ****
for (i = 0, j = 0; relOpts[i]; i++)
{
! if (relOpts[i]->kind == kind)
{
reloptions[j].gen = relOpts[i];
reloptions[j].isset = false;
--- 622,628 ----
for (i = 0, j = 0; relOpts[i]; i++)
{
! if (relOpts[i]->kind == kind || relOpts[i]->kind == RELOPT_KIND_ALL)
{
reloptions[j].gen = relOpts[i];
reloptions[j].isset = false;
***************
*** 868,874 ****
/*
! * Option parser for anything that uses StdRdOptions (i.e. fillfactor only)
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
--- 885,891 ----
/*
! * Option parser for anything that uses StdRdOptions (i.e. fillfactor)
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
***************
*** 877,883 ****
StdRdOptions *rdopts;
int numoptions;
relopt_parse_elt tab[] = {
! {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
--- 894,902 ----
StdRdOptions *rdopts;
int numoptions;
relopt_parse_elt tab[] = {
! {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
! {"rs_perpage", RELOPT_TYPE_INT, offsetof(StdRdOptions, rs_perpage)},
! {"rs_pertuple", RELOPT_TYPE_INT, offsetof(StdRdOptions, rs_pertuple)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/gin/ginentrypage.c pgsql_spacereserve/src/backend/access/gin/ginentrypage.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/gin/ginentrypage.c 2009-01-23 14:53:17.557611451 +0100
--- pgsql_spacereserve/src/backend/access/gin/ginentrypage.c 2009-01-23 14:53:17.785727884 +0100
***************
*** 314,320 ****
itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
}
! if (PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
return true;
return false;
--- 314,323 ----
itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
}
! if (PageGetFreeSpace(page,
! RelationGetReservedSpacePerPage(btree->index),
! RelationGetReservedSpacePerTuple(btree->index)) + itupsz
! >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
return true;
return false;
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gist.c pgsql_spacereserve/src/backend/access/gist/gist.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gist.c 2009-01-23 14:53:17.566159107 +0100
--- pgsql_spacereserve/src/backend/access/gist/gist.c 2009-01-23 14:53:17.786021437 +0100
***************
*** 299,305 ****
* XXX: If we want to change fillfactors between node and leaf, fillfactor
* = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
*/
! if (gistnospace(state->stack->page, state->itup, state->ituplen,
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
state->freespace))
{
--- 299,305 ----
* XXX: If we want to change fillfactors between node and leaf, fillfactor
* = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
*/
! if (gistnospace(state->r, state->stack->page, state->itup, state->ituplen,
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
state->freespace))
{
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gistutil.c pgsql_spacereserve/src/backend/access/gist/gistutil.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gistutil.c 2009-01-23 14:53:17.571324407 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistutil.c 2009-01-23 14:53:17.786183788 +0100
***************
*** 56,62 ****
* Check space for itup vector on page
*/
bool
! gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
{
unsigned int size = freespace,
deleted = 0;
--- 56,62 ----
* Check space for itup vector on page
*/
bool
! gistnospace(Relation rel, Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
{
unsigned int size = freespace,
deleted = 0;
***************
*** 72,78 ****
deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
}
! return (PageGetFreeSpace(page) + deleted < size);
}
bool
--- 72,79 ----
deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
}
! return (PageGetFreeSpace(page, RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) + deleted < size);
}
bool
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gistvacuum.c pgsql_spacereserve/src/backend/access/gist/gistvacuum.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gistvacuum.c 2009-01-23 14:53:17.577307424 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistvacuum.c 2009-01-23 14:53:17.786351410 +0100
***************
*** 385,391 ****
if (curlenaddon)
{
/* insert updated tuples */
! if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
{
/* there is no space on page to insert tuples */
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
--- 385,391 ----
if (curlenaddon)
{
/* insert updated tuples */
! if (gistnospace(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
{
/* there is no space on page to insert tuples */
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gistxlog.c pgsql_spacereserve/src/backend/access/gist/gistxlog.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/gist/gistxlog.c 2009-01-23 14:53:17.583642716 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistxlog.c 2009-01-23 14:53:17.786531067 +0100
***************
*** 689,695 ****
* hope, that wiil be enough space....
*/
! if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
{
/* no space left on page, so we must split */
--- 689,695 ----
* hope, that wiil be enough space....
*/
! if (gistnospace(index, pages[0], itup, lenitup, *todelete, 0))
{
/* no space left on page, so we must split */
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/hash/hashinsert.c pgsql_spacereserve/src/backend/access/hash/hashinsert.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/hash/hashinsert.c 2009-01-23 14:53:17.587065560 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashinsert.c 2009-01-23 14:53:17.786787904 +0100
***************
*** 106,112 ****
Assert(pageopaque->hasho_bucket == bucket);
/* Do the insertion */
! while (PageGetFreeSpace(page) < itemsz)
{
/*
* no space on this page; check for an overflow page
--- 106,113 ----
Assert(pageopaque->hasho_bucket == bucket);
/* Do the insertion */
! while (PageGetFreeSpace(page,RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) < itemsz)
{
/*
* no space on this page; check for an overflow page
***************
*** 138,144 ****
page = BufferGetPage(buf);
/* should fit now, given test above */
! Assert(PageGetFreeSpace(page) >= itemsz);
}
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(pageopaque->hasho_flag == LH_OVERFLOW_PAGE);
--- 139,146 ----
page = BufferGetPage(buf);
/* should fit now, given test above */
! Assert(PageGetFreeSpace(page, RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) >= itemsz);
}
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(pageopaque->hasho_flag == LH_OVERFLOW_PAGE);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/hash/hashovfl.c pgsql_spacereserve/src/backend/access/hash/hashovfl.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/hash/hashovfl.c 2009-01-23 14:53:17.595447169 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashovfl.c 2009-01-23 14:53:17.786962823 +0100
***************
*** 656,662 ****
* Walk up the bucket chain, looking for a page big enough for
* this item. Exit if we reach the read page.
*/
! while (PageGetFreeSpace(wpage) < itemsz)
{
Assert(!PageIsEmpty(wpage));
--- 656,663 ----
* Walk up the bucket chain, looking for a page big enough for
* this item. Exit if we reach the read page.
*/
! while (PageGetFreeSpace(wpage, RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) < itemsz)
{
Assert(!PageIsEmpty(wpage));
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/hash/hashpage.c pgsql_spacereserve/src/backend/access/hash/hashpage.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/hash/hashpage.c 2009-01-23 14:53:17.605903238 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashpage.c 2009-01-23 14:53:17.787146081 +0100
***************
*** 856,862 ****
itemsz = IndexTupleDSize(*itup);
itemsz = MAXALIGN(itemsz);
! if (PageGetFreeSpace(npage) < itemsz)
{
/* write out nbuf and drop lock, but keep pin */
_hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK);
--- 856,863 ----
itemsz = IndexTupleDSize(*itup);
itemsz = MAXALIGN(itemsz);
! if (PageGetFreeSpace(npage, RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) < itemsz)
{
/* write out nbuf and drop lock, but keep pin */
_hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/heapam.c pgsql_spacereserve/src/backend/access/heap/heapam.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/heapam.c 2009-01-23 14:53:17.644676111 +0100
--- pgsql_spacereserve/src/backend/access/heap/heapam.c 2009-01-23 14:53:17.787631177 +0100
***************
*** 2635,2641 ****
HeapTupleHasExternal(newtup) ||
newtup->t_len > TOAST_TUPLE_THRESHOLD);
! pagefree = PageGetHeapFreeSpace(page);
newtupsize = MAXALIGN(newtup->t_len);
--- 2635,2643 ----
HeapTupleHasExternal(newtup) ||
newtup->t_len > TOAST_TUPLE_THRESHOLD);
! pagefree = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(relation),
! RelationGetReservedSpacePerTuple(relation));
newtupsize = MAXALIGN(newtup->t_len);
***************
*** 2700,2706 ****
/* Re-acquire the lock on the old tuple's page. */
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
/* Re-check using the up-to-date free space */
! pagefree = PageGetHeapFreeSpace(page);
if (newtupsize > pagefree)
{
/*
--- 2702,2710 ----
/* Re-acquire the lock on the old tuple's page. */
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
/* Re-check using the up-to-date free space */
! pagefree = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(relation),
! RelationGetReservedSpacePerTuple(relation));
if (newtupsize > pagefree)
{
/*
***************
*** 4156,4162 ****
nowunused, nunused,
clean_move);
! freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
/*
* Note: we don't worry about updating the page's prunability hints.
--- 4160,4168 ----
nowunused, nunused,
clean_move);
! /* needed to update FSM below, we ignore reservation here, because there is
! no relation information and FSM can be inaccurate */
! freespace = PageGetHeapFreeSpace(page, 0, 0);
/*
* Note: we don't worry about updating the page's prunability hints.
***************
*** 4398,4408 ****
HeapTupleHeaderSetCmin(htup, FirstCommandId);
htup->t_ctid = xlrec->target.tid;
offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
if (offnum == InvalidOffsetNumber)
elog(PANIC, "heap_insert_redo: failed to add tuple");
! freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
--- 4404,4418 ----
HeapTupleHeaderSetCmin(htup, FirstCommandId);
htup->t_ctid = xlrec->target.tid;
+ /* XXX: Should we check reserved space here? It is probably not problem,
+ because item is added and WAL logged only if reserved space is OK */
offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true);
if (offnum == InvalidOffsetNumber)
elog(PANIC, "heap_insert_redo: failed to add tuple");
! /* needed to update FSM below, we ignore reservation here, because there is
! no relation information and FSM can be inaccurate */
! freespace = PageGetHeapFreeSpace(page, 0, 0);
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
***************
*** 4636,4642 ****
if (xlrec->new_all_visible_cleared)
PageClearAllVisible(page);
! freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
--- 4646,4654 ----
if (xlrec->new_all_visible_cleared)
PageClearAllVisible(page);
! /* needed to update FSM below, we ignore reservation here, because there is
! no relation information and FSM can be inaccurate */
! freespace = PageGetHeapFreeSpace(page,0,0);
PageSetLSN(page, lsn);
PageSetTLI(page, ThisTimeLineID);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/hio.c pgsql_spacereserve/src/backend/access/heap/hio.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/hio.c 2009-01-23 14:53:17.650378515 +0100
--- pgsql_spacereserve/src/backend/access/heap/hio.c 2009-01-23 14:53:17.787790126 +0100
***************
*** 269,275 ****
* we're done.
*/
page = BufferGetPage(buffer);
! pageFreeSpace = PageGetHeapFreeSpace(page);
if (len + saveFreeSpace <= pageFreeSpace)
{
/* use this page as future insert target, too */
--- 269,277 ----
* we're done.
*/
page = BufferGetPage(buffer);
! pageFreeSpace = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(relation),
! RelationGetReservedSpacePerTuple(relation));
if (len + saveFreeSpace <= pageFreeSpace)
{
/* use this page as future insert target, too */
***************
*** 362,368 ****
PageInit(page, BufferGetPageSize(buffer), 0);
! if (len > PageGetHeapFreeSpace(page))
{
/* We should not get here given the test at the top */
elog(PANIC, "tuple is too big: size %lu", (unsigned long) len);
--- 364,372 ----
PageInit(page, BufferGetPageSize(buffer), 0);
! if (len > PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(relation),
! RelationGetReservedSpacePerTuple(relation)))
{
/* We should not get here given the test at the top */
elog(PANIC, "tuple is too big: size %lu", (unsigned long) len);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/pruneheap.c pgsql_spacereserve/src/backend/access/heap/pruneheap.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/pruneheap.c 2009-01-23 14:53:17.654232335 +0100
--- pgsql_spacereserve/src/backend/access/heap/pruneheap.c 2009-01-23 14:53:17.787968497 +0100
***************
*** 100,106 ****
HEAP_DEFAULT_FILLFACTOR);
minfree = Max(minfree, BLCKSZ / 10);
! if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
{
/* OK, try to get exclusive buffer lock */
if (!ConditionalLockBufferForCleanup(buffer))
--- 100,109 ----
HEAP_DEFAULT_FILLFACTOR);
minfree = Max(minfree, BLCKSZ / 10);
! if (PageIsFull(page) ||
! PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(relation),
! RelationGetReservedSpacePerTuple(relation)) < minfree)
{
/* OK, try to get exclusive buffer lock */
if (!ConditionalLockBufferForCleanup(buffer))
***************
*** 112,118 ****
* prune. (We needn't recheck PageIsPrunable, since no one else could
* have pruned while we hold pin.)
*/
! if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
{
/* OK to prune (though not to remove redirects) */
(void) heap_page_prune(relation, buffer, OldestXmin, false, true);
--- 115,124 ----
* prune. (We needn't recheck PageIsPrunable, since no one else could
* have pruned while we hold pin.)
*/
! if (PageIsFull(page) ||
! PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(relation),
! RelationGetReservedSpacePerTuple(relation)))
{
/* OK to prune (though not to remove redirects) */
(void) heap_page_prune(relation, buffer, OldestXmin, false, true);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/rewriteheap.c pgsql_spacereserve/src/backend/access/heap/rewriteheap.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/heap/rewriteheap.c 2009-01-23 14:53:17.657610976 +0100
--- pgsql_spacereserve/src/backend/access/heap/rewriteheap.c 2009-01-23 14:53:17.788139931 +0100
***************
*** 600,606 ****
/* Now we can check to see if there's enough free space already. */
if (state->rs_buffer_valid)
{
! pageFreeSpace = PageGetHeapFreeSpace(page);
if (len + saveFreeSpace > pageFreeSpace)
{
--- 600,608 ----
/* Now we can check to see if there's enough free space already. */
if (state->rs_buffer_valid)
{
! pageFreeSpace = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(state->rs_new_rel),
! RelationGetReservedSpacePerTuple(state->rs_new_rel));
if (len + saveFreeSpace > pageFreeSpace)
{
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/nbtree/nbtinsert.c pgsql_spacereserve/src/backend/access/nbtree/nbtinsert.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/nbtree/nbtinsert.c 2009-01-23 14:53:17.670183347 +0100
--- pgsql_spacereserve/src/backend/access/nbtree/nbtinsert.c 2009-01-23 14:53:17.788477683 +0100
***************
*** 79,85 ****
int keysz, ScanKey scankey);
static void _bt_vacuum_one_page(Relation rel, Buffer buffer);
-
/*
* _bt_doinsert() -- Handle insertion of a single index tuple in the tree.
*
--- 79,84 ----
***************
*** 445,451 ****
*/
movedright = false;
vacuumed = false;
! while (PageGetFreeSpace(page) < itemsz)
{
Buffer rbuf;
--- 444,452 ----
*/
movedright = false;
vacuumed = false;
! while (PageGetFreeSpace(page,
! RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) < itemsz)
{
Buffer rbuf;
***************
*** 463,469 ****
*/
vacuumed = true;
! if (PageGetFreeSpace(page) >= itemsz)
break; /* OK, now we have enough space */
}
--- 464,472 ----
*/
vacuumed = true;
! if (PageGetFreeSpace(page,
! RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) >= itemsz)
break; /* OK, now we have enough space */
}
***************
*** 579,585 ****
* so this comparison is correct even though we appear to be accounting
* only for the item and not for its line pointer.
*/
! if (PageGetFreeSpace(page) < itemsz)
{
bool is_root = P_ISROOT(lpageop);
bool is_only = P_LEFTMOST(lpageop) && P_RIGHTMOST(lpageop);
--- 582,590 ----
* so this comparison is correct even though we appear to be accounting
* only for the item and not for its line pointer.
*/
! if (PageGetFreeSpace(page,
! RelationGetReservedSpacePerPage(rel),
! RelationGetReservedSpacePerTuple(rel)) < itemsz)
{
bool is_root = P_ISROOT(lpageop);
bool is_only = P_LEFTMOST(lpageop) && P_RIGHTMOST(lpageop);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/access/nbtree/nbtsort.c pgsql_spacereserve/src/backend/access/nbtree/nbtsort.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/access/nbtree/nbtsort.c 2009-01-23 14:53:17.680045695 +0100
--- pgsql_spacereserve/src/backend/access/nbtree/nbtsort.c 2009-01-23 14:53:17.788658467 +0100
***************
*** 462,468 ****
nblkno = state->btps_blkno;
last_off = state->btps_lastoff;
! pgspc = PageGetFreeSpace(npage);
itupsz = IndexTupleDSize(*itup);
itupsz = MAXALIGN(itupsz);
--- 462,470 ----
nblkno = state->btps_blkno;
last_off = state->btps_lastoff;
! pgspc = PageGetFreeSpace(npage,
! RelationGetReservedSpacePerPage(wstate->index),
! RelationGetReservedSpacePerTuple(wstate->index));
itupsz = IndexTupleDSize(*itup);
itupsz = MAXALIGN(itupsz);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/commands/vacuum.c pgsql_spacereserve/src/backend/commands/vacuum.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/commands/vacuum.c 2009-01-23 14:53:17.735830104 +0100
--- pgsql_spacereserve/src/backend/commands/vacuum.c 2009-01-23 14:53:17.789307050 +0100
***************
*** 3834,3839 ****
--- 3834,3845 ----
Size freespace = PageGetExactFreeSpace(page);
Size targetfree;
+ /* we need to reserve space, it could reserved more space because we count
+ all line pointers, not only normal */
+ freespace -= (RelationGetReservedSpacePerPage(relation)+
+ PageGetMaxOffsetNumber(page)*RelationGetReservedSpacePerTuple(relation));
+
+ freespace = freespace < 0 ? 0 : freespace;
targetfree = RelationGetTargetPageFreeSpace(relation,
HEAP_DEFAULT_FILLFACTOR);
if (freespace > targetfree)
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/commands/vacuumlazy.c pgsql_spacereserve/src/backend/commands/vacuumlazy.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/commands/vacuumlazy.c 2009-01-23 14:53:17.749343111 +0100
--- pgsql_spacereserve/src/backend/commands/vacuumlazy.c 2009-01-23 14:53:17.789497947 +0100
***************
*** 387,393 ****
PageInit(page, BufferGetPageSize(buf), 0);
empty_pages++;
}
! freespace = PageGetHeapFreeSpace(page);
MarkBufferDirty(buf);
UnlockReleaseBuffer(buf);
--- 387,395 ----
PageInit(page, BufferGetPageSize(buf), 0);
empty_pages++;
}
! freespace = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(onerel),
! RelationGetReservedSpacePerTuple(onerel));
MarkBufferDirty(buf);
UnlockReleaseBuffer(buf);
***************
*** 398,404 ****
if (PageIsEmpty(page))
{
empty_pages++;
! freespace = PageGetHeapFreeSpace(page);
if (!PageIsAllVisible(page))
{
--- 400,408 ----
if (PageIsEmpty(page))
{
empty_pages++;
! freespace = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(onerel),
! RelationGetReservedSpacePerTuple(onerel));
if (!PageIsAllVisible(page))
{
***************
*** 623,629 ****
vacuumed_pages++;
}
! freespace = PageGetHeapFreeSpace(page);
/* Update the all-visible flag on the page */
if (!PageIsAllVisible(page) && all_visible)
--- 627,635 ----
vacuumed_pages++;
}
! freespace = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(onerel),
! RelationGetReservedSpacePerTuple(onerel));
/* Update the all-visible flag on the page */
if (!PageIsAllVisible(page) && all_visible)
***************
*** 764,770 ****
/* Now that we've compacted the page, record its available space */
page = BufferGetPage(buf);
! freespace = PageGetHeapFreeSpace(page);
UnlockReleaseBuffer(buf);
RecordPageWithFreeSpace(onerel, tblk, freespace);
--- 770,778 ----
/* Now that we've compacted the page, record its available space */
page = BufferGetPage(buf);
! freespace = PageGetHeapFreeSpace(page,
! RelationGetReservedSpacePerPage(onerel),
! RelationGetReservedSpacePerTuple(onerel));
UnlockReleaseBuffer(buf);
RecordPageWithFreeSpace(onerel, tblk, freespace);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/backend/storage/page/bufpage.c pgsql_spacereserve/src/backend/storage/page/bufpage.c
*** pgsql_spacereserve.7b2d095bfec6/src/backend/storage/page/bufpage.c 2009-01-23 14:53:17.759702299 +0100
--- pgsql_spacereserve/src/backend/storage/page/bufpage.c 2009-01-23 14:53:17.789881019 +0100
***************
*** 482,497 ****
* PageGetHeapFreeSpace on heap pages.
*/
Size
! PageGetFreeSpace(Page page)
{
int space;
/*
* Use signed arithmetic here so that we behave sensibly if pd_lower >
* pd_upper.
*/
space = (int) ((PageHeader) page)->pd_upper -
! (int) ((PageHeader) page)->pd_lower;
if (space < (int) sizeof(ItemIdData))
return 0;
--- 482,502 ----
* PageGetHeapFreeSpace on heap pages.
*/
Size
! PageGetFreeSpace(Page page, int rs_perpage, int rs_pertuple)
{
int space;
+ int reserved_space;
+
+ /* Count reserved space. It is used for in-place upgrade. Because this functions
+ is usually called before PageAddItem we need to count with new item */
+ reserved_space = rs_perpage+rs_pertuple*(PageGetMaxOffsetNumber(page)+1);
/*
* Use signed arithmetic here so that we behave sensibly if pd_lower >
* pd_upper.
*/
space = (int) ((PageHeader) page)->pd_upper -
! (int) ((PageHeader) page)->pd_lower - reserved_space;
if (space < (int) sizeof(ItemIdData))
return 0;
***************
*** 539,549 ****
* 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,
--- 544,554 ----
* on the number of line pointers, we make this extra check.)
*/
Size
! PageGetHeapFreeSpace(Page page, int rs_perpage, int rs_pertuple)
{
Size space;
! space = PageGetFreeSpace(page, rs_perpage, rs_pertuple);
if (space > 0)
{
OffsetNumber offnum,
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/include/access/gist_private.h pgsql_spacereserve/src/include/access/gist_private.h
*** pgsql_spacereserve.7b2d095bfec6/src/include/access/gist_private.h 2009-01-23 14:53:17.774314511 +0100
--- pgsql_spacereserve/src/include/access/gist_private.h 2009-01-23 14:53:17.790859139 +0100
***************
*** 279,285 ****
extern Datum gistoptions(PG_FUNCTION_ARGS);
extern bool gistfitpage(IndexTuple *itvec, int len);
! extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
extern void gistcheckpage(Relation rel, Buffer buf);
extern Buffer gistNewBuffer(Relation r);
extern void gistfillbuffer(Page page, IndexTuple *itup, int len,
--- 279,285 ----
extern Datum gistoptions(PG_FUNCTION_ARGS);
extern bool gistfitpage(IndexTuple *itvec, int len);
! extern bool gistnospace(Relation rel, Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
extern void gistcheckpage(Relation rel, Buffer buf);
extern Buffer gistNewBuffer(Relation r);
extern void gistfillbuffer(Page page, IndexTuple *itup, int len,
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/include/access/reloptions.h pgsql_spacereserve/src/include/access/reloptions.h
*** pgsql_spacereserve.7b2d095bfec6/src/include/access/reloptions.h 2009-01-23 14:53:17.774952860 +0100
--- pgsql_spacereserve/src/include/access/reloptions.h 2009-01-23 14:53:17.791013450 +0100
***************
*** 32,37 ****
--- 32,38 ----
/* kinds supported by reloptions */
typedef enum relopt_kind
{
+ RELOPT_KIND_ALL,
RELOPT_KIND_HEAP,
/* XXX do we need a separate kind for TOAST tables? */
RELOPT_KIND_BTREE,
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/include/storage/bufpage.h pgsql_spacereserve/src/include/storage/bufpage.h
*** pgsql_spacereserve.7b2d095bfec6/src/include/storage/bufpage.h 2009-01-23 14:53:17.782874050 +0100
--- pgsql_spacereserve/src/include/storage/bufpage.h 2009-01-23 14:53:17.791850824 +0100
***************
*** 361,366 ****
--- 361,374 ----
#define PageClearPrunable(page) \
(((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
+ /* PageGetMaxDataSpace
+ * It returns maximal possible amount of space for data on the page. If page has
+ * already item pointers we take them as a non-data space. The reason is that we
+ * cannot reclaim this space for data if it is marked as dead, beacause indexes
+ * can have a pointer on this item.
+ */
+ #define PageGetMaxDataSpace(page) \
+ ( ((PageHeader) (page))->pd_special - MAXALIGN(((PageHeader) (page))->pd_lower) )
/* ----------------------------------------------------------------
* extern declarations
***************
*** 376,384 ****
extern Page PageGetTempPageCopySpecial(Page page);
extern void PageRestoreTempPage(Page tempPage, Page oldPage);
extern void PageRepairFragmentation(Page page);
! extern Size PageGetFreeSpace(Page page);
extern Size PageGetExactFreeSpace(Page page);
! extern Size PageGetHeapFreeSpace(Page page);
extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
--- 384,392 ----
extern Page PageGetTempPageCopySpecial(Page page);
extern void PageRestoreTempPage(Page tempPage, Page oldPage);
extern void PageRepairFragmentation(Page page);
! extern Size PageGetFreeSpace(Page page, int rs_perpage, int rs_pertuple);
extern Size PageGetExactFreeSpace(Page page);
! extern Size PageGetHeapFreeSpace(Page page, int rs_perpage, int rs_pertuple);
extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
diff -Nrc pgsql_spacereserve.7b2d095bfec6/src/include/utils/rel.h pgsql_spacereserve/src/include/utils/rel.h
*** pgsql_spacereserve.7b2d095bfec6/src/include/utils/rel.h 2009-01-23 14:53:17.784845739 +0100
--- pgsql_spacereserve/src/include/utils/rel.h 2009-01-23 14:53:17.792111594 +0100
***************
*** 218,223 ****
--- 218,225 ----
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int fillfactor; /* page fill factor in percent (0..100) */
+ int rs_perpage; /* page reserved space per page for in-place upgrade in bytes */
+ int rs_pertuple; /* page reserved space per tuple for in-place upgrade in bytes */
} StdRdOptions;
#define HEAP_MIN_FILLFACTOR 10
***************
*** 232,237 ****
--- 234,255 ----
((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
/*
+ * RelationGetReservedSpacePerPage
+ * Returns the relation's reserved space per page.
+ */
+ #define RelationGetReservedSpacePerPage(relation) \
+ ((relation)->rd_options ? \
+ ((StdRdOptions *) (relation)->rd_options)->rs_perpage : 0)
+
+ /*
+ * RelationGetReservedSpacePerTuple
+ * Returns the relation's reserved space per tuple.
+ */
+ #define RelationGetReservedSpacePerTuple(relation) \
+ ((relation)->rd_options ? \
+ ((StdRdOptions *) (relation)->rd_options)->rs_pertuple : 0)
+
+ /*
* RelationGetTargetPageUsage
* Returns the relation's desired space usage per page in bytes.
*/
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers