diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/common/reloptions.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/common/reloptions.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/common/reloptions.c	2008-11-08 23:19:47.795930570 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/common/reloptions.c	2008-11-08 23:19:47.910535376 +0100
***************
*** 286,330 ****
  default_reloptions(Datum reloptions, bool validate,
  				   int minFillfactor, int defaultFillfactor)
  {
! 	static const char *const default_keywords[1] = {"fillfactor"};
! 	char	   *values[1];
! 	int			fillfactor;
  	StdRdOptions *result;
  
! 	parseRelOptions(reloptions, 1, default_keywords, values, validate);
  
  	/*
  	 * If no options, we can just return NULL rather than doing anything.
  	 * (defaultFillfactor is thus not used, but we require callers to pass it
  	 * anyway since we would need it if more options were added.)
  	 */
! 	if (values[0] == NULL)
  		return NULL;
  
! 	if (!parse_int(values[0], &fillfactor, 0, NULL))
  	{
! 		if (validate)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 					 errmsg("fillfactor must be an integer: \"%s\"",
! 							values[0])));
! 		return NULL;
  	}
  
! 	if (fillfactor < minFillfactor || fillfactor > 100)
  	{
! 		if (validate)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 					 errmsg("fillfactor=%d is out of range (should be between %d and 100)",
! 							fillfactor, minFillfactor)));
! 		return NULL;
  	}
  
  	result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
  	SET_VARSIZE(result, sizeof(StdRdOptions));
  
  	result->fillfactor = fillfactor;
  
  	return (bytea *) result;
  }
--- 286,360 ----
  default_reloptions(Datum reloptions, bool validate,
  				   int minFillfactor, int defaultFillfactor)
  {
! 	static const char *const default_keywords[2] = {"fillfactor","reservedspace"};
! 	char	   *values[2];
! 	int			fillfactor=defaultFillfactor;
! 	int			reservedspace=0;
  	StdRdOptions *result;
  
! 	parseRelOptions(reloptions, 2, default_keywords, values, validate);
  
  	/*
  	 * If no options, we can just return NULL rather than doing anything.
  	 * (defaultFillfactor is thus not used, but we require callers to pass it
  	 * anyway since we would need it if more options were added.)
  	 */
! 	if ((values[0] == NULL) && (values[1] == NULL))
  		return NULL;
  
! 	/* fill factor */
! 	if (values[0] != NULL)
  	{
! 		if (!parse_int(values[0], &fillfactor, 0, NULL))
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("fillfactor must be an integer: \"%s\"",
! 								values[0])));
! 			return NULL;
! 		}
! 
! 		if (fillfactor < minFillfactor || fillfactor > 100)
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("fillfactor=%d is out of range (should be between %d and 100)",
! 								fillfactor, minFillfactor)));
! 			return NULL;
! 		}
  	}
  
! 	/* reserved space */
! 	if (values[1] != NULL)
  	{
! 		if (!parse_int(values[1], &reservedspace, 0, NULL))
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("reservedspace must be an integer: \"%s\"",
! 								values[1])));
! 			return NULL;
! 		}
! 
! 		if (reservedspace < 0 || reservedspace > BLCKSZ/4)
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("reservedspace=%d is out of range (should be between 0 and %d)",
! 								reservedspace, BLCKSZ/4)));
! 			return NULL;
! 		}
  	}
  
  	result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
  	SET_VARSIZE(result, sizeof(StdRdOptions));
  
  	result->fillfactor = fillfactor;
+ 	result->reservedspace = reservedspace;
  
  	return (bytea *) result;
  }
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/gin/ginentrypage.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/gin/ginentrypage.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/gin/ginentrypage.c	2008-11-08 23:19:47.799408407 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/gin/ginentrypage.c	2008-11-08 23:19:47.911560880 +0100
***************
*** 314,320 ****
  		itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
  	}
  
! 	if (PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
  		return true;
  
  	return false;
--- 314,321 ----
  		itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
  	}
  
! 	if (PageGetFreeSpace(page) - RelationGetReservedSpace(btree->index) + itupsz
! 			 >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
  		return true;
  
  	return false;
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/hash/hashinsert.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/hash/hashinsert.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/hash/hashinsert.c	2008-11-08 23:19:47.802614678 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/hash/hashinsert.c	2008-11-08 23:19:47.912878140 +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,112 ----
  	Assert(pageopaque->hasho_bucket == bucket);
  
  	/* Do the insertion */
! 	while (PageGetFreeSpace(page)-RelationGetReservedSpace(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);
--- 138,144 ----
  			page = BufferGetPage(buf);
  
  			/* should fit now, given test above */
! 			Assert(PageGetFreeSpace(page)-RelationGetReservedSpace(rel) >= itemsz);
  		}
  		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
  		Assert(pageopaque->hasho_flag == LH_OVERFLOW_PAGE);
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/hash/hashovfl.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/hash/hashovfl.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/hash/hashovfl.c	2008-11-08 23:19:47.810863015 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/hash/hashovfl.c	2008-11-08 23:19:47.915444493 +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,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)-RelationGetReservedSpace(rel) < itemsz)
  			{
  				Assert(!PageIsEmpty(wpage));
  
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/hash/hashpage.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/hash/hashpage.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/hash/hashpage.c	2008-11-08 23:19:47.821028802 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/hash/hashpage.c	2008-11-08 23:19:47.918694933 +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,862 ----
  			itemsz = IndexTupleDSize(*itup);
  			itemsz = MAXALIGN(itemsz);
  
! 			if (PageGetFreeSpace(npage)-RelationGetReservedSpace(rel) < itemsz)
  			{
  				/* write out nbuf and drop lock, but keep pin */
  				_hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK);
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/heap/heapam.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/heapam.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/heap/heapam.c	2008-11-08 23:19:47.868737614 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/heapam.c	2008-11-08 23:19:47.930477950 +0100
***************
*** 2593,2599 ****
  					  HeapTupleHasExternal(newtup) ||
  					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
  
! 	pagefree = PageGetHeapFreeSpace(page);
  
  	newtupsize = MAXALIGN(newtup->t_len);
  
--- 2593,2599 ----
  					  HeapTupleHasExternal(newtup) ||
  					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
  
! 	pagefree = PageGetHeapFreeSpace(page)-RelationGetReservedSpace(relation);
  
  	newtupsize = MAXALIGN(newtup->t_len);
  
***************
*** 2658,2664 ****
  			/* 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)
  			{
  				/*
--- 2658,2664 ----
  			/* 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)-RelationGetReservedSpace(relation);
  			if (newtupsize > pagefree)
  			{
  				/*
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/heap/hio.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/hio.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/heap/hio.c	2008-11-08 23:19:47.874146098 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/hio.c	2008-11-08 23:19:47.932167154 +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,275 ----
  		 * we're done.
  		 */
  		page = BufferGetPage(buffer);
! 		pageFreeSpace = PageGetHeapFreeSpace(page)-RelationGetReservedSpace(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);
--- 362,368 ----
  
  	PageInit(page, BufferGetPageSize(buffer), 0);
  
! 	if (len > PageGetHeapFreeSpace(page)-RelationGetReservedSpace(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.9e46c188067f/src/backend/access/heap/pruneheap.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/pruneheap.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/heap/pruneheap.c	2008-11-08 23:19:47.877897804 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/pruneheap.c	2008-11-08 23:19:47.933351529 +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,106 ----
  											 HEAP_DEFAULT_FILLFACTOR);
  	minfree = Max(minfree, BLCKSZ / 10);
  
! 	if (PageIsFull(page) || PageGetHeapFreeSpace(page)-RelationGetReservedSpace(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);
--- 112,118 ----
  		 * prune. (We needn't recheck PageIsPrunable, since no one else could
  		 * have pruned while we hold pin.)
  		 */
! 		if (PageIsFull(page) || PageGetHeapFreeSpace(page)-RelationGetReservedSpace(relation) < minfree)
  		{
  			/* OK to prune (though not to remove redirects) */
  			(void) heap_page_prune(relation, buffer, OldestXmin, false, true);
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/heap/rewriteheap.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/rewriteheap.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/heap/rewriteheap.c	2008-11-08 23:19:47.881338490 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/heap/rewriteheap.c	2008-11-08 23:19:47.934390304 +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,606 ----
  	/* Now we can check to see if there's enough free space already. */
  	if (state->rs_buffer_valid)
  	{
! 		pageFreeSpace = PageGetHeapFreeSpace(page)-RelationGetReservedSpace(state->rs_new_rel);
  
  		if (len + saveFreeSpace > pageFreeSpace)
  		{
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/nbtree/nbtinsert.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/nbtree/nbtinsert.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/nbtree/nbtinsert.c	2008-11-08 23:19:47.891455345 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/nbtree/nbtinsert.c	2008-11-08 23:19:47.938184262 +0100
***************
*** 445,451 ****
  	 */
  	movedright = false;
  	vacuumed = false;
! 	while (PageGetFreeSpace(page) < itemsz)
  	{
  		Buffer		rbuf;
  
--- 445,451 ----
  	 */
  	movedright = false;
  	vacuumed = false;
! 	while (PageGetFreeSpace(page)-RelationGetReservedSpace(rel) < itemsz)
  	{
  		Buffer		rbuf;
  
***************
*** 463,469 ****
  			 */
  			vacuumed = true;
  
! 			if (PageGetFreeSpace(page) >= itemsz)
  				break;			/* OK, now we have enough space */
  		}
  
--- 463,469 ----
  			 */
  			vacuumed = true;
  
! 			if (PageGetFreeSpace(page)-RelationGetReservedSpace(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);
--- 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)-RelationGetReservedSpace(rel) < itemsz)
  	{
  		bool		is_root = P_ISROOT(lpageop);
  		bool		is_only = P_LEFTMOST(lpageop) && P_RIGHTMOST(lpageop);
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/access/nbtree/nbtsort.c pgsql_spacereserve.c901d4bb8cca/src/backend/access/nbtree/nbtsort.c
*** pgsql_spacereserve.9e46c188067f/src/backend/access/nbtree/nbtsort.c	2008-11-08 23:19:47.894508546 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/access/nbtree/nbtsort.c	2008-11-08 23:19:47.941241651 +0100
***************
*** 462,468 ****
  	nblkno = state->btps_blkno;
  	last_off = state->btps_lastoff;
  
! 	pgspc = PageGetFreeSpace(npage);
  	itupsz = IndexTupleDSize(*itup);
  	itupsz = MAXALIGN(itupsz);
  
--- 462,468 ----
  	nblkno = state->btps_blkno;
  	last_off = state->btps_lastoff;
  
! 	pgspc = PageGetFreeSpace(npage)-RelationGetReservedSpace(wstate->index);
  	itupsz = IndexTupleDSize(*itup);
  	itupsz = MAXALIGN(itupsz);
  
diff -Nrc pgsql_spacereserve.9e46c188067f/src/backend/commands/vacuumlazy.c pgsql_spacereserve.c901d4bb8cca/src/backend/commands/vacuumlazy.c
*** pgsql_spacereserve.9e46c188067f/src/backend/commands/vacuumlazy.c	2008-11-08 23:19:47.898479299 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/backend/commands/vacuumlazy.c	2008-11-08 23:19:47.945127252 +0100
***************
*** 343,349 ****
  				PageInit(page, BufferGetPageSize(buf), 0);
  				empty_pages++;
  			}
! 			freespace = PageGetHeapFreeSpace(page);
  			MarkBufferDirty(buf);
  			UnlockReleaseBuffer(buf);
  
--- 343,349 ----
  				PageInit(page, BufferGetPageSize(buf), 0);
  				empty_pages++;
  			}
! 			freespace = PageGetHeapFreeSpace(page)-RelationGetReservedSpace(onerel);
  			MarkBufferDirty(buf);
  			UnlockReleaseBuffer(buf);
  
***************
*** 354,360 ****
  		if (PageIsEmpty(page))
  		{
  			empty_pages++;
! 			freespace = PageGetHeapFreeSpace(page);
  			UnlockReleaseBuffer(buf);
  			RecordPageWithFreeSpace(onerel, blkno, freespace);
  			continue;
--- 354,360 ----
  		if (PageIsEmpty(page))
  		{
  			empty_pages++;
! 			freespace = PageGetHeapFreeSpace(page)-RelationGetReservedSpace(onerel);
  			UnlockReleaseBuffer(buf);
  			RecordPageWithFreeSpace(onerel, blkno, freespace);
  			continue;
***************
*** 524,530 ****
  			vacuumed_pages++;
  		}
  
! 		freespace = PageGetHeapFreeSpace(page);
  
  		/* Remember the location of the last page with nonremovable tuples */
  		if (hastup)
--- 524,530 ----
  			vacuumed_pages++;
  		}
  
! 		freespace = PageGetHeapFreeSpace(page)-RelationGetReservedSpace(onerel);
  
  		/* Remember the location of the last page with nonremovable tuples */
  		if (hastup)
***************
*** 626,632 ****
  
  		/* Now that we've compacted the page, record its available space */
  		page = BufferGetPage(buf);
! 		freespace = PageGetHeapFreeSpace(page);
  
  		UnlockReleaseBuffer(buf);
  		RecordPageWithFreeSpace(onerel, tblk, freespace);
--- 626,632 ----
  
  		/* Now that we've compacted the page, record its available space */
  		page = BufferGetPage(buf);
! 		freespace = PageGetHeapFreeSpace(page)-RelationGetReservedSpace(onerel);
  
  		UnlockReleaseBuffer(buf);
  		RecordPageWithFreeSpace(onerel, tblk, freespace);
diff -Nrc pgsql_spacereserve.9e46c188067f/src/include/utils/rel.h pgsql_spacereserve.c901d4bb8cca/src/include/utils/rel.h
*** pgsql_spacereserve.9e46c188067f/src/include/utils/rel.h	2008-11-08 23:19:47.900403231 +0100
--- pgsql_spacereserve.c901d4bb8cca/src/include/utils/rel.h	2008-11-08 23:19:47.946913616 +0100
***************
*** 214,219 ****
--- 214,220 ----
  {
  	int32		vl_len_;		/* varlena header (do not touch directly!) */
  	int			fillfactor;		/* page fill factor in percent (0..100) */
+ 	int			reservedspace;  /* page reserved space for in-place upgrade in bytes */
  } StdRdOptions;
  
  #define HEAP_MIN_FILLFACTOR			10
***************
*** 228,233 ****
--- 229,242 ----
  	 ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
  
  /*
+  * RelationGetReservedSpace
+  *		Returns the relation's reserved space.
+  */
+ #define RelationGetReservedSpace(relation) \
+ 	((relation)->rd_options ? \
+ 	 ((StdRdOptions *) (relation)->rd_options)->reservedspace : 0)
+ 
+ /*
   * RelationGetTargetPageUsage
   *		Returns the relation's desired space usage per page in bytes.
   */
