Dead code in _bt_split?

Started by Heikki Linnakangasabout 19 years ago13 messages
#1Heikki Linnakangas
heikki@enterprisedb.com

This piece of code in _bt_split, starting at line 859, looks curious to me:

/* cope with possibility that newitem goes at the end */
if (i <= newitemoff)
{
if (newitemonleft)
{
_bt_pgaddtup(rel, leftpage, newitemsz, newitem, leftoff,
"left sibling");
itup_off = leftoff;
itup_blkno = BufferGetBlockNumber(buf);
leftoff = OffsetNumberNext(leftoff);
}
else
{
_bt_pgaddtup(rel, rightpage, newitemsz, newitem, rightoff,
"right sibling");
itup_off = rightoff;
itup_blkno = BufferGetBlockNumber(rbuf);
rightoff = OffsetNumberNext(rightoff);
}
}

This is right after a for-loop, which exits when i = maxoff + 1. So the
first if-statement could be written as "if (newitemoff > maxoff)". If
that's true, newitemonleft shouldn't be true, because that would mean
that we've split a page so that all items went to the left page, and the
right page is empty.

Is that really dead code, or am I missing something? How about putting
an Assert in there instead?

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Heikki Linnakangas (#1)
Re: Dead code in _bt_split?

"Heikki Linnakangas" <heikki@enterprisedb.com> writes:

This is right after a for-loop, which exits when i = maxoff + 1. So the
first if-statement could be written as "if (newitemoff > maxoff)". If
that's true, newitemonleft shouldn't be true, because that would mean
that we've split a page so that all items went to the left page, and the
right page is empty.

No, it would mean that we split the page in such a way that only the new
item is going to the right page. Probably not hard to duplicate if you
use near-maximal-sized keys.

regards, tom lane

#3Heikki Linnakangas
heikki@enterprisedb.com
In reply to: Tom Lane (#2)
Re: Dead code in _bt_split?

Tom Lane wrote:

"Heikki Linnakangas" <heikki@enterprisedb.com> writes:

This is right after a for-loop, which exits when i = maxoff + 1. So the
first if-statement could be written as "if (newitemoff > maxoff)". If
that's true, newitemonleft shouldn't be true, because that would mean
that we've split a page so that all items went to the left page, and the
right page is empty.

No, it would mean that we split the page in such a way that only the new
item is going to the right page. Probably not hard to duplicate if you
use near-maximal-sized keys.

In that case, newitemleft would be false, right?

I'm saying the piece marked with X> below is unreachable:

/* cope with possibility that newitem goes at the end */
if (i <= newitemoff)
{
if (newitemonleft)
{

X> _bt_pgaddtup(rel, leftpage, newitemsz, newitem, leftoff,
X> "left sibling");
X> itup_off = leftoff;
X> itup_blkno = BufferGetBlockNumber(buf);
X> leftoff = OffsetNumberNext(leftoff);

}
else
{
_bt_pgaddtup(rel, rightpage, newitemsz, newitem, rightoff,
"right sibling");
itup_off = rightoff;
itup_blkno = BufferGetBlockNumber(rbuf);
rightoff = OffsetNumberNext(rightoff);
}
}

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Heikki Linnakangas (#3)
Re: Dead code in _bt_split?

Heikki Linnakangas <heikki@enterprisedb.com> writes:

In that case, newitemleft would be false, right?
I'm saying the piece marked with X> below is unreachable:

Oh, I see. Hmm ... probably so, I think that chunk of code was just
copied and pasted from where it occurs within the loop.

regards, tom lane

#5Bruce Momjian
bruce@momjian.us
In reply to: Tom Lane (#4)
Re: Dead code in _bt_split?

Heikki, did this code cleanup get included in your recent btree split
fix?

---------------------------------------------------------------------------

Tom Lane wrote:

Heikki Linnakangas <heikki@enterprisedb.com> writes:

In that case, newitemleft would be false, right?
I'm saying the piece marked with X> below is unreachable:

Oh, I see. Hmm ... probably so, I think that chunk of code was just
copied and pasted from where it occurs within the loop.

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#6Heikki Linnakangas
heikki@enterprisedb.com
In reply to: Bruce Momjian (#5)
Re: Dead code in _bt_split?

Bruce Momjian wrote:

Heikki, did this code cleanup get included in your recent btree split
fix?

No.

---------------------------------------------------------------------------

Tom Lane wrote:

Heikki Linnakangas <heikki@enterprisedb.com> writes:

In that case, newitemleft would be false, right?
I'm saying the piece marked with X> below is unreachable:

Oh, I see. Hmm ... probably so, I think that chunk of code was just
copied and pasted from where it occurs within the loop.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#7Bruce Momjian
bruce@momjian.us
In reply to: Heikki Linnakangas (#6)
Re: Dead code in _bt_split?

Heikki Linnakangas wrote:

Bruce Momjian wrote:

Heikki, did this code cleanup get included in your recent btree split
fix?

No.

OK, would you please send a patch to remove the unused code. Thanks.

--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#8Heikki Linnakangas
heikki@enterprisedb.com
In reply to: Bruce Momjian (#7)
1 attachment(s)
Re: Dead code in _bt_split?

Bruce Momjian wrote:

Heikki Linnakangas wrote:

Bruce Momjian wrote:

Heikki, did this code cleanup get included in your recent btree split
fix?

No.

OK, would you please send a patch to remove the unused code. Thanks.

Ok, here you are.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

Attachments:

deadcode_in_split.patchtext/x-patch; name=deadcode_in_split.patchDownload
Index: src/backend/access/nbtree/nbtinsert.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/nbtree/nbtinsert.c,v
retrieving revision 1.148
diff -c -r1.148 nbtinsert.c
*** src/backend/access/nbtree/nbtinsert.c	27 Jan 2007 20:53:30 -0000	1.148
--- src/backend/access/nbtree/nbtinsert.c	6 Feb 2007 10:23:26 -0000
***************
*** 855,876 ****
  	/* cope with possibility that newitem goes at the end */
  	if (i <= newitemoff)
  	{
! 		if (newitemonleft)
! 		{
! 			_bt_pgaddtup(rel, leftpage, newitemsz, newitem, leftoff,
! 						 "left sibling");
! 			itup_off = leftoff;
! 			itup_blkno = BufferGetBlockNumber(buf);
! 			leftoff = OffsetNumberNext(leftoff);
! 		}
! 		else
! 		{
! 			_bt_pgaddtup(rel, rightpage, newitemsz, newitem, rightoff,
! 						 "right sibling");
! 			itup_off = rightoff;
! 			itup_blkno = BufferGetBlockNumber(rbuf);
! 			rightoff = OffsetNumberNext(rightoff);
! 		}
  	}
  
  	/*
--- 855,865 ----
  	/* cope with possibility that newitem goes at the end */
  	if (i <= newitemoff)
  	{
! 		_bt_pgaddtup(rel, rightpage, newitemsz, newitem, rightoff,
! 					 "right sibling");
! 		itup_off = rightoff;
! 		itup_blkno = BufferGetBlockNumber(rbuf);
! 		rightoff = OffsetNumberNext(rightoff);
  	}
  
  	/*
#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Heikki Linnakangas (#8)
Re: Dead code in _bt_split?

Heikki Linnakangas <heikki@enterprisedb.com> writes:

Bruce Momjian wrote:

OK, would you please send a patch to remove the unused code. Thanks.

Ok, here you are.

Applied with an added comment and Assert.

While testing it I realized that there seems to be a nearby bug in
_bt_findsplitloc: it fails to consider the possibility of moving all the
extant items to the left side. It will always return a firstright <=
maxoff. ISTM this would mean that it could choose a bad split if the
incoming item goes at the end and both it and the last extant item are
large: in this case they should be split apart, but they won't be.

Heikki, do you feel like looking at that, or shall I?

regards, tom lane

#10Heikki Linnakangas
heikki@enterprisedb.com
In reply to: Tom Lane (#9)
Re: Dead code in _bt_split?

Tom Lane wrote:

Heikki Linnakangas <heikki@enterprisedb.com> writes:

Bruce Momjian wrote:

OK, would you please send a patch to remove the unused code. Thanks.

Ok, here you are.

Applied with an added comment and Assert.

While testing it I realized that there seems to be a nearby bug in
_bt_findsplitloc: it fails to consider the possibility of moving all the
extant items to the left side. It will always return a firstright <=
maxoff. ISTM this would mean that it could choose a bad split if the
incoming item goes at the end and both it and the last extant item are
large: in this case they should be split apart, but they won't be.

Heikki, do you feel like looking at that, or shall I?

I'll take a look at it.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#11Heikki Linnakangas
heikki@enterprisedb.com
In reply to: Tom Lane (#9)
1 attachment(s)
Re: [HACKERS] Dead code in _bt_split?

Tom Lane wrote:

While testing it I realized that there seems to be a nearby bug in
_bt_findsplitloc: it fails to consider the possibility of moving all the
extant items to the left side. It will always return a firstright <=
maxoff. ISTM this would mean that it could choose a bad split if the
incoming item goes at the end and both it and the last extant item are
large: in this case they should be split apart, but they won't be.

Heikki, do you feel like looking at that, or shall I?

I refactored findsplitloc and checksplitloc so that the division of
labor is more clear IMO. I pushed all the space calculation inside the
loop to checksplitloc.

I also fixed the off by 4 in free space calculation caused by
PageGetFreeSpace subtracting sizeof(ItemIdData), even though it was
harmless, because it was distracting and I felt it might come back to
bite us in the future if we change the page layout or alignments.
There's now a new function PageGetExactFreeSpace that doesn't do the
subtraction.

findsplitloc now tries the "just the new item to right page" split as
well. If people don't like the refactoring, I can write a patch to just
add that.

Some of the long variable names look ugly. camelCase or underscores
between words would be more readable, but I retained the old style for
the sake of consistency.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

Attachments:

checksplitloc-refactoring.patchtext/x-patch; name=checksplitloc-refactoring.patchDownload
Index: src/backend/access/nbtree/nbtinsert.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/nbtree/nbtinsert.c,v
retrieving revision 1.150
diff -c -r1.150 nbtinsert.c
*** src/backend/access/nbtree/nbtinsert.c	8 Feb 2007 05:05:53 -0000	1.150
--- src/backend/access/nbtree/nbtinsert.c	8 Feb 2007 13:24:50 -0000
***************
*** 29,34 ****
--- 29,38 ----
  	int			fillfactor;		/* needed when splitting rightmost page */
  	bool		is_leaf;		/* T if splitting a leaf page */
  	bool		is_rightmost;	/* T if splitting a rightmost page */
+ 	OffsetNumber newitemoff;	/* where the new item is to be inserted */
+ 	int			leftspace;		/* space available for items on left page */
+ 	int			rightspace;		/* space available for items on right page */
+ 	int			olddataitemstotal; /* space taken by old items */
  
  	bool		have_split;		/* found a valid split? */
  
***************
*** 57,65 ****
  				 OffsetNumber newitemoff,
  				 Size newitemsz,
  				 bool *newitemonleft);
! static void _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
! 				  int leftfree, int rightfree,
! 				  bool newitemonleft, Size firstrightitemsz);
  static void _bt_pgaddtup(Relation rel, Page page,
  			 Size itemsize, IndexTuple itup,
  			 OffsetNumber itup_off, const char *where);
--- 61,69 ----
  				 OffsetNumber newitemoff,
  				 Size newitemsz,
  				 bool *newitemonleft);
! static void _bt_checksplitloc(FindSplitData *state, 
! 				  OffsetNumber firstoldonright, bool newitemonleft,
! 				  int dataitemstoleft, Size firstoldonrightsz);
  static void _bt_pgaddtup(Relation rel, Page page,
  			 Size itemsize, IndexTuple itup,
  			 OffsetNumber itup_off, const char *where);
***************
*** 1101,1113 ****
  	int			leftspace,
  				rightspace,
  				goodenough,
! 				dataitemtotal,
! 				dataitemstoleft;
  
  	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  
  	/* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
  	newitemsz += sizeof(ItemIdData);
  	state.newitemsz = newitemsz;
  	state.is_leaf = P_ISLEAF(opaque);
  	state.is_rightmost = P_RIGHTMOST(opaque);
--- 1105,1135 ----
  	int			leftspace,
  				rightspace,
  				goodenough,
! 				olddataitemstotal,
! 				olddataitemstoleft;
! 	bool		goodenoughfound;
  
  	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
  
  	/* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
  	newitemsz += sizeof(ItemIdData);
+ 
+ 	/* Total free space available on a btree page, after fixed overhead */
+ 	leftspace = rightspace =
+ 		PageGetPageSize(page) - SizeOfPageHeaderData -
+ 		MAXALIGN(sizeof(BTPageOpaqueData));
+ 
+ 	/* The right page will have the same high key as the old page */
+ 	if (!P_RIGHTMOST(opaque))
+ 	{
+ 		itemid = PageGetItemId(page, P_HIKEY);
+ 		rightspace -= (int) (MAXALIGN(ItemIdGetLength(itemid)) +
+ 							 sizeof(ItemIdData));
+ 	}
+ 
+ 	/* Count up total space in data items without actually scanning 'em */
+ 	olddataitemstotal = rightspace - (int) PageGetExactFreeSpace(page);
+ 
  	state.newitemsz = newitemsz;
  	state.is_leaf = P_ISLEAF(opaque);
  	state.is_rightmost = P_RIGHTMOST(opaque);
***************
*** 1120,1130 ****
  	state.newitemonleft = false;	/* these just to keep compiler quiet */
  	state.firstright = 0;
  	state.best_delta = 0;
! 
! 	/* Total free space available on a btree page, after fixed overhead */
! 	leftspace = rightspace =
! 		PageGetPageSize(page) - SizeOfPageHeaderData -
! 		MAXALIGN(sizeof(BTPageOpaqueData));
  
  	/*
  	 * Finding the best possible split would require checking all the possible
--- 1142,1151 ----
  	state.newitemonleft = false;	/* these just to keep compiler quiet */
  	state.firstright = 0;
  	state.best_delta = 0;
! 	state.leftspace = leftspace;
! 	state.rightspace = rightspace;
! 	state.olddataitemstotal = olddataitemstotal;
! 	state.newitemoff = newitemoff;
  
  	/*
  	 * Finding the best possible split would require checking all the possible
***************
*** 1137,1210 ****
  	 */
  	goodenough = leftspace / 16;
  
- 	/* The right page will have the same high key as the old page */
- 	if (!P_RIGHTMOST(opaque))
- 	{
- 		itemid = PageGetItemId(page, P_HIKEY);
- 		rightspace -= (int) (MAXALIGN(ItemIdGetLength(itemid)) +
- 							 sizeof(ItemIdData));
- 	}
- 
- 	/* Count up total space in data items without actually scanning 'em */
- 	dataitemtotal = rightspace - (int) PageGetFreeSpace(page);
- 
  	/*
  	 * Scan through the data items and calculate space usage for a split at
  	 * each possible position.
  	 */
! 	dataitemstoleft = 0;
  	maxoff = PageGetMaxOffsetNumber(page);
! 
  	for (offnum = P_FIRSTDATAKEY(opaque);
  		 offnum <= maxoff;
  		 offnum = OffsetNumberNext(offnum))
  	{
  		Size		itemsz;
- 		int			leftfree,
- 					rightfree;
  
  		itemid = PageGetItemId(page, offnum);
  		itemsz = MAXALIGN(ItemIdGetLength(itemid)) + sizeof(ItemIdData);
  
  		/*
- 		 * We have to allow for the current item becoming the high key of the
- 		 * left page; therefore it counts against left space as well as right
- 		 * space.
- 		 */
- 		leftfree = leftspace - dataitemstoleft - (int) itemsz;
- 		rightfree = rightspace - (dataitemtotal - dataitemstoleft);
- 
- 		/*
  		 * Will the new item go to left or right of split?
  		 */
  		if (offnum > newitemoff)
! 			_bt_checksplitloc(&state, offnum, leftfree, rightfree,
! 							  true, itemsz);
  		else if (offnum < newitemoff)
! 			_bt_checksplitloc(&state, offnum, leftfree, rightfree,
! 							  false, itemsz);
  		else
  		{
  			/* need to try it both ways! */
! 			_bt_checksplitloc(&state, offnum, leftfree, rightfree,
! 							  true, itemsz);
! 			/*
! 			 * Here we are contemplating newitem as first on right.  In this
! 			 * case it, not the current item, will become the high key of the
! 			 * left page, and so we have to correct the allowance made above.
! 			 */
! 			leftfree += (int) itemsz - (int) newitemsz;
! 			_bt_checksplitloc(&state, offnum, leftfree, rightfree,
! 							  false, newitemsz);
  		}
  
  		/* Abort scan once we find a good-enough choice */
  		if (state.have_split && state.best_delta <= goodenough)
  			break;
  
! 		dataitemstoleft += itemsz;
  	}
  
  	/*
  	 * I believe it is not possible to fail to find a feasible split, but just
  	 * in case ...
--- 1158,1217 ----
  	 */
  	goodenough = leftspace / 16;
  
  	/*
  	 * Scan through the data items and calculate space usage for a split at
  	 * each possible position.
  	 */
! 	olddataitemstoleft = 0;
! 	goodenoughfound = false;
  	maxoff = PageGetMaxOffsetNumber(page);
! 	
  	for (offnum = P_FIRSTDATAKEY(opaque);
  		 offnum <= maxoff;
  		 offnum = OffsetNumberNext(offnum))
  	{
  		Size		itemsz;
  
  		itemid = PageGetItemId(page, offnum);
  		itemsz = MAXALIGN(ItemIdGetLength(itemid)) + sizeof(ItemIdData);
  
  		/*
  		 * Will the new item go to left or right of split?
  		 */
  		if (offnum > newitemoff)
! 			_bt_checksplitloc(&state, offnum, true,
! 							  olddataitemstoleft, itemsz);
! 
  		else if (offnum < newitemoff)
! 			_bt_checksplitloc(&state, offnum, false, 
! 							  olddataitemstoleft, itemsz);
  		else
  		{
  			/* need to try it both ways! */
! 			_bt_checksplitloc(&state, offnum, true,
! 							  olddataitemstoleft, itemsz);
! 
! 			_bt_checksplitloc(&state, offnum, false,
! 							  olddataitemstoleft, itemsz);
  		}
  
  		/* Abort scan once we find a good-enough choice */
  		if (state.have_split && state.best_delta <= goodenough)
+ 		{
+ 			goodenoughfound = true;
  			break;
+ 		}
  
! 		olddataitemstoleft += itemsz;
  	}
  
+ 	/* If the new item goes as the last item, check for splitting so that
+ 	 * all the old items go to the left page and the new item goes to the
+ 	 * right page.
+ 	 */
+ 	if (newitemoff > maxoff && !goodenoughfound)
+ 		_bt_checksplitloc(&state, newitemoff, false, olddataitemstotal, 0);
+ 
  	/*
  	 * I believe it is not possible to fail to find a feasible split, but just
  	 * in case ...
***************
*** 1220,1234 ****
  /*
   * Subroutine to analyze a particular possible split choice (ie, firstright
   * and newitemonleft settings), and record the best split so far in *state.
   */
  static void
! _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
! 				  int leftfree, int rightfree,
! 				  bool newitemonleft, Size firstrightitemsz)
  {
  	/*
! 	 * Account for the new item on whichever side it is to be put.
  	 */
  	if (newitemonleft)
  		leftfree -= (int) state->newitemsz;
  	else
--- 1227,1276 ----
  /*
   * Subroutine to analyze a particular possible split choice (ie, firstright
   * and newitemonleft settings), and record the best split so far in *state.
+  *
+  * firstoldonright is the offset of the first item on the original page
+  * that goes to the right page, and firstoldonrightsz is the size of that
+  * tuple. firstoldonright can be > max offset, which means that all the old
+  * items go to the left page and only the new item goes to the right page.
+  * In that case, firstoldonrightsz is not used.
+  *
+  * olddataitemstoleft is the total size of all old items to the left of 
+  * firstoldonright. 
   */
  static void
! _bt_checksplitloc(FindSplitData *state, 
! 				  OffsetNumber firstoldonright,
! 				  bool newitemonleft,
! 				  int olddataitemstoleft,
! 				  Size firstoldonrightsz)
  {
+ 	int		leftfree,
+ 			rightfree;
+ 	Size	firstrightitemsz;
+ 	bool	newitemisfirstonright;
+ 
+ 	/* Is the new item going to be the first item on the right page? */
+ 	newitemisfirstonright = (firstoldonright == state->newitemoff
+ 							 && !newitemonleft);
+ 
+ 	if(newitemisfirstonright)
+ 		firstrightitemsz = state->newitemsz;
+ 	else
+ 		firstrightitemsz = firstoldonrightsz;
+ 
+ 	/* Account for all the old tuples */
+ 	leftfree = state->leftspace - olddataitemstoleft;
+ 	rightfree = state->rightspace - 
+ 		(state->olddataitemstotal - olddataitemstoleft);
+ 
  	/*
! 	 * The first item on the right page becomes the high key of the
! 	 * left page; therefore it counts against left space as well as right
! 	 * space.
  	 */
+ 	leftfree -= firstrightitemsz;
+ 
+ 	/* account for the new item */
  	if (newitemonleft)
  		leftfree -= (int) state->newitemsz;
  	else
***************
*** 1270,1276 ****
  		{
  			state->have_split = true;
  			state->newitemonleft = newitemonleft;
! 			state->firstright = firstright;
  			state->best_delta = delta;
  		}
  	}
--- 1312,1318 ----
  		{
  			state->have_split = true;
  			state->newitemonleft = newitemonleft;
! 			state->firstright = firstoldonright;
  			state->best_delta = delta;
  		}
  	}
Index: src/backend/storage/page/bufpage.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/storage/page/bufpage.c,v
retrieving revision 1.70
diff -c -r1.70 bufpage.c
*** src/backend/storage/page/bufpage.c	5 Jan 2007 22:19:38 -0000	1.70
--- src/backend/storage/page/bufpage.c	8 Feb 2007 13:02:11 -0000
***************
*** 418,424 ****
  
  /*
   * PageGetFreeSpace
!  *		Returns the size of the free (allocatable) space on a page.
   */
  Size
  PageGetFreeSpace(Page page)
--- 418,425 ----
  
  /*
   * PageGetFreeSpace
!  *		Returns the size of the free (allocatable) space on a page,
!  *		deducted by the space needed for a new line pointer.
   */
  Size
  PageGetFreeSpace(Page page)
***************
*** 434,440 ****
  
  	if (space < (int) sizeof(ItemIdData))
  		return 0;
! 	space -= sizeof(ItemIdData);	/* XXX not always appropriate */
  
  	return (Size) space;
  }
--- 435,460 ----
  
  	if (space < (int) sizeof(ItemIdData))
  		return 0;
! 	space -= sizeof(ItemIdData);
! 
! 	return (Size) space;
! }
! 
! /*
!  * PageGetExactFreeSpace
!  *		Returns the size of the free (allocatable) space on a page.
!  */
! Size
! PageGetExactFreeSpace(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;
  
  	return (Size) space;
  }
Index: src/include/storage/bufpage.h
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/storage/bufpage.h,v
retrieving revision 1.69
diff -c -r1.69 bufpage.h
*** src/include/storage/bufpage.h	5 Jan 2007 22:19:57 -0000	1.69
--- src/include/storage/bufpage.h	7 Feb 2007 13:13:42 -0000
***************
*** 321,326 ****
--- 321,327 ----
  extern void PageRestoreTempPage(Page tempPage, Page oldPage);
  extern int	PageRepairFragmentation(Page page, OffsetNumber *unused);
  extern Size PageGetFreeSpace(Page page);
+ extern Size PageGetExactFreeSpace(Page page);
  extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
  extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
  
#12Bruce Momjian
bruce@momjian.us
In reply to: Heikki Linnakangas (#11)
Re: [HACKERS] Dead code in _bt_split?

Your patch has been added to the PostgreSQL unapplied patches list at:

http://momjian.postgresql.org/cgi-bin/pgpatches

It will be applied as soon as one of the PostgreSQL committers reviews
and approves it.

---------------------------------------------------------------------------

Heikki Linnakangas wrote:

Tom Lane wrote:

While testing it I realized that there seems to be a nearby bug in
_bt_findsplitloc: it fails to consider the possibility of moving all the
extant items to the left side. It will always return a firstright <=
maxoff. ISTM this would mean that it could choose a bad split if the
incoming item goes at the end and both it and the last extant item are
large: in this case they should be split apart, but they won't be.

Heikki, do you feel like looking at that, or shall I?

I refactored findsplitloc and checksplitloc so that the division of
labor is more clear IMO. I pushed all the space calculation inside the
loop to checksplitloc.

I also fixed the off by 4 in free space calculation caused by
PageGetFreeSpace subtracting sizeof(ItemIdData), even though it was
harmless, because it was distracting and I felt it might come back to
bite us in the future if we change the page layout or alignments.
There's now a new function PageGetExactFreeSpace that doesn't do the
subtraction.

findsplitloc now tries the "just the new item to right page" split as
well. If people don't like the refactoring, I can write a patch to just
add that.

Some of the long variable names look ugly. camelCase or underscores
between words would be more readable, but I retained the old style for
the sake of consistency.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

http://archives.postgresql.org

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#13Bruce Momjian
bruce@momjian.us
In reply to: Heikki Linnakangas (#11)
Re: [HACKERS] Dead code in _bt_split?

Patch applied. Thanks.

---------------------------------------------------------------------------

Heikki Linnakangas wrote:

Tom Lane wrote:

While testing it I realized that there seems to be a nearby bug in
_bt_findsplitloc: it fails to consider the possibility of moving all the
extant items to the left side. It will always return a firstright <=
maxoff. ISTM this would mean that it could choose a bad split if the
incoming item goes at the end and both it and the last extant item are
large: in this case they should be split apart, but they won't be.

Heikki, do you feel like looking at that, or shall I?

I refactored findsplitloc and checksplitloc so that the division of
labor is more clear IMO. I pushed all the space calculation inside the
loop to checksplitloc.

I also fixed the off by 4 in free space calculation caused by
PageGetFreeSpace subtracting sizeof(ItemIdData), even though it was
harmless, because it was distracting and I felt it might come back to
bite us in the future if we change the page layout or alignments.
There's now a new function PageGetExactFreeSpace that doesn't do the
subtraction.

findsplitloc now tries the "just the new item to right page" split as
well. If people don't like the refactoring, I can write a patch to just
add that.

Some of the long variable names look ugly. camelCase or underscores
between words would be more readable, but I retained the old style for
the sake of consistency.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

http://archives.postgresql.org

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +