I attached patch which add capability to reserve space on page for future upgrade. It is mandatory for future in-place upgrade implementation. This patch contains basic infrastructure not preupgrade script itself. I'm going to send WIP preupgrade script today in separate mail.

This patch contains following modifications:

1) I added datpreupgstatus and relpreupgstatus attribute into pg_database and pg_class. Original idea was to use only flag, but I need more info for tracking several process status (like 0 - not set, 1 - reserved space set, 2 - reservation is finished and so on).

I'm not sure if datpreupgstatus will be useful, but I think better is to have it here.

2) I added two reloption rs_perpage and rs_pertuple for setup amount of reserved space. I think these two attributes are enough for configure all case. Keep in mind that for each relation could be these parameters different.

3) I adapted source code to respect new reloptions. Basic idea of it is that before someone call PageAddItem it checks free space on a page (PageGetFreeSpace...). I modify PageGetFreeSpace function to count reserved space. Unfortunately, it requires additional parameters.

It works, but I'm not sure if any external enhancement cannot shortcut this and call PageAddItem without PageFreeSpace call.

I'm thinking now about refactoring it and replace PageGetFreeSpace(Heap) functions with RelPageGetFreeSpace and add new function RelPageAddItem. RelPageAddItem will replace all direct call of PageAddItem.

        Comments, ideas?

                thanks Zdenek

diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/common/reloptions.c pgsql_spacereserve/src/backend/access/common/reloptions.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/common/reloptions.c	2008-12-12 11:36:42.140563612 +0100
--- pgsql_spacereserve/src/backend/access/common/reloptions.c	2008-12-12 11:36:42.233907101 +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,386 ----
  default_reloptions(Datum reloptions, bool validate,
  				   int minFillfactor, int defaultFillfactor)
  {
! 	static const char *const default_keywords[3] = {"fillfactor","rs_perpage","rs_pertuple"};
! 	char	   *values[3];
! 	int			fillfactor=defaultFillfactor;
! 	int			rs_perpage=0;
! 	int			rs_pertuple=0;
  	StdRdOptions *result;
  
! 	parseRelOptions(reloptions, 3, 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) && (values[2] == 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 per page */
! 	if (values[1] != NULL)
  	{
! 		if (!parse_int(values[1], &rs_perpage, 0, NULL))
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_perpage must be an integer: \"%s\"",
! 								values[1])));
! 			return NULL;
! 		}
! 
! 		if (rs_perpage < 0 || rs_perpage > BLCKSZ/4)
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_perpage=%d is out of range (should be between 0 and %d)",
! 								rs_perpage, BLCKSZ/4)));
! 			return NULL;
! 		}
! 	}
! 
! 	/* reserved space per tuple */
! 	if (values[2] != NULL)
! 	{
! 		if (!parse_int(values[2], &rs_pertuple, 0, NULL))
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_pertuple must be an integer: \"%s\"",
! 								values[2])));
! 			return NULL;
! 		}
! 
! 		if (rs_pertuple < 0 || rs_pertuple > BLCKSZ/16)
! 		{
! 			if (validate)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! 						 errmsg("rs_pertuple=%d is out of range (should be between 0 and %d)",
! 								rs_perpage, BLCKSZ/16)));
! 			return NULL;
! 		}
  	}
  
  	result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
  	SET_VARSIZE(result, sizeof(StdRdOptions));
  
  	result->fillfactor = fillfactor;
+ 	result->rs_perpage = rs_perpage;
+ 	result->rs_pertuple = rs_pertuple;
  
  	return (bytea *) result;
  }
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gin/ginentrypage.c pgsql_spacereserve/src/backend/access/gin/ginentrypage.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gin/ginentrypage.c	2008-12-12 11:36:42.142428004 +0100
--- pgsql_spacereserve/src/backend/access/gin/ginentrypage.c	2008-12-12 11:36:42.234193186 +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.84e2e9c42ef7/src/backend/access/gist/gist.c pgsql_spacereserve/src/backend/access/gist/gist.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gist.c	2008-12-12 11:36:42.145173957 +0100
--- pgsql_spacereserve/src/backend/access/gist/gist.c	2008-12-12 11:36:42.234512343 +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.84e2e9c42ef7/src/backend/access/gist/gistutil.c pgsql_spacereserve/src/backend/access/gist/gistutil.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistutil.c	2008-12-12 11:36:42.146684458 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistutil.c	2008-12-12 11:36:42.234672831 +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.84e2e9c42ef7/src/backend/access/gist/gistvacuum.c pgsql_spacereserve/src/backend/access/gist/gistvacuum.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistvacuum.c	2008-12-12 11:36:42.148527110 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistvacuum.c	2008-12-12 11:36:42.234839579 +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.84e2e9c42ef7/src/backend/access/gist/gistxlog.c pgsql_spacereserve/src/backend/access/gist/gistxlog.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/gist/gistxlog.c	2008-12-12 11:36:42.150448436 +0100
--- pgsql_spacereserve/src/backend/access/gist/gistxlog.c	2008-12-12 11:36:42.235025843 +0100
***************
*** 688,694 ****
  			 * hope, that wiil be enough space....
  			 */
  
! 			if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
  			{
  
  				/* no space left on page, so we must split */
--- 688,694 ----
  			 * 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.84e2e9c42ef7/src/backend/access/hash/hashinsert.c pgsql_spacereserve/src/backend/access/hash/hashinsert.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashinsert.c	2008-12-12 11:36:42.151473973 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashinsert.c	2008-12-12 11:36:42.235298303 +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.84e2e9c42ef7/src/backend/access/hash/hashovfl.c pgsql_spacereserve/src/backend/access/hash/hashovfl.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashovfl.c	2008-12-12 11:36:42.154025625 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashovfl.c	2008-12-12 11:36:42.235471115 +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.84e2e9c42ef7/src/backend/access/hash/hashpage.c pgsql_spacereserve/src/backend/access/hash/hashpage.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/hash/hashpage.c	2008-12-12 11:36:42.157263189 +0100
--- pgsql_spacereserve/src/backend/access/hash/hashpage.c	2008-12-12 11:36:42.235655078 +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.84e2e9c42ef7/src/backend/access/heap/heapam.c pgsql_spacereserve/src/backend/access/heap/heapam.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/heapam.c	2008-12-12 11:36:42.169918324 +0100
--- pgsql_spacereserve/src/backend/access/heap/heapam.c	2008-12-12 11:36:42.236162107 +0100
***************
*** 2634,2640 ****
  					  HeapTupleHasExternal(newtup) ||
  					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
  
! 	pagefree = PageGetHeapFreeSpace(page);
  
  	newtupsize = MAXALIGN(newtup->t_len);
  
--- 2634,2642 ----
  					  HeapTupleHasExternal(newtup) ||
  					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
  
! 	pagefree = PageGetHeapFreeSpace(page,
! 									RelationGetReservedSpacePerPage(relation),
! 									RelationGetReservedSpacePerTuple(relation));
  
  	newtupsize = MAXALIGN(newtup->t_len);
  
***************
*** 2699,2705 ****
  			/* 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)
  			{
  				/*
--- 2701,2709 ----
  			/* 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)
  			{
  				/*
***************
*** 4155,4161 ****
  							nowunused, nunused,
  							clean_move);
  
! 	freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
  
  	/*
  	 * Note: we don't worry about updating the page's prunability hints.
--- 4159,4167 ----
  							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.
***************
*** 4397,4407 ****
  	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);
--- 4403,4417 ----
  	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);
***************
*** 4635,4641 ****
  	if (xlrec->new_all_visible_cleared)
  		PageClearAllVisible(page);
  
! 	freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
  
  	PageSetLSN(page, lsn);
  	PageSetTLI(page, ThisTimeLineID);
--- 4645,4653 ----
  	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.84e2e9c42ef7/src/backend/access/heap/hio.c pgsql_spacereserve/src/backend/access/heap/hio.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/hio.c	2008-12-12 11:36:42.172119886 +0100
--- pgsql_spacereserve/src/backend/access/heap/hio.c	2008-12-12 11:36:42.236322663 +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.84e2e9c42ef7/src/backend/access/heap/pruneheap.c pgsql_spacereserve/src/backend/access/heap/pruneheap.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/pruneheap.c	2008-12-12 11:36:42.173608706 +0100
--- pgsql_spacereserve/src/backend/access/heap/pruneheap.c	2008-12-12 11:36:42.236500498 +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.84e2e9c42ef7/src/backend/access/heap/rewriteheap.c pgsql_spacereserve/src/backend/access/heap/rewriteheap.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/heap/rewriteheap.c	2008-12-12 11:36:42.174776964 +0100
--- pgsql_spacereserve/src/backend/access/heap/rewriteheap.c	2008-12-12 11:36:42.236670422 +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.84e2e9c42ef7/src/backend/access/nbtree/nbtinsert.c pgsql_spacereserve/src/backend/access/nbtree/nbtinsert.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/nbtree/nbtinsert.c	2008-12-12 11:36:42.179054235 +0100
--- pgsql_spacereserve/src/backend/access/nbtree/nbtinsert.c	2008-12-12 11:36:42.237013648 +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.84e2e9c42ef7/src/backend/access/nbtree/nbtsort.c pgsql_spacereserve/src/backend/access/nbtree/nbtsort.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/access/nbtree/nbtsort.c	2008-12-12 11:36:42.182353003 +0100
--- pgsql_spacereserve/src/backend/access/nbtree/nbtsort.c	2008-12-12 11:36:42.237190941 +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.84e2e9c42ef7/src/backend/commands/dbcommands.c pgsql_spacereserve/src/backend/commands/dbcommands.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/dbcommands.c	2008-12-12 11:36:42.188926495 +0100
--- pgsql_spacereserve/src/backend/commands/dbcommands.c	2008-12-12 11:36:42.237524718 +0100
***************
*** 518,523 ****
--- 518,524 ----
  	new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
  	new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
  	new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
+ 	new_record[Anum_pg_database_datpreupgstatus - 1] = Int32GetDatum(0);
  
  	/*
  	 * We deliberately set datconfig and datacl to defaults (NULL), rather
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/vacuum.c pgsql_spacereserve/src/backend/commands/vacuum.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/vacuum.c	2008-12-12 11:36:42.200107235 +0100
--- pgsql_spacereserve/src/backend/commands/vacuum.c	2008-12-12 11:36:42.237837082 +0100
***************
*** 3796,3801 ****
--- 3796,3807 ----
  	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.84e2e9c42ef7/src/backend/commands/vacuumlazy.c pgsql_spacereserve/src/backend/commands/vacuumlazy.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/commands/vacuumlazy.c	2008-12-12 11:36:42.204215141 +0100
--- pgsql_spacereserve/src/backend/commands/vacuumlazy.c	2008-12-12 11:36:42.238023285 +0100
***************
*** 370,376 ****
  				PageInit(page, BufferGetPageSize(buf), 0);
  				empty_pages++;
  			}
! 			freespace = PageGetHeapFreeSpace(page);
  			MarkBufferDirty(buf);
  			UnlockReleaseBuffer(buf);
  
--- 370,378 ----
  				PageInit(page, BufferGetPageSize(buf), 0);
  				empty_pages++;
  			}
! 			freespace = PageGetHeapFreeSpace(page,
! 						 	 				 RelationGetReservedSpacePerPage(onerel),
! 						 	 				 RelationGetReservedSpacePerTuple(onerel));
  			MarkBufferDirty(buf);
  			UnlockReleaseBuffer(buf);
  
***************
*** 381,387 ****
  		if (PageIsEmpty(page))
  		{
  			empty_pages++;
! 			freespace = PageGetHeapFreeSpace(page);
  
  			if (!PageIsAllVisible(page))
  			{
--- 383,391 ----
  		if (PageIsEmpty(page))
  		{
  			empty_pages++;
! 			freespace = PageGetHeapFreeSpace(page,
! 						 	 				 RelationGetReservedSpacePerPage(onerel),
! 						 	 				 RelationGetReservedSpacePerTuple(onerel));
  
  			if (!PageIsAllVisible(page))
  			{
***************
*** 606,612 ****
  			vacuumed_pages++;
  		}
  
! 		freespace = PageGetHeapFreeSpace(page);
  
  		/* Update the all-visible flag on the page */
  		if (!PageIsAllVisible(page) && all_visible)
--- 610,618 ----
  			vacuumed_pages++;
  		}
  
