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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers