LCOV - code coverage report
Current view: top level - src/backend/access/nbtree - nbtinsert.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 92.2 % 782 721
Test Date: 2026-09-21 06:15:44 Functions: 100.0 % 17 17
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 77.5 % 466 361

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * nbtinsert.c
       4                 :             :  *    Item insertion in Lehman and Yao btrees for Postgres.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *    src/backend/access/nbtree/nbtinsert.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : 
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include "access/nbtree.h"
      19                 :             : #include "access/nbtxlog.h"
      20                 :             : #include "access/tableam.h"
      21                 :             : #include "access/transam.h"
      22                 :             : #include "access/xloginsert.h"
      23                 :             : #include "common/int.h"
      24                 :             : #include "common/pg_prng.h"
      25                 :             : #include "lib/qunique.h"
      26                 :             : #include "miscadmin.h"
      27                 :             : #include "storage/lmgr.h"
      28                 :             : #include "storage/predicate.h"
      29                 :             : #include "utils/injection_point.h"
      30                 :             : 
      31                 :             : /* Minimum tree height for application of fastpath optimization */
      32                 :             : #define BTREE_FASTPATH_MIN_LEVEL    2
      33                 :             : 
      34                 :             : 
      35                 :             : static BTStack _bt_search_insert(Relation rel, Relation heaprel,
      36                 :             :                                  BTInsertState insertstate);
      37                 :             : static TransactionId _bt_check_unique(Relation rel, BTInsertState insertstate,
      38                 :             :                                       Relation heapRel,
      39                 :             :                                       IndexUniqueCheck checkUnique, bool *is_unique,
      40                 :             :                                       uint32 *speculativeToken);
      41                 :             : static OffsetNumber _bt_findinsertloc(Relation rel,
      42                 :             :                                       BTInsertState insertstate,
      43                 :             :                                       bool checkingunique,
      44                 :             :                                       bool indexUnchanged,
      45                 :             :                                       BTStack stack,
      46                 :             :                                       Relation heapRel);
      47                 :             : static void _bt_stepright(Relation rel, Relation heaprel,
      48                 :             :                           BTInsertState insertstate, BTStack stack);
      49                 :             : static void _bt_insertonpg(Relation rel, Relation heaprel, BTScanInsert itup_key,
      50                 :             :                            Buffer buf,
      51                 :             :                            Buffer cbuf,
      52                 :             :                            BTStack stack,
      53                 :             :                            IndexTuple itup,
      54                 :             :                            Size itemsz,
      55                 :             :                            OffsetNumber newitemoff,
      56                 :             :                            int postingoff,
      57                 :             :                            bool split_only_page);
      58                 :             : static Buffer _bt_split(Relation rel, Relation heaprel, BTScanInsert itup_key,
      59                 :             :                         Buffer buf, Buffer cbuf, OffsetNumber newitemoff,
      60                 :             :                         Size newitemsz, IndexTuple newitem, IndexTuple orignewitem,
      61                 :             :                         IndexTuple nposting, uint16 postingoff);
      62                 :             : static void _bt_insert_parent(Relation rel, Relation heaprel, Buffer buf,
      63                 :             :                               Buffer rbuf, BTStack stack, bool isroot, bool isonly);
      64                 :             : static void _bt_freestack(BTStack stack);
      65                 :             : static Buffer _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf);
      66                 :             : static inline bool _bt_pgaddtup(Page page, Size itemsize, const IndexTupleData *itup,
      67                 :             :                                 OffsetNumber itup_off, bool newfirstdataitem);
      68                 :             : static void _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel,
      69                 :             :                                          BTInsertState insertstate,
      70                 :             :                                          bool simpleonly, bool checkingunique,
      71                 :             :                                          bool uniquedup, bool indexUnchanged);
      72                 :             : static void _bt_simpledel_pass(Relation rel, Buffer buffer, Relation heapRel,
      73                 :             :                                OffsetNumber *deletable, int ndeletable,
      74                 :             :                                IndexTuple newitem, OffsetNumber minoff,
      75                 :             :                                OffsetNumber maxoff);
      76                 :             : static BlockNumber *_bt_deadblocks(Page page, OffsetNumber *deletable,
      77                 :             :                                    int ndeletable, IndexTuple newitem,
      78                 :             :                                    int *nblocks);
      79                 :             : static inline int _bt_blk_cmp(const void *arg1, const void *arg2);
      80                 :             : 
      81                 :             : /*
      82                 :             :  *  _bt_doinsert() -- Handle insertion of a single index tuple in the tree.
      83                 :             :  *
      84                 :             :  *      This routine is called by the public interface routine, btinsert.
      85                 :             :  *      By here, itup is filled in, including the TID.
      86                 :             :  *
      87                 :             :  *      If checkUnique is UNIQUE_CHECK_NO or UNIQUE_CHECK_PARTIAL, this
      88                 :             :  *      will allow duplicates.  Otherwise (UNIQUE_CHECK_YES or
      89                 :             :  *      UNIQUE_CHECK_EXISTING) it will throw error for a duplicate.
      90                 :             :  *      For UNIQUE_CHECK_EXISTING we merely run the duplicate check, and
      91                 :             :  *      don't actually insert.
      92                 :             :  *
      93                 :             :  *      indexUnchanged executor hint indicates if itup is from an
      94                 :             :  *      UPDATE that didn't logically change the indexed value, but
      95                 :             :  *      must nevertheless have a new entry to point to a successor
      96                 :             :  *      version.
      97                 :             :  *
      98                 :             :  *      The result value is only significant for UNIQUE_CHECK_PARTIAL:
      99                 :             :  *      it must be true if the entry is known unique, else false.
     100                 :             :  *      (In the current implementation we'll also return true after a
     101                 :             :  *      successful UNIQUE_CHECK_YES or UNIQUE_CHECK_EXISTING call, but
     102                 :             :  *      that's just a coding artifact.)
     103                 :             :  */
     104                 :             : bool
     105                 :     5276755 : _bt_doinsert(Relation rel, IndexTuple itup,
     106                 :             :              IndexUniqueCheck checkUnique, bool indexUnchanged,
     107                 :             :              Relation heapRel)
     108                 :             : {
     109                 :     5276755 :     bool        is_unique = false;
     110                 :             :     BTInsertStateData insertstate;
     111                 :             :     BTScanInsert itup_key;
     112                 :             :     BTStack     stack;
     113                 :     5276755 :     bool        checkingunique = (checkUnique != UNIQUE_CHECK_NO);
     114                 :             : 
     115                 :             :     /* we need an insertion scan key to do our search, so build one */
     116                 :     5276755 :     itup_key = _bt_mkscankey(rel, itup);
     117                 :             : 
     118         [ +  + ]:     5276755 :     if (checkingunique)
     119                 :             :     {
     120         [ +  + ]:     3592817 :         if (!itup_key->anynullkeys)
     121                 :             :         {
     122                 :             :             /* No (heapkeyspace) scantid until uniqueness established */
     123                 :     3582683 :             itup_key->scantid = NULL;
     124                 :             :         }
     125                 :             :         else
     126                 :             :         {
     127                 :             :             /*
     128                 :             :              * Scan key for new tuple contains NULL key values.  Bypass
     129                 :             :              * checkingunique steps.  They are unnecessary because core code
     130                 :             :              * considers NULL unequal to every value, including NULL.
     131                 :             :              *
     132                 :             :              * This optimization avoids O(N^2) behavior within the
     133                 :             :              * _bt_findinsertloc() heapkeyspace path when a unique index has a
     134                 :             :              * large number of "duplicates" with NULL key values.
     135                 :             :              */
     136                 :       10134 :             checkingunique = false;
     137                 :             :             /* Tuple is unique in the sense that core code cares about */
     138                 :             :             Assert(checkUnique != UNIQUE_CHECK_EXISTING);
     139                 :       10134 :             is_unique = true;
     140                 :             :         }
     141                 :             :     }
     142                 :             : 
     143                 :             :     /*
     144                 :             :      * Fill in the BTInsertState working area, to track the current page and
     145                 :             :      * position within the page to insert on.
     146                 :             :      *
     147                 :             :      * Note that itemsz is passed down to lower level code that deals with
     148                 :             :      * inserting the item.  It must be MAXALIGN()'d.  This ensures that space
     149                 :             :      * accounting code consistently considers the alignment overhead that we
     150                 :             :      * expect PageAddItem() will add later.  (Actually, index_form_tuple() is
     151                 :             :      * already conservative about alignment, but we don't rely on that from
     152                 :             :      * this distance.  Besides, preserving the "true" tuple size in index
     153                 :             :      * tuple headers for the benefit of nbtsplitloc.c might happen someday.
     154                 :             :      * Note that heapam does not MAXALIGN() each heap tuple's lp_len field.)
     155                 :             :      */
     156                 :     5276755 :     insertstate.itup = itup;
     157                 :     5276755 :     insertstate.itemsz = MAXALIGN(IndexTupleSize(itup));
     158                 :     5276755 :     insertstate.itup_key = itup_key;
     159                 :     5276755 :     insertstate.bounds_valid = false;
     160                 :     5276755 :     insertstate.buf = InvalidBuffer;
     161                 :     5276755 :     insertstate.postingoff = 0;
     162                 :             : 
     163                 :     5276767 : search:
     164                 :             : 
     165                 :             :     /*
     166                 :             :      * Find and lock the leaf page that the tuple should be added to by
     167                 :             :      * searching from the root page.  insertstate.buf will hold a buffer that
     168                 :             :      * is locked in exclusive mode afterwards.
     169                 :             :      */
     170                 :     5276767 :     stack = _bt_search_insert(rel, heapRel, &insertstate);
     171                 :             : 
     172                 :             :     /*
     173                 :             :      * checkingunique inserts are not allowed to go ahead when two tuples with
     174                 :             :      * equal key attribute values would be visible to new MVCC snapshots once
     175                 :             :      * the xact commits.  Check for conflicts in the locked page/buffer (if
     176                 :             :      * needed) here.
     177                 :             :      *
     178                 :             :      * It might be necessary to check a page to the right in _bt_check_unique,
     179                 :             :      * though that should be very rare.  In practice the first page the value
     180                 :             :      * could be on (with scantid omitted) is almost always also the only page
     181                 :             :      * that a matching tuple might be found on.  This is due to the behavior
     182                 :             :      * of _bt_findsplitloc with duplicate tuples -- a group of duplicates can
     183                 :             :      * only be allowed to cross a page boundary when there is no candidate
     184                 :             :      * leaf page split point that avoids it.  Also, _bt_check_unique can use
     185                 :             :      * the leaf page high key to determine that there will be no duplicates on
     186                 :             :      * the right sibling without actually visiting it (it uses the high key in
     187                 :             :      * cases where the new item happens to belong at the far right of the leaf
     188                 :             :      * page).
     189                 :             :      *
     190                 :             :      * NOTE: obviously, _bt_check_unique can only detect keys that are already
     191                 :             :      * in the index; so it cannot defend against concurrent insertions of the
     192                 :             :      * same key.  We protect against that by means of holding a write lock on
     193                 :             :      * the first page the value could be on, with omitted/-inf value for the
     194                 :             :      * implicit heap TID tiebreaker attribute.  Any other would-be inserter of
     195                 :             :      * the same key must acquire a write lock on the same page, so only one
     196                 :             :      * would-be inserter can be making the check at one time.  Furthermore,
     197                 :             :      * once we are past the check we hold write locks continuously until we
     198                 :             :      * have performed our insertion, so no later inserter can fail to see our
     199                 :             :      * insertion.  (This requires some care in _bt_findinsertloc.)
     200                 :             :      *
     201                 :             :      * If we must wait for another xact, we release the lock while waiting,
     202                 :             :      * and then must perform a new search.
     203                 :             :      *
     204                 :             :      * For a partial uniqueness check, we don't wait for the other xact. Just
     205                 :             :      * let the tuple in and return false for possibly non-unique, or true for
     206                 :             :      * definitely unique.
     207                 :             :      */
     208         [ +  + ]:     5276767 :     if (checkingunique)
     209                 :             :     {
     210                 :             :         TransactionId xwait;
     211                 :             :         uint32      speculativeToken;
     212                 :             : 
     213                 :     3582695 :         xwait = _bt_check_unique(rel, &insertstate, heapRel, checkUnique,
     214                 :             :                                  &is_unique, &speculativeToken);
     215                 :             : 
     216         [ +  + ]:     3582314 :         if (unlikely(TransactionIdIsValid(xwait)))
     217                 :             :         {
     218                 :             :             /* Have to wait for the other guy ... */
     219                 :          12 :             _bt_relbuf(rel, insertstate.buf);
     220                 :          12 :             insertstate.buf = InvalidBuffer;
     221                 :             : 
     222                 :             :             /*
     223                 :             :              * If it's a speculative insertion, wait for it to finish (ie. to
     224                 :             :              * go ahead with the insertion, or kill the tuple).  Otherwise
     225                 :             :              * wait for the transaction to finish as usual.
     226                 :             :              */
     227         [ -  + ]:          12 :             if (speculativeToken)
     228                 :           0 :                 SpeculativeInsertionWait(xwait, speculativeToken);
     229                 :             :             else
     230                 :          12 :                 XactLockTableWait(xwait, rel, &itup->t_tid, XLTW_InsertIndex);
     231                 :             : 
     232                 :             :             /* start over... */
     233         [ -  + ]:          12 :             if (stack)
     234                 :           0 :                 _bt_freestack(stack);
     235                 :          12 :             goto search;
     236                 :             :         }
     237                 :             : 
     238                 :             :         /* Uniqueness is established -- restore heap tid as scantid */
     239         [ +  - ]:     3582302 :         if (itup_key->heapkeyspace)
     240                 :     3582302 :             itup_key->scantid = &itup->t_tid;
     241                 :             :     }
     242                 :             : 
     243         [ +  + ]:     5276374 :     if (checkUnique != UNIQUE_CHECK_EXISTING)
     244                 :             :     {
     245                 :             :         OffsetNumber newitemoff;
     246                 :             : 
     247                 :             :         /*
     248                 :             :          * The only conflict predicate locking cares about for indexes is when
     249                 :             :          * an index tuple insert conflicts with an existing lock.  We don't
     250                 :             :          * know the actual page we're going to insert on for sure just yet in
     251                 :             :          * checkingunique and !heapkeyspace cases, but it's okay to use the
     252                 :             :          * first page the value could be on (with scantid omitted) instead.
     253                 :             :          */
     254                 :     5276338 :         CheckForSerializableConflictIn(rel, NULL, BufferGetBlockNumber(insertstate.buf));
     255                 :             : 
     256                 :             :         /*
     257                 :             :          * Do the insertion.  Note that insertstate contains cached binary
     258                 :             :          * search bounds established within _bt_check_unique when insertion is
     259                 :             :          * checkingunique.
     260                 :             :          */
     261                 :     5276335 :         newitemoff = _bt_findinsertloc(rel, &insertstate, checkingunique,
     262                 :             :                                        indexUnchanged, stack, heapRel);
     263                 :     5276335 :         _bt_insertonpg(rel, heapRel, itup_key, insertstate.buf, InvalidBuffer,
     264                 :             :                        stack, itup, insertstate.itemsz, newitemoff,
     265                 :             :                        insertstate.postingoff, false);
     266                 :             :     }
     267                 :             :     else
     268                 :             :     {
     269                 :             :         /* just release the buffer */
     270                 :          36 :         _bt_relbuf(rel, insertstate.buf);
     271                 :             :     }
     272                 :             : 
     273                 :             :     /* be tidy */
     274         [ +  + ]:     5276369 :     if (stack)
     275                 :     4666724 :         _bt_freestack(stack);
     276                 :     5276369 :     pfree(itup_key);
     277                 :             : 
     278                 :     5276369 :     return is_unique;
     279                 :             : }
     280                 :             : 
     281                 :             : /*
     282                 :             :  *  _bt_search_insert() -- _bt_search() wrapper for inserts
     283                 :             :  *
     284                 :             :  * Search the tree for a particular scankey, or more precisely for the first
     285                 :             :  * leaf page it could be on.  Try to make use of the fastpath optimization's
     286                 :             :  * rightmost leaf page cache before actually searching the tree from the root
     287                 :             :  * page, though.
     288                 :             :  *
     289                 :             :  * Return value is a stack of parent-page pointers (though see notes about
     290                 :             :  * fastpath optimization and page splits below).  insertstate->buf is set to
     291                 :             :  * the address of the leaf-page buffer, which is write-locked and pinned in
     292                 :             :  * all cases (if necessary by creating a new empty root page for caller).
     293                 :             :  *
     294                 :             :  * The fastpath optimization avoids most of the work of searching the tree
     295                 :             :  * repeatedly when a single backend inserts successive new tuples on the
     296                 :             :  * rightmost leaf page of an index.  A backend cache of the rightmost leaf
     297                 :             :  * page is maintained within _bt_insertonpg(), and used here.  The cache is
     298                 :             :  * invalidated here when an insert of a non-pivot tuple must take place on a
     299                 :             :  * non-rightmost leaf page.
     300                 :             :  *
     301                 :             :  * The optimization helps with indexes on an auto-incremented field.  It also
     302                 :             :  * helps with indexes on datetime columns, as well as indexes with lots of
     303                 :             :  * NULL values.  (NULLs usually get inserted in the rightmost page for single
     304                 :             :  * column indexes, since they usually get treated as coming after everything
     305                 :             :  * else in the key space.  Individual NULL tuples will generally be placed on
     306                 :             :  * the rightmost leaf page due to the influence of the heap TID column.)
     307                 :             :  *
     308                 :             :  * Note that we avoid applying the optimization when there is insufficient
     309                 :             :  * space on the rightmost page to fit caller's new item.  This is necessary
     310                 :             :  * because we'll need to return a real descent stack when a page split is
     311                 :             :  * expected (actually, caller can cope with a leaf page split that uses a NULL
     312                 :             :  * stack, but that's very slow and so must be avoided).  Note also that the
     313                 :             :  * fastpath optimization acquires the lock on the page conditionally as a way
     314                 :             :  * of reducing extra contention when there are concurrent insertions into the
     315                 :             :  * rightmost page (we give up if we'd have to wait for the lock).  We assume
     316                 :             :  * that it isn't useful to apply the optimization when there is contention,
     317                 :             :  * since each per-backend cache won't stay valid for long.
     318                 :             :  */
     319                 :             : static BTStack
     320                 :     5276767 : _bt_search_insert(Relation rel, Relation heaprel, BTInsertState insertstate)
     321                 :             : {
     322                 :             :     Assert(insertstate->buf == InvalidBuffer);
     323                 :             :     Assert(!insertstate->bounds_valid);
     324                 :             :     Assert(insertstate->postingoff == 0);
     325                 :             : 
     326   [ +  -  +  + ]:     5276767 :     if (RelationGetTargetBlock(rel) != InvalidBlockNumber)
     327                 :             :     {
     328                 :             :         /* Simulate a _bt_getbuf() call with conditional locking */
     329         [ +  - ]:       31301 :         insertstate->buf = ReadBuffer(rel, RelationGetTargetBlock(rel));
     330         [ +  + ]:       31301 :         if (_bt_conditionallockbuf(rel, insertstate->buf))
     331                 :             :         {
     332                 :             :             Page        page;
     333                 :             :             BTPageOpaque opaque;
     334                 :             : 
     335                 :       30890 :             _bt_checkpage(rel, insertstate->buf);
     336                 :       30890 :             page = BufferGetPage(insertstate->buf);
     337                 :       30890 :             opaque = BTPageGetOpaque(page);
     338                 :             : 
     339                 :             :             /*
     340                 :             :              * Check if the page is still the rightmost leaf page and has
     341                 :             :              * enough free space to accommodate the new tuple.  Also check
     342                 :             :              * that the insertion scan key is strictly greater than the first
     343                 :             :              * non-pivot tuple on the page.  (Note that we expect itup_key's
     344                 :             :              * scantid to be unset when our caller is a checkingunique
     345                 :             :              * inserter.)
     346                 :             :              */
     347         [ +  + ]:       30890 :             if (P_RIGHTMOST(opaque) &&
     348         [ +  - ]:       30860 :                 P_ISLEAF(opaque) &&
     349         [ +  - ]:       30860 :                 !P_IGNORE(opaque) &&
     350   [ +  +  +  - ]:       61501 :                 PageGetFreeSpace(page) > insertstate->itemsz &&
     351         [ +  + ]:       61282 :                 PageGetMaxOffsetNumber(page) >= P_HIKEY &&
     352                 :       30641 :                 _bt_compare(rel, insertstate->itup_key, page, P_HIKEY) > 0)
     353                 :             :             {
     354                 :             :                 /*
     355                 :             :                  * Caller can use the fastpath optimization because cached
     356                 :             :                  * block is still rightmost leaf page, which can fit caller's
     357                 :             :                  * new tuple without splitting.  Keep block in local cache for
     358                 :             :                  * next insert, and have caller use NULL stack.
     359                 :             :                  *
     360                 :             :                  * Note that _bt_insert_parent() has an assertion that catches
     361                 :             :                  * leaf page splits that somehow follow from a fastpath insert
     362                 :             :                  * (it should only be passed a NULL stack when it must deal
     363                 :             :                  * with a concurrent root page split, and never because a NULL
     364                 :             :                  * stack was returned here).
     365                 :             :                  */
     366                 :       30622 :                 return NULL;
     367                 :             :             }
     368                 :             : 
     369                 :             :             /* Page unsuitable for caller, drop lock and pin */
     370                 :         268 :             _bt_relbuf(rel, insertstate->buf);
     371                 :             :         }
     372                 :             :         else
     373                 :             :         {
     374                 :             :             /* Lock unavailable, drop pin */
     375                 :         411 :             ReleaseBuffer(insertstate->buf);
     376                 :             :         }
     377                 :             : 
     378                 :             :         /* Forget block, since cache doesn't appear to be useful */
     379                 :         679 :         RelationSetTargetBlock(rel, InvalidBlockNumber);
     380                 :             :     }
     381                 :             : 
     382                 :             :     /* Cannot use optimization -- descend tree, return proper descent stack */
     383                 :     5246145 :     return _bt_search(rel, heaprel, insertstate->itup_key, &insertstate->buf,
     384                 :             :                       BT_WRITE, true);
     385                 :             : }
     386                 :             : 
     387                 :             : /*
     388                 :             :  *  _bt_check_unique() -- Check for violation of unique index constraint
     389                 :             :  *
     390                 :             :  * Returns InvalidTransactionId if there is no conflict, else an xact ID
     391                 :             :  * we must wait for to see if it commits a conflicting tuple.   If an actual
     392                 :             :  * conflict is detected, no return --- just ereport().  If an xact ID is
     393                 :             :  * returned, and the conflicting tuple still has a speculative insertion in
     394                 :             :  * progress, *speculativeToken is set to non-zero, and the caller can wait for
     395                 :             :  * the verdict on the insertion using SpeculativeInsertionWait().
     396                 :             :  *
     397                 :             :  * However, if checkUnique == UNIQUE_CHECK_PARTIAL, we always return
     398                 :             :  * InvalidTransactionId because we don't want to wait.  In this case we
     399                 :             :  * set *is_unique to false if there is a potential conflict, and the
     400                 :             :  * core code must redo the uniqueness check later.
     401                 :             :  *
     402                 :             :  * As a side-effect, sets state in insertstate that can later be used by
     403                 :             :  * _bt_findinsertloc() to reuse most of the binary search work we do
     404                 :             :  * here.
     405                 :             :  *
     406                 :             :  * This code treats NULLs as equal, unlike the default semantics for unique
     407                 :             :  * indexes.  So do not call here when there are NULL values in scan key and
     408                 :             :  * the index uses the default NULLS DISTINCT mode.
     409                 :             :  */
     410                 :             : static TransactionId
     411                 :     3582695 : _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
     412                 :             :                  IndexUniqueCheck checkUnique, bool *is_unique,
     413                 :             :                  uint32 *speculativeToken)
     414                 :             : {
     415                 :     3582695 :     IndexTuple  itup = insertstate->itup;
     416                 :     3582695 :     IndexTuple  curitup = NULL;
     417                 :     3582695 :     ItemId      curitemid = NULL;
     418                 :     3582695 :     BTScanInsert itup_key = insertstate->itup_key;
     419                 :             :     SnapshotData SnapshotDirty;
     420                 :             :     OffsetNumber offset;
     421                 :             :     OffsetNumber maxoff;
     422                 :             :     Page        page;
     423                 :             :     BTPageOpaque opaque;
     424                 :     3582695 :     Buffer      nbuf = InvalidBuffer;
     425                 :     3582695 :     bool        found = false;
     426                 :     3582695 :     bool        inposting = false;
     427                 :     3582695 :     bool        prevalldead = true;
     428                 :     3582695 :     int         curposti = 0;
     429                 :             : 
     430                 :             :     /* Assume unique until we find a duplicate */
     431                 :     3582695 :     *is_unique = true;
     432                 :             : 
     433                 :     3582695 :     InitDirtySnapshot(SnapshotDirty);
     434                 :             : 
     435                 :     3582695 :     page = BufferGetPage(insertstate->buf);
     436                 :     3582695 :     opaque = BTPageGetOpaque(page);
     437                 :     3582695 :     maxoff = PageGetMaxOffsetNumber(page);
     438                 :             : 
     439                 :             :     /*
     440                 :             :      * Find the first tuple with the same key.
     441                 :             :      *
     442                 :             :      * This also saves the binary search bounds in insertstate.  We use them
     443                 :             :      * in the fastpath below, but also in the _bt_findinsertloc() call later.
     444                 :             :      */
     445                 :             :     Assert(!insertstate->bounds_valid);
     446                 :     3582695 :     offset = _bt_binsrch_insert(rel, insertstate);
     447                 :             : 
     448                 :             :     /*
     449                 :             :      * Scan over all equal tuples, looking for live conflicts.
     450                 :             :      */
     451                 :             :     Assert(!insertstate->bounds_valid || insertstate->low == offset);
     452                 :             :     Assert(!itup_key->anynullkeys);
     453                 :             :     Assert(itup_key->scantid == NULL);
     454                 :             :     for (;;)
     455                 :             :     {
     456                 :             :         /*
     457                 :             :          * Each iteration of the loop processes one heap TID, not one index
     458                 :             :          * tuple.  Current offset number for page isn't usually advanced on
     459                 :             :          * iterations that process heap TIDs from posting list tuples.
     460                 :             :          *
     461                 :             :          * "inposting" state is set when _inside_ a posting list --- not when
     462                 :             :          * we're at the start (or end) of a posting list.  We advance curposti
     463                 :             :          * at the end of the iteration when inside a posting list tuple.  In
     464                 :             :          * general, every loop iteration either advances the page offset or
     465                 :             :          * advances curposti --- an iteration that handles the rightmost/max
     466                 :             :          * heap TID in a posting list finally advances the page offset (and
     467                 :             :          * unsets "inposting").
     468                 :             :          *
     469                 :             :          * Make sure the offset points to an actual index tuple before trying
     470                 :             :          * to examine it...
     471                 :             :          */
     472         [ +  + ]:    11511381 :         if (offset <= maxoff)
     473                 :             :         {
     474                 :             :             /*
     475                 :             :              * Fastpath: In most cases, we can use cached search bounds to
     476                 :             :              * limit our consideration to items that are definitely
     477                 :             :              * duplicates.  This fastpath doesn't apply when the original page
     478                 :             :              * is empty, or when initial offset is past the end of the
     479                 :             :              * original page, which may indicate that we need to examine a
     480                 :             :              * second or subsequent page.
     481                 :             :              *
     482                 :             :              * Note that this optimization allows us to avoid calling
     483                 :             :              * _bt_compare() directly when there are no duplicates, as long as
     484                 :             :              * the offset where the key will go is not at the end of the page.
     485                 :             :              */
     486   [ +  +  +  + ]:     9331016 :             if (nbuf == InvalidBuffer && offset == insertstate->stricthigh)
     487                 :             :             {
     488                 :             :                 Assert(insertstate->bounds_valid);
     489                 :             :                 Assert(insertstate->low >= P_FIRSTDATAKEY(opaque));
     490                 :             :                 Assert(insertstate->low <= insertstate->stricthigh);
     491                 :             :                 Assert(_bt_compare(rel, itup_key, page, offset) < 0);
     492                 :     1256775 :                 break;
     493                 :             :             }
     494                 :             : 
     495                 :             :             /*
     496                 :             :              * We can skip items that are already marked killed.
     497                 :             :              *
     498                 :             :              * In the presence of heavy update activity an index may contain
     499                 :             :              * many killed items with the same key; running _bt_compare() on
     500                 :             :              * each killed item gets expensive.  Just advance over killed
     501                 :             :              * items as quickly as we can.  We only apply _bt_compare() when
     502                 :             :              * we get to a non-killed item.  We could reuse the bounds to
     503                 :             :              * avoid _bt_compare() calls for known equal tuples, but it
     504                 :             :              * doesn't seem worth it.
     505                 :             :              */
     506         [ +  + ]:     8074241 :             if (!inposting)
     507                 :     5064345 :                 curitemid = PageGetItemId(page, offset);
     508   [ +  +  +  + ]:     8074241 :             if (inposting || !ItemIdIsDead(curitemid))
     509                 :             :             {
     510                 :             :                 ItemPointerData htid;
     511                 :     7736528 :                 bool        all_dead = false;
     512                 :             : 
     513         [ +  + ]:     7736528 :                 if (!inposting)
     514                 :             :                 {
     515                 :             :                     /* Plain tuple, or first TID in posting list tuple */
     516         [ +  + ]:     4726632 :                     if (_bt_compare(rel, itup_key, page, offset) != 0)
     517                 :      127757 :                         break;  /* we're past all the equal tuples */
     518                 :             : 
     519                 :             :                     /* Advanced curitup */
     520                 :     4598875 :                     curitup = (IndexTuple) PageGetItem(page, curitemid);
     521                 :             :                     Assert(!BTreeTupleIsPivot(curitup));
     522                 :             :                 }
     523                 :             : 
     524                 :             :                 /* okay, we gotta fetch the heap tuple using htid ... */
     525         [ +  + ]:     7608771 :                 if (!BTreeTupleIsPosting(curitup))
     526                 :             :                 {
     527                 :             :                     /* ... htid is from simple non-pivot tuple */
     528                 :             :                     Assert(!inposting);
     529                 :     4569660 :                     htid = curitup->t_tid;
     530                 :             :                 }
     531         [ +  + ]:     3039111 :                 else if (!inposting)
     532                 :             :                 {
     533                 :             :                     /* ... htid is first TID in new posting list */
     534                 :       29215 :                     inposting = true;
     535                 :       29215 :                     prevalldead = true;
     536                 :       29215 :                     curposti = 0;
     537                 :       29215 :                     htid = *BTreeTupleGetPostingN(curitup, 0);
     538                 :             :                 }
     539                 :             :                 else
     540                 :             :                 {
     541                 :             :                     /* ... htid is second or subsequent TID in posting list */
     542                 :             :                     Assert(curposti > 0);
     543                 :     3009896 :                     htid = *BTreeTupleGetPostingN(curitup, curposti);
     544                 :             :                 }
     545                 :             : 
     546                 :             :                 /*
     547                 :             :                  * If we are doing a recheck, we expect to find the tuple we
     548                 :             :                  * are rechecking.  It's not a duplicate, but we have to keep
     549                 :             :                  * scanning.
     550                 :             :                  */
     551   [ +  +  +  + ]:     7608935 :                 if (checkUnique == UNIQUE_CHECK_EXISTING &&
     552                 :         164 :                     ItemPointerCompare(&htid, &itup->t_tid) == 0)
     553                 :             :                 {
     554                 :          36 :                     found = true;
     555                 :             :                 }
     556                 :             : 
     557                 :             :                 /*
     558                 :             :                  * Check if there's any table tuples for this index entry
     559                 :             :                  * satisfying SnapshotDirty. This is necessary because for AMs
     560                 :             :                  * with optimizations like heap's HOT, we have just a single
     561                 :             :                  * index entry for the entire chain.
     562                 :             :                  */
     563         [ +  + ]:     7608735 :                 else if (table_fetch_tid(heapRel, &htid, &SnapshotDirty,
     564                 :             :                                          &all_dead))
     565                 :             :                 {
     566                 :             :                     TransactionId xwait;
     567                 :             : 
     568                 :             :                     /*
     569                 :             :                      * It is a duplicate. If we are only doing a partial
     570                 :             :                      * check, then don't bother checking if the tuple is being
     571                 :             :                      * updated in another transaction. Just return the fact
     572                 :             :                      * that it is a potential conflict and leave the full
     573                 :             :                      * check till later. Don't invalidate binary search
     574                 :             :                      * bounds.
     575                 :             :                      */
     576         [ +  + ]:         627 :                     if (checkUnique == UNIQUE_CHECK_PARTIAL)
     577                 :             :                     {
     578         [ -  + ]:         234 :                         if (nbuf != InvalidBuffer)
     579                 :           0 :                             _bt_relbuf(rel, nbuf);
     580                 :         234 :                         *is_unique = false;
     581                 :         246 :                         return InvalidTransactionId;
     582                 :             :                     }
     583                 :             : 
     584                 :             :                     /*
     585                 :             :                      * If this tuple is being updated by other transaction
     586                 :             :                      * then we have to wait for its commit/abort.
     587                 :             :                      */
     588                 :         786 :                     xwait = (TransactionIdIsValid(SnapshotDirty.xmin)) ?
     589         [ +  + ]:         393 :                         SnapshotDirty.xmin : SnapshotDirty.xmax;
     590                 :             : 
     591         [ +  + ]:         393 :                     if (TransactionIdIsValid(xwait))
     592                 :             :                     {
     593         [ -  + ]:          12 :                         if (nbuf != InvalidBuffer)
     594                 :           0 :                             _bt_relbuf(rel, nbuf);
     595                 :             :                         /* Tell _bt_doinsert to wait... */
     596                 :          12 :                         *speculativeToken = SnapshotDirty.speculativeToken;
     597                 :             :                         /* Caller releases lock on buf immediately */
     598                 :          12 :                         insertstate->bounds_valid = false;
     599                 :          12 :                         return xwait;
     600                 :             :                     }
     601                 :             : 
     602                 :             :                     /*
     603                 :             :                      * Otherwise we have a definite conflict.  But before
     604                 :             :                      * complaining, look to see if the tuple we want to insert
     605                 :             :                      * is itself now committed dead --- if so, don't complain.
     606                 :             :                      * This is a waste of time in normal scenarios but we must
     607                 :             :                      * do it to support CREATE INDEX CONCURRENTLY.
     608                 :             :                      *
     609                 :             :                      * We must follow HOT-chains here because during
     610                 :             :                      * concurrent index build, we insert the root TID though
     611                 :             :                      * the actual tuple may be somewhere in the HOT-chain.
     612                 :             :                      * While following the chain we might not stop at the
     613                 :             :                      * exact tuple which triggered the insert, but that's OK
     614                 :             :                      * because if we find a live tuple anywhere in this chain,
     615                 :             :                      * we have a unique key conflict.  The other live tuple is
     616                 :             :                      * not part of this chain because it had a different index
     617                 :             :                      * entry.
     618                 :             :                      */
     619                 :         381 :                     htid = itup->t_tid;
     620         [ -  + ]:         381 :                     if (table_fetch_tid(heapRel, &htid, SnapshotSelf, NULL))
     621                 :             :                     {
     622                 :             :                         /* Normal case --- it's still live */
     623                 :             :                     }
     624                 :             :                     else
     625                 :             :                     {
     626                 :             :                         /*
     627                 :             :                          * It's been deleted, so no error, and no need to
     628                 :             :                          * continue searching
     629                 :             :                          */
     630                 :           0 :                         break;
     631                 :             :                     }
     632                 :             : 
     633                 :             :                     /*
     634                 :             :                      * Check for a conflict-in as we would if we were going to
     635                 :             :                      * write to this page.  We aren't actually going to write,
     636                 :             :                      * but we want a chance to report SSI conflicts that would
     637                 :             :                      * otherwise be masked by this unique constraint
     638                 :             :                      * violation.
     639                 :             :                      */
     640                 :         381 :                     CheckForSerializableConflictIn(rel, NULL, BufferGetBlockNumber(insertstate->buf));
     641                 :             : 
     642                 :             :                     /*
     643                 :             :                      * This is a definite conflict.  Break the tuple down into
     644                 :             :                      * datums and report the error.  But first, make sure we
     645                 :             :                      * release the buffer locks we're holding ---
     646                 :             :                      * BuildIndexValueDescription could make catalog accesses,
     647                 :             :                      * which in the worst case might touch this same index and
     648                 :             :                      * cause deadlocks.
     649                 :             :                      */
     650         [ -  + ]:         377 :                     if (nbuf != InvalidBuffer)
     651                 :           0 :                         _bt_relbuf(rel, nbuf);
     652                 :         377 :                     _bt_relbuf(rel, insertstate->buf);
     653                 :         377 :                     insertstate->buf = InvalidBuffer;
     654                 :         377 :                     insertstate->bounds_valid = false;
     655                 :             : 
     656                 :             :                     {
     657                 :             :                         Datum       values[INDEX_MAX_KEYS];
     658                 :             :                         bool        isnull[INDEX_MAX_KEYS];
     659                 :             :                         char       *key_desc;
     660                 :             : 
     661                 :         377 :                         index_deform_tuple(itup, RelationGetDescr(rel),
     662                 :             :                                            values, isnull);
     663                 :             : 
     664                 :         377 :                         key_desc = BuildIndexValueDescription(rel, values,
     665                 :             :                                                               isnull);
     666                 :             : 
     667   [ +  -  +  + ]:         377 :                         ereport(ERROR,
     668                 :             :                                 (errcode(ERRCODE_UNIQUE_VIOLATION),
     669                 :             :                                  errmsg("duplicate key value violates unique constraint \"%s\"",
     670                 :             :                                         RelationGetRelationName(rel)),
     671                 :             :                                  key_desc ? errdetail("Key %s already exists.",
     672                 :             :                                                       key_desc) : 0,
     673                 :             :                                  errtableconstraint(heapRel,
     674                 :             :                                                     RelationGetRelationName(rel))));
     675                 :             :                     }
     676                 :             :                 }
     677   [ +  +  +  +  :     7608108 :                 else if (all_dead && (!inposting ||
                   +  + ]
     678                 :       18652 :                                       (prevalldead &&
     679         [ +  + ]:       18652 :                                        curposti == BTreeTupleGetNPosting(curitup) - 1)))
     680                 :             :                 {
     681                 :             :                     /*
     682                 :             :                      * The conflicting tuple (or all HOT chains pointed to by
     683                 :             :                      * all posting list TIDs) is dead to everyone, so try to
     684                 :             :                      * mark the index entry killed. It's ok if we're not
     685                 :             :                      * allowed to, this isn't required for correctness.
     686                 :             :                      */
     687                 :             :                     Buffer      buf;
     688                 :             : 
     689                 :             :                     /* Be sure to operate on the proper buffer */
     690         [ +  + ]:       52458 :                     if (nbuf != InvalidBuffer)
     691                 :           2 :                         buf = nbuf;
     692                 :             :                     else
     693                 :       52456 :                         buf = insertstate->buf;
     694                 :             : 
     695                 :             :                     /*
     696                 :             :                      * Use the hint bit infrastructure to check if we can
     697                 :             :                      * update the page while just holding a share lock.
     698                 :             :                      *
     699                 :             :                      * Can't use BufferSetHintBits16() here as we update two
     700                 :             :                      * different locations.
     701                 :             :                      */
     702         [ +  - ]:       52458 :                     if (BufferBeginSetHintBits(buf))
     703                 :             :                     {
     704                 :       52458 :                         ItemIdMarkDead(curitemid);
     705                 :       52458 :                         opaque->btpo_flags |= BTP_HAS_GARBAGE;
     706                 :       52458 :                         BufferFinishSetHintBits(buf, true, true);
     707                 :             :                     }
     708                 :             :                 }
     709                 :             : 
     710                 :             :                 /*
     711                 :             :                  * Remember if posting list tuple has even a single HOT chain
     712                 :             :                  * whose members are not all dead
     713                 :             :                  */
     714   [ +  +  +  + ]:     7608144 :                 if (!all_dead && inposting)
     715                 :     3020215 :                     prevalldead = false;
     716                 :             :             }
     717                 :             :         }
     718                 :             : 
     719   [ +  +  +  + ]:    10126222 :         if (inposting && curposti < BTreeTupleGetNPosting(curitup) - 1)
     720                 :             :         {
     721                 :             :             /* Advance to next TID in same posting list */
     722                 :     3009896 :             curposti++;
     723                 :     3009896 :             continue;
     724                 :             :         }
     725         [ +  + ]:     7116326 :         else if (offset < maxoff)
     726                 :             :         {
     727                 :             :             /* Advance to next tuple */
     728                 :     4912094 :             curposti = 0;
     729                 :     4912094 :             inposting = false;
     730                 :     4912094 :             offset = OffsetNumberNext(offset);
     731                 :             :         }
     732                 :             :         else
     733                 :             :         {
     734                 :             :             int         highkeycmp;
     735                 :             : 
     736                 :             :             /* If scankey == hikey we gotta check the next page too */
     737         [ +  + ]:     2204232 :             if (P_RIGHTMOST(opaque))
     738                 :     2125595 :                 break;
     739                 :       78637 :             highkeycmp = _bt_compare(rel, itup_key, page, P_HIKEY);
     740                 :             :             Assert(highkeycmp <= 0);
     741         [ +  + ]:       78637 :             if (highkeycmp != 0)
     742                 :       71941 :                 break;
     743                 :             :             /* Advance to next non-dead page --- there must be one */
     744                 :             :             for (;;)
     745                 :           0 :             {
     746                 :        6696 :                 BlockNumber nblkno = opaque->btpo_next;
     747                 :             : 
     748                 :        6696 :                 nbuf = _bt_relandgetbuf(rel, nbuf, nblkno, BT_READ);
     749                 :        6696 :                 page = BufferGetPage(nbuf);
     750                 :        6696 :                 opaque = BTPageGetOpaque(page);
     751         [ +  - ]:        6696 :                 if (!P_IGNORE(opaque))
     752                 :        6696 :                     break;
     753         [ #  # ]:           0 :                 if (P_RIGHTMOST(opaque))
     754         [ #  # ]:           0 :                     elog(ERROR, "fell off the end of index \"%s\"",
     755                 :             :                          RelationGetRelationName(rel));
     756                 :             :             }
     757                 :             :             /* Will also advance to next tuple */
     758                 :        6696 :             curposti = 0;
     759                 :        6696 :             inposting = false;
     760                 :        6696 :             maxoff = PageGetMaxOffsetNumber(page);
     761         [ +  + ]:        6696 :             offset = P_FIRSTDATAKEY(opaque);
     762                 :             :             /* Don't invalidate binary search bounds */
     763                 :             :         }
     764                 :             :     }
     765                 :             : 
     766                 :             :     /*
     767                 :             :      * If we are doing a recheck then we should have found the tuple we are
     768                 :             :      * checking.  Otherwise there's something very wrong --- probably, the
     769                 :             :      * index is on a non-immutable expression.
     770                 :             :      */
     771   [ +  +  -  + ]:     3582068 :     if (checkUnique == UNIQUE_CHECK_EXISTING && !found)
     772         [ #  # ]:           0 :         ereport(ERROR,
     773                 :             :                 (errcode(ERRCODE_INTERNAL_ERROR),
     774                 :             :                  errmsg("failed to re-find tuple within index \"%s\"",
     775                 :             :                         RelationGetRelationName(rel)),
     776                 :             :                  errhint("This may be because of a non-immutable index expression."),
     777                 :             :                  errtableconstraint(heapRel,
     778                 :             :                                     RelationGetRelationName(rel))));
     779                 :             : 
     780         [ +  + ]:     3582068 :     if (nbuf != InvalidBuffer)
     781                 :        3840 :         _bt_relbuf(rel, nbuf);
     782                 :             : 
     783                 :     3582068 :     return InvalidTransactionId;
     784                 :             : }
     785                 :             : 
     786                 :             : 
     787                 :             : /*
     788                 :             :  *  _bt_findinsertloc() -- Finds an insert location for a tuple
     789                 :             :  *
     790                 :             :  *      On entry, insertstate buffer contains the page the new tuple belongs
     791                 :             :  *      on.  It is exclusive-locked and pinned by the caller.
     792                 :             :  *
     793                 :             :  *      If 'checkingunique' is true, the buffer on entry is the first page
     794                 :             :  *      that contains duplicates of the new key.  If there are duplicates on
     795                 :             :  *      multiple pages, the correct insertion position might be some page to
     796                 :             :  *      the right, rather than the first page.  In that case, this function
     797                 :             :  *      moves right to the correct target page.
     798                 :             :  *
     799                 :             :  *      (In a !heapkeyspace index, there can be multiple pages with the same
     800                 :             :  *      high key, where the new tuple could legitimately be placed on.  In
     801                 :             :  *      that case, the caller passes the first page containing duplicates,
     802                 :             :  *      just like when checkingunique=true.  If that page doesn't have enough
     803                 :             :  *      room for the new tuple, this function moves right, trying to find a
     804                 :             :  *      legal page that does.)
     805                 :             :  *
     806                 :             :  *      If 'indexUnchanged' is true, this is for an UPDATE that didn't
     807                 :             :  *      logically change the indexed value, but must nevertheless have a new
     808                 :             :  *      entry to point to a successor version.  This hint from the executor
     809                 :             :  *      will influence our behavior when the page might have to be split and
     810                 :             :  *      we must consider our options.  Bottom-up index deletion can avoid
     811                 :             :  *      pathological version-driven page splits, but we only want to go to the
     812                 :             :  *      trouble of trying it when we already have moderate confidence that
     813                 :             :  *      it's appropriate.  The hint should not significantly affect our
     814                 :             :  *      behavior over time unless practically all inserts on to the leaf page
     815                 :             :  *      get the hint.
     816                 :             :  *
     817                 :             :  *      On exit, insertstate buffer contains the chosen insertion page, and
     818                 :             :  *      the offset within that page is returned.  If _bt_findinsertloc needed
     819                 :             :  *      to move right, the lock and pin on the original page are released, and
     820                 :             :  *      the new buffer is exclusively locked and pinned instead.
     821                 :             :  *
     822                 :             :  *      If insertstate contains cached binary search bounds, we will take
     823                 :             :  *      advantage of them.  This avoids repeating comparisons that we made in
     824                 :             :  *      _bt_check_unique() already.
     825                 :             :  */
     826                 :             : static OffsetNumber
     827                 :     5276335 : _bt_findinsertloc(Relation rel,
     828                 :             :                   BTInsertState insertstate,
     829                 :             :                   bool checkingunique,
     830                 :             :                   bool indexUnchanged,
     831                 :             :                   BTStack stack,
     832                 :             :                   Relation heapRel)
     833                 :             : {
     834                 :     5276335 :     BTScanInsert itup_key = insertstate->itup_key;
     835                 :     5276335 :     Page        page = BufferGetPage(insertstate->buf);
     836                 :             :     BTPageOpaque opaque;
     837                 :             :     OffsetNumber newitemoff;
     838                 :             : 
     839                 :     5276335 :     opaque = BTPageGetOpaque(page);
     840                 :             : 
     841                 :             :     /* Check 1/3 of a page restriction */
     842         [ -  + ]:     5276335 :     if (unlikely(insertstate->itemsz > BTMaxItemSize))
     843                 :           0 :         _bt_check_third_page(rel, heapRel, itup_key->heapkeyspace, page,
     844                 :             :                              insertstate->itup);
     845                 :             : 
     846                 :             :     Assert(P_ISLEAF(opaque) && !P_INCOMPLETE_SPLIT(opaque));
     847                 :             :     Assert(!insertstate->bounds_valid || checkingunique);
     848                 :             :     Assert(!itup_key->heapkeyspace || itup_key->scantid != NULL);
     849                 :             :     Assert(itup_key->heapkeyspace || itup_key->scantid == NULL);
     850                 :             :     Assert(!itup_key->allequalimage || itup_key->heapkeyspace);
     851                 :             : 
     852         [ +  - ]:     5276335 :     if (itup_key->heapkeyspace)
     853                 :             :     {
     854                 :             :         /* Keep track of whether checkingunique duplicate seen */
     855                 :     5276335 :         bool        uniquedup = indexUnchanged;
     856                 :             : 
     857                 :             :         /*
     858                 :             :          * If we're inserting into a unique index, we may have to walk right
     859                 :             :          * through leaf pages to find the one leaf page that we must insert on
     860                 :             :          * to.
     861                 :             :          *
     862                 :             :          * This is needed for checkingunique callers because a scantid was not
     863                 :             :          * used when we called _bt_search().  scantid can only be set after
     864                 :             :          * _bt_check_unique() has checked for duplicates.  The buffer
     865                 :             :          * initially stored in insertstate->buf has the page where the first
     866                 :             :          * duplicate key might be found, which isn't always the page that new
     867                 :             :          * tuple belongs on.  The heap TID attribute for new tuple (scantid)
     868                 :             :          * could force us to insert on a sibling page, though that should be
     869                 :             :          * very rare in practice.
     870                 :             :          */
     871         [ +  + ]:     5276335 :         if (checkingunique)
     872                 :             :         {
     873         [ +  + ]:     3582263 :             if (insertstate->low < insertstate->stricthigh)
     874                 :             :             {
     875                 :             :                 /* Encountered a duplicate in _bt_check_unique() */
     876                 :             :                 Assert(insertstate->bounds_valid);
     877                 :      286450 :                 uniquedup = true;
     878                 :             :             }
     879                 :             : 
     880                 :             :             for (;;)
     881                 :             :             {
     882                 :             :                 /*
     883                 :             :                  * Does the new tuple belong on this page?
     884                 :             :                  *
     885                 :             :                  * The earlier _bt_check_unique() call may well have
     886                 :             :                  * established a strict upper bound on the offset for the new
     887                 :             :                  * item.  If it's not the last item of the page (i.e. if there
     888                 :             :                  * is at least one tuple on the page that goes after the tuple
     889                 :             :                  * we're inserting) then we know that the tuple belongs on
     890                 :             :                  * this page.  We can skip the high key check.
     891                 :             :                  */
     892         [ +  + ]:     3588959 :                 if (insertstate->bounds_valid &&
     893   [ +  -  +  + ]:     7151578 :                     insertstate->low <= insertstate->stricthigh &&
     894                 :     3575789 :                     insertstate->stricthigh <= PageGetMaxOffsetNumber(page))
     895                 :     1367738 :                     break;
     896                 :             : 
     897                 :             :                 /* Test '<=', not '!=', since scantid is set now */
     898   [ +  +  +  + ]:     2309662 :                 if (P_RIGHTMOST(opaque) ||
     899                 :       88441 :                     _bt_compare(rel, itup_key, page, P_HIKEY) <= 0)
     900                 :             :                     break;
     901                 :             : 
     902                 :        6696 :                 _bt_stepright(rel, heapRel, insertstate, stack);
     903                 :             :                 /* Update local state after stepping right */
     904                 :        6696 :                 page = BufferGetPage(insertstate->buf);
     905                 :        6696 :                 opaque = BTPageGetOpaque(page);
     906                 :             :                 /* Assume duplicates (if checkingunique) */
     907                 :        6696 :                 uniquedup = true;
     908                 :             :             }
     909                 :             :         }
     910                 :             : 
     911                 :             :         /*
     912                 :             :          * If the target page cannot fit newitem, try to avoid splitting the
     913                 :             :          * page on insert by performing deletion or deduplication now
     914                 :             :          */
     915         [ +  + ]:     5276335 :         if (PageGetFreeSpace(page) < insertstate->itemsz)
     916                 :       34709 :             _bt_delete_or_dedup_one_page(rel, heapRel, insertstate, false,
     917                 :             :                                          checkingunique, uniquedup,
     918                 :             :                                          indexUnchanged);
     919                 :             :     }
     920                 :             :     else
     921                 :             :     {
     922                 :             :         /*----------
     923                 :             :          * This is a !heapkeyspace (version 2 or 3) index.  The current page
     924                 :             :          * is the first page that we could insert the new tuple to, but there
     925                 :             :          * may be other pages to the right that we could opt to use instead.
     926                 :             :          *
     927                 :             :          * If the new key is equal to one or more existing keys, we can
     928                 :             :          * legitimately place it anywhere in the series of equal keys.  In
     929                 :             :          * fact, if the new key is equal to the page's "high key" we can place
     930                 :             :          * it on the next page.  If it is equal to the high key, and there's
     931                 :             :          * not room to insert the new tuple on the current page without
     932                 :             :          * splitting, then we move right hoping to find more free space and
     933                 :             :          * avoid a split.
     934                 :             :          *
     935                 :             :          * Keep scanning right until we
     936                 :             :          *      (a) find a page with enough free space,
     937                 :             :          *      (b) reach the last page where the tuple can legally go, or
     938                 :             :          *      (c) get tired of searching.
     939                 :             :          * (c) is not flippant; it is important because if there are many
     940                 :             :          * pages' worth of equal keys, it's better to split one of the early
     941                 :             :          * pages than to scan all the way to the end of the run of equal keys
     942                 :             :          * on every insert.  We implement "get tired" as a random choice,
     943                 :             :          * since stopping after scanning a fixed number of pages wouldn't work
     944                 :             :          * well (we'd never reach the right-hand side of previously split
     945                 :             :          * pages).  The probability of moving right is set at 0.99, which may
     946                 :             :          * seem too high to change the behavior much, but it does an excellent
     947                 :             :          * job of preventing O(N^2) behavior with many equal keys.
     948                 :             :          *----------
     949                 :             :          */
     950         [ #  # ]:           0 :         while (PageGetFreeSpace(page) < insertstate->itemsz)
     951                 :             :         {
     952                 :             :             /*
     953                 :             :              * Before considering moving right, see if we can obtain enough
     954                 :             :              * space by erasing LP_DEAD items
     955                 :             :              */
     956         [ #  # ]:           0 :             if (P_HAS_GARBAGE(opaque))
     957                 :             :             {
     958                 :             :                 /* Perform simple deletion */
     959                 :           0 :                 _bt_delete_or_dedup_one_page(rel, heapRel, insertstate, true,
     960                 :             :                                              false, false, false);
     961                 :             : 
     962         [ #  # ]:           0 :                 if (PageGetFreeSpace(page) >= insertstate->itemsz)
     963                 :           0 :                     break;      /* OK, now we have enough space */
     964                 :             :             }
     965                 :             : 
     966                 :             :             /*
     967                 :             :              * Nope, so check conditions (b) and (c) enumerated above
     968                 :             :              *
     969                 :             :              * The earlier _bt_check_unique() call may well have established a
     970                 :             :              * strict upper bound on the offset for the new item.  If it's not
     971                 :             :              * the last item of the page (i.e. if there is at least one tuple
     972                 :             :              * on the page that's greater than the tuple we're inserting to)
     973                 :             :              * then we know that the tuple belongs on this page.  We can skip
     974                 :             :              * the high key check.
     975                 :             :              */
     976         [ #  # ]:           0 :             if (insertstate->bounds_valid &&
     977   [ #  #  #  # ]:           0 :                 insertstate->low <= insertstate->stricthigh &&
     978                 :           0 :                 insertstate->stricthigh <= PageGetMaxOffsetNumber(page))
     979                 :           0 :                 break;
     980                 :             : 
     981   [ #  #  #  # ]:           0 :             if (P_RIGHTMOST(opaque) ||
     982         [ #  # ]:           0 :                 _bt_compare(rel, itup_key, page, P_HIKEY) != 0 ||
     983                 :           0 :                 pg_prng_uint32(&pg_global_prng_state) <= (PG_UINT32_MAX / 100))
     984                 :             :                 break;
     985                 :             : 
     986                 :           0 :             _bt_stepright(rel, heapRel, insertstate, stack);
     987                 :             :             /* Update local state after stepping right */
     988                 :           0 :             page = BufferGetPage(insertstate->buf);
     989                 :           0 :             opaque = BTPageGetOpaque(page);
     990                 :             :         }
     991                 :             :     }
     992                 :             : 
     993                 :             :     /*
     994                 :             :      * We should now be on the correct page.  Find the offset within the page
     995                 :             :      * for the new tuple. (Possibly reusing earlier search bounds.)
     996                 :             :      */
     997                 :             :     Assert(P_RIGHTMOST(opaque) ||
     998                 :             :            _bt_compare(rel, itup_key, page, P_HIKEY) <= 0);
     999                 :             : 
    1000                 :     5276335 :     newitemoff = _bt_binsrch_insert(rel, insertstate);
    1001                 :             : 
    1002         [ -  + ]:     5276335 :     if (insertstate->postingoff == -1)
    1003                 :             :     {
    1004                 :             :         /*
    1005                 :             :          * There is an overlapping posting list tuple with its LP_DEAD bit
    1006                 :             :          * set.  We don't want to unnecessarily unset its LP_DEAD bit while
    1007                 :             :          * performing a posting list split, so perform simple index tuple
    1008                 :             :          * deletion early.
    1009                 :             :          */
    1010                 :           0 :         _bt_delete_or_dedup_one_page(rel, heapRel, insertstate, true,
    1011                 :             :                                      false, false, false);
    1012                 :             : 
    1013                 :             :         /*
    1014                 :             :          * Do new binary search.  New insert location cannot overlap with any
    1015                 :             :          * posting list now.
    1016                 :             :          */
    1017                 :             :         Assert(!insertstate->bounds_valid);
    1018                 :           0 :         insertstate->postingoff = 0;
    1019                 :           0 :         newitemoff = _bt_binsrch_insert(rel, insertstate);
    1020                 :             :         Assert(insertstate->postingoff == 0);
    1021                 :             :     }
    1022                 :             : 
    1023                 :     5276335 :     return newitemoff;
    1024                 :             : }
    1025                 :             : 
    1026                 :             : /*
    1027                 :             :  * Step right to next non-dead page, during insertion.
    1028                 :             :  *
    1029                 :             :  * This is a bit more complicated than moving right in a search.  We must
    1030                 :             :  * write-lock the target page before releasing write lock on current page;
    1031                 :             :  * else someone else's _bt_check_unique scan could fail to see our insertion.
    1032                 :             :  * Write locks on intermediate dead pages won't do because we don't know when
    1033                 :             :  * they will get de-linked from the tree.
    1034                 :             :  *
    1035                 :             :  * This is more aggressive than it needs to be for non-unique !heapkeyspace
    1036                 :             :  * indexes.
    1037                 :             :  */
    1038                 :             : static void
    1039                 :        6696 : _bt_stepright(Relation rel, Relation heaprel, BTInsertState insertstate,
    1040                 :             :               BTStack stack)
    1041                 :             : {
    1042                 :             :     Page        page;
    1043                 :             :     BTPageOpaque opaque;
    1044                 :             :     Buffer      rbuf;
    1045                 :             :     BlockNumber rblkno;
    1046                 :             : 
    1047                 :             :     Assert(heaprel != NULL);
    1048                 :        6696 :     page = BufferGetPage(insertstate->buf);
    1049                 :        6696 :     opaque = BTPageGetOpaque(page);
    1050                 :             : 
    1051                 :        6696 :     rbuf = InvalidBuffer;
    1052                 :        6696 :     rblkno = opaque->btpo_next;
    1053                 :             :     for (;;)
    1054                 :             :     {
    1055                 :        6696 :         rbuf = _bt_relandgetbuf(rel, rbuf, rblkno, BT_WRITE);
    1056                 :        6696 :         page = BufferGetPage(rbuf);
    1057                 :        6696 :         opaque = BTPageGetOpaque(page);
    1058                 :             : 
    1059                 :             :         /*
    1060                 :             :          * If this page was incompletely split, finish the split now.  We do
    1061                 :             :          * this while holding a lock on the left sibling, which is not good
    1062                 :             :          * because finishing the split could be a fairly lengthy operation.
    1063                 :             :          * But this should happen very seldom.
    1064                 :             :          */
    1065         [ -  + ]:        6696 :         if (P_INCOMPLETE_SPLIT(opaque))
    1066                 :             :         {
    1067                 :           0 :             _bt_finish_split(rel, heaprel, rbuf, stack);
    1068                 :           0 :             rbuf = InvalidBuffer;
    1069                 :           0 :             continue;
    1070                 :             :         }
    1071                 :             : 
    1072         [ +  - ]:        6696 :         if (!P_IGNORE(opaque))
    1073                 :        6696 :             break;
    1074         [ #  # ]:           0 :         if (P_RIGHTMOST(opaque))
    1075         [ #  # ]:           0 :             elog(ERROR, "fell off the end of index \"%s\"",
    1076                 :             :                  RelationGetRelationName(rel));
    1077                 :             : 
    1078                 :           0 :         rblkno = opaque->btpo_next;
    1079                 :             :     }
    1080                 :             :     /* rbuf locked; unlock buf, update state for caller */
    1081                 :        6696 :     _bt_relbuf(rel, insertstate->buf);
    1082                 :        6696 :     insertstate->buf = rbuf;
    1083                 :        6696 :     insertstate->bounds_valid = false;
    1084                 :        6696 : }
    1085                 :             : 
    1086                 :             : /*----------
    1087                 :             :  *  _bt_insertonpg() -- Insert a tuple on a particular page in the index.
    1088                 :             :  *
    1089                 :             :  *      This recursive procedure does the following things:
    1090                 :             :  *
    1091                 :             :  *          +  if postingoff != 0, splits existing posting list tuple
    1092                 :             :  *             (since it overlaps with new 'itup' tuple).
    1093                 :             :  *          +  if necessary, splits the target page, using 'itup_key' for
    1094                 :             :  *             suffix truncation on leaf pages (caller passes NULL for
    1095                 :             :  *             non-leaf pages).
    1096                 :             :  *          +  inserts the new tuple (might be split from posting list).
    1097                 :             :  *          +  if the page was split, pops the parent stack, and finds the
    1098                 :             :  *             right place to insert the new child pointer (by walking
    1099                 :             :  *             right using information stored in the parent stack).
    1100                 :             :  *          +  invokes itself with the appropriate tuple for the right
    1101                 :             :  *             child page on the parent.
    1102                 :             :  *          +  updates the metapage if a true root or fast root is split.
    1103                 :             :  *
    1104                 :             :  *      On entry, we must have the correct buffer in which to do the
    1105                 :             :  *      insertion, and the buffer must be pinned and write-locked.  On return,
    1106                 :             :  *      we will have dropped both the pin and the lock on the buffer.
    1107                 :             :  *
    1108                 :             :  *      This routine only performs retail tuple insertions.  'itup' should
    1109                 :             :  *      always be either a non-highkey leaf item, or a downlink (new high
    1110                 :             :  *      key items are created indirectly, when a page is split).  When
    1111                 :             :  *      inserting to a non-leaf page, 'cbuf' is the left-sibling of the page
    1112                 :             :  *      we're inserting the downlink for.  This function will clear the
    1113                 :             :  *      INCOMPLETE_SPLIT flag on it, and release the buffer.
    1114                 :             :  *----------
    1115                 :             :  */
    1116                 :             : static void
    1117                 :     5291158 : _bt_insertonpg(Relation rel,
    1118                 :             :                Relation heaprel,
    1119                 :             :                BTScanInsert itup_key,
    1120                 :             :                Buffer buf,
    1121                 :             :                Buffer cbuf,
    1122                 :             :                BTStack stack,
    1123                 :             :                IndexTuple itup,
    1124                 :             :                Size itemsz,
    1125                 :             :                OffsetNumber newitemoff,
    1126                 :             :                int postingoff,
    1127                 :             :                bool split_only_page)
    1128                 :             : {
    1129                 :             :     Page        page;
    1130                 :             :     BTPageOpaque opaque;
    1131                 :             :     bool        isleaf,
    1132                 :             :                 isroot,
    1133                 :             :                 isrightmost,
    1134                 :             :                 isonly;
    1135                 :     5291158 :     IndexTuple  oposting = NULL;
    1136                 :     5291158 :     IndexTuple  origitup = NULL;
    1137                 :     5291158 :     IndexTuple  nposting = NULL;
    1138                 :             :     XLogRecPtr  recptr;
    1139                 :             : 
    1140                 :     5291158 :     page = BufferGetPage(buf);
    1141                 :     5291158 :     opaque = BTPageGetOpaque(page);
    1142                 :     5291158 :     isleaf = P_ISLEAF(opaque);
    1143                 :     5291158 :     isroot = P_ISROOT(opaque);
    1144                 :     5291158 :     isrightmost = P_RIGHTMOST(opaque);
    1145   [ +  +  +  + ]:     5291158 :     isonly = P_LEFTMOST(opaque) && P_RIGHTMOST(opaque);
    1146                 :             : 
    1147                 :             :     /* child buffer must be given iff inserting on an internal page */
    1148                 :             :     Assert(isleaf == !BufferIsValid(cbuf));
    1149                 :             :     /* tuple must have appropriate number of attributes */
    1150                 :             :     Assert(!isleaf ||
    1151                 :             :            BTreeTupleGetNAtts(itup, rel) ==
    1152                 :             :            IndexRelationGetNumberOfAttributes(rel));
    1153                 :             :     Assert(isleaf ||
    1154                 :             :            BTreeTupleGetNAtts(itup, rel) <=
    1155                 :             :            IndexRelationGetNumberOfKeyAttributes(rel));
    1156                 :             :     Assert(!BTreeTupleIsPosting(itup));
    1157                 :             :     Assert(MAXALIGN(IndexTupleSize(itup)) == itemsz);
    1158                 :             :     /* Caller must always finish incomplete split for us */
    1159                 :             :     Assert(!P_INCOMPLETE_SPLIT(opaque));
    1160                 :             : 
    1161                 :             :     /*
    1162                 :             :      * Every internal page should have exactly one negative infinity item at
    1163                 :             :      * all times.  Only _bt_split() and _bt_newlevel() should add items that
    1164                 :             :      * become negative infinity items through truncation, since they're the
    1165                 :             :      * only routines that allocate new internal pages.
    1166                 :             :      */
    1167                 :             :     Assert(isleaf || newitemoff > P_FIRSTDATAKEY(opaque));
    1168                 :             : 
    1169                 :             :     /*
    1170                 :             :      * Do we need to split an existing posting list item?
    1171                 :             :      */
    1172         [ +  + ]:     5291158 :     if (postingoff != 0)
    1173                 :             :     {
    1174                 :       21651 :         ItemId      itemid = PageGetItemId(page, newitemoff);
    1175                 :             : 
    1176                 :             :         /*
    1177                 :             :          * The new tuple is a duplicate with a heap TID that falls inside the
    1178                 :             :          * range of an existing posting list tuple on a leaf page.  Prepare to
    1179                 :             :          * split an existing posting list.  Overwriting the posting list with
    1180                 :             :          * its post-split version is treated as an extra step in either the
    1181                 :             :          * insert or page split critical section.
    1182                 :             :          */
    1183                 :             :         Assert(isleaf && itup_key->heapkeyspace && itup_key->allequalimage);
    1184                 :       21651 :         oposting = (IndexTuple) PageGetItem(page, itemid);
    1185                 :             : 
    1186                 :             :         /*
    1187                 :             :          * postingoff value comes from earlier call to _bt_binsrch_posting().
    1188                 :             :          * Its binary search might think that a plain tuple must be a posting
    1189                 :             :          * list tuple that needs to be split.  This can happen with corruption
    1190                 :             :          * involving an existing plain tuple that is a duplicate of the new
    1191                 :             :          * item, up to and including its table TID.  Check for that here in
    1192                 :             :          * passing.
    1193                 :             :          *
    1194                 :             :          * Also verify that our caller has made sure that the existing posting
    1195                 :             :          * list tuple does not have its LP_DEAD bit set.
    1196                 :             :          */
    1197   [ +  -  -  + ]:       21651 :         if (!BTreeTupleIsPosting(oposting) || ItemIdIsDead(itemid))
    1198         [ #  # ]:           0 :             ereport(ERROR,
    1199                 :             :                     (errcode(ERRCODE_INDEX_CORRUPTED),
    1200                 :             :                      errmsg_internal("table tid from new index tuple (%u,%u) overlaps with invalid duplicate tuple at offset %u of block %u in index \"%s\"",
    1201                 :             :                                      ItemPointerGetBlockNumber(&itup->t_tid),
    1202                 :             :                                      ItemPointerGetOffsetNumber(&itup->t_tid),
    1203                 :             :                                      newitemoff, BufferGetBlockNumber(buf),
    1204                 :             :                                      RelationGetRelationName(rel))));
    1205                 :             : 
    1206                 :             :         /* use a mutable copy of itup as our itup from here on */
    1207                 :       21651 :         origitup = itup;
    1208                 :       21651 :         itup = CopyIndexTuple(origitup);
    1209                 :       21651 :         nposting = _bt_swap_posting(itup, oposting, postingoff);
    1210                 :             :         /* itup now contains rightmost/max TID from oposting */
    1211                 :             : 
    1212                 :             :         /* Alter offset so that newitem goes after posting list */
    1213                 :       21651 :         newitemoff = OffsetNumberNext(newitemoff);
    1214                 :             :     }
    1215                 :             : 
    1216                 :             :     /*
    1217                 :             :      * Do we need to split the page to fit the item on it?
    1218                 :             :      *
    1219                 :             :      * Note: PageGetFreeSpace() subtracts sizeof(ItemIdData) from its result,
    1220                 :             :      * so this comparison is correct even though we appear to be accounting
    1221                 :             :      * only for the item and not for its line pointer.
    1222                 :             :      */
    1223         [ +  + ]:     5291158 :     if (PageGetFreeSpace(page) < itemsz)
    1224                 :             :     {
    1225                 :             :         Buffer      rbuf;
    1226                 :             : 
    1227                 :             :         Assert(!split_only_page);
    1228                 :             : 
    1229                 :             :         /* split the buffer into left and right halves */
    1230                 :       15672 :         rbuf = _bt_split(rel, heaprel, itup_key, buf, cbuf, newitemoff, itemsz,
    1231                 :             :                          itup, origitup, nposting, postingoff);
    1232                 :       15672 :         PredicateLockPageSplit(rel,
    1233                 :             :                                BufferGetBlockNumber(buf),
    1234                 :             :                                BufferGetBlockNumber(rbuf));
    1235                 :             : 
    1236                 :             :         /*----------
    1237                 :             :          * By here,
    1238                 :             :          *
    1239                 :             :          *      +  our target page has been split;
    1240                 :             :          *      +  the original tuple has been inserted;
    1241                 :             :          *      +  we have write locks on both the old (left half)
    1242                 :             :          *         and new (right half) buffers, after the split; and
    1243                 :             :          *      +  we know the key we want to insert into the parent
    1244                 :             :          *         (it's the "high key" on the left child page).
    1245                 :             :          *
    1246                 :             :          * We're ready to do the parent insertion.  We need to hold onto the
    1247                 :             :          * locks for the child pages until we locate the parent, but we can
    1248                 :             :          * at least release the lock on the right child before doing the
    1249                 :             :          * actual insertion.  The lock on the left child will be released
    1250                 :             :          * last of all by parent insertion, where it is the 'cbuf' of parent
    1251                 :             :          * page.
    1252                 :             :          *----------
    1253                 :             :          */
    1254                 :             : #ifdef USE_INJECTION_POINTS
    1255         [ +  + ]:       15672 :         if (P_ISLEAF(opaque))
    1256                 :       15491 :             INJECTION_POINT("nbtree-leave-leaf-split-incomplete", NULL);
    1257                 :             :         else
    1258                 :         181 :             INJECTION_POINT("nbtree-leave-internal-split-incomplete", NULL);
    1259                 :             : #endif
    1260                 :             : 
    1261                 :       15670 :         _bt_insert_parent(rel, heaprel, buf, rbuf, stack, isroot, isonly);
    1262                 :             :     }
    1263                 :             :     else
    1264                 :             :     {
    1265                 :     5275486 :         Buffer      metabuf = InvalidBuffer;
    1266                 :     5275486 :         Page        metapg = NULL;
    1267                 :     5275486 :         BTMetaPageData *metad = NULL;
    1268                 :             :         BlockNumber blockcache;
    1269                 :             : 
    1270                 :             :         /*
    1271                 :             :          * If we are doing this insert because we split a page that was the
    1272                 :             :          * only one on its tree level, but was not the root, it may have been
    1273                 :             :          * the "fast root".  We need to ensure that the fast root link points
    1274                 :             :          * at or above the current page.  We can safely acquire a lock on the
    1275                 :             :          * metapage here --- see comments for _bt_newlevel().
    1276                 :             :          */
    1277         [ +  + ]:     5275486 :         if (unlikely(split_only_page))
    1278                 :             :         {
    1279                 :             :             Assert(!isleaf);
    1280                 :             :             Assert(BufferIsValid(cbuf));
    1281                 :             : 
    1282                 :          16 :             metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
    1283                 :          16 :             metapg = BufferGetPage(metabuf);
    1284                 :          16 :             metad = BTPageGetMeta(metapg);
    1285                 :             : 
    1286         [ -  + ]:          16 :             if (metad->btm_fastlevel >= opaque->btpo_level)
    1287                 :             :             {
    1288                 :             :                 /* no update wanted */
    1289                 :           0 :                 _bt_relbuf(rel, metabuf);
    1290                 :           0 :                 metabuf = InvalidBuffer;
    1291                 :             :             }
    1292                 :             :         }
    1293                 :             : 
    1294                 :             :         /* Do the update.  No ereport(ERROR) until changes are logged */
    1295                 :     5275486 :         START_CRIT_SECTION();
    1296                 :             : 
    1297         [ +  + ]:     5275486 :         if (postingoff != 0)
    1298                 :       21611 :             memcpy(oposting, nposting, MAXALIGN(IndexTupleSize(nposting)));
    1299                 :             : 
    1300         [ -  + ]:     5275486 :         if (PageAddItem(page, itup, itemsz, newitemoff, false, false) == InvalidOffsetNumber)
    1301         [ #  # ]:           0 :             elog(PANIC, "failed to add new item to block %u in index \"%s\"",
    1302                 :             :                  BufferGetBlockNumber(buf), RelationGetRelationName(rel));
    1303                 :             : 
    1304                 :     5275486 :         MarkBufferDirty(buf);
    1305                 :             : 
    1306         [ +  + ]:     5275486 :         if (BufferIsValid(metabuf))
    1307                 :             :         {
    1308                 :             :             /* upgrade meta-page if needed */
    1309         [ -  + ]:          16 :             if (metad->btm_version < BTREE_NOVAC_VERSION)
    1310                 :           0 :                 _bt_upgrademetapage(metapg);
    1311                 :          16 :             metad->btm_fastroot = BufferGetBlockNumber(buf);
    1312                 :          16 :             metad->btm_fastlevel = opaque->btpo_level;
    1313                 :          16 :             MarkBufferDirty(metabuf);
    1314                 :             :         }
    1315                 :             : 
    1316                 :             :         /*
    1317                 :             :          * Clear INCOMPLETE_SPLIT flag on child if inserting the new item
    1318                 :             :          * finishes a split
    1319                 :             :          */
    1320         [ +  + ]:     5275486 :         if (!isleaf)
    1321                 :             :         {
    1322                 :       14642 :             Page        cpage = BufferGetPage(cbuf);
    1323                 :       14642 :             BTPageOpaque cpageop = BTPageGetOpaque(cpage);
    1324                 :             : 
    1325                 :             :             Assert(P_INCOMPLETE_SPLIT(cpageop));
    1326                 :       14642 :             cpageop->btpo_flags &= ~BTP_INCOMPLETE_SPLIT;
    1327                 :       14642 :             MarkBufferDirty(cbuf);
    1328                 :             :         }
    1329                 :             : 
    1330                 :             :         /* XLOG stuff */
    1331   [ +  +  +  +  :     5275486 :         if (RelationNeedsWAL(rel))
             +  +  +  + ]
    1332                 :     5000524 :         {
    1333                 :             :             xl_btree_insert xlrec;
    1334                 :             :             xl_btree_metadata xlmeta;
    1335                 :             :             uint8       xlinfo;
    1336                 :             :             uint16      upostingoff;
    1337                 :             : 
    1338                 :     5000524 :             xlrec.offnum = newitemoff;
    1339                 :             : 
    1340                 :     5000524 :             XLogBeginInsert();
    1341                 :     5000524 :             XLogRegisterData(&xlrec, SizeOfBtreeInsert);
    1342                 :             : 
    1343   [ +  +  +  + ]:     5000524 :             if (isleaf && postingoff == 0)
    1344                 :             :             {
    1345                 :             :                 /* Simple leaf insert */
    1346                 :     4964978 :                 xlinfo = XLOG_BTREE_INSERT_LEAF;
    1347                 :             :             }
    1348         [ +  + ]:       35546 :             else if (postingoff != 0)
    1349                 :             :             {
    1350                 :             :                 /*
    1351                 :             :                  * Leaf insert with posting list split.  Must include
    1352                 :             :                  * postingoff field before newitem/orignewitem.
    1353                 :             :                  */
    1354                 :             :                 Assert(isleaf);
    1355                 :       21611 :                 xlinfo = XLOG_BTREE_INSERT_POST;
    1356                 :             :             }
    1357                 :             :             else
    1358                 :             :             {
    1359                 :             :                 /* Internal page insert, which finishes a split on cbuf */
    1360                 :       13935 :                 xlinfo = XLOG_BTREE_INSERT_UPPER;
    1361                 :       13935 :                 XLogRegisterBuffer(1, cbuf, REGBUF_STANDARD);
    1362                 :             : 
    1363         [ +  + ]:       13935 :                 if (BufferIsValid(metabuf))
    1364                 :             :                 {
    1365                 :             :                     /* Actually, it's an internal page insert + meta update */
    1366                 :          16 :                     xlinfo = XLOG_BTREE_INSERT_META;
    1367                 :             : 
    1368                 :             :                     Assert(metad->btm_version >= BTREE_NOVAC_VERSION);
    1369                 :          16 :                     xlmeta.version = metad->btm_version;
    1370                 :          16 :                     xlmeta.root = metad->btm_root;
    1371                 :          16 :                     xlmeta.level = metad->btm_level;
    1372                 :          16 :                     xlmeta.fastroot = metad->btm_fastroot;
    1373                 :          16 :                     xlmeta.fastlevel = metad->btm_fastlevel;
    1374                 :          16 :                     xlmeta.last_cleanup_num_delpages = metad->btm_last_cleanup_num_delpages;
    1375                 :          16 :                     xlmeta.allequalimage = metad->btm_allequalimage;
    1376                 :             : 
    1377                 :          16 :                     XLogRegisterBuffer(2, metabuf,
    1378                 :             :                                        REGBUF_WILL_INIT | REGBUF_STANDARD);
    1379                 :          16 :                     XLogRegisterBufData(2, &xlmeta,
    1380                 :             :                                         sizeof(xl_btree_metadata));
    1381                 :             :                 }
    1382                 :             :             }
    1383                 :             : 
    1384                 :     5000524 :             XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
    1385         [ +  + ]:     5000524 :             if (postingoff == 0)
    1386                 :             :             {
    1387                 :             :                 /* Just log itup from caller */
    1388                 :     4978913 :                 XLogRegisterBufData(0, itup, IndexTupleSize(itup));
    1389                 :             :             }
    1390                 :             :             else
    1391                 :             :             {
    1392                 :             :                 /*
    1393                 :             :                  * Insert with posting list split (XLOG_BTREE_INSERT_POST
    1394                 :             :                  * record) case.
    1395                 :             :                  *
    1396                 :             :                  * Log postingoff.  Also log origitup, not itup.  REDO routine
    1397                 :             :                  * must reconstruct final itup (as well as nposting) using
    1398                 :             :                  * _bt_swap_posting().
    1399                 :             :                  */
    1400                 :       21611 :                 upostingoff = postingoff;
    1401                 :             : 
    1402                 :       21611 :                 XLogRegisterBufData(0, &upostingoff, sizeof(uint16));
    1403                 :       21611 :                 XLogRegisterBufData(0, origitup,
    1404                 :       21611 :                                     IndexTupleSize(origitup));
    1405                 :             :             }
    1406                 :             : 
    1407                 :     5000524 :             recptr = XLogInsert(RM_BTREE_ID, xlinfo);
    1408                 :             :         }
    1409                 :             :         else
    1410                 :      274962 :             recptr = XLogGetFakeLSN(rel);
    1411                 :             : 
    1412         [ +  + ]:     5275486 :         if (BufferIsValid(metabuf))
    1413                 :          16 :             PageSetLSN(metapg, recptr);
    1414         [ +  + ]:     5275486 :         if (!isleaf)
    1415                 :       14642 :             PageSetLSN(BufferGetPage(cbuf), recptr);
    1416                 :             : 
    1417                 :     5275486 :         PageSetLSN(page, recptr);
    1418                 :             : 
    1419                 :     5275486 :         END_CRIT_SECTION();
    1420                 :             : 
    1421                 :             :         /* Release subsidiary buffers */
    1422         [ +  + ]:     5275486 :         if (BufferIsValid(metabuf))
    1423                 :          16 :             _bt_relbuf(rel, metabuf);
    1424         [ +  + ]:     5275486 :         if (!isleaf)
    1425                 :       14642 :             _bt_relbuf(rel, cbuf);
    1426                 :             : 
    1427                 :             :         /*
    1428                 :             :          * Cache the block number if this is the rightmost leaf page.  Cache
    1429                 :             :          * may be used by a future inserter within _bt_search_insert().
    1430                 :             :          */
    1431                 :     5275486 :         blockcache = InvalidBlockNumber;
    1432   [ +  +  +  +  :     5275486 :         if (isrightmost && isleaf && !isroot)
                   +  + ]
    1433                 :     3180364 :             blockcache = BufferGetBlockNumber(buf);
    1434                 :             : 
    1435                 :             :         /* Release buffer for insertion target block */
    1436                 :     5275486 :         _bt_relbuf(rel, buf);
    1437                 :             : 
    1438                 :             :         /*
    1439                 :             :          * If we decided to cache the insertion target block before releasing
    1440                 :             :          * its buffer lock, then cache it now.  Check the height of the tree
    1441                 :             :          * first, though.  We don't go for the optimization with small
    1442                 :             :          * indexes.  Defer final check to this point to ensure that we don't
    1443                 :             :          * call _bt_getrootheight while holding a buffer lock.
    1444                 :             :          */
    1445   [ +  +  +  + ]:     8455850 :         if (BlockNumberIsValid(blockcache) &&
    1446                 :     3180364 :             _bt_getrootheight(rel) >= BTREE_FASTPATH_MIN_LEVEL)
    1447                 :       31317 :             RelationSetTargetBlock(rel, blockcache);
    1448                 :             :     }
    1449                 :             : 
    1450                 :             :     /* be tidy */
    1451         [ +  + ]:     5291155 :     if (postingoff != 0)
    1452                 :             :     {
    1453                 :             :         /* itup is actually a modified copy of caller's original */
    1454                 :       21651 :         pfree(nposting);
    1455                 :       21651 :         pfree(itup);
    1456                 :             :     }
    1457                 :     5291155 : }
    1458                 :             : 
    1459                 :             : /*
    1460                 :             :  *  _bt_split() -- split a page in the btree.
    1461                 :             :  *
    1462                 :             :  *      On entry, buf is the page to split, and is pinned and write-locked.
    1463                 :             :  *      newitemoff etc. tell us about the new item that must be inserted
    1464                 :             :  *      along with the data from the original page.
    1465                 :             :  *
    1466                 :             :  *      itup_key is used for suffix truncation on leaf pages (internal
    1467                 :             :  *      page callers pass NULL).  When splitting a non-leaf page, 'cbuf'
    1468                 :             :  *      is the left-sibling of the page we're inserting the downlink for.
    1469                 :             :  *      This function will clear the INCOMPLETE_SPLIT flag on it, and
    1470                 :             :  *      release the buffer.
    1471                 :             :  *
    1472                 :             :  *      orignewitem, nposting, and postingoff are needed when an insert of
    1473                 :             :  *      orignewitem results in both a posting list split and a page split.
    1474                 :             :  *      These extra posting list split details are used here in the same
    1475                 :             :  *      way as they are used in the more common case where a posting list
    1476                 :             :  *      split does not coincide with a page split.  We need to deal with
    1477                 :             :  *      posting list splits directly in order to ensure that everything
    1478                 :             :  *      that follows from the insert of orignewitem is handled as a single
    1479                 :             :  *      atomic operation (though caller's insert of a new pivot/downlink
    1480                 :             :  *      into parent page will still be a separate operation).  See
    1481                 :             :  *      nbtree/README for details on the design of posting list splits.
    1482                 :             :  *
    1483                 :             :  *      Returns the new right sibling of buf, pinned and write-locked.
    1484                 :             :  *      The pin and lock on buf are maintained.
    1485                 :             :  */
    1486                 :             : static Buffer
    1487                 :       15672 : _bt_split(Relation rel, Relation heaprel, BTScanInsert itup_key, Buffer buf,
    1488                 :             :           Buffer cbuf, OffsetNumber newitemoff, Size newitemsz, IndexTuple newitem,
    1489                 :             :           IndexTuple orignewitem, IndexTuple nposting, uint16 postingoff)
    1490                 :             : {
    1491                 :             :     Buffer      rbuf;
    1492                 :             :     Page        origpage;
    1493                 :             :     Page        leftpage,
    1494                 :             :                 rightpage;
    1495                 :             :     PGAlignedBlock leftpage_buf,
    1496                 :             :                 rightpage_buf;
    1497                 :             :     BlockNumber origpagenumber,
    1498                 :             :                 rightpagenumber;
    1499                 :             :     BTPageOpaque ropaque,
    1500                 :             :                 lopaque,
    1501                 :             :                 oopaque;
    1502                 :       15672 :     Buffer      sbuf = InvalidBuffer;
    1503                 :       15672 :     Page        spage = NULL;
    1504                 :       15672 :     BTPageOpaque sopaque = NULL;
    1505                 :             :     Size        itemsz;
    1506                 :             :     ItemId      itemid;
    1507                 :             :     IndexTuple  firstright,
    1508                 :             :                 lefthighkey;
    1509                 :             :     OffsetNumber firstrightoff;
    1510                 :             :     OffsetNumber afterleftoff,
    1511                 :             :                 afterrightoff,
    1512                 :             :                 minusinfoff;
    1513                 :             :     OffsetNumber origpagepostingoff;
    1514                 :             :     OffsetNumber maxoff;
    1515                 :             :     OffsetNumber i;
    1516                 :             :     bool        newitemonleft,
    1517                 :             :                 isleaf,
    1518                 :             :                 isrightmost;
    1519                 :             :     XLogRecPtr  recptr;
    1520                 :             : 
    1521                 :             :     /*
    1522                 :             :      * origpage is the original page to be split.  leftpage is a temporary
    1523                 :             :      * buffer that receives the left-sibling data, which will be copied back
    1524                 :             :      * into origpage on success.  rightpage is the new page that will receive
    1525                 :             :      * the right-sibling data.
    1526                 :             :      *
    1527                 :             :      * leftpage is allocated after choosing a split point.  rightpage's new
    1528                 :             :      * buffer isn't acquired until after leftpage is initialized and has new
    1529                 :             :      * high key, the last point where splitting the page may fail (barring
    1530                 :             :      * corruption).  Failing before acquiring new buffer won't have lasting
    1531                 :             :      * consequences, since origpage won't have been modified and leftpage is
    1532                 :             :      * only workspace.
    1533                 :             :      */
    1534                 :       15672 :     origpage = BufferGetPage(buf);
    1535                 :       15672 :     oopaque = BTPageGetOpaque(origpage);
    1536                 :       15672 :     isleaf = P_ISLEAF(oopaque);
    1537                 :       15672 :     isrightmost = P_RIGHTMOST(oopaque);
    1538                 :       15672 :     maxoff = PageGetMaxOffsetNumber(origpage);
    1539                 :       15672 :     origpagenumber = BufferGetBlockNumber(buf);
    1540                 :             : 
    1541                 :             :     /*
    1542                 :             :      * Choose a point to split origpage at.
    1543                 :             :      *
    1544                 :             :      * A split point can be thought of as a point _between_ two existing data
    1545                 :             :      * items on origpage (the lastleft and firstright tuples), provided you
    1546                 :             :      * pretend that the new item that didn't fit is already on origpage.
    1547                 :             :      *
    1548                 :             :      * Since origpage does not actually contain newitem, the representation of
    1549                 :             :      * split points needs to work with two boundary cases: splits where
    1550                 :             :      * newitem is lastleft, and splits where newitem is firstright.
    1551                 :             :      * newitemonleft resolves the ambiguity that would otherwise exist when
    1552                 :             :      * newitemoff == firstrightoff.  In all other cases it's clear which side
    1553                 :             :      * of the split every tuple goes on from context.  newitemonleft is
    1554                 :             :      * usually (but not always) redundant information.
    1555                 :             :      *
    1556                 :             :      * firstrightoff is supposed to be an origpage offset number, but it's
    1557                 :             :      * possible that its value will be maxoff+1, which is "past the end" of
    1558                 :             :      * origpage.  This happens in the rare case where newitem goes after all
    1559                 :             :      * existing items (i.e. newitemoff is maxoff+1) and we end up splitting
    1560                 :             :      * origpage at the point that leaves newitem alone on new right page.  Any
    1561                 :             :      * "!newitemonleft && newitemoff == firstrightoff" split point makes
    1562                 :             :      * newitem the firstright tuple, though, so this case isn't a special
    1563                 :             :      * case.
    1564                 :             :      */
    1565                 :       15672 :     firstrightoff = _bt_findsplitloc(rel, origpage, newitemoff, newitemsz,
    1566                 :             :                                      newitem, &newitemonleft);
    1567                 :             : 
    1568                 :             :     /* Use temporary buffer for leftpage */
    1569                 :       15672 :     leftpage = leftpage_buf.data;
    1570                 :       15672 :     _bt_pageinit(leftpage, BufferGetPageSize(buf));
    1571                 :       15672 :     lopaque = BTPageGetOpaque(leftpage);
    1572                 :             : 
    1573                 :             :     /*
    1574                 :             :      * leftpage won't be the root when we're done.  Also, clear the SPLIT_END
    1575                 :             :      * and HAS_GARBAGE flags.
    1576                 :             :      */
    1577                 :       15672 :     lopaque->btpo_flags = oopaque->btpo_flags;
    1578                 :       15672 :     lopaque->btpo_flags &= ~(BTP_ROOT | BTP_SPLIT_END | BTP_HAS_GARBAGE);
    1579                 :             :     /* set flag in leftpage indicating that rightpage has no downlink yet */
    1580                 :       15672 :     lopaque->btpo_flags |= BTP_INCOMPLETE_SPLIT;
    1581                 :       15672 :     lopaque->btpo_prev = oopaque->btpo_prev;
    1582                 :             :     /* handle btpo_next after rightpage buffer acquired */
    1583                 :       15672 :     lopaque->btpo_level = oopaque->btpo_level;
    1584                 :             :     /* handle btpo_cycleid after rightpage buffer acquired */
    1585                 :             : 
    1586                 :             :     /*
    1587                 :             :      * Copy the original page's LSN into leftpage, which will become the
    1588                 :             :      * updated version of the page.  We need this because XLogInsert will
    1589                 :             :      * examine the LSN and possibly dump it in a page image.
    1590                 :             :      */
    1591                 :       15672 :     PageSetLSN(leftpage, PageGetLSN(origpage));
    1592                 :             : 
    1593                 :             :     /*
    1594                 :             :      * Determine page offset number of existing overlapped-with-orignewitem
    1595                 :             :      * posting list when it is necessary to perform a posting list split in
    1596                 :             :      * passing.  Note that newitem was already changed by caller (newitem no
    1597                 :             :      * longer has the orignewitem TID).
    1598                 :             :      *
    1599                 :             :      * This page offset number (origpagepostingoff) will be used to pretend
    1600                 :             :      * that the posting split has already taken place, even though the
    1601                 :             :      * required modifications to origpage won't occur until we reach the
    1602                 :             :      * critical section.  The lastleft and firstright tuples of our page split
    1603                 :             :      * point should, in effect, come from an imaginary version of origpage
    1604                 :             :      * that has the nposting tuple instead of the original posting list tuple.
    1605                 :             :      *
    1606                 :             :      * Note: _bt_findsplitloc() should have compensated for coinciding posting
    1607                 :             :      * list splits in just the same way, at least in theory.  It doesn't
    1608                 :             :      * bother with that, though.  In practice it won't affect its choice of
    1609                 :             :      * split point.
    1610                 :             :      */
    1611                 :       15672 :     origpagepostingoff = InvalidOffsetNumber;
    1612         [ +  + ]:       15672 :     if (postingoff != 0)
    1613                 :             :     {
    1614                 :             :         Assert(isleaf);
    1615                 :             :         Assert(ItemPointerCompare(&orignewitem->t_tid,
    1616                 :             :                                   &newitem->t_tid) < 0);
    1617                 :             :         Assert(BTreeTupleIsPosting(nposting));
    1618                 :          40 :         origpagepostingoff = OffsetNumberPrev(newitemoff);
    1619                 :             :     }
    1620                 :             : 
    1621                 :             :     /*
    1622                 :             :      * The high key for the new left page is a possibly-truncated copy of
    1623                 :             :      * firstright on the leaf level (it's "firstright itself" on internal
    1624                 :             :      * pages; see !isleaf comments below).  This may seem to be contrary to
    1625                 :             :      * Lehman & Yao's approach of using a copy of lastleft as the new high key
    1626                 :             :      * when splitting on the leaf level.  It isn't, though.
    1627                 :             :      *
    1628                 :             :      * Suffix truncation will leave the left page's high key fully equal to
    1629                 :             :      * lastleft when lastleft and firstright are equal prior to heap TID (that
    1630                 :             :      * is, the tiebreaker TID value comes from lastleft).  It isn't actually
    1631                 :             :      * necessary for a new leaf high key to be a copy of lastleft for the L&Y
    1632                 :             :      * "subtree" invariant to hold.  It's sufficient to make sure that the new
    1633                 :             :      * leaf high key is strictly less than firstright, and greater than or
    1634                 :             :      * equal to (not necessarily equal to) lastleft.  In other words, when
    1635                 :             :      * suffix truncation isn't possible during a leaf page split, we take
    1636                 :             :      * L&Y's exact approach to generating a new high key for the left page.
    1637                 :             :      * (Actually, that is slightly inaccurate.  We don't just use a copy of
    1638                 :             :      * lastleft.  A tuple with all the keys from firstright but the max heap
    1639                 :             :      * TID from lastleft is used, to avoid introducing a special case.)
    1640                 :             :      */
    1641   [ +  +  +  + ]:       15672 :     if (!newitemonleft && newitemoff == firstrightoff)
    1642                 :             :     {
    1643                 :             :         /* incoming tuple becomes firstright */
    1644                 :          26 :         itemsz = newitemsz;
    1645                 :          26 :         firstright = newitem;
    1646                 :             :     }
    1647                 :             :     else
    1648                 :             :     {
    1649                 :             :         /* existing item at firstrightoff becomes firstright */
    1650                 :       15646 :         itemid = PageGetItemId(origpage, firstrightoff);
    1651                 :       15646 :         itemsz = ItemIdGetLength(itemid);
    1652                 :       15646 :         firstright = (IndexTuple) PageGetItem(origpage, itemid);
    1653         [ -  + ]:       15646 :         if (firstrightoff == origpagepostingoff)
    1654                 :           0 :             firstright = nposting;
    1655                 :             :     }
    1656                 :             : 
    1657         [ +  + ]:       15672 :     if (isleaf)
    1658                 :             :     {
    1659                 :             :         IndexTuple  lastleft;
    1660                 :             : 
    1661                 :             :         /* Attempt suffix truncation for leaf page splits */
    1662   [ +  +  +  + ]:       15491 :         if (newitemonleft && newitemoff == firstrightoff)
    1663                 :             :         {
    1664                 :             :             /* incoming tuple becomes lastleft */
    1665                 :         234 :             lastleft = newitem;
    1666                 :             :         }
    1667                 :             :         else
    1668                 :             :         {
    1669                 :             :             OffsetNumber lastleftoff;
    1670                 :             : 
    1671                 :             :             /* existing item before firstrightoff becomes lastleft */
    1672                 :       15257 :             lastleftoff = OffsetNumberPrev(firstrightoff);
    1673                 :             :             Assert(lastleftoff >= P_FIRSTDATAKEY(oopaque));
    1674                 :       15257 :             itemid = PageGetItemId(origpage, lastleftoff);
    1675                 :       15257 :             lastleft = (IndexTuple) PageGetItem(origpage, itemid);
    1676         [ +  + ]:       15257 :             if (lastleftoff == origpagepostingoff)
    1677                 :           3 :                 lastleft = nposting;
    1678                 :             :         }
    1679                 :             : 
    1680                 :       15491 :         lefthighkey = _bt_truncate(rel, lastleft, firstright, itup_key);
    1681                 :       15491 :         itemsz = IndexTupleSize(lefthighkey);
    1682                 :             :     }
    1683                 :             :     else
    1684                 :             :     {
    1685                 :             :         /*
    1686                 :             :          * Don't perform suffix truncation on a copy of firstright to make
    1687                 :             :          * left page high key for internal page splits.  Must use firstright
    1688                 :             :          * as new high key directly.
    1689                 :             :          *
    1690                 :             :          * Each distinct separator key value originates as a leaf level high
    1691                 :             :          * key; all other separator keys/pivot tuples are copied from one
    1692                 :             :          * level down.  A separator key in a grandparent page must be
    1693                 :             :          * identical to high key in rightmost parent page of the subtree to
    1694                 :             :          * its left, which must itself be identical to high key in rightmost
    1695                 :             :          * child page of that same subtree (this even applies to separator
    1696                 :             :          * from grandparent's high key).  There must always be an unbroken
    1697                 :             :          * "seam" of identical separator keys that guide index scans at every
    1698                 :             :          * level, starting from the grandparent.  That's why suffix truncation
    1699                 :             :          * is unsafe here.
    1700                 :             :          *
    1701                 :             :          * Internal page splits will truncate firstright into a "negative
    1702                 :             :          * infinity" data item when it gets inserted on the new right page
    1703                 :             :          * below, though.  This happens during the call to _bt_pgaddtup() for
    1704                 :             :          * the new first data item for right page.  Do not confuse this
    1705                 :             :          * mechanism with suffix truncation.  It is just a convenient way of
    1706                 :             :          * implementing page splits that split the internal page "inside"
    1707                 :             :          * firstright.  The lefthighkey separator key cannot appear a second
    1708                 :             :          * time in the right page (only firstright's downlink goes in right
    1709                 :             :          * page).
    1710                 :             :          */
    1711                 :         181 :         lefthighkey = firstright;
    1712                 :             :     }
    1713                 :             : 
    1714                 :             :     /*
    1715                 :             :      * Add new high key to leftpage
    1716                 :             :      */
    1717                 :       15672 :     afterleftoff = P_HIKEY;
    1718                 :             : 
    1719                 :             :     Assert(BTreeTupleGetNAtts(lefthighkey, rel) > 0);
    1720                 :             :     Assert(BTreeTupleGetNAtts(lefthighkey, rel) <=
    1721                 :             :            IndexRelationGetNumberOfKeyAttributes(rel));
    1722                 :             :     Assert(itemsz == MAXALIGN(IndexTupleSize(lefthighkey)));
    1723         [ -  + ]:       15672 :     if (PageAddItem(leftpage, lefthighkey, itemsz, afterleftoff, false, false) == InvalidOffsetNumber)
    1724         [ #  # ]:           0 :         elog(ERROR, "failed to add high key to the left sibling"
    1725                 :             :              " while splitting block %u of index \"%s\"",
    1726                 :             :              origpagenumber, RelationGetRelationName(rel));
    1727                 :       15672 :     afterleftoff = OffsetNumberNext(afterleftoff);
    1728                 :             : 
    1729                 :             :     /*
    1730                 :             :      * Acquire a new right page to split into, now that left page has a new
    1731                 :             :      * high key.
    1732                 :             :      *
    1733                 :             :      * To not confuse future VACUUM operations, we zero the right page and
    1734                 :             :      * work on an in-memory copy of it before writing WAL, then copy its
    1735                 :             :      * contents back to the actual page once we start the critical section
    1736                 :             :      * work.  This simplifies the split work, so as there is no need to zero
    1737                 :             :      * the right page before throwing an error.
    1738                 :             :      */
    1739                 :       15672 :     rbuf = _bt_allocbuf(rel, heaprel);
    1740                 :       15672 :     rightpage = rightpage_buf.data;
    1741                 :             : 
    1742                 :             :     /*
    1743                 :             :      * Copy the contents of the right page into its temporary location, and
    1744                 :             :      * zero the original space.
    1745                 :             :      */
    1746                 :       15672 :     memcpy(rightpage, BufferGetPage(rbuf), BLCKSZ);
    1747                 :       15672 :     memset(BufferGetPage(rbuf), 0, BLCKSZ);
    1748                 :       15672 :     rightpagenumber = BufferGetBlockNumber(rbuf);
    1749                 :             :     /* rightpage was initialized by _bt_allocbuf */
    1750                 :       15672 :     ropaque = BTPageGetOpaque(rightpage);
    1751                 :             : 
    1752                 :             :     /*
    1753                 :             :      * Finish off remaining leftpage special area fields.  They cannot be set
    1754                 :             :      * before both origpage (leftpage) and rightpage buffers are acquired and
    1755                 :             :      * locked.
    1756                 :             :      *
    1757                 :             :      * btpo_cycleid is only used with leaf pages, though we set it here in all
    1758                 :             :      * cases just to be consistent.
    1759                 :             :      */
    1760                 :       15672 :     lopaque->btpo_next = rightpagenumber;
    1761                 :       15672 :     lopaque->btpo_cycleid = _bt_vacuum_cycleid(rel);
    1762                 :             : 
    1763                 :             :     /*
    1764                 :             :      * rightpage won't be the root when we're done.  Also, clear the SPLIT_END
    1765                 :             :      * and HAS_GARBAGE flags.
    1766                 :             :      */
    1767                 :       15672 :     ropaque->btpo_flags = oopaque->btpo_flags;
    1768                 :       15672 :     ropaque->btpo_flags &= ~(BTP_ROOT | BTP_SPLIT_END | BTP_HAS_GARBAGE);
    1769                 :       15672 :     ropaque->btpo_prev = origpagenumber;
    1770                 :       15672 :     ropaque->btpo_next = oopaque->btpo_next;
    1771                 :       15672 :     ropaque->btpo_level = oopaque->btpo_level;
    1772                 :       15672 :     ropaque->btpo_cycleid = lopaque->btpo_cycleid;
    1773                 :             : 
    1774                 :             :     /*
    1775                 :             :      * Add new high key to rightpage where necessary.
    1776                 :             :      *
    1777                 :             :      * If the page we're splitting is not the rightmost page at its level in
    1778                 :             :      * the tree, then the first entry on the page is the high key from
    1779                 :             :      * origpage.
    1780                 :             :      */
    1781                 :       15672 :     afterrightoff = P_HIKEY;
    1782                 :             : 
    1783         [ +  + ]:       15672 :     if (!isrightmost)
    1784                 :             :     {
    1785                 :             :         IndexTuple  righthighkey;
    1786                 :             : 
    1787                 :        5898 :         itemid = PageGetItemId(origpage, P_HIKEY);
    1788                 :        5898 :         itemsz = ItemIdGetLength(itemid);
    1789                 :        5898 :         righthighkey = (IndexTuple) PageGetItem(origpage, itemid);
    1790                 :             :         Assert(BTreeTupleGetNAtts(righthighkey, rel) > 0);
    1791                 :             :         Assert(BTreeTupleGetNAtts(righthighkey, rel) <=
    1792                 :             :                IndexRelationGetNumberOfKeyAttributes(rel));
    1793         [ -  + ]:        5898 :         if (PageAddItem(rightpage, righthighkey, itemsz, afterrightoff, false, false) == InvalidOffsetNumber)
    1794                 :             :         {
    1795         [ #  # ]:           0 :             elog(ERROR, "failed to add high key to the right sibling"
    1796                 :             :                  " while splitting block %u of index \"%s\"",
    1797                 :             :                  origpagenumber, RelationGetRelationName(rel));
    1798                 :             :         }
    1799                 :        5898 :         afterrightoff = OffsetNumberNext(afterrightoff);
    1800                 :             :     }
    1801                 :             : 
    1802                 :             :     /*
    1803                 :             :      * Internal page splits truncate first data item on right page -- it
    1804                 :             :      * becomes "minus infinity" item for the page.  Set this up here.
    1805                 :             :      */
    1806                 :       15672 :     minusinfoff = InvalidOffsetNumber;
    1807         [ +  + ]:       15672 :     if (!isleaf)
    1808                 :         181 :         minusinfoff = afterrightoff;
    1809                 :             : 
    1810                 :             :     /*
    1811                 :             :      * Now transfer all the data items (non-pivot tuples in isleaf case, or
    1812                 :             :      * additional pivot tuples in !isleaf case) to the appropriate page.
    1813                 :             :      *
    1814                 :             :      * Note: we *must* insert at least the right page's items in item-number
    1815                 :             :      * order, for the benefit of _bt_restore_page().
    1816                 :             :      */
    1817   [ +  +  +  + ]:     4918695 :     for (i = P_FIRSTDATAKEY(oopaque); i <= maxoff; i = OffsetNumberNext(i))
    1818                 :             :     {
    1819                 :             :         IndexTuple  dataitem;
    1820                 :             : 
    1821                 :     4903023 :         itemid = PageGetItemId(origpage, i);
    1822                 :     4903023 :         itemsz = ItemIdGetLength(itemid);
    1823                 :     4903023 :         dataitem = (IndexTuple) PageGetItem(origpage, itemid);
    1824                 :             : 
    1825                 :             :         /* replace original item with nposting due to posting split? */
    1826         [ +  + ]:     4903023 :         if (i == origpagepostingoff)
    1827                 :             :         {
    1828                 :             :             Assert(BTreeTupleIsPosting(dataitem));
    1829                 :             :             Assert(itemsz == MAXALIGN(IndexTupleSize(nposting)));
    1830                 :          40 :             dataitem = nposting;
    1831                 :             :         }
    1832                 :             : 
    1833                 :             :         /* does new item belong before this one? */
    1834         [ +  + ]:     4902983 :         else if (i == newitemoff)
    1835                 :             :         {
    1836         [ +  + ]:        8266 :             if (newitemonleft)
    1837                 :             :             {
    1838                 :             :                 Assert(newitemoff <= firstrightoff);
    1839         [ -  + ]:        2206 :                 if (!_bt_pgaddtup(leftpage, newitemsz, newitem, afterleftoff,
    1840                 :             :                                   false))
    1841                 :             :                 {
    1842         [ #  # ]:           0 :                     elog(ERROR, "failed to add new item to the left sibling"
    1843                 :             :                          " while splitting block %u of index \"%s\"",
    1844                 :             :                          origpagenumber, RelationGetRelationName(rel));
    1845                 :             :                 }
    1846                 :        2206 :                 afterleftoff = OffsetNumberNext(afterleftoff);
    1847                 :             :             }
    1848                 :             :             else
    1849                 :             :             {
    1850                 :             :                 Assert(newitemoff >= firstrightoff);
    1851         [ -  + ]:        6060 :                 if (!_bt_pgaddtup(rightpage, newitemsz, newitem, afterrightoff,
    1852                 :             :                                   afterrightoff == minusinfoff))
    1853                 :             :                 {
    1854         [ #  # ]:           0 :                     elog(ERROR, "failed to add new item to the right sibling"
    1855                 :             :                          " while splitting block %u of index \"%s\"",
    1856                 :             :                          origpagenumber, RelationGetRelationName(rel));
    1857                 :             :                 }
    1858                 :        6060 :                 afterrightoff = OffsetNumberNext(afterrightoff);
    1859                 :             :             }
    1860                 :             :         }
    1861                 :             : 
    1862                 :             :         /* decide which page to put it on */
    1863         [ +  + ]:     4903023 :         if (i < firstrightoff)
    1864                 :             :         {
    1865         [ -  + ]:     3832294 :             if (!_bt_pgaddtup(leftpage, itemsz, dataitem, afterleftoff, false))
    1866                 :             :             {
    1867         [ #  # ]:           0 :                 elog(ERROR, "failed to add old item to the left sibling"
    1868                 :             :                      " while splitting block %u of index \"%s\"",
    1869                 :             :                      origpagenumber, RelationGetRelationName(rel));
    1870                 :             :             }
    1871                 :     3832294 :             afterleftoff = OffsetNumberNext(afterleftoff);
    1872                 :             :         }
    1873                 :             :         else
    1874                 :             :         {
    1875         [ -  + ]:     1070729 :             if (!_bt_pgaddtup(rightpage, itemsz, dataitem, afterrightoff,
    1876                 :             :                               afterrightoff == minusinfoff))
    1877                 :             :             {
    1878         [ #  # ]:           0 :                 elog(ERROR, "failed to add old item to the right sibling"
    1879                 :             :                      " while splitting block %u of index \"%s\"",
    1880                 :             :                      origpagenumber, RelationGetRelationName(rel));
    1881                 :             :             }
    1882                 :     1070729 :             afterrightoff = OffsetNumberNext(afterrightoff);
    1883                 :             :         }
    1884                 :             :     }
    1885                 :             : 
    1886                 :             :     /* Handle case where newitem goes at the end of rightpage */
    1887         [ +  + ]:       15672 :     if (i <= newitemoff)
    1888                 :             :     {
    1889                 :             :         /*
    1890                 :             :          * Can't have newitemonleft here; that would imply we were told to put
    1891                 :             :          * *everything* on the left page, which cannot fit (if it could, we'd
    1892                 :             :          * not be splitting the page).
    1893                 :             :          */
    1894                 :             :         Assert(!newitemonleft && newitemoff == maxoff + 1);
    1895         [ -  + ]:        7406 :         if (!_bt_pgaddtup(rightpage, newitemsz, newitem, afterrightoff,
    1896                 :             :                           afterrightoff == minusinfoff))
    1897                 :             :         {
    1898         [ #  # ]:           0 :             elog(ERROR, "failed to add new item to the right sibling"
    1899                 :             :                  " while splitting block %u of index \"%s\"",
    1900                 :             :                  origpagenumber, RelationGetRelationName(rel));
    1901                 :             :         }
    1902                 :        7406 :         afterrightoff = OffsetNumberNext(afterrightoff);
    1903                 :             :     }
    1904                 :             : 
    1905                 :             :     /*
    1906                 :             :      * We have to grab the original right sibling (if any) and update its prev
    1907                 :             :      * link.  We are guaranteed that this is deadlock-free, since we couple
    1908                 :             :      * the locks in the standard order: left to right.
    1909                 :             :      */
    1910         [ +  + ]:       15672 :     if (!isrightmost)
    1911                 :             :     {
    1912                 :        5898 :         sbuf = _bt_getbuf(rel, oopaque->btpo_next, BT_WRITE);
    1913                 :        5898 :         spage = BufferGetPage(sbuf);
    1914                 :        5898 :         sopaque = BTPageGetOpaque(spage);
    1915         [ -  + ]:        5898 :         if (sopaque->btpo_prev != origpagenumber)
    1916                 :             :         {
    1917         [ #  # ]:           0 :             ereport(ERROR,
    1918                 :             :                     (errcode(ERRCODE_INDEX_CORRUPTED),
    1919                 :             :                      errmsg_internal("right sibling's left-link doesn't match: "
    1920                 :             :                                      "block %u links to %u instead of expected %u in index \"%s\"",
    1921                 :             :                                      oopaque->btpo_next, sopaque->btpo_prev, origpagenumber,
    1922                 :             :                                      RelationGetRelationName(rel))));
    1923                 :             :         }
    1924                 :             : 
    1925                 :             :         /*
    1926                 :             :          * Check to see if we can set the SPLIT_END flag in the right-hand
    1927                 :             :          * split page; this can save some I/O for vacuum since it need not
    1928                 :             :          * proceed to the right sibling.  We can set the flag if the right
    1929                 :             :          * sibling has a different cycleid: that means it could not be part of
    1930                 :             :          * a group of pages that were all split off from the same ancestor
    1931                 :             :          * page.  If you're confused, imagine that page A splits to A B and
    1932                 :             :          * then again, yielding A C B, while vacuum is in progress.  Tuples
    1933                 :             :          * originally in A could now be in either B or C, hence vacuum must
    1934                 :             :          * examine both pages.  But if D, our right sibling, has a different
    1935                 :             :          * cycleid then it could not contain any tuples that were in A when
    1936                 :             :          * the vacuum started.
    1937                 :             :          */
    1938         [ +  + ]:        5898 :         if (sopaque->btpo_cycleid != ropaque->btpo_cycleid)
    1939                 :           1 :             ropaque->btpo_flags |= BTP_SPLIT_END;
    1940                 :             :     }
    1941                 :             : 
    1942                 :             :     /*
    1943                 :             :      * Right sibling is locked, new siblings are prepared, but original page
    1944                 :             :      * is not updated yet.
    1945                 :             :      *
    1946                 :             :      * NO EREPORT(ERROR) till right sibling is updated.  We can get away with
    1947                 :             :      * not starting the critical section till here because we haven't been
    1948                 :             :      * scribbling on the original page yet; see comments above.
    1949                 :             :      */
    1950                 :       15672 :     START_CRIT_SECTION();
    1951                 :             : 
    1952                 :             :     /*
    1953                 :             :      * By here, the original data page has been split into two new halves, and
    1954                 :             :      * these are correct.  The algorithm requires that the left page never
    1955                 :             :      * move during a split, so we copy the new left page back on top of the
    1956                 :             :      * original.  We need to do this before writing the WAL record, so that
    1957                 :             :      * XLogInsert can WAL log an image of the page if necessary.
    1958                 :             :      */
    1959                 :       15672 :     memcpy(origpage, leftpage, BLCKSZ);
    1960                 :             :     /* leftpage, lopaque must not be used below here */
    1961                 :             : 
    1962                 :             :     /*
    1963                 :             :      * Move the contents of the right page from its temporary location to the
    1964                 :             :      * destination buffer, before writing the WAL record.  Unlike the left
    1965                 :             :      * page, the right page and its opaque area are still needed to complete
    1966                 :             :      * the update of the page, so reinitialize them.
    1967                 :             :      */
    1968                 :       15672 :     rightpage = BufferGetPage(rbuf);
    1969                 :       15672 :     memcpy(rightpage, rightpage_buf.data, BLCKSZ);
    1970                 :       15672 :     ropaque = BTPageGetOpaque(rightpage);
    1971                 :             : 
    1972                 :       15672 :     MarkBufferDirty(buf);
    1973                 :       15672 :     MarkBufferDirty(rbuf);
    1974                 :             : 
    1975         [ +  + ]:       15672 :     if (!isrightmost)
    1976                 :             :     {
    1977                 :        5898 :         sopaque->btpo_prev = rightpagenumber;
    1978                 :        5898 :         MarkBufferDirty(sbuf);
    1979                 :             :     }
    1980                 :             : 
    1981                 :             :     /*
    1982                 :             :      * Clear INCOMPLETE_SPLIT flag on child if inserting the new item finishes
    1983                 :             :      * a split
    1984                 :             :      */
    1985         [ +  + ]:       15672 :     if (!isleaf)
    1986                 :             :     {
    1987                 :         181 :         Page        cpage = BufferGetPage(cbuf);
    1988                 :         181 :         BTPageOpaque cpageop = BTPageGetOpaque(cpage);
    1989                 :             : 
    1990                 :         181 :         cpageop->btpo_flags &= ~BTP_INCOMPLETE_SPLIT;
    1991                 :         181 :         MarkBufferDirty(cbuf);
    1992                 :             :     }
    1993                 :             : 
    1994                 :             :     /* XLOG stuff */
    1995   [ +  +  +  +  :       15672 :     if (RelationNeedsWAL(rel))
             +  +  +  - ]
    1996                 :       14945 :     {
    1997                 :             :         xl_btree_split xlrec;
    1998                 :             :         uint8       xlinfo;
    1999                 :             : 
    2000                 :       14945 :         xlrec.level = ropaque->btpo_level;
    2001                 :             :         /* See comments below on newitem, orignewitem, and posting lists */
    2002                 :       14945 :         xlrec.firstrightoff = firstrightoff;
    2003                 :       14945 :         xlrec.newitemoff = newitemoff;
    2004                 :       14945 :         xlrec.postingoff = 0;
    2005   [ +  +  +  + ]:       14945 :         if (postingoff != 0 && origpagepostingoff < firstrightoff)
    2006                 :          20 :             xlrec.postingoff = postingoff;
    2007                 :             : 
    2008                 :       14945 :         XLogBeginInsert();
    2009                 :       14945 :         XLogRegisterData(&xlrec, SizeOfBtreeSplit);
    2010                 :             : 
    2011                 :       14945 :         XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
    2012                 :       14945 :         XLogRegisterBuffer(1, rbuf, REGBUF_WILL_INIT);
    2013                 :             :         /* Log original right sibling, since we've changed its prev-pointer */
    2014         [ +  + ]:       14945 :         if (!isrightmost)
    2015                 :        5863 :             XLogRegisterBuffer(2, sbuf, REGBUF_STANDARD);
    2016         [ +  + ]:       14945 :         if (!isleaf)
    2017                 :         181 :             XLogRegisterBuffer(3, cbuf, REGBUF_STANDARD);
    2018                 :             : 
    2019                 :             :         /*
    2020                 :             :          * Log the new item, if it was inserted on the left page. (If it was
    2021                 :             :          * put on the right page, we don't need to explicitly WAL log it
    2022                 :             :          * because it's included with all the other items on the right page.)
    2023                 :             :          * Show the new item as belonging to the left page buffer, so that it
    2024                 :             :          * is not stored if XLogInsert decides it needs a full-page image of
    2025                 :             :          * the left page.  We always store newitemoff in the record, though.
    2026                 :             :          *
    2027                 :             :          * The details are sometimes slightly different for page splits that
    2028                 :             :          * coincide with a posting list split.  If both the replacement
    2029                 :             :          * posting list and newitem go on the right page, then we don't need
    2030                 :             :          * to log anything extra, just like the simple !newitemonleft
    2031                 :             :          * no-posting-split case (postingoff is set to zero in the WAL record,
    2032                 :             :          * so recovery doesn't need to process a posting list split at all).
    2033                 :             :          * Otherwise, we set postingoff and log orignewitem instead of
    2034                 :             :          * newitem, despite having actually inserted newitem.  REDO routine
    2035                 :             :          * must reconstruct nposting and newitem using _bt_swap_posting().
    2036                 :             :          *
    2037                 :             :          * Note: It's possible that our page split point is the point that
    2038                 :             :          * makes the posting list lastleft and newitem firstright.  This is
    2039                 :             :          * the only case where we log orignewitem/newitem despite newitem
    2040                 :             :          * going on the right page.  If XLogInsert decides that it can omit
    2041                 :             :          * orignewitem due to logging a full-page image of the left page,
    2042                 :             :          * everything still works out, since recovery only needs to log
    2043                 :             :          * orignewitem for items on the left page (just like the regular
    2044                 :             :          * newitem-logged case).
    2045                 :             :          */
    2046   [ +  +  +  + ]:       14945 :         if (newitemonleft && xlrec.postingoff == 0)
    2047                 :        2158 :             XLogRegisterBufData(0, newitem, newitemsz);
    2048         [ +  + ]:       12787 :         else if (xlrec.postingoff != 0)
    2049                 :             :         {
    2050                 :             :             Assert(isleaf);
    2051                 :             :             Assert(newitemonleft || firstrightoff == newitemoff);
    2052                 :             :             Assert(newitemsz == IndexTupleSize(orignewitem));
    2053                 :          20 :             XLogRegisterBufData(0, orignewitem, newitemsz);
    2054                 :             :         }
    2055                 :             : 
    2056                 :             :         /* Log the left page's new high key */
    2057         [ +  + ]:       14945 :         if (!isleaf)
    2058                 :             :         {
    2059                 :             :             /* lefthighkey isn't local copy, get current pointer */
    2060                 :         181 :             itemid = PageGetItemId(origpage, P_HIKEY);
    2061                 :         181 :             lefthighkey = (IndexTuple) PageGetItem(origpage, itemid);
    2062                 :             :         }
    2063                 :       14945 :         XLogRegisterBufData(0, lefthighkey,
    2064                 :       14945 :                             MAXALIGN(IndexTupleSize(lefthighkey)));
    2065                 :             : 
    2066                 :             :         /*
    2067                 :             :          * Log the contents of the right page in the format understood by
    2068                 :             :          * _bt_restore_page().  The whole right page will be recreated.
    2069                 :             :          *
    2070                 :             :          * Direct access to page is not good but faster - we should implement
    2071                 :             :          * some new func in page API.  Note we only store the tuples
    2072                 :             :          * themselves, knowing that they were inserted in item-number order
    2073                 :             :          * and so the line pointers can be reconstructed.  See comments for
    2074                 :             :          * _bt_restore_page().
    2075                 :             :          */
    2076                 :       14945 :         XLogRegisterBufData(1,
    2077                 :       14945 :                             (char *) rightpage + ((PageHeader) rightpage)->pd_upper,
    2078                 :       14945 :                             ((PageHeader) rightpage)->pd_special - ((PageHeader) rightpage)->pd_upper);
    2079                 :             : 
    2080         [ +  + ]:       14945 :         xlinfo = newitemonleft ? XLOG_BTREE_SPLIT_L : XLOG_BTREE_SPLIT_R;
    2081                 :       14945 :         recptr = XLogInsert(RM_BTREE_ID, xlinfo);
    2082                 :             :     }
    2083                 :             :     else
    2084                 :         727 :         recptr = XLogGetFakeLSN(rel);
    2085                 :             : 
    2086                 :       15672 :     PageSetLSN(origpage, recptr);
    2087                 :       15672 :     PageSetLSN(rightpage, recptr);
    2088         [ +  + ]:       15672 :     if (!isrightmost)
    2089                 :        5898 :         PageSetLSN(spage, recptr);
    2090         [ +  + ]:       15672 :     if (!isleaf)
    2091                 :         181 :         PageSetLSN(BufferGetPage(cbuf), recptr);
    2092                 :             : 
    2093                 :       15672 :     END_CRIT_SECTION();
    2094                 :             : 
    2095                 :             :     /* release the old right sibling */
    2096         [ +  + ]:       15672 :     if (!isrightmost)
    2097                 :        5898 :         _bt_relbuf(rel, sbuf);
    2098                 :             : 
    2099                 :             :     /* release the child */
    2100         [ +  + ]:       15672 :     if (!isleaf)
    2101                 :         181 :         _bt_relbuf(rel, cbuf);
    2102                 :             : 
    2103                 :             :     /* be tidy */
    2104         [ +  + ]:       15672 :     if (isleaf)
    2105                 :       15491 :         pfree(lefthighkey);
    2106                 :             : 
    2107                 :             :     /* split's done */
    2108                 :       15672 :     return rbuf;
    2109                 :             : }
    2110                 :             : 
    2111                 :             : /*
    2112                 :             :  * _bt_insert_parent() -- Insert downlink into parent, completing split.
    2113                 :             :  *
    2114                 :             :  * On entry, buf and rbuf are the left and right split pages, which we
    2115                 :             :  * still hold write locks on.  Both locks will be released here.  We
    2116                 :             :  * release the rbuf lock once we have a write lock on the page that we
    2117                 :             :  * intend to insert a downlink to rbuf on (i.e. buf's current parent page).
    2118                 :             :  * The lock on buf is released at the same point as the lock on the parent
    2119                 :             :  * page, since buf's INCOMPLETE_SPLIT flag must be cleared by the same
    2120                 :             :  * atomic operation that completes the split by inserting a new downlink.
    2121                 :             :  *
    2122                 :             :  * stack - stack showing how we got here.  Will be NULL when splitting true
    2123                 :             :  *          root, or during concurrent root split, where we can be inefficient
    2124                 :             :  * isroot - we split the true root
    2125                 :             :  * isonly - we split a page alone on its level (might have been fast root)
    2126                 :             :  */
    2127                 :             : static void
    2128                 :       15672 : _bt_insert_parent(Relation rel,
    2129                 :             :                   Relation heaprel,
    2130                 :             :                   Buffer buf,
    2131                 :             :                   Buffer rbuf,
    2132                 :             :                   BTStack stack,
    2133                 :             :                   bool isroot,
    2134                 :             :                   bool isonly)
    2135                 :             : {
    2136                 :             :     Assert(heaprel != NULL);
    2137                 :             : 
    2138                 :             :     /*
    2139                 :             :      * Here we have to do something Lehman and Yao don't talk about: deal with
    2140                 :             :      * a root split and construction of a new root.  If our stack is empty
    2141                 :             :      * then we have just split a node on what had been the root level when we
    2142                 :             :      * descended the tree.  If it was still the root then we perform a
    2143                 :             :      * new-root construction.  If it *wasn't* the root anymore, search to find
    2144                 :             :      * the next higher level that someone constructed meanwhile, and find the
    2145                 :             :      * right place to insert as for the normal case.
    2146                 :             :      *
    2147                 :             :      * If we have to search for the parent level, we do so by re-descending
    2148                 :             :      * from the root.  This is not super-efficient, but it's rare enough not
    2149                 :             :      * to matter.
    2150                 :             :      */
    2151         [ +  + ]:       15672 :     if (isroot)
    2152                 :             :     {
    2153                 :             :         Buffer      rootbuf;
    2154                 :             : 
    2155                 :             :         Assert(stack == NULL);
    2156                 :             :         Assert(isonly);
    2157                 :             :         /* create a new root node one level up and update the metapage */
    2158                 :         849 :         rootbuf = _bt_newlevel(rel, heaprel, buf, rbuf);
    2159                 :             :         /* release the split buffers */
    2160                 :         849 :         _bt_relbuf(rel, rootbuf);
    2161                 :         849 :         _bt_relbuf(rel, rbuf);
    2162                 :         849 :         _bt_relbuf(rel, buf);
    2163                 :             :     }
    2164                 :             :     else
    2165                 :             :     {
    2166                 :       14823 :         BlockNumber bknum = BufferGetBlockNumber(buf);
    2167                 :       14823 :         BlockNumber rbknum = BufferGetBlockNumber(rbuf);
    2168                 :       14823 :         Page        page = BufferGetPage(buf);
    2169                 :             :         IndexTuple  new_item;
    2170                 :             :         BTStackData fakestack;
    2171                 :             :         IndexTuple  ritem;
    2172                 :             :         Buffer      pbuf;
    2173                 :             : 
    2174         [ +  + ]:       14823 :         if (stack == NULL)
    2175                 :             :         {
    2176                 :             :             BTPageOpaque opaque;
    2177                 :             : 
    2178         [ -  + ]:          16 :             elog(DEBUG2, "concurrent ROOT page split");
    2179                 :          16 :             opaque = BTPageGetOpaque(page);
    2180                 :             : 
    2181                 :             :             /*
    2182                 :             :              * We should never reach here when a leaf page split takes place
    2183                 :             :              * despite the insert of newitem being able to apply the fastpath
    2184                 :             :              * optimization.  Make sure of that with an assertion.
    2185                 :             :              *
    2186                 :             :              * This is more of a performance issue than a correctness issue.
    2187                 :             :              * The fastpath won't have a descent stack.  Using a phony stack
    2188                 :             :              * here works, but never rely on that.  The fastpath should be
    2189                 :             :              * rejected within _bt_search_insert() when the rightmost leaf
    2190                 :             :              * page will split, since it's faster to go through _bt_search()
    2191                 :             :              * and get a stack in the usual way.
    2192                 :             :              */
    2193                 :             :             Assert(!(P_ISLEAF(opaque) &&
    2194                 :             :                      BlockNumberIsValid(RelationGetTargetBlock(rel))));
    2195                 :             : 
    2196                 :             :             /* Find the leftmost page at the next level up */
    2197                 :          16 :             pbuf = _bt_get_endpoint(rel, opaque->btpo_level + 1, false);
    2198                 :             :             /* Set up a phony stack entry pointing there */
    2199                 :          16 :             stack = &fakestack;
    2200                 :          16 :             stack->bts_blkno = BufferGetBlockNumber(pbuf);
    2201                 :          16 :             stack->bts_offset = InvalidOffsetNumber;
    2202                 :          16 :             stack->bts_parent = NULL;
    2203                 :          16 :             _bt_relbuf(rel, pbuf);
    2204                 :             :         }
    2205                 :             : 
    2206                 :             :         /* get high key from left, a strict lower bound for new right page */
    2207                 :       14823 :         ritem = (IndexTuple) PageGetItem(page,
    2208                 :       14823 :                                          PageGetItemId(page, P_HIKEY));
    2209                 :             : 
    2210                 :             :         /* form an index tuple that points at the new right page */
    2211                 :       14823 :         new_item = CopyIndexTuple(ritem);
    2212                 :       14823 :         BTreeTupleSetDownLink(new_item, rbknum);
    2213                 :             : 
    2214                 :             :         /*
    2215                 :             :          * Re-find and write lock the parent of buf.
    2216                 :             :          *
    2217                 :             :          * It's possible that the location of buf's downlink has changed since
    2218                 :             :          * our initial _bt_search() descent.  _bt_getstackbuf() will detect
    2219                 :             :          * and recover from this, updating the stack, which ensures that the
    2220                 :             :          * new downlink will be inserted at the correct offset. Even buf's
    2221                 :             :          * parent may have changed.
    2222                 :             :          */
    2223                 :       14823 :         pbuf = _bt_getstackbuf(rel, heaprel, stack, bknum);
    2224                 :             : 
    2225                 :             :         /*
    2226                 :             :          * Unlock the right child.  The left child will be unlocked in
    2227                 :             :          * _bt_insertonpg().
    2228                 :             :          *
    2229                 :             :          * Unlocking the right child must be delayed until here to ensure that
    2230                 :             :          * no concurrent VACUUM operation can become confused.  Page deletion
    2231                 :             :          * cannot be allowed to fail to re-find a downlink for the rbuf page.
    2232                 :             :          * (Actually, this is just a vestige of how things used to work.  The
    2233                 :             :          * page deletion code is expected to check for the INCOMPLETE_SPLIT
    2234                 :             :          * flag on the left child.  It won't attempt deletion of the right
    2235                 :             :          * child until the split is complete.  Despite all this, we opt to
    2236                 :             :          * conservatively delay unlocking the right child until here.)
    2237                 :             :          */
    2238                 :       14823 :         _bt_relbuf(rel, rbuf);
    2239                 :             : 
    2240         [ -  + ]:       14823 :         if (pbuf == InvalidBuffer)
    2241         [ #  # ]:           0 :             ereport(ERROR,
    2242                 :             :                     (errcode(ERRCODE_INDEX_CORRUPTED),
    2243                 :             :                      errmsg_internal("failed to re-find parent key in index \"%s\" for split pages %u/%u",
    2244                 :             :                                      RelationGetRelationName(rel), bknum, rbknum)));
    2245                 :             : 
    2246                 :             :         /* Recursively insert into the parent */
    2247                 :       29646 :         _bt_insertonpg(rel, heaprel, NULL, pbuf, buf, stack->bts_parent,
    2248                 :       14823 :                        new_item, MAXALIGN(IndexTupleSize(new_item)),
    2249                 :       14823 :                        stack->bts_offset + 1, 0, isonly);
    2250                 :             : 
    2251                 :             :         /* be tidy */
    2252                 :       14822 :         pfree(new_item);
    2253                 :             :     }
    2254                 :       15671 : }
    2255                 :             : 
    2256                 :             : /*
    2257                 :             :  * _bt_finish_split() -- Finish an incomplete split
    2258                 :             :  *
    2259                 :             :  * A crash or other failure can leave a split incomplete.  The insertion
    2260                 :             :  * routines won't allow to insert on a page that is incompletely split.
    2261                 :             :  * Before inserting on such a page, call _bt_finish_split().
    2262                 :             :  *
    2263                 :             :  * On entry, 'lbuf' must be locked in write-mode.  On exit, it is unlocked
    2264                 :             :  * and unpinned.
    2265                 :             :  *
    2266                 :             :  * Caller must provide a valid heaprel, since finishing a page split requires
    2267                 :             :  * allocating a new page if and when the parent page splits in turn.
    2268                 :             :  */
    2269                 :             : void
    2270                 :           2 : _bt_finish_split(Relation rel, Relation heaprel, Buffer lbuf, BTStack stack)
    2271                 :             : {
    2272                 :           2 :     Page        lpage = BufferGetPage(lbuf);
    2273                 :           2 :     BTPageOpaque lpageop = BTPageGetOpaque(lpage);
    2274                 :             :     Buffer      rbuf;
    2275                 :             :     Page        rpage;
    2276                 :             :     BTPageOpaque rpageop;
    2277                 :             :     bool        wasroot;
    2278                 :             :     bool        wasonly;
    2279                 :             : 
    2280                 :             :     Assert(P_INCOMPLETE_SPLIT(lpageop));
    2281                 :             :     Assert(heaprel != NULL);
    2282                 :             : 
    2283                 :             :     /* Lock right sibling, the one missing the downlink */
    2284                 :           2 :     rbuf = _bt_getbuf(rel, lpageop->btpo_next, BT_WRITE);
    2285                 :           2 :     rpage = BufferGetPage(rbuf);
    2286                 :           2 :     rpageop = BTPageGetOpaque(rpage);
    2287                 :             : 
    2288                 :             :     /* Could this be a root split? */
    2289         [ +  + ]:           2 :     if (!stack)
    2290                 :             :     {
    2291                 :             :         Buffer      metabuf;
    2292                 :             :         Page        metapg;
    2293                 :             :         BTMetaPageData *metad;
    2294                 :             : 
    2295                 :             :         /* acquire lock on the metapage */
    2296                 :           1 :         metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
    2297                 :           1 :         metapg = BufferGetPage(metabuf);
    2298                 :           1 :         metad = BTPageGetMeta(metapg);
    2299                 :             : 
    2300                 :           1 :         wasroot = (metad->btm_root == BufferGetBlockNumber(lbuf));
    2301                 :             : 
    2302                 :           1 :         _bt_relbuf(rel, metabuf);
    2303                 :             :     }
    2304                 :             :     else
    2305                 :           1 :         wasroot = false;
    2306                 :             : 
    2307                 :             :     /* Was this the only page on the level before split? */
    2308   [ +  +  +  - ]:           2 :     wasonly = (P_LEFTMOST(lpageop) && P_RIGHTMOST(rpageop));
    2309                 :             : 
    2310                 :           2 :     INJECTION_POINT("nbtree-finish-incomplete-split", NULL);
    2311         [ -  + ]:           2 :     elog(DEBUG1, "finishing incomplete split of %u/%u",
    2312                 :             :          BufferGetBlockNumber(lbuf), BufferGetBlockNumber(rbuf));
    2313                 :             : 
    2314                 :           2 :     _bt_insert_parent(rel, heaprel, lbuf, rbuf, stack, wasroot, wasonly);
    2315                 :           2 : }
    2316                 :             : 
    2317                 :             : /*
    2318                 :             :  *  _bt_getstackbuf() -- Walk back up the tree one step, and find the pivot
    2319                 :             :  *                       tuple whose downlink points to child page.
    2320                 :             :  *
    2321                 :             :  *      Caller passes child's block number, which is used to identify
    2322                 :             :  *      associated pivot tuple in parent page using a linear search that
    2323                 :             :  *      matches on pivot's downlink/block number.  The expected location of
    2324                 :             :  *      the pivot tuple is taken from the stack one level above the child
    2325                 :             :  *      page.  This is used as a starting point.  Insertions into the
    2326                 :             :  *      parent level could cause the pivot tuple to move right; deletions
    2327                 :             :  *      could cause it to move left, but not left of the page we previously
    2328                 :             :  *      found it on.
    2329                 :             :  *
    2330                 :             :  *      Caller can use its stack to relocate the pivot tuple/downlink for
    2331                 :             :  *      any same-level page to the right of the page found by its initial
    2332                 :             :  *      descent.  This is necessary because of the possibility that caller
    2333                 :             :  *      moved right to recover from a concurrent page split.  It's also
    2334                 :             :  *      convenient for certain callers to be able to step right when there
    2335                 :             :  *      wasn't a concurrent page split, while still using their original
    2336                 :             :  *      stack.  For example, the checkingunique _bt_doinsert() case may
    2337                 :             :  *      have to step right when there are many physical duplicates, and its
    2338                 :             :  *      scantid forces an insertion to the right of the "first page the
    2339                 :             :  *      value could be on".  (This is also relied on by all of our callers
    2340                 :             :  *      when dealing with !heapkeyspace indexes.)
    2341                 :             :  *
    2342                 :             :  *      Returns write-locked parent page buffer, or InvalidBuffer if pivot
    2343                 :             :  *      tuple not found (should not happen).  Adjusts bts_blkno &
    2344                 :             :  *      bts_offset if changed.  Page split caller should insert its new
    2345                 :             :  *      pivot tuple for its new right sibling page on parent page, at the
    2346                 :             :  *      offset number bts_offset + 1.
    2347                 :             :  */
    2348                 :             : Buffer
    2349                 :       18822 : _bt_getstackbuf(Relation rel, Relation heaprel, BTStack stack, BlockNumber child)
    2350                 :             : {
    2351                 :             :     BlockNumber blkno;
    2352                 :             :     OffsetNumber start;
    2353                 :             : 
    2354                 :       18822 :     blkno = stack->bts_blkno;
    2355                 :       18822 :     start = stack->bts_offset;
    2356                 :             : 
    2357                 :             :     for (;;)
    2358                 :          10 :     {
    2359                 :             :         Buffer      buf;
    2360                 :             :         Page        page;
    2361                 :             :         BTPageOpaque opaque;
    2362                 :             : 
    2363                 :       18832 :         buf = _bt_getbuf(rel, blkno, BT_WRITE);
    2364                 :       18832 :         page = BufferGetPage(buf);
    2365                 :       18832 :         opaque = BTPageGetOpaque(page);
    2366                 :             : 
    2367                 :             :         Assert(heaprel != NULL);
    2368         [ -  + ]:       18832 :         if (P_INCOMPLETE_SPLIT(opaque))
    2369                 :             :         {
    2370                 :           0 :             _bt_finish_split(rel, heaprel, buf, stack->bts_parent);
    2371                 :           0 :             continue;
    2372                 :             :         }
    2373                 :             : 
    2374         [ +  + ]:       18832 :         if (!P_IGNORE(opaque))
    2375                 :             :         {
    2376                 :             :             OffsetNumber offnum,
    2377                 :             :                         minoff,
    2378                 :             :                         maxoff;
    2379                 :             :             ItemId      itemid;
    2380                 :             :             IndexTuple  item;
    2381                 :             : 
    2382         [ +  + ]:       18823 :             minoff = P_FIRSTDATAKEY(opaque);
    2383                 :       18823 :             maxoff = PageGetMaxOffsetNumber(page);
    2384                 :             : 
    2385                 :             :             /*
    2386                 :             :              * start = InvalidOffsetNumber means "search the whole page". We
    2387                 :             :              * need this test anyway due to possibility that page has a high
    2388                 :             :              * key now when it didn't before.
    2389                 :             :              */
    2390         [ +  + ]:       18823 :             if (start < minoff)
    2391                 :          26 :                 start = minoff;
    2392                 :             : 
    2393                 :             :             /*
    2394                 :             :              * Need this check too, to guard against possibility that page
    2395                 :             :              * split since we visited it originally.
    2396                 :             :              */
    2397         [ +  + ]:       18823 :             if (start > maxoff)
    2398                 :           1 :                 start = OffsetNumberNext(maxoff);
    2399                 :             : 
    2400                 :             :             /*
    2401                 :             :              * These loops will check every item on the page --- but in an
    2402                 :             :              * order that's attuned to the probability of where it actually
    2403                 :             :              * is.  Scan to the right first, then to the left.
    2404                 :             :              */
    2405                 :       18823 :             for (offnum = start;
    2406         [ +  + ]:       18999 :                  offnum <= maxoff;
    2407                 :         176 :                  offnum = OffsetNumberNext(offnum))
    2408                 :             :             {
    2409                 :       18998 :                 itemid = PageGetItemId(page, offnum);
    2410                 :       18998 :                 item = (IndexTuple) PageGetItem(page, itemid);
    2411                 :             : 
    2412         [ +  + ]:       18998 :                 if (BTreeTupleGetDownLink(item) == child)
    2413                 :             :                 {
    2414                 :             :                     /* Return accurate pointer to where link is now */
    2415                 :       18822 :                     stack->bts_blkno = blkno;
    2416                 :       18822 :                     stack->bts_offset = offnum;
    2417                 :       18822 :                     return buf;
    2418                 :             :                 }
    2419                 :             :             }
    2420                 :             : 
    2421                 :           1 :             for (offnum = OffsetNumberPrev(start);
    2422         [ +  + ]:         286 :                  offnum >= minoff;
    2423                 :         285 :                  offnum = OffsetNumberPrev(offnum))
    2424                 :             :             {
    2425                 :         285 :                 itemid = PageGetItemId(page, offnum);
    2426                 :         285 :                 item = (IndexTuple) PageGetItem(page, itemid);
    2427                 :             : 
    2428         [ -  + ]:         285 :                 if (BTreeTupleGetDownLink(item) == child)
    2429                 :             :                 {
    2430                 :             :                     /* Return accurate pointer to where link is now */
    2431                 :           0 :                     stack->bts_blkno = blkno;
    2432                 :           0 :                     stack->bts_offset = offnum;
    2433                 :           0 :                     return buf;
    2434                 :             :                 }
    2435                 :             :             }
    2436                 :             :         }
    2437                 :             : 
    2438                 :             :         /*
    2439                 :             :          * The item we're looking for moved right at least one page.
    2440                 :             :          *
    2441                 :             :          * Lehman and Yao couple/chain locks when moving right here, which we
    2442                 :             :          * can avoid.  See nbtree/README.
    2443                 :             :          */
    2444         [ -  + ]:          10 :         if (P_RIGHTMOST(opaque))
    2445                 :             :         {
    2446                 :           0 :             _bt_relbuf(rel, buf);
    2447                 :           0 :             return InvalidBuffer;
    2448                 :             :         }
    2449                 :          10 :         blkno = opaque->btpo_next;
    2450                 :          10 :         start = InvalidOffsetNumber;
    2451                 :          10 :         _bt_relbuf(rel, buf);
    2452                 :             :     }
    2453                 :             : }
    2454                 :             : 
    2455                 :             : /*
    2456                 :             :  * _bt_freestack() -- free a retracement stack made by _bt_search_insert.
    2457                 :             :  */
    2458                 :             : static void
    2459                 :     4666724 : _bt_freestack(BTStack stack)
    2460                 :             : {
    2461                 :             :     BTStack     ostack;
    2462                 :             : 
    2463         [ +  + ]:     9392082 :     while (stack != NULL)
    2464                 :             :     {
    2465                 :     4725358 :         ostack = stack;
    2466                 :     4725358 :         stack = stack->bts_parent;
    2467                 :     4725358 :         pfree(ostack);
    2468                 :             :     }
    2469                 :     4666724 : }
    2470                 :             : 
    2471                 :             : /*
    2472                 :             :  *  _bt_newlevel() -- Create a new level above root page.
    2473                 :             :  *
    2474                 :             :  *      We've just split the old root page and need to create a new one.
    2475                 :             :  *      In order to do this, we add a new root page to the file, then lock
    2476                 :             :  *      the metadata page and update it.  This is guaranteed to be deadlock-
    2477                 :             :  *      free, because all readers release their locks on the metadata page
    2478                 :             :  *      before trying to lock the root, and all writers lock the root before
    2479                 :             :  *      trying to lock the metadata page.  We have a write lock on the old
    2480                 :             :  *      root page, so we have not introduced any cycles into the waits-for
    2481                 :             :  *      graph.
    2482                 :             :  *
    2483                 :             :  *      On entry, lbuf (the old root) and rbuf (its new peer) are write-
    2484                 :             :  *      locked. On exit, a new root page exists with entries for the
    2485                 :             :  *      two new children, metapage is updated and unlocked/unpinned.
    2486                 :             :  *      The new root buffer is returned to caller which has to unlock/unpin
    2487                 :             :  *      lbuf, rbuf & rootbuf.
    2488                 :             :  */
    2489                 :             : static Buffer
    2490                 :         849 : _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf)
    2491                 :             : {
    2492                 :             :     Buffer      rootbuf;
    2493                 :             :     Page        lpage,
    2494                 :             :                 rootpage;
    2495                 :             :     BlockNumber lbkno,
    2496                 :             :                 rbkno;
    2497                 :             :     BlockNumber rootblknum;
    2498                 :             :     BTPageOpaque rootopaque;
    2499                 :             :     BTPageOpaque lopaque;
    2500                 :             :     ItemId      itemid;
    2501                 :             :     IndexTuple  item;
    2502                 :             :     IndexTuple  left_item;
    2503                 :             :     Size        left_item_sz;
    2504                 :             :     IndexTuple  right_item;
    2505                 :             :     Size        right_item_sz;
    2506                 :             :     Buffer      metabuf;
    2507                 :             :     Page        metapg;
    2508                 :             :     BTMetaPageData *metad;
    2509                 :             :     XLogRecPtr  recptr;
    2510                 :             : 
    2511                 :         849 :     lbkno = BufferGetBlockNumber(lbuf);
    2512                 :         849 :     rbkno = BufferGetBlockNumber(rbuf);
    2513                 :         849 :     lpage = BufferGetPage(lbuf);
    2514                 :         849 :     lopaque = BTPageGetOpaque(lpage);
    2515                 :             : 
    2516                 :             :     /* get a new root page */
    2517                 :         849 :     rootbuf = _bt_allocbuf(rel, heaprel);
    2518                 :         849 :     rootpage = BufferGetPage(rootbuf);
    2519                 :         849 :     rootblknum = BufferGetBlockNumber(rootbuf);
    2520                 :             : 
    2521                 :             :     /* acquire lock on the metapage */
    2522                 :         849 :     metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
    2523                 :         849 :     metapg = BufferGetPage(metabuf);
    2524                 :         849 :     metad = BTPageGetMeta(metapg);
    2525                 :             : 
    2526                 :             :     /*
    2527                 :             :      * Create downlink item for left page (old root).  The key value used is
    2528                 :             :      * "minus infinity", a sentinel value that's reliably less than any real
    2529                 :             :      * key value that could appear in the left page.
    2530                 :             :      */
    2531                 :         849 :     left_item_sz = sizeof(IndexTupleData);
    2532                 :         849 :     left_item = (IndexTuple) palloc(left_item_sz);
    2533                 :         849 :     left_item->t_info = left_item_sz;
    2534                 :         849 :     BTreeTupleSetDownLink(left_item, lbkno);
    2535                 :         849 :     BTreeTupleSetNAtts(left_item, 0, false);
    2536                 :             : 
    2537                 :             :     /*
    2538                 :             :      * Create downlink item for right page.  The key for it is obtained from
    2539                 :             :      * the "high key" position in the left page.
    2540                 :             :      */
    2541                 :         849 :     itemid = PageGetItemId(lpage, P_HIKEY);
    2542                 :         849 :     right_item_sz = ItemIdGetLength(itemid);
    2543                 :         849 :     item = (IndexTuple) PageGetItem(lpage, itemid);
    2544                 :         849 :     right_item = CopyIndexTuple(item);
    2545                 :         849 :     BTreeTupleSetDownLink(right_item, rbkno);
    2546                 :             : 
    2547                 :             :     /* NO EREPORT(ERROR) from here till newroot op is logged */
    2548                 :         849 :     START_CRIT_SECTION();
    2549                 :             : 
    2550                 :             :     /* upgrade metapage if needed */
    2551         [ -  + ]:         849 :     if (metad->btm_version < BTREE_NOVAC_VERSION)
    2552                 :           0 :         _bt_upgrademetapage(metapg);
    2553                 :             : 
    2554                 :             :     /* set btree special data */
    2555                 :         849 :     rootopaque = BTPageGetOpaque(rootpage);
    2556                 :         849 :     rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
    2557                 :         849 :     rootopaque->btpo_flags = BTP_ROOT;
    2558                 :         849 :     rootopaque->btpo_level =
    2559                 :         849 :         (BTPageGetOpaque(lpage))->btpo_level + 1;
    2560                 :         849 :     rootopaque->btpo_cycleid = 0;
    2561                 :             : 
    2562                 :             :     /* update metapage data */
    2563                 :         849 :     metad->btm_root = rootblknum;
    2564                 :         849 :     metad->btm_level = rootopaque->btpo_level;
    2565                 :         849 :     metad->btm_fastroot = rootblknum;
    2566                 :         849 :     metad->btm_fastlevel = rootopaque->btpo_level;
    2567                 :             : 
    2568                 :             :     /*
    2569                 :             :      * Insert the left page pointer into the new root page.  The root page is
    2570                 :             :      * the rightmost page on its level so there is no "high key" in it; the
    2571                 :             :      * two items will go into positions P_HIKEY and P_FIRSTKEY.
    2572                 :             :      *
    2573                 :             :      * Note: we *must* insert the two items in item-number order, for the
    2574                 :             :      * benefit of _bt_restore_page().
    2575                 :             :      */
    2576                 :             :     Assert(BTreeTupleGetNAtts(left_item, rel) == 0);
    2577         [ -  + ]:         849 :     if (PageAddItem(rootpage, left_item, left_item_sz, P_HIKEY, false, false) == InvalidOffsetNumber)
    2578         [ #  # ]:           0 :         elog(PANIC, "failed to add leftkey to new root page"
    2579                 :             :              " while splitting block %u of index \"%s\"",
    2580                 :             :              BufferGetBlockNumber(lbuf), RelationGetRelationName(rel));
    2581                 :             : 
    2582                 :             :     /*
    2583                 :             :      * insert the right page pointer into the new root page.
    2584                 :             :      */
    2585                 :             :     Assert(BTreeTupleGetNAtts(right_item, rel) > 0);
    2586                 :             :     Assert(BTreeTupleGetNAtts(right_item, rel) <=
    2587                 :             :            IndexRelationGetNumberOfKeyAttributes(rel));
    2588         [ -  + ]:         849 :     if (PageAddItem(rootpage, right_item, right_item_sz, P_FIRSTKEY, false, false) == InvalidOffsetNumber)
    2589         [ #  # ]:           0 :         elog(PANIC, "failed to add rightkey to new root page"
    2590                 :             :              " while splitting block %u of index \"%s\"",
    2591                 :             :              BufferGetBlockNumber(lbuf), RelationGetRelationName(rel));
    2592                 :             : 
    2593                 :             :     /* Clear the incomplete-split flag in the left child */
    2594                 :             :     Assert(P_INCOMPLETE_SPLIT(lopaque));
    2595                 :         849 :     lopaque->btpo_flags &= ~BTP_INCOMPLETE_SPLIT;
    2596                 :         849 :     MarkBufferDirty(lbuf);
    2597                 :             : 
    2598                 :         849 :     MarkBufferDirty(rootbuf);
    2599                 :         849 :     MarkBufferDirty(metabuf);
    2600                 :             : 
    2601                 :             :     /* XLOG stuff */
    2602   [ +  +  +  +  :         849 :     if (RelationNeedsWAL(rel))
             +  +  +  - ]
    2603                 :         829 :     {
    2604                 :             :         xl_btree_newroot xlrec;
    2605                 :             :         xl_btree_metadata md;
    2606                 :             : 
    2607                 :         829 :         xlrec.rootblk = rootblknum;
    2608                 :         829 :         xlrec.level = metad->btm_level;
    2609                 :             : 
    2610                 :         829 :         XLogBeginInsert();
    2611                 :         829 :         XLogRegisterData(&xlrec, SizeOfBtreeNewroot);
    2612                 :             : 
    2613                 :         829 :         XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
    2614                 :         829 :         XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD);
    2615                 :         829 :         XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
    2616                 :             : 
    2617                 :             :         Assert(metad->btm_version >= BTREE_NOVAC_VERSION);
    2618                 :         829 :         md.version = metad->btm_version;
    2619                 :         829 :         md.root = rootblknum;
    2620                 :         829 :         md.level = metad->btm_level;
    2621                 :         829 :         md.fastroot = rootblknum;
    2622                 :         829 :         md.fastlevel = metad->btm_level;
    2623                 :         829 :         md.last_cleanup_num_delpages = metad->btm_last_cleanup_num_delpages;
    2624                 :         829 :         md.allequalimage = metad->btm_allequalimage;
    2625                 :             : 
    2626                 :         829 :         XLogRegisterBufData(2, &md, sizeof(xl_btree_metadata));
    2627                 :             : 
    2628                 :             :         /*
    2629                 :             :          * Direct access to page is not good but faster - we should implement
    2630                 :             :          * some new func in page API.
    2631                 :             :          */
    2632                 :         829 :         XLogRegisterBufData(0,
    2633                 :         829 :                             (char *) rootpage + ((PageHeader) rootpage)->pd_upper,
    2634                 :         829 :                             ((PageHeader) rootpage)->pd_special -
    2635                 :         829 :                             ((PageHeader) rootpage)->pd_upper);
    2636                 :             : 
    2637                 :         829 :         recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT);
    2638                 :             :     }
    2639                 :             :     else
    2640                 :          20 :         recptr = XLogGetFakeLSN(rel);
    2641                 :             : 
    2642                 :         849 :     PageSetLSN(lpage, recptr);
    2643                 :         849 :     PageSetLSN(rootpage, recptr);
    2644                 :         849 :     PageSetLSN(metapg, recptr);
    2645                 :             : 
    2646                 :         849 :     END_CRIT_SECTION();
    2647                 :             : 
    2648                 :             :     /* done with metapage */
    2649                 :         849 :     _bt_relbuf(rel, metabuf);
    2650                 :             : 
    2651                 :         849 :     pfree(left_item);
    2652                 :         849 :     pfree(right_item);
    2653                 :             : 
    2654                 :         849 :     return rootbuf;
    2655                 :             : }
    2656                 :             : 
    2657                 :             : /*
    2658                 :             :  *  _bt_pgaddtup() -- add a data item to a particular page during split.
    2659                 :             :  *
    2660                 :             :  *      The difference between this routine and a bare PageAddItem call is
    2661                 :             :  *      that this code can deal with the first data item on an internal btree
    2662                 :             :  *      page in passing.  This data item (which is called "firstright" within
    2663                 :             :  *      _bt_split()) has a key that must be treated as minus infinity after
    2664                 :             :  *      the split.  Therefore, we truncate away all attributes when caller
    2665                 :             :  *      specifies it's the first data item on page (downlink is not changed,
    2666                 :             :  *      though).  This extra step is only needed for the right page of an
    2667                 :             :  *      internal page split.  There is no need to do this for the first data
    2668                 :             :  *      item on the existing/left page, since that will already have been
    2669                 :             :  *      truncated during an earlier page split.
    2670                 :             :  *
    2671                 :             :  *      See _bt_split() for a high level explanation of why we truncate here.
    2672                 :             :  *      Note that this routine has nothing to do with suffix truncation,
    2673                 :             :  *      despite using some of the same infrastructure.
    2674                 :             :  */
    2675                 :             : static inline bool
    2676                 :     4918695 : _bt_pgaddtup(Page page,
    2677                 :             :              Size itemsize,
    2678                 :             :              const IndexTupleData *itup,
    2679                 :             :              OffsetNumber itup_off,
    2680                 :             :              bool newfirstdataitem)
    2681                 :             : {
    2682                 :             :     IndexTupleData trunctuple;
    2683                 :             : 
    2684         [ +  + ]:     4918695 :     if (newfirstdataitem)
    2685                 :             :     {
    2686                 :         181 :         trunctuple = *itup;
    2687                 :         181 :         trunctuple.t_info = sizeof(IndexTupleData);
    2688                 :         181 :         BTreeTupleSetNAtts(&trunctuple, 0, false);
    2689                 :         181 :         itup = &trunctuple;
    2690                 :         181 :         itemsize = sizeof(IndexTupleData);
    2691                 :             :     }
    2692                 :             : 
    2693         [ -  + ]:     4918695 :     if (unlikely(PageAddItem(page, itup, itemsize, itup_off, false, false) == InvalidOffsetNumber))
    2694                 :           0 :         return false;
    2695                 :             : 
    2696                 :     4918695 :     return true;
    2697                 :             : }
    2698                 :             : 
    2699                 :             : /*
    2700                 :             :  * _bt_delete_or_dedup_one_page - Try to avoid a leaf page split.
    2701                 :             :  *
    2702                 :             :  * There are three operations performed here: simple index deletion, bottom-up
    2703                 :             :  * index deletion, and deduplication.  If all three operations fail to free
    2704                 :             :  * enough space for the incoming item then caller will go on to split the
    2705                 :             :  * page.  We always consider simple deletion first.  If that doesn't work out
    2706                 :             :  * we consider alternatives.  Callers that only want us to consider simple
    2707                 :             :  * deletion (without any fallback) ask for that using the 'simpleonly'
    2708                 :             :  * argument.
    2709                 :             :  *
    2710                 :             :  * We usually pick only one alternative "complex" operation when simple
    2711                 :             :  * deletion alone won't prevent a page split.  The 'checkingunique',
    2712                 :             :  * 'uniquedup', and 'indexUnchanged' arguments are used for that.
    2713                 :             :  *
    2714                 :             :  * Note: We used to only delete LP_DEAD items when the BTP_HAS_GARBAGE page
    2715                 :             :  * level flag was found set.  The flag was useful back when there wasn't
    2716                 :             :  * necessarily one single page for a duplicate tuple to go on (before heap TID
    2717                 :             :  * became a part of the key space in version 4 indexes).  But we don't
    2718                 :             :  * actually look at the flag anymore (it's not a gating condition for our
    2719                 :             :  * caller).  That would cause us to miss tuples that are safe to delete,
    2720                 :             :  * without getting any benefit in return.  We know that the alternative is to
    2721                 :             :  * split the page; scanning the line pointer array in passing won't have
    2722                 :             :  * noticeable overhead.  (We still maintain the BTP_HAS_GARBAGE flag despite
    2723                 :             :  * all this because !heapkeyspace indexes must still do a "getting tired"
    2724                 :             :  * linear search, and so are likely to get some benefit from using it as a
    2725                 :             :  * gating condition.)
    2726                 :             :  */
    2727                 :             : static void
    2728                 :       34709 : _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel,
    2729                 :             :                              BTInsertState insertstate,
    2730                 :             :                              bool simpleonly, bool checkingunique,
    2731                 :             :                              bool uniquedup, bool indexUnchanged)
    2732                 :             : {
    2733                 :             :     OffsetNumber deletable[MaxIndexTuplesPerPage];
    2734                 :       34709 :     int         ndeletable = 0;
    2735                 :             :     OffsetNumber offnum,
    2736                 :             :                 minoff,
    2737                 :             :                 maxoff;
    2738                 :       34709 :     Buffer      buffer = insertstate->buf;
    2739                 :       34709 :     BTScanInsert itup_key = insertstate->itup_key;
    2740                 :       34709 :     Page        page = BufferGetPage(buffer);
    2741                 :       34709 :     BTPageOpaque opaque = BTPageGetOpaque(page);
    2742                 :             : 
    2743                 :             :     Assert(P_ISLEAF(opaque));
    2744                 :             :     Assert(simpleonly || itup_key->heapkeyspace);
    2745                 :             :     Assert(!simpleonly || (!checkingunique && !uniquedup && !indexUnchanged));
    2746                 :             : 
    2747                 :             :     /*
    2748                 :             :      * Scan over all items to see which ones need to be deleted according to
    2749                 :             :      * LP_DEAD flags.  We'll usually manage to delete a few extra items that
    2750                 :             :      * are not marked LP_DEAD in passing.  Often the extra items that actually
    2751                 :             :      * end up getting deleted are items that would have had their LP_DEAD bit
    2752                 :             :      * set before long anyway (if we opted not to include them as extras).
    2753                 :             :      */
    2754         [ +  + ]:       34709 :     minoff = P_FIRSTDATAKEY(opaque);
    2755                 :       34709 :     maxoff = PageGetMaxOffsetNumber(page);
    2756                 :       34709 :     for (offnum = minoff;
    2757         [ +  + ]:     9579585 :          offnum <= maxoff;
    2758                 :     9544876 :          offnum = OffsetNumberNext(offnum))
    2759                 :             :     {
    2760                 :     9544876 :         ItemId      itemId = PageGetItemId(page, offnum);
    2761                 :             : 
    2762         [ +  + ]:     9544876 :         if (ItemIdIsDead(itemId))
    2763                 :      153658 :             deletable[ndeletable++] = offnum;
    2764                 :             :     }
    2765                 :             : 
    2766         [ +  + ]:       34709 :     if (ndeletable > 0)
    2767                 :             :     {
    2768                 :        4903 :         _bt_simpledel_pass(rel, buffer, heapRel, deletable, ndeletable,
    2769                 :             :                            insertstate->itup, minoff, maxoff);
    2770                 :        4903 :         insertstate->bounds_valid = false;
    2771                 :             : 
    2772                 :             :         /* Return when a page split has already been avoided */
    2773         [ +  + ]:        4903 :         if (PageGetFreeSpace(page) >= insertstate->itemsz)
    2774                 :       15400 :             return;
    2775                 :             : 
    2776                 :             :         /* Might as well assume duplicates (if checkingunique) */
    2777                 :          58 :         uniquedup = true;
    2778                 :             :     }
    2779                 :             : 
    2780                 :             :     /*
    2781                 :             :      * We're done with simple deletion.  Return early with callers that only
    2782                 :             :      * call here so that simple deletion can be considered.  This includes
    2783                 :             :      * callers that explicitly ask for this and checkingunique callers that
    2784                 :             :      * probably don't have any version churn duplicates on the page.
    2785                 :             :      *
    2786                 :             :      * Note: The page's BTP_HAS_GARBAGE hint flag may still be set when we
    2787                 :             :      * return at this point (or when we go on the try either or both of our
    2788                 :             :      * other strategies and they also fail).  We do not bother expending a
    2789                 :             :      * separate write to clear it, however.  Caller will definitely clear it
    2790                 :             :      * when it goes on to split the page (note also that the deduplication
    2791                 :             :      * process will clear the flag in passing, just to keep things tidy).
    2792                 :             :      */
    2793   [ +  -  +  +  :       29864 :     if (simpleonly || (checkingunique && !uniquedup))
                   +  + ]
    2794                 :             :     {
    2795                 :             :         Assert(!indexUnchanged);
    2796                 :       10283 :         return;
    2797                 :             :     }
    2798                 :             : 
    2799                 :             :     /* Assume bounds about to be invalidated (this is almost certain now) */
    2800                 :       19581 :     insertstate->bounds_valid = false;
    2801                 :             : 
    2802                 :             :     /*
    2803                 :             :      * Perform bottom-up index deletion pass when executor hint indicated that
    2804                 :             :      * incoming item is logically unchanged, or for a unique index that is
    2805                 :             :      * known to have physical duplicates for some other reason.  (There is a
    2806                 :             :      * large overlap between these two cases for a unique index.  It's worth
    2807                 :             :      * having both triggering conditions in order to apply the optimization in
    2808                 :             :      * the event of successive related INSERT and DELETE statements.)
    2809                 :             :      *
    2810                 :             :      * We'll go on to do a deduplication pass when a bottom-up pass fails to
    2811                 :             :      * delete an acceptable amount of free space (a significant fraction of
    2812                 :             :      * the page, or space for the new item, whichever is greater).
    2813                 :             :      *
    2814                 :             :      * Note: Bottom-up index deletion uses the same equality/equivalence
    2815                 :             :      * routines as deduplication internally.  However, it does not merge
    2816                 :             :      * together index tuples, so the same correctness considerations do not
    2817                 :             :      * apply.  We deliberately omit an index-is-allequalimage test here.
    2818                 :             :      */
    2819   [ +  +  +  +  :       22641 :     if ((indexUnchanged || uniquedup) &&
                   +  + ]
    2820                 :        3060 :         _bt_bottomupdel_pass(rel, buffer, heapRel, insertstate->itemsz))
    2821                 :         272 :         return;
    2822                 :             : 
    2823                 :             :     /* Perform deduplication pass (when enabled and index-is-allequalimage) */
    2824   [ +  +  +  +  :       19309 :     if (BTGetDeduplicateItems(rel) && itup_key->allequalimage)
                   +  - ]
    2825                 :       19274 :         _bt_dedup_pass(rel, buffer, insertstate->itup, insertstate->itemsz,
    2826   [ +  +  +  + ]:       19274 :                        (indexUnchanged || uniquedup));
    2827                 :             : }
    2828                 :             : 
    2829                 :             : /*
    2830                 :             :  * _bt_simpledel_pass - Simple index tuple deletion pass.
    2831                 :             :  *
    2832                 :             :  * We delete all LP_DEAD-set index tuples on a leaf page.  The offset numbers
    2833                 :             :  * of all such tuples are determined by caller (caller passes these to us as
    2834                 :             :  * its 'deletable' argument).
    2835                 :             :  *
    2836                 :             :  * We might also delete extra index tuples that turn out to be safe to delete
    2837                 :             :  * in passing (though they must be cheap to check in passing to begin with).
    2838                 :             :  * There is no certainty that any extra tuples will be deleted, though.  The
    2839                 :             :  * high level goal of the approach we take is to get the most out of each call
    2840                 :             :  * here (without noticeably increasing the per-call overhead compared to what
    2841                 :             :  * we need to do just to be able to delete the page's LP_DEAD-marked index
    2842                 :             :  * tuples).
    2843                 :             :  *
    2844                 :             :  * The number of extra index tuples that turn out to be deletable might
    2845                 :             :  * greatly exceed the number of LP_DEAD-marked index tuples due to various
    2846                 :             :  * locality related effects.  For example, it's possible that the total number
    2847                 :             :  * of table blocks (pointed to by all TIDs on the leaf page) is naturally
    2848                 :             :  * quite low, in which case we might end up checking if it's possible to
    2849                 :             :  * delete _most_ index tuples on the page (without the tableam needing to
    2850                 :             :  * access additional table blocks).  The tableam will sometimes stumble upon
    2851                 :             :  * _many_ extra deletable index tuples in indexes where this pattern is
    2852                 :             :  * common.
    2853                 :             :  *
    2854                 :             :  * See nbtree/README for further details on simple index tuple deletion.
    2855                 :             :  */
    2856                 :             : static void
    2857                 :        4903 : _bt_simpledel_pass(Relation rel, Buffer buffer, Relation heapRel,
    2858                 :             :                    OffsetNumber *deletable, int ndeletable, IndexTuple newitem,
    2859                 :             :                    OffsetNumber minoff, OffsetNumber maxoff)
    2860                 :             : {
    2861                 :        4903 :     Page        page = BufferGetPage(buffer);
    2862                 :             :     BlockNumber *deadblocks;
    2863                 :             :     int         ndeadblocks;
    2864                 :             :     TM_IndexDeleteOp delstate;
    2865                 :             :     OffsetNumber offnum;
    2866                 :             : 
    2867                 :             :     /* Get array of table blocks pointed to by LP_DEAD-set tuples */
    2868                 :        4903 :     deadblocks = _bt_deadblocks(page, deletable, ndeletable, newitem,
    2869                 :             :                                 &ndeadblocks);
    2870                 :             : 
    2871                 :             :     /* Initialize tableam state that describes index deletion operation */
    2872                 :        4903 :     delstate.irel = rel;
    2873                 :        4903 :     delstate.iblknum = BufferGetBlockNumber(buffer);
    2874                 :        4903 :     delstate.bottomup = false;
    2875                 :        4903 :     delstate.bottomupfreespace = 0;
    2876                 :        4903 :     delstate.ndeltids = 0;
    2877                 :        4903 :     delstate.deltids = palloc_array(TM_IndexDelete, MaxTIDsPerBTreePage);
    2878                 :        4903 :     delstate.status = palloc_array(TM_IndexStatus, MaxTIDsPerBTreePage);
    2879                 :             : 
    2880                 :        4903 :     for (offnum = minoff;
    2881         [ +  + ]:     1406577 :          offnum <= maxoff;
    2882                 :     1401674 :          offnum = OffsetNumberNext(offnum))
    2883                 :             :     {
    2884                 :     1401674 :         ItemId      itemid = PageGetItemId(page, offnum);
    2885                 :     1401674 :         IndexTuple  itup = (IndexTuple) PageGetItem(page, itemid);
    2886                 :     1401674 :         TM_IndexDelete *odeltid = &delstate.deltids[delstate.ndeltids];
    2887                 :     1401674 :         TM_IndexStatus *ostatus = &delstate.status[delstate.ndeltids];
    2888                 :             :         BlockNumber tidblock;
    2889                 :             :         void       *match;
    2890                 :             : 
    2891         [ +  + ]:     1401674 :         if (!BTreeTupleIsPosting(itup))
    2892                 :             :         {
    2893                 :     1336496 :             tidblock = ItemPointerGetBlockNumber(&itup->t_tid);
    2894                 :     1336496 :             match = bsearch(&tidblock, deadblocks, ndeadblocks,
    2895                 :             :                             sizeof(BlockNumber), _bt_blk_cmp);
    2896                 :             : 
    2897         [ +  + ]:     1336496 :             if (!match)
    2898                 :             :             {
    2899                 :             :                 Assert(!ItemIdIsDead(itemid));
    2900                 :      844410 :                 continue;
    2901                 :             :             }
    2902                 :             : 
    2903                 :             :             /*
    2904                 :             :              * TID's table block is among those pointed to by the TIDs from
    2905                 :             :              * LP_DEAD-bit set tuples on page -- add TID to deltids
    2906                 :             :              */
    2907                 :      492086 :             odeltid->tid = itup->t_tid;
    2908                 :      492086 :             odeltid->id = delstate.ndeltids;
    2909                 :      492086 :             ostatus->idxoffnum = offnum;
    2910                 :      492086 :             ostatus->knowndeletable = ItemIdIsDead(itemid);
    2911                 :      492086 :             ostatus->promising = false; /* unused */
    2912                 :      492086 :             ostatus->freespace = 0; /* unused */
    2913                 :             : 
    2914                 :      492086 :             delstate.ndeltids++;
    2915                 :             :         }
    2916                 :             :         else
    2917                 :             :         {
    2918                 :       65178 :             int         nitem = BTreeTupleGetNPosting(itup);
    2919                 :             : 
    2920         [ +  + ]:      302342 :             for (int p = 0; p < nitem; p++)
    2921                 :             :             {
    2922                 :      237164 :                 ItemPointer tid = BTreeTupleGetPostingN(itup, p);
    2923                 :             : 
    2924                 :      237164 :                 tidblock = ItemPointerGetBlockNumber(tid);
    2925                 :      237164 :                 match = bsearch(&tidblock, deadblocks, ndeadblocks,
    2926                 :             :                                 sizeof(BlockNumber), _bt_blk_cmp);
    2927                 :             : 
    2928         [ +  + ]:      237164 :                 if (!match)
    2929                 :             :                 {
    2930                 :             :                     Assert(!ItemIdIsDead(itemid));
    2931                 :      209470 :                     continue;
    2932                 :             :                 }
    2933                 :             : 
    2934                 :             :                 /*
    2935                 :             :                  * TID's table block is among those pointed to by the TIDs
    2936                 :             :                  * from LP_DEAD-bit set tuples on page -- add TID to deltids
    2937                 :             :                  */
    2938                 :       27694 :                 odeltid->tid = *tid;
    2939                 :       27694 :                 odeltid->id = delstate.ndeltids;
    2940                 :       27694 :                 ostatus->idxoffnum = offnum;
    2941                 :       27694 :                 ostatus->knowndeletable = ItemIdIsDead(itemid);
    2942                 :       27694 :                 ostatus->promising = false; /* unused */
    2943                 :       27694 :                 ostatus->freespace = 0; /* unused */
    2944                 :             : 
    2945                 :       27694 :                 odeltid++;
    2946                 :       27694 :                 ostatus++;
    2947                 :       27694 :                 delstate.ndeltids++;
    2948                 :             :             }
    2949                 :             :         }
    2950                 :             :     }
    2951                 :             : 
    2952                 :        4903 :     pfree(deadblocks);
    2953                 :             : 
    2954                 :             :     Assert(delstate.ndeltids >= ndeletable);
    2955                 :             : 
    2956                 :             :     /* Physically delete LP_DEAD tuples (plus any delete-safe extra TIDs) */
    2957                 :        4903 :     _bt_delitems_delete_check(rel, buffer, heapRel, &delstate);
    2958                 :             : 
    2959                 :        4903 :     pfree(delstate.deltids);
    2960                 :        4903 :     pfree(delstate.status);
    2961                 :        4903 : }
    2962                 :             : 
    2963                 :             : /*
    2964                 :             :  * _bt_deadblocks() -- Get LP_DEAD related table blocks.
    2965                 :             :  *
    2966                 :             :  * Builds sorted and unique-ified array of table block numbers from index
    2967                 :             :  * tuple TIDs whose line pointers are marked LP_DEAD.  Also adds the table
    2968                 :             :  * block from incoming newitem just in case it isn't among the LP_DEAD-related
    2969                 :             :  * table blocks.
    2970                 :             :  *
    2971                 :             :  * Always counting the newitem's table block as an LP_DEAD related block makes
    2972                 :             :  * sense because the cost is consistently low; it is practically certain that
    2973                 :             :  * the table block will not incur a buffer miss in tableam.  On the other hand
    2974                 :             :  * the benefit is often quite high.  There is a decent chance that there will
    2975                 :             :  * be some deletable items from this block, since in general most garbage
    2976                 :             :  * tuples became garbage in the recent past (in many cases this won't be the
    2977                 :             :  * first logical row that core code added to/modified in table block
    2978                 :             :  * recently).
    2979                 :             :  *
    2980                 :             :  * Returns final array, and sets *nblocks to its final size for caller.
    2981                 :             :  */
    2982                 :             : static BlockNumber *
    2983                 :        4903 : _bt_deadblocks(Page page, OffsetNumber *deletable, int ndeletable,
    2984                 :             :                IndexTuple newitem, int *nblocks)
    2985                 :             : {
    2986                 :             :     int         spacentids,
    2987                 :             :                 ntids;
    2988                 :             :     BlockNumber *tidblocks;
    2989                 :             : 
    2990                 :             :     /*
    2991                 :             :      * Accumulate each TID's block in array whose initial size has space for
    2992                 :             :      * one table block per LP_DEAD-set tuple (plus space for the newitem table
    2993                 :             :      * block).  Array will only need to grow when there are LP_DEAD-marked
    2994                 :             :      * posting list tuples (which is not that common).
    2995                 :             :      */
    2996                 :        4903 :     spacentids = ndeletable + 1;
    2997                 :        4903 :     ntids = 0;
    2998                 :        4903 :     tidblocks = palloc_array(BlockNumber, spacentids);
    2999                 :             : 
    3000                 :             :     /*
    3001                 :             :      * First add the table block for the incoming newitem.  This is the one
    3002                 :             :      * case where simple deletion can visit a table block that doesn't have
    3003                 :             :      * any known deletable items.
    3004                 :             :      */
    3005                 :             :     Assert(!BTreeTupleIsPosting(newitem) && !BTreeTupleIsPivot(newitem));
    3006                 :        4903 :     tidblocks[ntids++] = ItemPointerGetBlockNumber(&newitem->t_tid);
    3007                 :             : 
    3008         [ +  + ]:      158561 :     for (int i = 0; i < ndeletable; i++)
    3009                 :             :     {
    3010                 :      153658 :         ItemId      itemid = PageGetItemId(page, deletable[i]);
    3011                 :      153658 :         IndexTuple  itup = (IndexTuple) PageGetItem(page, itemid);
    3012                 :             : 
    3013                 :             :         Assert(ItemIdIsDead(itemid));
    3014                 :             : 
    3015         [ +  + ]:      153658 :         if (!BTreeTupleIsPosting(itup))
    3016                 :             :         {
    3017         [ +  + ]:      149215 :             if (ntids + 1 > spacentids)
    3018                 :             :             {
    3019                 :         111 :                 spacentids *= 2;
    3020                 :         111 :                 tidblocks = repalloc_array(tidblocks, BlockNumber, spacentids);
    3021                 :             :             }
    3022                 :             : 
    3023                 :      149215 :             tidblocks[ntids++] = ItemPointerGetBlockNumber(&itup->t_tid);
    3024                 :             :         }
    3025                 :             :         else
    3026                 :             :         {
    3027                 :        4443 :             int         nposting = BTreeTupleGetNPosting(itup);
    3028                 :             : 
    3029         [ +  + ]:        4443 :             if (ntids + nposting > spacentids)
    3030                 :             :             {
    3031                 :         104 :                 spacentids = Max(spacentids * 2, ntids + nposting);
    3032                 :         104 :                 tidblocks = repalloc_array(tidblocks, BlockNumber, spacentids);
    3033                 :             :             }
    3034                 :             : 
    3035         [ +  + ]:       14653 :             for (int j = 0; j < nposting; j++)
    3036                 :             :             {
    3037                 :       10210 :                 ItemPointer tid = BTreeTupleGetPostingN(itup, j);
    3038                 :             : 
    3039                 :       10210 :                 tidblocks[ntids++] = ItemPointerGetBlockNumber(tid);
    3040                 :             :             }
    3041                 :             :         }
    3042                 :             :     }
    3043                 :             : 
    3044                 :        4903 :     qsort(tidblocks, ntids, sizeof(BlockNumber), _bt_blk_cmp);
    3045                 :        4903 :     *nblocks = qunique(tidblocks, ntids, sizeof(BlockNumber), _bt_blk_cmp);
    3046                 :             : 
    3047                 :        4903 :     return tidblocks;
    3048                 :             : }
    3049                 :             : 
    3050                 :             : /*
    3051                 :             :  * _bt_blk_cmp() -- qsort comparison function for _bt_simpledel_pass
    3052                 :             :  */
    3053                 :             : static inline int
    3054                 :     3447253 : _bt_blk_cmp(const void *arg1, const void *arg2)
    3055                 :             : {
    3056                 :     3447253 :     BlockNumber b1 = *((const BlockNumber *) arg1);
    3057                 :     3447253 :     BlockNumber b2 = *((const BlockNumber *) arg2);
    3058                 :             : 
    3059                 :     3447253 :     return pg_cmp_u32(b1, b2);
    3060                 :             : }
        

Generated by: LCOV version 2.0-1