2626#include "storage/smgr.h"
2727#include "utils/tqual.h"
2828
29+ /* Minimum tree height for application of fastpath optimization */
30+ #define BTREE_FASTPATH_MIN_LEVEL 2
2931
3032typedef struct
3133{
@@ -125,7 +127,7 @@ _bt_doinsert(Relation rel, IndexTuple itup,
125127/*
126128 * It's very common to have an index on an auto-incremented or
127129 * monotonically increasing value. In such cases, every insertion happens
128- * towards the end of the index. We try tooptimise that case by caching
130+ * towards the end of the index. We try tooptimize that case by caching
129131 * the right-most leaf of the index. If our cached block is still the
130132 * rightmost leaf, has enough free space to accommodate a new entry and
131133 * the insertion key is strictly greater than the first key in this page,
@@ -176,13 +178,17 @@ _bt_doinsert(Relation rel, IndexTuple itup,
176178 * the first key on the page.
177179 */
178180if (P_ISLEAF (lpageop )&& P_RIGHTMOST (lpageop )&&
179- !P_INCOMPLETE_SPLIT (lpageop )&&
180181!P_IGNORE (lpageop )&&
181182(PageGetFreeSpace (page )> itemsz )&&
182183PageGetMaxOffsetNumber (page ) >=P_FIRSTDATAKEY (lpageop )&&
183184_bt_compare (rel ,indnkeyatts ,itup_scankey ,page ,
184185P_FIRSTDATAKEY (lpageop ))> 0 )
185186{
187+ /*
188+ * The right-most block should never have incomplete split. But
189+ * be paranoid and check for it anyway.
190+ */
191+ Assert (!P_INCOMPLETE_SPLIT (lpageop ));
186192fastpath = true;
187193}
188194else
@@ -868,6 +874,24 @@ _bt_insertonpg(Relation rel,
868874bool newitemonleft ;
869875Buffer rbuf ;
870876
877+ /*
878+ * If we're here then a pagesplit is needed. We should never reach here
879+ * if we're using the fastpath since we should have checked for all the
880+ * required conditions, including the fact that this page has enough
881+ * freespace. Note that this routine can in theory deal with the
882+ * situation where a NULL stack pointer is passed (that's what would
883+ * happen if the fastpath is taken), like it does during crash
884+ * recovery. But that path is much slower, defeating the very purpose
885+ * of the optimization. The following assertion should protect us from
886+ * any future code changes that invalidate those assumptions.
887+ *
888+ * Note that whenever we fail to take the fastpath, we clear the
889+ * cached block. Checking for a valid cached block at this point is
890+ * enough to decide whether we're in a fastpath or not.
891+ */
892+ Assert (!(P_ISLEAF (lpageop )&&
893+ BlockNumberIsValid (RelationGetTargetBlock (rel ))));
894+
871895/* Choose the split point */
872896firstright = _bt_findsplitloc (rel ,page ,
873897newitemoff ,itemsz ,
@@ -905,6 +929,7 @@ _bt_insertonpg(Relation rel,
905929BTMetaPageData * metad = NULL ;
906930OffsetNumber itup_off ;
907931BlockNumber itup_blkno ;
932+ BlockNumber cachedBlock = InvalidBlockNumber ;
908933
909934itup_off = newitemoff ;
910935itup_blkno = BufferGetBlockNumber (buf );
@@ -962,6 +987,15 @@ _bt_insertonpg(Relation rel,
962987MarkBufferDirty (cbuf );
963988}
964989
990+ /*
991+ * Cache the block information if we just inserted into the rightmost
992+ * leaf page of the index and it's not the root page. For very small
993+ * index where root is also the leaf, there is no point trying for any
994+ * optimization.
995+ */
996+ if (P_RIGHTMOST (lpageop )&& P_ISLEAF (lpageop )&& !P_ISROOT (lpageop ))
997+ cachedBlock = BufferGetBlockNumber (buf );
998+
965999/* XLOG stuff */
9661000if (RelationNeedsWAL (rel ))
9671001{
@@ -977,16 +1011,7 @@ _bt_insertonpg(Relation rel,
9771011XLogRegisterData ((char * )& xlrec ,SizeOfBtreeInsert );
9781012
9791013if (P_ISLEAF (lpageop ))
980- {
9811014xlinfo = XLOG_BTREE_INSERT_LEAF ;
982-
983- /*
984- * Cache the block information if we just inserted into the
985- * rightmost leaf page of the index.
986- */
987- if (P_RIGHTMOST (lpageop ))
988- RelationSetTargetBlock (rel ,BufferGetBlockNumber (buf ));
989- }
9901015else
9911016{
9921017/*
@@ -1048,6 +1073,22 @@ _bt_insertonpg(Relation rel,
10481073if (BufferIsValid (cbuf ))
10491074_bt_relbuf (rel ,cbuf );
10501075_bt_relbuf (rel ,buf );
1076+
1077+ /*
1078+ * If we decided to cache the insertion target block, then set it now.
1079+ * But before that, check for the height of the tree and don't go for
1080+ * the optimization for small indexes. We defer that check to this
1081+ * point to ensure that we don't call _bt_getrootheight while holding
1082+ * lock on any other block.
1083+ *
1084+ * We do this after dropping locks on all buffers. So the information
1085+ * about whether the insertion block is still the rightmost block or
1086+ * not may have changed in between. But we will deal with that during
1087+ * next insert operation. No special care is required while setting it.
1088+ */
1089+ if (BlockNumberIsValid (cachedBlock )&&
1090+ _bt_getrootheight (rel ) >=BTREE_FASTPATH_MIN_LEVEL )
1091+ RelationSetTargetBlock (rel ,cachedBlock );
10511092}
10521093}
10531094