! 		freespace = PageGetHeapFreeSpace(page,
! 						 	 			 RelationGetReservedSpacePerPage(onerel),
! 						 	 			 RelationGetReservedSpacePerTuple(onerel));
  
  		/* Update the all-visible flag on the page */
  		if (!PageIsAllVisible(page) && all_visible)
***************
*** 747,753 ****
  
  		/* Now that we've compacted the page, record its available space */
  		page = BufferGetPage(buf);
! 		freespace = PageGetHeapFreeSpace(page);
  
  		UnlockReleaseBuffer(buf);
  		RecordPageWithFreeSpace(onerel, tblk, freespace);
--- 753,761 ----
  
  		/* 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.84e2e9c42ef7/src/backend/storage/page/bufpage.c pgsql_spacereserve/src/backend/storage/page/bufpage.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/storage/page/bufpage.c	2008-12-12 11:36:42.207450074 +0100
--- pgsql_spacereserve/src/backend/storage/page/bufpage.c	2008-12-12 11:36:42.238404271 +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.84e2e9c42ef7/src/backend/utils/cache/relcache.c pgsql_spacereserve/src/backend/utils/cache/relcache.c
*** pgsql_spacereserve.84e2e9c42ef7/src/backend/utils/cache/relcache.c	2008-12-12 11:36:42.220122442 +0100
--- pgsql_spacereserve/src/backend/utils/cache/relcache.c	2008-12-12 11:36:42.238944249 +0100
***************
*** 2409,2414 ****
--- 2409,2415 ----
  	rel->rd_rel->relhasoids = rel->rd_att->tdhasoid;
  	rel->rd_rel->relnatts = natts;
  	rel->rd_rel->reltype = InvalidOid;
+ 	rel->rd_rel->relpreupgstatus = 0;
  	/* needed when bootstrapping: */
  	rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
  
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/access/gist_private.h pgsql_spacereserve/src/include/access/gist_private.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/access/gist_private.h	2008-12-12 11:36:42.221738954 +0100
--- pgsql_spacereserve/src/include/access/gist_private.h	2008-12-12 11:36:42.239308369 +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.84e2e9c42ef7/src/include/catalog/pg_attribute.h pgsql_spacereserve/src/include/catalog/pg_attribute.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_attribute.h	2008-12-12 11:36:42.225592264 +0100
--- pgsql_spacereserve/src/include/catalog/pg_attribute.h	2008-12-12 11:36:42.239591992 +0100
***************
*** 419,426 ****
  { 1259, {"relhastriggers"},16, -1,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relhassubclass"},16, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relfrozenxid"},  28, -1,	4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
