88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.60 2000/07/2106:42:32 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.61 2000/07/2119:21:00 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -377,6 +377,10 @@ _bt_insertonpg(Relation rel,
377377
378378/*
379379 * Do we need to split the page to fit the item on it?
380+ *
381+ * Note: PageGetFreeSpace() subtracts sizeof(ItemIdData) from its
382+ * result, so this comparison is correct even though we appear to
383+ * be accounting only for the item and not for its line pointer.
380384 */
381385if (PageGetFreeSpace (page )< itemsz )
382386{
@@ -743,11 +747,14 @@ _bt_findsplitloc(Relation rel,
743747FindSplitData state ;
744748int leftspace ,
745749rightspace ,
750+ goodenough ,
746751dataitemtotal ,
747752dataitemstoleft ;
748753
749754opaque = (BTPageOpaque )PageGetSpecialPointer (page );
750755
756+ /* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
757+ newitemsz += sizeof (ItemIdData );
751758state .newitemsz = newitemsz ;
752759state .non_leaf = !P_ISLEAF (opaque );
753760state .have_split = false;
@@ -758,20 +765,31 @@ _bt_findsplitloc(Relation rel,
758765MAXALIGN (sizeof (BTPageOpaqueData ))
759766+ sizeof (ItemIdData );
760767
768+ /*
769+ * Finding the best possible split would require checking all the possible
770+ * split points, because of the high-key and left-key special cases.
771+ * That's probably more work than it's worth; instead, stop as soon as
772+ * we find a "good-enough" split, where good-enough is defined as an
773+ * imbalance in free space of no more than pagesize/16 (arbitrary...)
774+ * This should let us stop near the middle on most pages, instead of
775+ * plowing to the end.
776+ */
777+ goodenough = leftspace /16 ;
778+
761779/* The right page will have the same high key as the old page */
762780if (!P_RIGHTMOST (opaque ))
763781{
764782itemid = PageGetItemId (page ,P_HIKEY );
765- rightspace -= (int ) (ItemIdGetLength (itemid )+ sizeof (ItemIdData ));
783+ rightspace -= (int ) (MAXALIGN (ItemIdGetLength (itemid ))+
784+ sizeof (ItemIdData ));
766785}
767786
768787/* Count up total space in data items without actually scanning 'em */
769788dataitemtotal = rightspace - (int )PageGetFreeSpace (page );
770789
771790/*
772791 * Scan through the data items and calculate space usage for a split
773- * at each possible position. XXX we could probably stop somewhere
774- * near the middle...
792+ * at each possible position.
775793 */
776794dataitemstoleft = 0 ;
777795maxoff = PageGetMaxOffsetNumber (page );
@@ -785,44 +803,65 @@ _bt_findsplitloc(Relation rel,
785803rightfree ;
786804
787805itemid = PageGetItemId (page ,offnum );
788- itemsz = ItemIdGetLength (itemid )+ sizeof (ItemIdData );
806+ itemsz = MAXALIGN ( ItemIdGetLength (itemid ) )+ sizeof (ItemIdData );
789807
790808/*
791809 * We have to allow for the current item becoming the high key of
792- * the left page; therefore it counts against left space.
810+ * the left page; therefore it counts against left space as well
811+ * as right space.
793812 */
794813leftfree = leftspace - dataitemstoleft - (int )itemsz ;
795814rightfree = rightspace - (dataitemtotal - dataitemstoleft );
796- if ( offnum < newitemoff )
797- _bt_checksplitloc ( & state , offnum , leftfree , rightfree ,
798- false, itemsz );
799- else if (offnum > newitemoff )
815+ /*
816+ * Will the new item go to left or right of split?
817+ */
818+ if (offnum > newitemoff )
800819_bt_checksplitloc (& state ,offnum ,leftfree ,rightfree ,
801820 true,itemsz );
821+ else if (offnum < newitemoff )
822+ _bt_checksplitloc (& state ,offnum ,leftfree ,rightfree ,
823+ false,itemsz );
802824else
803825{
804- /* need to try it both ways!! */
805- _bt_checksplitloc (& state ,offnum ,leftfree ,rightfree ,
806- false,newitemsz );
826+ /* need to try it both ways! */
807827_bt_checksplitloc (& state ,offnum ,leftfree ,rightfree ,
808828 true,itemsz );
829+ /* here we are contemplating newitem as first on right */
830+ _bt_checksplitloc (& state ,offnum ,leftfree ,rightfree ,
831+ false,newitemsz );
809832}
810833
834+ /* Abort scan once we find a good-enough choice */
835+ if (state .have_split && state .best_delta <=goodenough )
836+ break ;
837+
811838dataitemstoleft += itemsz ;
812839}
813840
841+ /*
842+ * I believe it is not possible to fail to find a feasible split,
843+ * but just in case ...
844+ */
814845if (!state .have_split )
815846elog (FATAL ,"_bt_findsplitloc: can't find a feasible split point for %s" ,
816847RelationGetRelationName (rel ));
848+
817849* newitemonleft = state .newitemonleft ;
818850return state .firstright ;
819851}
820852
853+ /*
854+ * Subroutine to analyze a particular possible split choice (ie, firstright
855+ * and newitemonleft settings), and record the best split so far in *state.
856+ */
821857static void
822858_bt_checksplitloc (FindSplitData * state ,OffsetNumber firstright ,
823859int leftfree ,int rightfree ,
824860bool newitemonleft ,Size firstrightitemsz )
825861{
862+ /*
863+ * Account for the new item on whichever side it is to be put.
864+ */
826865if (newitemonleft )
827866leftfree -= (int )state -> newitemsz ;
828867else
@@ -833,7 +872,7 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
833872 */
834873if (state -> non_leaf )
835874rightfree += (int )firstrightitemsz -
836- (int ) (sizeof (BTItemData )+ sizeof (ItemIdData ));
875+ (int ) (MAXALIGN ( sizeof (BTItemData ) )+ sizeof (ItemIdData ));
837876/*
838877 * If feasible split point, remember best delta.
839878 */