! { 1259, {"relacl"},		 1034, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
! { 1259, {"reloptions"},  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
  
  DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0));
  DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0));
--- 419,427 ----
  { 1259, {"relhastriggers"},16, -1,	1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relhassubclass"},16, -1,	1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
  { 1259, {"relfrozenxid"},  28, -1,	4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
! { 1259, {"relpreupgstatus"}, 21, -1,	2, 23, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
! { 1259, {"relacl"},		 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
! { 1259, {"reloptions"},  1009, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
  
  DATA(insert ( 1259 relname			19 -1 NAMEDATALEN	1 0 -1 -1 f p c t f f t 0));
  DATA(insert ( 1259 relnamespace		26 -1 4   2 0 -1 -1 t p i t f f t 0));
***************
*** 444,451 ****
  DATA(insert ( 1259 relhastriggers	16 -1 1  20 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relhassubclass	16 -1 1  21 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relfrozenxid		28 -1 4  22 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1259 relacl		  1034 -1 -1 23 1 -1 -1 f x i f f f t 0));
! DATA(insert ( 1259 reloptions	  1009 -1 -1 24 1 -1 -1 f x i f f f t 0));
  DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0));
  DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0));
--- 445,453 ----
  DATA(insert ( 1259 relhastriggers	16 -1 1  20 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relhassubclass	16 -1 1  21 0 -1 -1 t p c t f f t 0));
  DATA(insert ( 1259 relfrozenxid		28 -1 4  22 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1259 relpreupgstatus	21 -1 2  23 0 -1 -1 t p s t f f t 0));
! DATA(insert ( 1259 relacl		  1034 -1 -1 24 1 -1 -1 f x i f f f t 0));
! DATA(insert ( 1259 reloptions	  1009 -1 -1 25 1 -1 -1 f x i f f f t 0));
  DATA(insert ( 1259 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0));
  DATA(insert ( 1259 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1259 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0));
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_class.h pgsql_spacereserve/src/include/catalog/pg_class.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_class.h	2008-12-12 11:36:42.227311049 +0100
--- pgsql_spacereserve/src/include/catalog/pg_class.h	2008-12-12 11:36:42.239737867 +0100
***************
*** 58,63 ****
--- 58,64 ----
  	bool		relhastriggers;	/* has (or has had) any TRIGGERs */
  	bool		relhassubclass; /* has (or has had) derived classes */
  	TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */
+ 	int2		relpreupgstatus;  /* tatus of pre-upgrade process */
  
  	/*
  	 * VARIABLE LENGTH FIELDS start here.  These fields may be NULL, too.
***************
*** 71,77 ****
  
  /* Size of fixed part of pg_class tuples, not counting var-length fields */
  #define CLASS_TUPLE_SIZE \
! 	 (offsetof(FormData_pg_class,relfrozenxid) + sizeof(TransactionId))
  
  /* ----------------
   *		Form_pg_class corresponds to a pointer to a tuple with
--- 72,78 ----
  
  /* Size of fixed part of pg_class tuples, not counting var-length fields */
  #define CLASS_TUPLE_SIZE \
! 	 (offsetof(FormData_pg_class,relpreupgstatus) + sizeof(int2))
  
  /* ----------------
   *		Form_pg_class corresponds to a pointer to a tuple with
***************
*** 85,91 ****
   * ----------------
   */
  
! #define Natts_pg_class					24
  #define Anum_pg_class_relname			1
  #define Anum_pg_class_relnamespace		2
  #define Anum_pg_class_reltype			3
--- 86,92 ----
   * ----------------
   */
  
! #define Natts_pg_class					25
  #define Anum_pg_class_relname			1
  #define Anum_pg_class_relnamespace		2
  #define Anum_pg_class_reltype			3
***************
*** 108,115 ****
  #define Anum_pg_class_relhastriggers	20
  #define Anum_pg_class_relhassubclass	21
  #define Anum_pg_class_relfrozenxid		22
! #define Anum_pg_class_relacl			23
! #define Anum_pg_class_reloptions		24
  
  /* ----------------
   *		initial contents of pg_class
--- 109,117 ----
  #define Anum_pg_class_relhastriggers	20
  #define Anum_pg_class_relhassubclass	21
  #define Anum_pg_class_relfrozenxid		22
! #define Anum_pg_class_relisupgready		23
! #define Anum_pg_class_relacl			24
! #define Anum_pg_class_reloptions		25
  
  /* ----------------
   *		initial contents of pg_class
***************
*** 121,133 ****
   */
  
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
! DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1259 (  pg_class		PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
  
  #define		  RELKIND_INDEX			  'i'		/* secondary index */
--- 123,135 ----
   */
  
  /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
! DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t f f f f 3 0 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 0 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1255 (  pg_proc		PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 24 0 t f f f f 3 0 _null_ _null_ ));
  DESCR("");
! DATA(insert OID = 1259 (  pg_class		PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 25 0 t f f f f 3 0 _null_ _null_ ));
  DESCR("");
  
  #define		  RELKIND_INDEX			  'i'		/* secondary index */
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_database.h pgsql_spacereserve/src/include/catalog/pg_database.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/catalog/pg_database.h	2008-12-12 11:36:42.228306479 +0100
--- pgsql_spacereserve/src/include/catalog/pg_database.h	2008-12-12 11:36:42.239875956 +0100
***************
*** 41,46 ****
--- 41,47 ----
  	Oid			datlastsysoid;	/* highest OID to consider a system OID */
  	TransactionId datfrozenxid; /* all Xids < this are frozen in this DB */
  	Oid			dattablespace;	/* default table space for this DB */
+ 	int2		datpreupgstatus;/* status of pre-upgrade process */
  	text		datconfig[1];	/* database-specific GUC (VAR LENGTH) */
  	aclitem		datacl[1];		/* access permissions (VAR LENGTH) */
  } FormData_pg_database;
***************
*** 56,62 ****
   *		compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database				13
  #define Anum_pg_database_datname		1
  #define Anum_pg_database_datdba			2
  #define Anum_pg_database_encoding		3
--- 57,63 ----
   *		compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database				14
  #define Anum_pg_database_datname		1
  #define Anum_pg_database_datdba			2
  #define Anum_pg_database_encoding		3
***************
*** 68,77 ****
  #define Anum_pg_database_datlastsysoid	9
  #define Anum_pg_database_datfrozenxid	10
  #define Anum_pg_database_dattablespace	11
! #define Anum_pg_database_datconfig		12
! #define Anum_pg_database_datacl			13
  
! DATA(insert OID = 1 (  template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_ _null_));
  SHDESCR("default template database");
  #define TemplateDbOid			1
  
--- 69,79 ----
  #define Anum_pg_database_datlastsysoid	9
  #define Anum_pg_database_datfrozenxid	10
  #define Anum_pg_database_dattablespace	11
! #define Anum_pg_database_datpreupgstatus 12
! #define Anum_pg_database_datconfig		13
! #define Anum_pg_database_datacl			14
  
! DATA(insert OID = 1 (  template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 0 _null_ _null_));
  SHDESCR("default template database");
  #define TemplateDbOid			1
  
diff -Nrc pgsql_spacereserve.84e2e9c42ef7/src/include/storage/bufpage.h pgsql_spacereserve/src/include/storage/bufpage.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/storage/bufpage.h	2008-12-12 11:36:42.231179457 +0100
--- pgsql_spacereserve/src/include/storage/bufpage.h	2008-12-12 11:36:42.240214381 +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.84e2e9c42ef7/src/include/utils/rel.h pgsql_spacereserve/src/include/utils/rel.h
*** pgsql_spacereserve.84e2e9c42ef7/src/include/utils/rel.h	2008-12-12 11:36:42.233198428 +0100
--- pgsql_spacereserve/src/include/utils/rel.h	2008-12-12 11:36:42.240482307 +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

Reply via email to