LCOV - differential code coverage report
Current view: top level - src/backend/access/nbtree - nbtsort.c (source / functions) Coverage Total Hit LBC UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 97.0 % 569 552 17 552
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 22 22 22
Baseline: lcov-20250906-005545-baseline Branches: 72.4 % 250 181 1 68 181
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 6 6 6
(360..) days: 97.0 % 563 546 17 546
Function coverage date bins:
(360..) days: 100.0 % 22 22 22
Branch coverage date bins:
(30,360] days: 66.7 % 6 4 2 4
(360..) days: 72.5 % 244 177 1 66 177

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * nbtsort.c
                                  4                 :                :  *      Build a btree from sorted input by loading leaf pages sequentially.
                                  5                 :                :  *
                                  6                 :                :  * NOTES
                                  7                 :                :  *
                                  8                 :                :  * We use tuplesort.c to sort the given index tuples into order.
                                  9                 :                :  * Then we scan the index tuples in order and build the btree pages
                                 10                 :                :  * for each level.  We load source tuples into leaf-level pages.
                                 11                 :                :  * Whenever we fill a page at one level, we add a link to it to its
                                 12                 :                :  * parent level (starting a new parent level if necessary).  When
                                 13                 :                :  * done, we write out each final page on each level, adding it to
                                 14                 :                :  * its parent level.  When we have only one page on a level, it must be
                                 15                 :                :  * the root -- it can be attached to the btree metapage and we are done.
                                 16                 :                :  *
                                 17                 :                :  * It is not wise to pack the pages entirely full, since then *any*
                                 18                 :                :  * insertion would cause a split (and not only of the leaf page; the need
                                 19                 :                :  * for a split would cascade right up the tree).  The steady-state load
                                 20                 :                :  * factor for btrees is usually estimated at 70%.  We choose to pack leaf
                                 21                 :                :  * pages to the user-controllable fill factor (default 90%) while upper pages
                                 22                 :                :  * are always packed to 70%.  This gives us reasonable density (there aren't
                                 23                 :                :  * many upper pages if the keys are reasonable-size) without risking a lot of
                                 24                 :                :  * cascading splits during early insertions.
                                 25                 :                :  *
                                 26                 :                :  * We use the bulk smgr loading facility to bypass the buffer cache and
                                 27                 :                :  * WAL-log the pages efficiently.
                                 28                 :                :  *
                                 29                 :                :  * This code isn't concerned about the FSM at all. The caller is responsible
                                 30                 :                :  * for initializing that.
                                 31                 :                :  *
                                 32                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                 33                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 34                 :                :  *
                                 35                 :                :  * IDENTIFICATION
                                 36                 :                :  *    src/backend/access/nbtree/nbtsort.c
                                 37                 :                :  *
                                 38                 :                :  *-------------------------------------------------------------------------
                                 39                 :                :  */
                                 40                 :                : 
                                 41                 :                : #include "postgres.h"
                                 42                 :                : 
                                 43                 :                : #include "access/nbtree.h"
                                 44                 :                : #include "access/parallel.h"
                                 45                 :                : #include "access/relscan.h"
                                 46                 :                : #include "access/table.h"
                                 47                 :                : #include "access/tableam.h"
                                 48                 :                : #include "access/xact.h"
                                 49                 :                : #include "catalog/index.h"
                                 50                 :                : #include "commands/progress.h"
                                 51                 :                : #include "executor/instrument.h"
                                 52                 :                : #include "miscadmin.h"
                                 53                 :                : #include "pgstat.h"
                                 54                 :                : #include "storage/bulk_write.h"
                                 55                 :                : #include "tcop/tcopprot.h"
                                 56                 :                : #include "utils/rel.h"
                                 57                 :                : #include "utils/sortsupport.h"
                                 58                 :                : #include "utils/tuplesort.h"
                                 59                 :                : 
                                 60                 :                : 
                                 61                 :                : /* Magic numbers for parallel state sharing */
                                 62                 :                : #define PARALLEL_KEY_BTREE_SHARED       UINT64CONST(0xA000000000000001)
                                 63                 :                : #define PARALLEL_KEY_TUPLESORT          UINT64CONST(0xA000000000000002)
                                 64                 :                : #define PARALLEL_KEY_TUPLESORT_SPOOL2   UINT64CONST(0xA000000000000003)
                                 65                 :                : #define PARALLEL_KEY_QUERY_TEXT         UINT64CONST(0xA000000000000004)
                                 66                 :                : #define PARALLEL_KEY_WAL_USAGE          UINT64CONST(0xA000000000000005)
                                 67                 :                : #define PARALLEL_KEY_BUFFER_USAGE       UINT64CONST(0xA000000000000006)
                                 68                 :                : 
                                 69                 :                : /*
                                 70                 :                :  * DISABLE_LEADER_PARTICIPATION disables the leader's participation in
                                 71                 :                :  * parallel index builds.  This may be useful as a debugging aid.
                                 72                 :                : #undef DISABLE_LEADER_PARTICIPATION
                                 73                 :                :  */
                                 74                 :                : 
                                 75                 :                : /*
                                 76                 :                :  * Status record for spooling/sorting phase.  (Note we may have two of
                                 77                 :                :  * these due to the special requirements for uniqueness-checking with
                                 78                 :                :  * dead tuples.)
                                 79                 :                :  */
                                 80                 :                : typedef struct BTSpool
                                 81                 :                : {
                                 82                 :                :     Tuplesortstate *sortstate;  /* state data for tuplesort.c */
                                 83                 :                :     Relation    heap;
                                 84                 :                :     Relation    index;
                                 85                 :                :     bool        isunique;
                                 86                 :                :     bool        nulls_not_distinct;
                                 87                 :                : } BTSpool;
                                 88                 :                : 
                                 89                 :                : /*
                                 90                 :                :  * Status for index builds performed in parallel.  This is allocated in a
                                 91                 :                :  * dynamic shared memory segment.  Note that there is a separate tuplesort TOC
                                 92                 :                :  * entry, private to tuplesort.c but allocated by this module on its behalf.
                                 93                 :                :  */
                                 94                 :                : typedef struct BTShared
                                 95                 :                : {
                                 96                 :                :     /*
                                 97                 :                :      * These fields are not modified during the sort.  They primarily exist
                                 98                 :                :      * for the benefit of worker processes that need to create BTSpool state
                                 99                 :                :      * corresponding to that used by the leader.
                                100                 :                :      */
                                101                 :                :     Oid         heaprelid;
                                102                 :                :     Oid         indexrelid;
                                103                 :                :     bool        isunique;
                                104                 :                :     bool        nulls_not_distinct;
                                105                 :                :     bool        isconcurrent;
                                106                 :                :     int         scantuplesortstates;
                                107                 :                : 
                                108                 :                :     /* Query ID, for report in worker processes */
                                109                 :                :     int64       queryid;
                                110                 :                : 
                                111                 :                :     /*
                                112                 :                :      * workersdonecv is used to monitor the progress of workers.  All parallel
                                113                 :                :      * participants must indicate that they are done before leader can use
                                114                 :                :      * mutable state that workers maintain during scan (and before leader can
                                115                 :                :      * proceed to tuplesort_performsort()).
                                116                 :                :      */
                                117                 :                :     ConditionVariable workersdonecv;
                                118                 :                : 
                                119                 :                :     /*
                                120                 :                :      * mutex protects all fields before heapdesc.
                                121                 :                :      *
                                122                 :                :      * These fields contain status information of interest to B-Tree index
                                123                 :                :      * builds that must work just the same when an index is built in parallel.
                                124                 :                :      */
                                125                 :                :     slock_t     mutex;
                                126                 :                : 
                                127                 :                :     /*
                                128                 :                :      * Mutable state that is maintained by workers, and reported back to
                                129                 :                :      * leader at end of parallel scan.
                                130                 :                :      *
                                131                 :                :      * nparticipantsdone is number of worker processes finished.
                                132                 :                :      *
                                133                 :                :      * reltuples is the total number of input heap tuples.
                                134                 :                :      *
                                135                 :                :      * havedead indicates if RECENTLY_DEAD tuples were encountered during
                                136                 :                :      * build.
                                137                 :                :      *
                                138                 :                :      * indtuples is the total number of tuples that made it into the index.
                                139                 :                :      *
                                140                 :                :      * brokenhotchain indicates if any worker detected a broken HOT chain
                                141                 :                :      * during build.
                                142                 :                :      */
                                143                 :                :     int         nparticipantsdone;
                                144                 :                :     double      reltuples;
                                145                 :                :     bool        havedead;
                                146                 :                :     double      indtuples;
                                147                 :                :     bool        brokenhotchain;
                                148                 :                : 
                                149                 :                :     /*
                                150                 :                :      * ParallelTableScanDescData data follows. Can't directly embed here, as
                                151                 :                :      * implementations of the parallel table scan desc interface might need
                                152                 :                :      * stronger alignment.
                                153                 :                :      */
                                154                 :                : } BTShared;
                                155                 :                : 
                                156                 :                : /*
                                157                 :                :  * Return pointer to a BTShared's parallel table scan.
                                158                 :                :  *
                                159                 :                :  * c.f. shm_toc_allocate as to why BUFFERALIGN is used, rather than just
                                160                 :                :  * MAXALIGN.
                                161                 :                :  */
                                162                 :                : #define ParallelTableScanFromBTShared(shared) \
                                163                 :                :     (ParallelTableScanDesc) ((char *) (shared) + BUFFERALIGN(sizeof(BTShared)))
                                164                 :                : 
                                165                 :                : /*
                                166                 :                :  * Status for leader in parallel index build.
                                167                 :                :  */
                                168                 :                : typedef struct BTLeader
                                169                 :                : {
                                170                 :                :     /* parallel context itself */
                                171                 :                :     ParallelContext *pcxt;
                                172                 :                : 
                                173                 :                :     /*
                                174                 :                :      * nparticipanttuplesorts is the exact number of worker processes
                                175                 :                :      * successfully launched, plus one leader process if it participates as a
                                176                 :                :      * worker (only DISABLE_LEADER_PARTICIPATION builds avoid leader
                                177                 :                :      * participating as a worker).
                                178                 :                :      */
                                179                 :                :     int         nparticipanttuplesorts;
                                180                 :                : 
                                181                 :                :     /*
                                182                 :                :      * Leader process convenience pointers to shared state (leader avoids TOC
                                183                 :                :      * lookups).
                                184                 :                :      *
                                185                 :                :      * btshared is the shared state for entire build.  sharedsort is the
                                186                 :                :      * shared, tuplesort-managed state passed to each process tuplesort.
                                187                 :                :      * sharedsort2 is the corresponding btspool2 shared state, used only when
                                188                 :                :      * building unique indexes.  snapshot is the snapshot used by the scan iff
                                189                 :                :      * an MVCC snapshot is required.
                                190                 :                :      */
                                191                 :                :     BTShared   *btshared;
                                192                 :                :     Sharedsort *sharedsort;
                                193                 :                :     Sharedsort *sharedsort2;
                                194                 :                :     Snapshot    snapshot;
                                195                 :                :     WalUsage   *walusage;
                                196                 :                :     BufferUsage *bufferusage;
                                197                 :                : } BTLeader;
                                198                 :                : 
                                199                 :                : /*
                                200                 :                :  * Working state for btbuild and its callback.
                                201                 :                :  *
                                202                 :                :  * When parallel CREATE INDEX is used, there is a BTBuildState for each
                                203                 :                :  * participant.
                                204                 :                :  */
                                205                 :                : typedef struct BTBuildState
                                206                 :                : {
                                207                 :                :     bool        isunique;
                                208                 :                :     bool        nulls_not_distinct;
                                209                 :                :     bool        havedead;
                                210                 :                :     Relation    heap;
                                211                 :                :     BTSpool    *spool;
                                212                 :                : 
                                213                 :                :     /*
                                214                 :                :      * spool2 is needed only when the index is a unique index. Dead tuples are
                                215                 :                :      * put into spool2 instead of spool in order to avoid uniqueness check.
                                216                 :                :      */
                                217                 :                :     BTSpool    *spool2;
                                218                 :                :     double      indtuples;
                                219                 :                : 
                                220                 :                :     /*
                                221                 :                :      * btleader is only present when a parallel index build is performed, and
                                222                 :                :      * only in the leader process. (Actually, only the leader has a
                                223                 :                :      * BTBuildState.  Workers have their own spool and spool2, though.)
                                224                 :                :      */
                                225                 :                :     BTLeader   *btleader;
                                226                 :                : } BTBuildState;
                                227                 :                : 
                                228                 :                : /*
                                229                 :                :  * Status record for a btree page being built.  We have one of these
                                230                 :                :  * for each active tree level.
                                231                 :                :  */
                                232                 :                : typedef struct BTPageState
                                233                 :                : {
                                234                 :                :     BulkWriteBuffer btps_buf;   /* workspace for page building */
                                235                 :                :     BlockNumber btps_blkno;     /* block # to write this page at */
                                236                 :                :     IndexTuple  btps_lowkey;    /* page's strict lower bound pivot tuple */
                                237                 :                :     OffsetNumber btps_lastoff;  /* last item offset loaded */
                                238                 :                :     Size        btps_lastextra; /* last item's extra posting list space */
                                239                 :                :     uint32      btps_level;     /* tree level (0 = leaf) */
                                240                 :                :     Size        btps_full;      /* "full" if less than this much free space */
                                241                 :                :     struct BTPageState *btps_next;  /* link to parent level, if any */
                                242                 :                : } BTPageState;
                                243                 :                : 
                                244                 :                : /*
                                245                 :                :  * Overall status record for index writing phase.
                                246                 :                :  */
                                247                 :                : typedef struct BTWriteState
                                248                 :                : {
                                249                 :                :     Relation    heap;
                                250                 :                :     Relation    index;
                                251                 :                :     BulkWriteState *bulkstate;
                                252                 :                :     BTScanInsert inskey;        /* generic insertion scankey */
                                253                 :                :     BlockNumber btws_pages_alloced; /* # pages allocated */
                                254                 :                : } BTWriteState;
                                255                 :                : 
                                256                 :                : 
                                257                 :                : static double _bt_spools_heapscan(Relation heap, Relation index,
                                258                 :                :                                   BTBuildState *buildstate, IndexInfo *indexInfo);
                                259                 :                : static void _bt_spooldestroy(BTSpool *btspool);
                                260                 :                : static void _bt_spool(BTSpool *btspool, ItemPointer self,
                                261                 :                :                       Datum *values, bool *isnull);
                                262                 :                : static void _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2);
                                263                 :                : static void _bt_build_callback(Relation index, ItemPointer tid, Datum *values,
                                264                 :                :                                bool *isnull, bool tupleIsAlive, void *state);
                                265                 :                : static BulkWriteBuffer _bt_blnewpage(BTWriteState *wstate, uint32 level);
                                266                 :                : static BTPageState *_bt_pagestate(BTWriteState *wstate, uint32 level);
                                267                 :                : static void _bt_slideleft(Page rightmostpage);
                                268                 :                : static void _bt_sortaddtup(Page page, Size itemsize,
                                269                 :                :                            IndexTuple itup, OffsetNumber itup_off,
                                270                 :                :                            bool newfirstdataitem);
                                271                 :                : static void _bt_buildadd(BTWriteState *wstate, BTPageState *state,
                                272                 :                :                          IndexTuple itup, Size truncextra);
                                273                 :                : static void _bt_sort_dedup_finish_pending(BTWriteState *wstate,
                                274                 :                :                                           BTPageState *state,
                                275                 :                :                                           BTDedupState dstate);
                                276                 :                : static void _bt_uppershutdown(BTWriteState *wstate, BTPageState *state);
                                277                 :                : static void _bt_load(BTWriteState *wstate,
                                278                 :                :                      BTSpool *btspool, BTSpool *btspool2);
                                279                 :                : static void _bt_begin_parallel(BTBuildState *buildstate, bool isconcurrent,
                                280                 :                :                                int request);
                                281                 :                : static void _bt_end_parallel(BTLeader *btleader);
                                282                 :                : static Size _bt_parallel_estimate_shared(Relation heap, Snapshot snapshot);
                                283                 :                : static double _bt_parallel_heapscan(BTBuildState *buildstate,
                                284                 :                :                                     bool *brokenhotchain);
                                285                 :                : static void _bt_leader_participate_as_worker(BTBuildState *buildstate);
                                286                 :                : static void _bt_parallel_scan_and_sort(BTSpool *btspool, BTSpool *btspool2,
                                287                 :                :                                        BTShared *btshared, Sharedsort *sharedsort,
                                288                 :                :                                        Sharedsort *sharedsort2, int sortmem,
                                289                 :                :                                        bool progress);
                                290                 :                : 
                                291                 :                : 
                                292                 :                : /*
                                293                 :                :  *  btbuild() -- build a new btree index.
                                294                 :                :  */
                                295                 :                : IndexBuildResult *
 2773 rhaas@postgresql.org      296                 :CBC       25073 : btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
                                297                 :                : {
                                298                 :                :     IndexBuildResult *result;
                                299                 :                :     BTBuildState buildstate;
                                300                 :                :     double      reltuples;
                                301                 :                : 
                                302                 :                : #ifdef BTREE_BUILD_STATS
                                303                 :                :     if (log_btree_build_stats)
                                304                 :                :         ResetUsage();
                                305                 :                : #endif                          /* BTREE_BUILD_STATS */
                                306                 :                : 
                                307                 :          25073 :     buildstate.isunique = indexInfo->ii_Unique;
 1311 peter@eisentraut.org      308                 :          25073 :     buildstate.nulls_not_distinct = indexInfo->ii_NullsNotDistinct;
 2773 rhaas@postgresql.org      309                 :          25073 :     buildstate.havedead = false;
                                310                 :          25073 :     buildstate.heap = heap;
                                311                 :          25073 :     buildstate.spool = NULL;
                                312                 :          25073 :     buildstate.spool2 = NULL;
                                313                 :          25073 :     buildstate.indtuples = 0;
                                314                 :          25073 :     buildstate.btleader = NULL;
                                315                 :                : 
                                316                 :                :     /*
                                317                 :                :      * We expect to be called exactly once for any index relation. If that's
                                318                 :                :      * not the case, big trouble's what we have.
                                319                 :                :      */
                                320         [ -  + ]:          25073 :     if (RelationGetNumberOfBlocks(index) != 0)
 2773 rhaas@postgresql.org      321         [ #  # ]:UBC           0 :         elog(ERROR, "index \"%s\" already contains data",
                                322                 :                :              RelationGetRelationName(index));
                                323                 :                : 
 2773 rhaas@postgresql.org      324                 :CBC       25073 :     reltuples = _bt_spools_heapscan(heap, index, &buildstate, indexInfo);
                                325                 :                : 
                                326                 :                :     /*
                                327                 :                :      * Finish the build by (1) completing the sort of the spool file, (2)
                                328                 :                :      * inserting the sorted tuples into btree pages and (3) building the upper
                                329                 :                :      * levels.  Finally, it may also be necessary to end use of parallelism.
                                330                 :                :      */
                                331                 :          25067 :     _bt_leafbuild(buildstate.spool, buildstate.spool2);
                                332                 :          25025 :     _bt_spooldestroy(buildstate.spool);
                                333         [ +  + ]:          25025 :     if (buildstate.spool2)
                                334                 :             11 :         _bt_spooldestroy(buildstate.spool2);
                                335         [ +  + ]:          25025 :     if (buildstate.btleader)
                                336                 :             74 :         _bt_end_parallel(buildstate.btleader);
                                337                 :                : 
                                338                 :          25025 :     result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
                                339                 :                : 
                                340                 :          25025 :     result->heap_tuples = reltuples;
                                341                 :          25025 :     result->index_tuples = buildstate.indtuples;
                                342                 :                : 
                                343                 :                : #ifdef BTREE_BUILD_STATS
                                344                 :                :     if (log_btree_build_stats)
                                345                 :                :     {
                                346                 :                :         ShowUsage("BTREE BUILD STATS");
                                347                 :                :         ResetUsage();
                                348                 :                :     }
                                349                 :                : #endif                          /* BTREE_BUILD_STATS */
                                350                 :                : 
                                351                 :          25025 :     return result;
                                352                 :                : }
                                353                 :                : 
                                354                 :                : /*
                                355                 :                :  * Create and initialize one or two spool structures, and save them in caller's
                                356                 :                :  * buildstate argument.  May also fill-in fields within indexInfo used by index
                                357                 :                :  * builds.
                                358                 :                :  *
                                359                 :                :  * Scans the heap, possibly in parallel, filling spools with IndexTuples.  This
                                360                 :                :  * routine encapsulates all aspects of managing parallelism.  Caller need only
                                361                 :                :  * call _bt_end_parallel() in parallel case after it is done with spool/spool2.
                                362                 :                :  *
                                363                 :                :  * Returns the total number of heap tuples scanned.
                                364                 :                :  */
                                365                 :                : static double
                                366                 :          25073 : _bt_spools_heapscan(Relation heap, Relation index, BTBuildState *buildstate,
                                367                 :                :                     IndexInfo *indexInfo)
                                368                 :                : {
 8333 bruce@momjian.us          369                 :          25073 :     BTSpool    *btspool = (BTSpool *) palloc0(sizeof(BTSpool));
 2773 rhaas@postgresql.org      370                 :          25073 :     SortCoordinate coordinate = NULL;
                                371                 :          25073 :     double      reltuples = 0;
                                372                 :                : 
                                373                 :                :     /*
                                374                 :                :      * We size the sort area as maintenance_work_mem rather than work_mem to
                                375                 :                :      * speed index creation.  This should be OK since a single backend can't
                                376                 :                :      * run multiple index creations in parallel (see also: notes on
                                377                 :                :      * parallelism and maintenance_work_mem below).
                                378                 :                :      */
 4603 tgl@sss.pgh.pa.us         379                 :          25073 :     btspool->heap = heap;
 9456                           380                 :          25073 :     btspool->index = index;
 2773 rhaas@postgresql.org      381                 :          25073 :     btspool->isunique = indexInfo->ii_Unique;
 1311 peter@eisentraut.org      382                 :          25073 :     btspool->nulls_not_distinct = indexInfo->ii_NullsNotDistinct;
                                383                 :                : 
                                384                 :                :     /* Save as primary spool */
 2773 rhaas@postgresql.org      385                 :          25073 :     buildstate->spool = btspool;
                                386                 :                : 
                                387                 :                :     /* Report table scan phase started */
 2349 alvherre@alvh.no-ip.      388                 :          25073 :     pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE,
                                389                 :                :                                  PROGRESS_BTREE_PHASE_INDEXBUILD_TABLESCAN);
                                390                 :                : 
                                391                 :                :     /* Attempt to launch parallel worker scan when required */
 2773 rhaas@postgresql.org      392         [ +  + ]:          25073 :     if (indexInfo->ii_ParallelWorkers > 0)
                                393                 :             74 :         _bt_begin_parallel(buildstate, indexInfo->ii_Concurrent,
                                394                 :                :                            indexInfo->ii_ParallelWorkers);
                                395                 :                : 
                                396                 :                :     /*
                                397                 :                :      * If parallel build requested and at least one worker process was
                                398                 :                :      * successfully launched, set up coordination state
                                399                 :                :      */
                                400         [ +  + ]:          25073 :     if (buildstate->btleader)
                                401                 :                :     {
                                402                 :             74 :         coordinate = (SortCoordinate) palloc0(sizeof(SortCoordinateData));
                                403                 :             74 :         coordinate->isWorker = false;
                                404                 :             74 :         coordinate->nParticipants =
                                405                 :             74 :             buildstate->btleader->nparticipanttuplesorts;
                                406                 :             74 :         coordinate->sharedsort = buildstate->btleader->sharedsort;
                                407                 :                :     }
                                408                 :                : 
                                409                 :                :     /*
                                410                 :                :      * Begin serial/leader tuplesort.
                                411                 :                :      *
                                412                 :                :      * In cases where parallelism is involved, the leader receives the same
                                413                 :                :      * share of maintenance_work_mem as a serial sort (it is generally treated
                                414                 :                :      * in the same way as a serial sort once we return).  Parallel worker
                                415                 :                :      * Tuplesortstates will have received only a fraction of
                                416                 :                :      * maintenance_work_mem, though.
                                417                 :                :      *
                                418                 :                :      * We rely on the lifetime of the Leader Tuplesortstate almost not
                                419                 :                :      * overlapping with any worker Tuplesortstate's lifetime.  There may be
                                420                 :                :      * some small overlap, but that's okay because we rely on leader
                                421                 :                :      * Tuplesortstate only allocating a small, fixed amount of memory here.
                                422                 :                :      * When its tuplesort_performsort() is called (by our caller), and
                                423                 :                :      * significant amounts of memory are likely to be used, all workers must
                                424                 :                :      * have already freed almost all memory held by their Tuplesortstates
                                425                 :                :      * (they are about to go away completely, too).  The overall effect is
                                426                 :                :      * that maintenance_work_mem always represents an absolute high watermark
                                427                 :                :      * on the amount of memory used by a CREATE INDEX operation, regardless of
                                428                 :                :      * the use of parallelism or any other factor.
                                429                 :                :      */
                                430                 :          50146 :     buildstate->spool->sortstate =
                                431                 :          25073 :         tuplesort_begin_index_btree(heap, index, buildstate->isunique,
 1311 peter@eisentraut.org      432                 :          25073 :                                     buildstate->nulls_not_distinct,
                                433                 :                :                                     maintenance_work_mem, coordinate,
                                434                 :                :                                     TUPLESORT_NONE);
                                435                 :                : 
                                436                 :                :     /*
                                437                 :                :      * If building a unique index, put dead tuples in a second spool to keep
                                438                 :                :      * them out of the uniqueness check.  We expect that the second spool (for
                                439                 :                :      * dead tuples) won't get very full, so we give it only work_mem.
                                440                 :                :      */
 2773 rhaas@postgresql.org      441         [ +  + ]:          25073 :     if (indexInfo->ii_Unique)
                                442                 :                :     {
                                443                 :          20522 :         BTSpool    *btspool2 = (BTSpool *) palloc0(sizeof(BTSpool));
                                444                 :          20522 :         SortCoordinate coordinate2 = NULL;
                                445                 :                : 
                                446                 :                :         /* Initialize secondary spool */
                                447                 :          20522 :         btspool2->heap = heap;
                                448                 :          20522 :         btspool2->index = index;
                                449                 :          20522 :         btspool2->isunique = false;
                                450                 :                :         /* Save as secondary spool */
                                451                 :          20522 :         buildstate->spool2 = btspool2;
                                452                 :                : 
                                453         [ +  + ]:          20522 :         if (buildstate->btleader)
                                454                 :                :         {
                                455                 :                :             /*
                                456                 :                :              * Set up non-private state that is passed to
                                457                 :                :              * tuplesort_begin_index_btree() about the basic high level
                                458                 :                :              * coordination of a parallel sort.
                                459                 :                :              */
                                460                 :             32 :             coordinate2 = (SortCoordinate) palloc0(sizeof(SortCoordinateData));
                                461                 :             32 :             coordinate2->isWorker = false;
                                462                 :             32 :             coordinate2->nParticipants =
                                463                 :             32 :                 buildstate->btleader->nparticipanttuplesorts;
                                464                 :             32 :             coordinate2->sharedsort = buildstate->btleader->sharedsort2;
                                465                 :                :         }
                                466                 :                : 
                                467                 :                :         /*
                                468                 :                :          * We expect that the second one (for dead tuples) won't get very
                                469                 :                :          * full, so we give it only work_mem
                                470                 :                :          */
                                471                 :          20522 :         buildstate->spool2->sortstate =
 1311 peter@eisentraut.org      472                 :          20522 :             tuplesort_begin_index_btree(heap, index, false, false, work_mem,
                                473                 :                :                                         coordinate2, TUPLESORT_NONE);
                                474                 :                :     }
                                475                 :                : 
                                476                 :                :     /* Fill spool using either serial or parallel heap scan */
 2773 rhaas@postgresql.org      477         [ +  + ]:          25073 :     if (!buildstate->btleader)
 2349 alvherre@alvh.no-ip.      478                 :          24999 :         reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
                                479                 :                :                                            _bt_build_callback, buildstate,
                                480                 :                :                                            NULL);
                                481                 :                :     else
 2773 rhaas@postgresql.org      482                 :             74 :         reltuples = _bt_parallel_heapscan(buildstate,
                                483                 :                :                                           &indexInfo->ii_BrokenHotChain);
                                484                 :                : 
                                485                 :                :     /*
                                486                 :                :      * Set the progress target for the next phase.  Reset the block number
                                487                 :                :      * values set by table_index_build_scan
                                488                 :                :      */
                                489                 :                :     {
 1677 peter@eisentraut.org      490                 :          25067 :         const int   progress_index[] = {
                                491                 :                :             PROGRESS_CREATEIDX_TUPLES_TOTAL,
                                492                 :                :             PROGRESS_SCAN_BLOCKS_TOTAL,
                                493                 :                :             PROGRESS_SCAN_BLOCKS_DONE
                                494                 :                :         };
                                495                 :          25067 :         const int64 progress_vals[] = {
 2349 alvherre@alvh.no-ip.      496                 :          25067 :             buildstate->indtuples,
                                497                 :                :             0, 0
                                498                 :                :         };
                                499                 :                : 
 1677 peter@eisentraut.org      500                 :          25067 :         pgstat_progress_update_multi_param(3, progress_index, progress_vals);
                                501                 :                :     }
                                502                 :                : 
                                503                 :                :     /* okay, all heap tuples are spooled */
 2773 rhaas@postgresql.org      504   [ +  +  +  + ]:          25067 :     if (buildstate->spool2 && !buildstate->havedead)
                                505                 :                :     {
                                506                 :                :         /* spool2 turns out to be unnecessary */
                                507                 :          20511 :         _bt_spooldestroy(buildstate->spool2);
                                508                 :          20511 :         buildstate->spool2 = NULL;
                                509                 :                :     }
                                510                 :                : 
                                511                 :          25067 :     return reltuples;
                                512                 :                : }
                                513                 :                : 
                                514                 :                : /*
                                515                 :                :  * clean up a spool structure and its substructures.
                                516                 :                :  */
                                517                 :                : static void
 9456 tgl@sss.pgh.pa.us         518                 :          45547 : _bt_spooldestroy(BTSpool *btspool)
                                519                 :                : {
                                520                 :          45547 :     tuplesort_end(btspool->sortstate);
 7649 neilc@samurai.com         521                 :          45547 :     pfree(btspool);
10651 scrappy@hub.org           522                 :          45547 : }
                                523                 :                : 
                                524                 :                : /*
                                525                 :                :  * spool an index entry into the sort file.
                                526                 :                :  */
                                527                 :                : static void
 4085 rhaas@postgresql.org      528                 :        6373805 : _bt_spool(BTSpool *btspool, ItemPointer self, Datum *values, bool *isnull)
                                529                 :                : {
                                530                 :        6373805 :     tuplesort_putindextuplevalues(btspool->sortstate, btspool->index,
                                531                 :                :                                   self, values, isnull);
10651 scrappy@hub.org           532                 :        6373805 : }
                                533                 :                : 
                                534                 :                : /*
                                535                 :                :  * given a spool loaded by successive calls to _bt_spool,
                                536                 :                :  * create an entire btree.
                                537                 :                :  */
                                538                 :                : static void
 9158 inoue@tpf.co.jp           539                 :          25067 : _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2)
                                540                 :                : {
                                541                 :                :     BTWriteState wstate;
                                542                 :                : 
                                543                 :                : #ifdef BTREE_BUILD_STATS
                                544                 :                :     if (log_btree_build_stats)
                                545                 :                :     {
                                546                 :                :         ShowUsage("BTREE BUILD (Spool) STATISTICS");
                                547                 :                :         ResetUsage();
                                548                 :                :     }
                                549                 :                : #endif                          /* BTREE_BUILD_STATS */
                                550                 :                : 
                                551                 :                :     /* Execute the sort */
 2349 alvherre@alvh.no-ip.      552                 :          25067 :     pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE,
                                553                 :                :                                  PROGRESS_BTREE_PHASE_PERFORMSORT_1);
 8232 tgl@sss.pgh.pa.us         554                 :          25067 :     tuplesort_performsort(btspool->sortstate);
 9158 inoue@tpf.co.jp           555         [ +  + ]:          25025 :     if (btspool2)
                                556                 :                :     {
 2349 alvherre@alvh.no-ip.      557                 :             11 :         pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE,
                                558                 :                :                                      PROGRESS_BTREE_PHASE_PERFORMSORT_2);
 9158 inoue@tpf.co.jp           559                 :             11 :         tuplesort_performsort(btspool2->sortstate);
                                560                 :                :     }
                                561                 :                : 
 4603 tgl@sss.pgh.pa.us         562                 :          25025 :     wstate.heap = btspool->heap;
 7766                           563                 :          25025 :     wstate.index = btspool->index;
  819 pg@bowt.ie                564                 :          25025 :     wstate.inskey = _bt_mkscankey(wstate.index, NULL);
                                565                 :                :     /* _bt_mkscankey() won't set allequalimage without metapage */
 2019                           566                 :          25025 :     wstate.inskey->allequalimage = _bt_allequalimage(wstate.index, true);
                                567                 :                : 
                                568                 :                :     /* reserve the metapage */
 7766 tgl@sss.pgh.pa.us         569                 :          25025 :     wstate.btws_pages_alloced = BTREE_METAPAGE + 1;
                                570                 :                : 
 2349 alvherre@alvh.no-ip.      571                 :          25025 :     pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE,
                                572                 :                :                                  PROGRESS_BTREE_PHASE_LEAF_LOAD);
 7766 tgl@sss.pgh.pa.us         573                 :          25025 :     _bt_load(&wstate, btspool, btspool2);
10651 scrappy@hub.org           574                 :          25025 : }
                                575                 :                : 
                                576                 :                : /*
                                577                 :                :  * Per-tuple callback for table_index_build_scan
                                578                 :                :  */
                                579                 :                : static void
 2773 rhaas@postgresql.org      580                 :        6373805 : _bt_build_callback(Relation index,
                                581                 :                :                    ItemPointer tid,
                                582                 :                :                    Datum *values,
                                583                 :                :                    bool *isnull,
                                584                 :                :                    bool tupleIsAlive,
                                585                 :                :                    void *state)
                                586                 :                : {
                                587                 :        6373805 :     BTBuildState *buildstate = (BTBuildState *) state;
                                588                 :                : 
                                589                 :                :     /*
                                590                 :                :      * insert the index tuple into the appropriate spool file for subsequent
                                591                 :                :      * processing
                                592                 :                :      */
                                593   [ +  +  +  + ]:        6373805 :     if (tupleIsAlive || buildstate->spool2 == NULL)
 2129 andres@anarazel.de        594                 :        6373554 :         _bt_spool(buildstate->spool, tid, values, isnull);
                                595                 :                :     else
                                596                 :                :     {
                                597                 :                :         /* dead tuples are put into spool2 */
 2773 rhaas@postgresql.org      598                 :            251 :         buildstate->havedead = true;
 2129 andres@anarazel.de        599                 :            251 :         _bt_spool(buildstate->spool2, tid, values, isnull);
                                600                 :                :     }
                                601                 :                : 
 2773 rhaas@postgresql.org      602                 :        6373805 :     buildstate->indtuples += 1;
                                603                 :        6373805 : }
                                604                 :                : 
                                605                 :                : /*
                                606                 :                :  * allocate workspace for a new, clean btree page, not linked to any siblings.
                                607                 :                :  */
                                608                 :                : static BulkWriteBuffer
  561 heikki.linnakangas@i      609                 :          26368 : _bt_blnewpage(BTWriteState *wstate, uint32 level)
                                610                 :                : {
                                611                 :                :     BulkWriteBuffer buf;
                                612                 :                :     Page        page;
                                613                 :                :     BTPageOpaque opaque;
                                614                 :                : 
                                615                 :          26368 :     buf = smgr_bulk_get_buf(wstate->bulkstate);
                                616                 :          26368 :     page = (Page) buf;
                                617                 :                : 
                                618                 :                :     /* Zero the page and set up standard page header info */
 7766 tgl@sss.pgh.pa.us         619                 :          26368 :     _bt_pageinit(page, BLCKSZ);
                                620                 :                : 
                                621                 :                :     /* Initialize BT opaque state */
 1254 michael@paquier.xyz       622                 :          26368 :     opaque = BTPageGetOpaque(page);
10226 bruce@momjian.us          623                 :          26368 :     opaque->btpo_prev = opaque->btpo_next = P_NONE;
 1655 pg@bowt.ie                624                 :          26368 :     opaque->btpo_level = level;
 8233 tgl@sss.pgh.pa.us         625                 :          26368 :     opaque->btpo_flags = (level > 0) ? 0 : BTP_LEAF;
 7061                           626                 :          26368 :     opaque->btpo_cycleid = 0;
                                627                 :                : 
                                628                 :                :     /* Make the P_HIKEY line pointer appear allocated */
 7766                           629                 :          26368 :     ((PageHeader) page)->pd_lower += sizeof(ItemIdData);
                                630                 :                : 
  561 heikki.linnakangas@i      631                 :          26368 :     return buf;
                                632                 :                : }
                                633                 :                : 
                                634                 :                : /*
                                635                 :                :  * emit a completed btree page, and release the working storage.
                                636                 :                :  */
                                637                 :                : static void
                                638                 :          51393 : _bt_blwritepage(BTWriteState *wstate, BulkWriteBuffer buf, BlockNumber blkno)
                                639                 :                : {
                                640                 :          51393 :     smgr_bulk_write(wstate->bulkstate, blkno, buf, true);
                                641                 :                :     /* smgr_bulk_write took ownership of 'buf' */
 8233 tgl@sss.pgh.pa.us         642                 :          51393 : }
                                643                 :                : 
                                644                 :                : /*
                                645                 :                :  * allocate and initialize a new BTPageState.  the returned structure
                                646                 :                :  * is suitable for immediate use by _bt_buildadd.
                                647                 :                :  */
                                648                 :                : static BTPageState *
 7766                           649                 :           6333 : _bt_pagestate(BTWriteState *wstate, uint32 level)
                                650                 :                : {
 8333 bruce@momjian.us          651                 :           6333 :     BTPageState *state = (BTPageState *) palloc0(sizeof(BTPageState));
                                652                 :                : 
                                653                 :                :     /* create initial page for level */
  561 heikki.linnakangas@i      654                 :           6333 :     state->btps_buf = _bt_blnewpage(wstate, level);
                                655                 :                : 
                                656                 :                :     /* and assign it a page position */
 7766 tgl@sss.pgh.pa.us         657                 :           6333 :     state->btps_blkno = wstate->btws_pages_alloced++;
                                658                 :                : 
 2130 pg@bowt.ie                659                 :           6333 :     state->btps_lowkey = NULL;
                                660                 :                :     /* initialize lastoff so first item goes into P_FIRSTKEY */
 9178 tgl@sss.pgh.pa.us         661                 :           6333 :     state->btps_lastoff = P_HIKEY;
 2019 pg@bowt.ie                662                 :           6333 :     state->btps_lastextra = 0;
 9178 tgl@sss.pgh.pa.us         663                 :           6333 :     state->btps_level = level;
                                664                 :                :     /* set "full" threshold based on level.  See notes at head of file. */
 7005                           665         [ +  + ]:           6333 :     if (level > 0)
 6997                           666                 :           1310 :         state->btps_full = (BLCKSZ * (100 - BTREE_NONLEAF_FILLFACTOR) / 100);
                                667                 :                :     else
 2112 michael@paquier.xyz       668   [ +  -  -  +  :           5023 :         state->btps_full = BTGetTargetPageFreeSpace(wstate->index);
                                              +  + ]
                                669                 :                : 
                                670                 :                :     /* no parent level, yet */
 7913 neilc@samurai.com         671                 :           6333 :     state->btps_next = NULL;
                                672                 :                : 
 9178 tgl@sss.pgh.pa.us         673                 :           6333 :     return state;
                                674                 :                : }
                                675                 :                : 
                                676                 :                : /*
                                677                 :                :  * Slide the array of ItemIds from the page back one slot (from P_FIRSTKEY to
                                678                 :                :  * P_HIKEY, overwriting P_HIKEY).
                                679                 :                :  *
                                680                 :                :  * _bt_blnewpage() makes the P_HIKEY line pointer appear allocated, but the
                                681                 :                :  * rightmost page on its level is not supposed to get a high key.  Now that
                                682                 :                :  * it's clear that this page is a rightmost page, remove the unneeded empty
                                683                 :                :  * P_HIKEY line pointer space.
                                684                 :                :  */
                                685                 :                : static void
 1888 pg@bowt.ie                686                 :           6333 : _bt_slideleft(Page rightmostpage)
                                687                 :                : {
                                688                 :                :     OffsetNumber off;
                                689                 :                :     OffsetNumber maxoff;
                                690                 :                :     ItemId      previi;
                                691                 :                : 
                                692                 :           6333 :     maxoff = PageGetMaxOffsetNumber(rightmostpage);
                                693         [ -  + ]:           6333 :     Assert(maxoff >= P_FIRSTKEY);
                                694                 :           6333 :     previi = PageGetItemId(rightmostpage, P_HIKEY);
                                695         [ +  + ]:         372398 :     for (off = P_FIRSTKEY; off <= maxoff; off = OffsetNumberNext(off))
                                696                 :                :     {
                                697                 :         366065 :         ItemId      thisii = PageGetItemId(rightmostpage, off);
                                698                 :                : 
                                699                 :         366065 :         *previi = *thisii;
                                700                 :         366065 :         previi = thisii;
                                701                 :                :     }
                                702                 :           6333 :     ((PageHeader) rightmostpage)->pd_lower -= sizeof(ItemIdData);
10651 scrappy@hub.org           703                 :           6333 : }
                                704                 :                : 
                                705                 :                : /*
                                706                 :                :  * Add an item to a page being built.
                                707                 :                :  *
                                708                 :                :  * This is very similar to nbtinsert.c's _bt_pgaddtup(), but this variant
                                709                 :                :  * raises an error directly.
                                710                 :                :  *
                                711                 :                :  * Note that our nbtsort.c caller does not know yet if the page will be
                                712                 :                :  * rightmost.  Offset P_FIRSTKEY is always assumed to be the first data key by
                                713                 :                :  * caller.  Page that turns out to be the rightmost on its level is fixed by
                                714                 :                :  * calling _bt_slideleft().
                                715                 :                :  */
                                716                 :                : static void
 9178 tgl@sss.pgh.pa.us         717                 :        5738494 : _bt_sortaddtup(Page page,
                                718                 :                :                Size itemsize,
                                719                 :                :                IndexTuple itup,
                                720                 :                :                OffsetNumber itup_off,
                                721                 :                :                bool newfirstdataitem)
                                722                 :                : {
                                723                 :                :     IndexTupleData trunctuple;
                                724                 :                : 
 1972 pg@bowt.ie                725         [ +  + ]:        5738494 :     if (newfirstdataitem)
                                726                 :                :     {
 7164 tgl@sss.pgh.pa.us         727                 :           1372 :         trunctuple = *itup;
                                728                 :           1372 :         trunctuple.t_info = sizeof(IndexTupleData);
 1978 pg@bowt.ie                729                 :           1372 :         BTreeTupleSetNAtts(&trunctuple, 0, false);
 7164 tgl@sss.pgh.pa.us         730                 :           1372 :         itup = &trunctuple;
                                731                 :           1372 :         itemsize = sizeof(IndexTupleData);
                                732                 :                :     }
                                733                 :                : 
                                734         [ -  + ]:        5738494 :     if (PageAddItem(page, (Item) itup, itemsize, itup_off,
                                735                 :                :                     false, false) == InvalidOffsetNumber)
 8083 tgl@sss.pgh.pa.us         736         [ #  # ]:UBC           0 :         elog(ERROR, "failed to add item to the index page");
10433 scrappy@hub.org           737                 :CBC     5738494 : }
                                738                 :                : 
                                739                 :                : /*----------
                                740                 :                :  * Add an item to a disk page from the sort output (or add a posting list
                                741                 :                :  * item formed from the sort output).
                                742                 :                :  *
                                743                 :                :  * We must be careful to observe the page layout conventions of nbtsearch.c:
                                744                 :                :  * - rightmost pages start data items at P_HIKEY instead of at P_FIRSTKEY.
                                745                 :                :  * - on non-leaf pages, the key portion of the first item need not be
                                746                 :                :  *   stored, we should store only the link.
                                747                 :                :  *
                                748                 :                :  * A leaf page being built looks like:
                                749                 :                :  *
                                750                 :                :  * +----------------+---------------------------------+
                                751                 :                :  * | PageHeaderData | linp0 linp1 linp2 ...           |
                                752                 :                :  * +-----------+----+---------------------------------+
                                753                 :                :  * | ... linpN |                                      |
                                754                 :                :  * +-----------+--------------------------------------+
                                755                 :                :  * |     ^ last                                       |
                                756                 :                :  * |                                                  |
                                757                 :                :  * +-------------+------------------------------------+
                                758                 :                :  * |             | itemN ...                          |
                                759                 :                :  * +-------------+------------------+-----------------+
                                760                 :                :  * |          ... item3 item2 item1 | "special space" |
                                761                 :                :  * +--------------------------------+-----------------+
                                762                 :                :  *
                                763                 :                :  * Contrast this with the diagram in bufpage.h; note the mismatch
                                764                 :                :  * between linps and items.  This is because we reserve linp0 as a
                                765                 :                :  * placeholder for the pointer to the "high key" item; when we have
                                766                 :                :  * filled up the page, we will set linp0 to point to itemN and clear
                                767                 :                :  * linpN.  On the other hand, if we find this is the last (rightmost)
                                768                 :                :  * page, we leave the items alone and slide the linp array over.  If
                                769                 :                :  * the high key is to be truncated, offset 1 is deleted, and we insert
                                770                 :                :  * the truncated high key at offset 1.
                                771                 :                :  *
                                772                 :                :  * 'last' pointer indicates the last offset added to the page.
                                773                 :                :  *
                                774                 :                :  * 'truncextra' is the size of the posting list in itup, if any.  This
                                775                 :                :  * information is stashed for the next call here, when we may benefit
                                776                 :                :  * from considering the impact of truncating away the posting list on
                                777                 :                :  * the page before deciding to finish the page off.  Posting lists are
                                778                 :                :  * often relatively large, so it is worth going to the trouble of
                                779                 :                :  * accounting for the saving from truncating away the posting list of
                                780                 :                :  * the tuple that becomes the high key (that may be the only way to
                                781                 :                :  * get close to target free space on the page).  Note that this is
                                782                 :                :  * only used for the soft fillfactor-wise limit, not the critical hard
                                783                 :                :  * limit.
                                784                 :                :  *----------
                                785                 :                :  */
                                786                 :                : static void
 2019 pg@bowt.ie                787                 :        5718459 : _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup,
                                788                 :                :              Size truncextra)
                                789                 :                : {
                                790                 :                :     BulkWriteBuffer nbuf;
                                791                 :                :     Page        npage;
                                792                 :                :     BlockNumber nblkno;
                                793                 :                :     OffsetNumber last_off;
                                794                 :                :     Size        last_truncextra;
                                795                 :                :     Size        pgspc;
                                796                 :                :     Size        itupsz;
                                797                 :                :     bool        isleaf;
                                798                 :                : 
                                799                 :                :     /*
                                800                 :                :      * This is a handy place to check for cancel interrupts during the btree
                                801                 :                :      * load phase of index creation.
                                802                 :                :      */
 7120 tgl@sss.pgh.pa.us         803         [ -  + ]:        5718459 :     CHECK_FOR_INTERRUPTS();
                                804                 :                : 
  561 heikki.linnakangas@i      805                 :        5718459 :     nbuf = state->btps_buf;
                                806                 :        5718459 :     npage = (Page) nbuf;
 7766 tgl@sss.pgh.pa.us         807                 :        5718459 :     nblkno = state->btps_blkno;
10226 bruce@momjian.us          808                 :        5718459 :     last_off = state->btps_lastoff;
 2019 pg@bowt.ie                809                 :        5718459 :     last_truncextra = state->btps_lastextra;
                                810                 :        5718459 :     state->btps_lastextra = truncextra;
                                811                 :                : 
10226 bruce@momjian.us          812                 :        5718459 :     pgspc = PageGetFreeSpace(npage);
 2747 tgl@sss.pgh.pa.us         813                 :        5718459 :     itupsz = IndexTupleSize(itup);
 7164                           814                 :        5718459 :     itupsz = MAXALIGN(itupsz);
                                815                 :                :     /* Leaf case has slightly different rules due to suffix truncation */
 2319 pg@bowt.ie                816                 :        5718459 :     isleaf = (state->btps_level == 0);
                                817                 :                : 
                                818                 :                :     /*
                                819                 :                :      * Check whether the new item can fit on a btree page on current level at
                                820                 :                :      * all.
                                821                 :                :      *
                                822                 :                :      * Every newly built index will treat heap TID as part of the keyspace,
                                823                 :                :      * which imposes the requirement that new high keys must occasionally have
                                824                 :                :      * a heap TID appended within _bt_truncate().  That may leave a new pivot
                                825                 :                :      * tuple one or two MAXALIGN() quantums larger than the original
                                826                 :                :      * firstright tuple it's derived from.  v4 deals with the problem by
                                827                 :                :      * decreasing the limit on the size of tuples inserted on the leaf level
                                828                 :                :      * by the same small amount.  Enforce the new v4+ limit on the leaf level,
                                829                 :                :      * and the old limit on internal levels, since pivot tuples may need to
                                830                 :                :      * make use of the reserved space.  This should never fail on internal
                                831                 :                :      * pages.
                                832                 :                :      */
  179                           833         [ +  + ]:        5718459 :     if (unlikely(itupsz > BTMaxItemSize))
 2319                           834                 :            132 :         _bt_check_third_page(wstate->index, wstate->heap, isleaf, npage,
                                835                 :                :                              itup);
                                836                 :                : 
                                837                 :                :     /*
                                838                 :                :      * Check to see if current page will fit new item, with space left over to
                                839                 :                :      * append a heap TID during suffix truncation when page is a leaf page.
                                840                 :                :      *
                                841                 :                :      * It is guaranteed that we can fit at least 2 non-pivot tuples plus a
                                842                 :                :      * high key with heap TID when finishing off a leaf page, since we rely on
                                843                 :                :      * _bt_check_third_page() rejecting oversized non-pivot tuples.  On
                                844                 :                :      * internal pages we can always fit 3 pivot tuples with larger internal
                                845                 :                :      * page tuple limit (includes page high key).
                                846                 :                :      *
                                847                 :                :      * Most of the time, a page is only "full" in the sense that the soft
                                848                 :                :      * fillfactor-wise limit has been exceeded.  However, we must always leave
                                849                 :                :      * at least two items plus a high key on each page before starting a new
                                850                 :                :      * page.  Disregard fillfactor and insert on "full" current page if we
                                851                 :                :      * don't have the minimum number of items yet.  (Note that we deliberately
                                852                 :                :      * assume that suffix truncation neither enlarges nor shrinks new high key
                                853                 :                :      * when applying soft limit, except when last tuple has a posting list.)
                                854                 :                :      */
 1985                           855   [ +  +  -  + ]:        5718459 :     Assert(last_truncextra == 0 || isleaf);
 2319                           856   [ +  +  +  + ]:        5718459 :     if (pgspc < itupsz + (isleaf ? MAXALIGN(sizeof(ItemPointerData)) : 0) ||
 2019                           857   [ +  +  +  - ]:        5717881 :         (pgspc + last_truncextra < state->btps_full && last_off > P_FIRSTKEY))
                                858                 :                :     {
                                859                 :                :         /*
                                860                 :                :          * Finish off the page and write it out.
                                861                 :                :          */
  561 heikki.linnakangas@i      862                 :          20035 :         BulkWriteBuffer obuf = nbuf;
10225 bruce@momjian.us          863                 :          20035 :         Page        opage = npage;
 7678                           864                 :          20035 :         BlockNumber oblkno = nblkno;
                                865                 :                :         ItemId      ii;
                                866                 :                :         ItemId      hii;
                                867                 :                :         IndexTuple  oitup;
                                868                 :                : 
                                869                 :                :         /* Create new page of same level */
  561 heikki.linnakangas@i      870                 :          20035 :         nbuf = _bt_blnewpage(wstate, state->btps_level);
                                871                 :          20035 :         npage = (Page) nbuf;
                                872                 :                : 
                                873                 :                :         /* and assign it a page position */
 7766 tgl@sss.pgh.pa.us         874                 :          20035 :         nblkno = wstate->btws_pages_alloced++;
                                875                 :                : 
                                876                 :                :         /*
                                877                 :                :          * We copy the last item on the page into the new page, and then
                                878                 :                :          * rearrange the old page so that the 'last item' becomes its high key
                                879                 :                :          * rather than a true data item.  There had better be at least two
                                880                 :                :          * items on the page already, else the page would be empty of useful
                                881                 :                :          * data.
                                882                 :                :          */
 9178                           883         [ -  + ]:          20035 :         Assert(last_off > P_FIRSTKEY);
                                884                 :          20035 :         ii = PageGetItemId(opage, last_off);
 7164                           885                 :          20035 :         oitup = (IndexTuple) PageGetItem(opage, ii);
 1972 pg@bowt.ie                886                 :          20035 :         _bt_sortaddtup(npage, ItemIdGetLength(ii), oitup, P_FIRSTKEY,
                                887                 :          20035 :                        !isleaf);
                                888                 :                : 
                                889                 :                :         /*
                                890                 :                :          * Move 'last' into the high key position on opage.  _bt_blnewpage()
                                891                 :                :          * allocated empty space for a line pointer when opage was first
                                892                 :                :          * created, so this is a matter of rearranging already-allocated space
                                893                 :                :          * on page, and initializing high key line pointer. (Actually, leaf
                                894                 :                :          * pages must also swap oitup with a truncated version of oitup, which
                                895                 :                :          * is sometimes larger than oitup, though never by more than the space
                                896                 :                :          * needed to append a heap TID.)
                                897                 :                :          */
10226 bruce@momjian.us          898                 :          20035 :         hii = PageGetItemId(opage, P_HIKEY);
                                899                 :          20035 :         *hii = *ii;
 6569 tgl@sss.pgh.pa.us         900                 :          20035 :         ItemIdSetUnused(ii);    /* redundant */
10226 bruce@momjian.us          901                 :          20035 :         ((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
                                902                 :                : 
 2319 pg@bowt.ie                903         [ +  + ]:          20035 :         if (isleaf)
                                904                 :                :         {
                                905                 :                :             IndexTuple  lastleft;
                                906                 :                :             IndexTuple  truncated;
                                907                 :                : 
                                908                 :                :             /*
                                909                 :                :              * Truncate away any unneeded attributes from high key on leaf
                                910                 :                :              * level.  This is only done at the leaf level because downlinks
                                911                 :                :              * in internal pages are either negative infinity items, or get
                                912                 :                :              * their contents from copying from one level down.  See also:
                                913                 :                :              * _bt_split().
                                914                 :                :              *
                                915                 :                :              * We don't try to bias our choice of split point to make it more
                                916                 :                :              * likely that _bt_truncate() can truncate away more attributes,
                                917                 :                :              * whereas the split point used within _bt_split() is chosen much
                                918                 :                :              * more delicately.  Even still, the lastleft and firstright
                                919                 :                :              * tuples passed to _bt_truncate() here are at least not fully
                                920                 :                :              * equal to each other when deduplication is used, unless there is
                                921                 :                :              * a large group of duplicates (also, unique index builds usually
                                922                 :                :              * have few or no spool2 duplicates).  When the split point is
                                923                 :                :              * between two unequal tuples, _bt_truncate() will avoid including
                                924                 :                :              * a heap TID in the new high key, which is the most important
                                925                 :                :              * benefit of suffix truncation.
                                926                 :                :              *
                                927                 :                :              * Overwrite the old item with new truncated high key directly.
                                928                 :                :              * oitup is already located at the physical beginning of tuple
                                929                 :                :              * space, so this should directly reuse the existing tuple space.
                                930                 :                :              */
 2362                           931                 :          19973 :             ii = PageGetItemId(opage, OffsetNumberPrev(last_off));
                                932                 :          19973 :             lastleft = (IndexTuple) PageGetItem(opage, ii);
                                933                 :                : 
 1985                           934         [ -  + ]:          19973 :             Assert(IndexTupleSize(oitup) > last_truncextra);
 2362                           935                 :          19973 :             truncated = _bt_truncate(wstate->index, lastleft, oitup,
                                936                 :                :                                      wstate->inskey);
 2216                           937         [ -  + ]:          19973 :             if (!PageIndexTupleOverwrite(opage, P_HIKEY, (Item) truncated,
                                938                 :                :                                          IndexTupleSize(truncated)))
 2216 pg@bowt.ie                939         [ #  # ]:UBC           0 :                 elog(ERROR, "failed to add high key to the index page");
 2697 teodor@sigaev.ru          940                 :CBC       19973 :             pfree(truncated);
                                941                 :                : 
                                942                 :                :             /* oitup should continue to point to the page's high key */
                                943                 :          19973 :             hii = PageGetItemId(opage, P_HIKEY);
                                944                 :          19973 :             oitup = (IndexTuple) PageGetItem(opage, hii);
                                945                 :                :         }
                                946                 :                : 
                                947                 :                :         /*
                                948                 :                :          * Link the old page into its parent, using its low key.  If we don't
                                949                 :                :          * have a parent, we have to create one; this adds a new btree level.
                                950                 :                :          */
 7913 neilc@samurai.com         951         [ +  + ]:          20035 :         if (state->btps_next == NULL)
 7766 tgl@sss.pgh.pa.us         952                 :           1310 :             state->btps_next = _bt_pagestate(wstate, state->btps_level + 1);
                                953                 :                : 
 2130 pg@bowt.ie                954   [ +  -  +  -  :          20035 :         Assert((BTreeTupleGetNAtts(state->btps_lowkey, wstate->index) <=
                                     +  -  +  +  -  
                                           -  -  + ]
                                955                 :                :                 IndexRelationGetNumberOfKeyAttributes(wstate->index) &&
                                956                 :                :                 BTreeTupleGetNAtts(state->btps_lowkey, wstate->index) > 0) ||
                                957                 :                :                P_LEFTMOST(BTPageGetOpaque(opage)));
                                958   [ +  -  +  +  :          20035 :         Assert(BTreeTupleGetNAtts(state->btps_lowkey, wstate->index) == 0 ||
                                              -  + ]
                                959                 :                :                !P_LEFTMOST(BTPageGetOpaque(opage)));
 2091                           960                 :          20035 :         BTreeTupleSetDownLink(state->btps_lowkey, oblkno);
 2019                           961                 :          20035 :         _bt_buildadd(wstate, state->btps_next, state->btps_lowkey, 0);
 2130                           962                 :          20035 :         pfree(state->btps_lowkey);
                                963                 :                : 
                                964                 :                :         /*
                                965                 :                :          * Save a copy of the high key from the old page.  It is also the low
                                966                 :                :          * key for the new page.
                                967                 :                :          */
                                968                 :          20035 :         state->btps_lowkey = CopyIndexTuple(oitup);
                                969                 :                : 
                                970                 :                :         /*
                                971                 :                :          * Set the sibling links for both pages.
                                972                 :                :          */
                                973                 :                :         {
 1254 michael@paquier.xyz       974                 :          20035 :             BTPageOpaque oopaque = BTPageGetOpaque(opage);
                                975                 :          20035 :             BTPageOpaque nopaque = BTPageGetOpaque(npage);
                                976                 :                : 
 7766 tgl@sss.pgh.pa.us         977                 :          20035 :             oopaque->btpo_next = nblkno;
                                978                 :          20035 :             nopaque->btpo_prev = oblkno;
 2999                           979                 :          20035 :             nopaque->btpo_next = P_NONE; /* redundant */
                                980                 :                :         }
                                981                 :                : 
                                982                 :                :         /*
                                983                 :                :          * Write out the old page. _bt_blwritepage takes ownership of the
                                984                 :                :          * 'opage' buffer.
                                985                 :                :          */
  561 heikki.linnakangas@i      986                 :          20035 :         _bt_blwritepage(wstate, obuf, oblkno);
                                987                 :                : 
                                988                 :                :         /*
                                989                 :                :          * Reset last_off to point to new page
                                990                 :                :          */
 9178 tgl@sss.pgh.pa.us         991                 :          20035 :         last_off = P_FIRSTKEY;
                                992                 :                :     }
                                993                 :                : 
                                994                 :                :     /*
                                995                 :                :      * By here, either original page is still the current page, or a new page
                                996                 :                :      * was created that became the current page.  Either way, the current page
                                997                 :                :      * definitely has space for new item.
                                998                 :                :      *
                                999                 :                :      * If the new item is the first for its page, it must also be the first
                               1000                 :                :      * item on its entire level.  On later same-level pages, a low key for a
                               1001                 :                :      * page will be copied from the prior page in the code above.  Generate a
                               1002                 :                :      * minus infinity low key here instead.
                               1003                 :                :      */
                               1004         [ +  + ]:        5718459 :     if (last_off == P_HIKEY)
                               1005                 :                :     {
 2130 pg@bowt.ie               1006         [ -  + ]:           6333 :         Assert(state->btps_lowkey == NULL);
                               1007                 :           6333 :         state->btps_lowkey = palloc0(sizeof(IndexTupleData));
                               1008                 :           6333 :         state->btps_lowkey->t_info = sizeof(IndexTupleData);
 1978                          1009                 :           6333 :         BTreeTupleSetNAtts(state->btps_lowkey, 0, false);
                               1010                 :                :     }
                               1011                 :                : 
                               1012                 :                :     /*
                               1013                 :                :      * Add the new item into the current page.
                               1014                 :                :      */
 9178 tgl@sss.pgh.pa.us        1015                 :        5718459 :     last_off = OffsetNumberNext(last_off);
 1972 pg@bowt.ie               1016                 :        5718459 :     _bt_sortaddtup(npage, itupsz, itup, last_off,
                               1017   [ +  +  +  + ]:        5718459 :                    !isleaf && last_off == P_FIRSTKEY);
                               1018                 :                : 
  561 heikki.linnakangas@i     1019                 :        5718459 :     state->btps_buf = nbuf;
 7766 tgl@sss.pgh.pa.us        1020                 :        5718459 :     state->btps_blkno = nblkno;
10226 bruce@momjian.us         1021                 :        5718459 :     state->btps_lastoff = last_off;
10433 scrappy@hub.org          1022                 :        5718459 : }
                               1023                 :                : 
                               1024                 :                : /*
                               1025                 :                :  * Finalize pending posting list tuple, and add it to the index.  Final tuple
                               1026                 :                :  * is based on saved base tuple, and saved list of heap TIDs.
                               1027                 :                :  *
                               1028                 :                :  * This is almost like _bt_dedup_finish_pending(), but it adds a new tuple
                               1029                 :                :  * using _bt_buildadd().
                               1030                 :                :  */
                               1031                 :                : static void
 2019 pg@bowt.ie               1032                 :        2358878 : _bt_sort_dedup_finish_pending(BTWriteState *wstate, BTPageState *state,
                               1033                 :                :                               BTDedupState dstate)
                               1034                 :                : {
                               1035         [ -  + ]:        2358878 :     Assert(dstate->nitems > 0);
                               1036                 :                : 
                               1037         [ +  + ]:        2358878 :     if (dstate->nitems == 1)
                               1038                 :        2338846 :         _bt_buildadd(wstate, state, dstate->base, 0);
                               1039                 :                :     else
                               1040                 :                :     {
                               1041                 :                :         IndexTuple  postingtuple;
                               1042                 :                :         Size        truncextra;
                               1043                 :                : 
                               1044                 :                :         /* form a tuple with a posting list */
                               1045                 :          20032 :         postingtuple = _bt_form_posting(dstate->base,
                               1046                 :                :                                         dstate->htids,
                               1047                 :                :                                         dstate->nhtids);
                               1048                 :                :         /* Calculate posting list overhead */
                               1049                 :          20032 :         truncextra = IndexTupleSize(postingtuple) -
                               1050                 :          20032 :             BTreeTupleGetPostingOffset(postingtuple);
                               1051                 :                : 
                               1052                 :          20032 :         _bt_buildadd(wstate, state, postingtuple, truncextra);
                               1053                 :          20032 :         pfree(postingtuple);
                               1054                 :                :     }
                               1055                 :                : 
 1905                          1056                 :        2358878 :     dstate->nmaxitems = 0;
 2019                          1057                 :        2358878 :     dstate->nhtids = 0;
                               1058                 :        2358878 :     dstate->nitems = 0;
                               1059                 :        2358878 :     dstate->phystupsize = 0;
                               1060                 :        2358878 : }
                               1061                 :                : 
                               1062                 :                : /*
                               1063                 :                :  * Finish writing out the completed btree.
                               1064                 :                :  */
                               1065                 :                : static void
 7766 tgl@sss.pgh.pa.us        1066                 :          25025 : _bt_uppershutdown(BTWriteState *wstate, BTPageState *state)
                               1067                 :                : {
                               1068                 :                :     BTPageState *s;
 7678 bruce@momjian.us         1069                 :          25025 :     BlockNumber rootblkno = P_NONE;
 8013 tgl@sss.pgh.pa.us        1070                 :          25025 :     uint32      rootlevel = 0;
                               1071                 :                :     BulkWriteBuffer metabuf;
                               1072                 :                : 
                               1073                 :                :     /*
                               1074                 :                :      * Each iteration of this loop completes one more level of the tree.
                               1075                 :                :      */
 7913 neilc@samurai.com        1076         [ +  + ]:          31358 :     for (s = state; s != NULL; s = s->btps_next)
                               1077                 :                :     {
                               1078                 :                :         BlockNumber blkno;
                               1079                 :                :         BTPageOpaque opaque;
                               1080                 :                : 
 7766 tgl@sss.pgh.pa.us        1081                 :           6333 :         blkno = s->btps_blkno;
  561 heikki.linnakangas@i     1082                 :           6333 :         opaque = BTPageGetOpaque((Page) s->btps_buf);
                               1083                 :                : 
                               1084                 :                :         /*
                               1085                 :                :          * We have to link the last page on this level to somewhere.
                               1086                 :                :          *
                               1087                 :                :          * If we're at the top, it's the root, so attach it to the metapage.
                               1088                 :                :          * Otherwise, add an entry for it to its parent using its low key.
                               1089                 :                :          * This may cause the last page of the parent level to split, but
                               1090                 :                :          * that's not a problem -- we haven't gotten to it yet.
                               1091                 :                :          */
 7913 neilc@samurai.com        1092         [ +  + ]:           6333 :         if (s->btps_next == NULL)
                               1093                 :                :         {
 9178 tgl@sss.pgh.pa.us        1094                 :           5023 :             opaque->btpo_flags |= BTP_ROOT;
 8013                          1095                 :           5023 :             rootblkno = blkno;
                               1096                 :           5023 :             rootlevel = s->btps_level;
                               1097                 :                :         }
                               1098                 :                :         else
                               1099                 :                :         {
 2130 pg@bowt.ie               1100   [ +  -  +  -  :           1310 :             Assert((BTreeTupleGetNAtts(s->btps_lowkey, wstate->index) <=
                                     +  -  -  +  -  
                                           -  -  - ]
                               1101                 :                :                     IndexRelationGetNumberOfKeyAttributes(wstate->index) &&
                               1102                 :                :                     BTreeTupleGetNAtts(s->btps_lowkey, wstate->index) > 0) ||
                               1103                 :                :                    P_LEFTMOST(opaque));
                               1104   [ +  -  +  -  :           1310 :             Assert(BTreeTupleGetNAtts(s->btps_lowkey, wstate->index) == 0 ||
                                              -  + ]
                               1105                 :                :                    !P_LEFTMOST(opaque));
 2091                          1106                 :           1310 :             BTreeTupleSetDownLink(s->btps_lowkey, blkno);
 2019                          1107                 :           1310 :             _bt_buildadd(wstate, s->btps_next, s->btps_lowkey, 0);
 2130                          1108                 :           1310 :             pfree(s->btps_lowkey);
                               1109                 :           1310 :             s->btps_lowkey = NULL;
                               1110                 :                :         }
                               1111                 :                : 
                               1112                 :                :         /*
                               1113                 :                :          * This is the rightmost page, so the ItemId array needs to be slid
                               1114                 :                :          * back one slot.  Then we can dump out the page.
                               1115                 :                :          */
  561 heikki.linnakangas@i     1116                 :           6333 :         _bt_slideleft((Page) s->btps_buf);
                               1117                 :           6333 :         _bt_blwritepage(wstate, s->btps_buf, s->btps_blkno);
                               1118                 :           6333 :         s->btps_buf = NULL;      /* writepage took ownership of the buffer */
                               1119                 :                :     }
                               1120                 :                : 
                               1121                 :                :     /*
                               1122                 :                :      * As the last step in the process, construct the metapage and make it
                               1123                 :                :      * point to the new root (unless we had no data at all, in which case it's
                               1124                 :                :      * set to point to "P_NONE").  This changes the index to the "valid" state
                               1125                 :                :      * by filling in a valid magic number in the metapage.
                               1126                 :                :      */
                               1127                 :          25025 :     metabuf = smgr_bulk_get_buf(wstate->bulkstate);
                               1128                 :          25025 :     _bt_initmetapage((Page) metabuf, rootblkno, rootlevel,
 2019 pg@bowt.ie               1129                 :          25025 :                      wstate->inskey->allequalimage);
  561 heikki.linnakangas@i     1130                 :          25025 :     _bt_blwritepage(wstate, metabuf, BTREE_METAPAGE);
10651 scrappy@hub.org          1131                 :          25025 : }
                               1132                 :                : 
                               1133                 :                : /*
                               1134                 :                :  * Read tuples in correct sort order from tuplesort, and load them into
                               1135                 :                :  * btree leaves.
                               1136                 :                :  */
                               1137                 :                : static void
 7766 tgl@sss.pgh.pa.us        1138                 :          25025 : _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2)
                               1139                 :                : {
 9178                          1140                 :          25025 :     BTPageState *state = NULL;
 9158 inoue@tpf.co.jp          1141                 :          25025 :     bool        merge = (btspool2 != NULL);
                               1142                 :                :     IndexTuple  itup,
 7164 tgl@sss.pgh.pa.us        1143                 :          25025 :                 itup2 = NULL;
                               1144                 :                :     bool        load1;
 7766                          1145                 :          25025 :     TupleDesc   tupdes = RelationGetDescr(wstate->index);
                               1146                 :                :     int         i,
 2709 teodor@sigaev.ru         1147                 :          25025 :                 keysz = IndexRelationGetNumberOfKeyAttributes(wstate->index);
                               1148                 :                :     SortSupport sortKeys;
 2322 alvherre@alvh.no-ip.     1149                 :          25025 :     int64       tuples_done = 0;
                               1150                 :                :     bool        deduplicate;
                               1151                 :                : 
  561 heikki.linnakangas@i     1152                 :          25025 :     wstate->bulkstate = smgr_bulk_start_rel(wstate->index, MAIN_FORKNUM);
                               1153                 :                : 
 1877 pg@bowt.ie               1154   [ +  +  +  +  :          29442 :     deduplicate = wstate->inskey->allequalimage && !btspool->isunique &&
                                              +  - ]
 2019                          1155   [ +  -  -  +  :           4417 :         BTGetDeduplicateItems(wstate->index);
                                        +  +  +  - ]
                               1156                 :                : 
 9158 inoue@tpf.co.jp          1157         [ +  + ]:          25025 :     if (merge)
                               1158                 :                :     {
                               1159                 :                :         /*
                               1160                 :                :          * Another BTSpool for dead tuples exists. Now we have to merge
                               1161                 :                :          * btspool and btspool2.
                               1162                 :                :          */
                               1163                 :                : 
                               1164                 :                :         /* the preparation of merge */
 3190 rhaas@postgresql.org     1165                 :             11 :         itup = tuplesort_getindextuple(btspool->sortstate, true);
                               1166                 :             11 :         itup2 = tuplesort_getindextuple(btspool2->sortstate, true);
                               1167                 :                : 
                               1168                 :                :         /* Prepare SortSupport data for each column */
 3956                          1169                 :             11 :         sortKeys = (SortSupport) palloc0(keysz * sizeof(SortSupportData));
                               1170                 :                : 
                               1171         [ +  + ]:             23 :         for (i = 0; i < keysz; i++)
                               1172                 :                :         {
                               1173                 :             12 :             SortSupport sortKey = sortKeys + i;
 2362 pg@bowt.ie               1174                 :             12 :             ScanKey     scanKey = wstate->inskey->scankeys + i;
                               1175                 :                :             bool        reverse;
                               1176                 :                : 
 3956 rhaas@postgresql.org     1177                 :             12 :             sortKey->ssup_cxt = CurrentMemoryContext;
                               1178                 :             12 :             sortKey->ssup_collation = scanKey->sk_collation;
                               1179                 :             12 :             sortKey->ssup_nulls_first =
                               1180                 :             12 :                 (scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
                               1181                 :             12 :             sortKey->ssup_attno = scanKey->sk_attno;
                               1182                 :                :             /* Abbreviation is not supported here */
 3883                          1183                 :             12 :             sortKey->abbreviate = false;
                               1184                 :                : 
 1044 peter@eisentraut.org     1185         [ -  + ]:             12 :             Assert(sortKey->ssup_attno != 0);
                               1186                 :                : 
  176                          1187                 :             12 :             reverse = (scanKey->sk_flags & SK_BT_DESC) != 0;
                               1188                 :                : 
                               1189                 :             12 :             PrepareSortSupportFromIndexRel(wstate->index, reverse, sortKey);
                               1190                 :                :         }
                               1191                 :                : 
                               1192                 :                :         for (;;)
                               1193                 :                :         {
 8934 bruce@momjian.us         1194                 :           1665 :             load1 = true;       /* load BTSpool next ? */
 7164 tgl@sss.pgh.pa.us        1195         [ +  + ]:           1665 :             if (itup2 == NULL)
                               1196                 :                :             {
                               1197         [ +  + ]:             77 :                 if (itup == NULL)
 9158 inoue@tpf.co.jp          1198                 :             11 :                     break;
                               1199                 :                :             }
 7164 tgl@sss.pgh.pa.us        1200         [ +  + ]:           1588 :             else if (itup != NULL)
                               1201                 :                :             {
 2362 pg@bowt.ie               1202                 :           1491 :                 int32       compare = 0;
                               1203                 :                : 
 9158 inoue@tpf.co.jp          1204         [ +  + ]:           1614 :                 for (i = 1; i <= keysz; i++)
                               1205                 :                :                 {
                               1206                 :                :                     SortSupport entry;
                               1207                 :                :                     Datum       attrDatum1,
                               1208                 :                :                                 attrDatum2;
                               1209                 :                :                     bool        isNull1,
                               1210                 :                :                                 isNull2;
                               1211                 :                : 
 3956 rhaas@postgresql.org     1212                 :           1517 :                     entry = sortKeys + i - 1;
 6815 tgl@sss.pgh.pa.us        1213                 :           1517 :                     attrDatum1 = index_getattr(itup, i, tupdes, &isNull1);
                               1214                 :           1517 :                     attrDatum2 = index_getattr(itup2, i, tupdes, &isNull2);
                               1215                 :                : 
 3956 rhaas@postgresql.org     1216                 :           1517 :                     compare = ApplySortComparator(attrDatum1, isNull1,
                               1217                 :                :                                                   attrDatum2, isNull2,
                               1218                 :                :                                                   entry);
 6815 tgl@sss.pgh.pa.us        1219         [ +  + ]:           1517 :                     if (compare > 0)
                               1220                 :                :                     {
                               1221                 :            139 :                         load1 = false;
                               1222                 :           1394 :                         break;
                               1223                 :                :                     }
                               1224         [ +  + ]:           1378 :                     else if (compare < 0)
                               1225                 :           1255 :                         break;
                               1226                 :                :                 }
                               1227                 :                : 
                               1228                 :                :                 /*
                               1229                 :                :                  * If key values are equal, we sort on ItemPointer.  This is
                               1230                 :                :                  * required for btree indexes, since heap TID is treated as an
                               1231                 :                :                  * implicit last key attribute in order to ensure that all
                               1232                 :                :                  * keys in the index are physically unique.
                               1233                 :                :                  */
 2362 pg@bowt.ie               1234         [ +  + ]:           1491 :                 if (compare == 0)
                               1235                 :                :                 {
                               1236                 :             97 :                     compare = ItemPointerCompare(&itup->t_tid, &itup2->t_tid);
                               1237         [ -  + ]:             97 :                     Assert(compare != 0);
                               1238         [ +  + ]:             97 :                     if (compare > 0)
                               1239                 :             15 :                         load1 = false;
                               1240                 :                :                 }
                               1241                 :                :             }
                               1242                 :                :             else
 9158 inoue@tpf.co.jp          1243                 :             97 :                 load1 = false;
                               1244                 :                : 
                               1245                 :                :             /* When we see first tuple, create first index page */
                               1246         [ +  + ]:           1654 :             if (state == NULL)
 7766 tgl@sss.pgh.pa.us        1247                 :             11 :                 state = _bt_pagestate(wstate, 0);
                               1248                 :                : 
 9158 inoue@tpf.co.jp          1249         [ +  + ]:           1654 :             if (load1)
                               1250                 :                :             {
 2019 pg@bowt.ie               1251                 :           1403 :                 _bt_buildadd(wstate, state, itup, 0);
 3190 rhaas@postgresql.org     1252                 :           1403 :                 itup = tuplesort_getindextuple(btspool->sortstate, true);
                               1253                 :                :             }
                               1254                 :                :             else
                               1255                 :                :             {
 2019 pg@bowt.ie               1256                 :            251 :                 _bt_buildadd(wstate, state, itup2, 0);
 3190 rhaas@postgresql.org     1257                 :            251 :                 itup2 = tuplesort_getindextuple(btspool2->sortstate, true);
                               1258                 :                :             }
                               1259                 :                : 
                               1260                 :                :             /* Report progress */
 2349 alvherre@alvh.no-ip.     1261                 :           1654 :             pgstat_progress_update_param(PROGRESS_CREATEIDX_TUPLES_DONE,
                               1262                 :                :                                          ++tuples_done);
                               1263                 :                :         }
 3956 rhaas@postgresql.org     1264                 :             11 :         pfree(sortKeys);
                               1265                 :                :     }
 2019 pg@bowt.ie               1266         [ +  + ]:          25014 :     else if (deduplicate)
                               1267                 :                :     {
                               1268                 :                :         /* merge is unnecessary, deduplicate into posting lists */
                               1269                 :                :         BTDedupState dstate;
                               1270                 :                : 
                               1271                 :           4417 :         dstate = (BTDedupState) palloc(sizeof(BTDedupStateData));
                               1272                 :           4417 :         dstate->deduplicate = true; /* unused */
 1905                          1273                 :           4417 :         dstate->nmaxitems = 0;   /* unused */
 2019                          1274                 :           4417 :         dstate->maxpostingsize = 0; /* set later */
                               1275                 :                :         /* Metadata about base tuple of current pending posting list */
                               1276                 :           4417 :         dstate->base = NULL;
                               1277                 :           4417 :         dstate->baseoff = InvalidOffsetNumber;   /* unused */
                               1278                 :           4417 :         dstate->basetupsize = 0;
                               1279                 :                :         /* Metadata about current pending posting list TIDs */
                               1280                 :           4417 :         dstate->htids = NULL;
                               1281                 :           4417 :         dstate->nhtids = 0;
                               1282                 :           4417 :         dstate->nitems = 0;
                               1283                 :           4417 :         dstate->phystupsize = 0; /* unused */
                               1284                 :           4417 :         dstate->nintervals = 0; /* unused */
                               1285                 :                : 
                               1286                 :        3039797 :         while ((itup = tuplesort_getindextuple(btspool->sortstate,
                               1287         [ +  + ]:        3039797 :                                                true)) != NULL)
                               1288                 :                :         {
                               1289                 :                :             /* When we see first tuple, create first index page */
                               1290         [ +  + ]:        3035380 :             if (state == NULL)
                               1291                 :                :             {
                               1292                 :           1169 :                 state = _bt_pagestate(wstate, 0);
                               1293                 :                : 
                               1294                 :                :                 /*
                               1295                 :                :                  * Limit size of posting list tuples to 1/10 space we want to
                               1296                 :                :                  * leave behind on the page, plus space for final item's line
                               1297                 :                :                  * pointer.  This is equal to the space that we'd like to
                               1298                 :                :                  * leave behind on each leaf page when fillfactor is 90,
                               1299                 :                :                  * allowing us to get close to fillfactor% space utilization
                               1300                 :                :                  * when there happen to be a great many duplicates.  (This
                               1301                 :                :                  * makes higher leaf fillfactor settings ineffective when
                               1302                 :                :                  * building indexes that have many duplicates, but packing
                               1303                 :                :                  * leaf pages full with few very large tuples doesn't seem
                               1304                 :                :                  * like a useful goal.)
                               1305                 :                :                  */
                               1306                 :           1169 :                 dstate->maxpostingsize = MAXALIGN_DOWN((BLCKSZ * 10 / 100)) -
                               1307                 :                :                     sizeof(ItemIdData);
  179                          1308   [ +  -  -  + ]:           1169 :                 Assert(dstate->maxpostingsize <= BTMaxItemSize &&
                               1309                 :                :                        dstate->maxpostingsize <= INDEX_SIZE_MASK);
 2019                          1310                 :           1169 :                 dstate->htids = palloc(dstate->maxpostingsize);
                               1311                 :                : 
                               1312                 :                :                 /* start new pending posting list with itup copy */
                               1313                 :           1169 :                 _bt_dedup_start_pending(dstate, CopyIndexTuple(itup),
                               1314                 :                :                                         InvalidOffsetNumber);
                               1315                 :                :             }
                               1316         [ +  + ]:        3034211 :             else if (_bt_keep_natts_fast(wstate->index, dstate->base,
                               1317         [ +  + ]:         680425 :                                          itup) > keysz &&
                               1318                 :         680425 :                      _bt_dedup_save_htid(dstate, itup))
                               1319                 :                :             {
                               1320                 :                :                 /*
                               1321                 :                :                  * Tuple is equal to base tuple of pending posting list.  Heap
                               1322                 :                :                  * TID from itup has been saved in state.
                               1323                 :                :                  */
                               1324                 :                :             }
                               1325                 :                :             else
                               1326                 :                :             {
                               1327                 :                :                 /*
                               1328                 :                :                  * Tuple is not equal to pending posting list tuple, or
                               1329                 :                :                  * _bt_dedup_save_htid() opted to not merge current item into
                               1330                 :                :                  * pending posting list.
                               1331                 :                :                  */
                               1332                 :        2357709 :                 _bt_sort_dedup_finish_pending(wstate, state, dstate);
                               1333                 :        2357709 :                 pfree(dstate->base);
                               1334                 :                : 
                               1335                 :                :                 /* start new pending posting list with itup copy */
                               1336                 :        2357709 :                 _bt_dedup_start_pending(dstate, CopyIndexTuple(itup),
                               1337                 :                :                                         InvalidOffsetNumber);
                               1338                 :                :             }
                               1339                 :                : 
                               1340                 :                :             /* Report progress */
                               1341                 :        3035380 :             pgstat_progress_update_param(PROGRESS_CREATEIDX_TUPLES_DONE,
                               1342                 :                :                                          ++tuples_done);
                               1343                 :                :         }
                               1344                 :                : 
                               1345         [ +  + ]:           4417 :         if (state)
                               1346                 :                :         {
                               1347                 :                :             /*
                               1348                 :                :              * Handle the last item (there must be a last item when the
                               1349                 :                :              * tuplesort returned one or more tuples)
                               1350                 :                :              */
                               1351                 :           1169 :             _bt_sort_dedup_finish_pending(wstate, state, dstate);
                               1352                 :           1169 :             pfree(dstate->base);
                               1353                 :           1169 :             pfree(dstate->htids);
                               1354                 :                :         }
                               1355                 :                : 
                               1356                 :           4417 :         pfree(dstate);
                               1357                 :                :     }
                               1358                 :                :     else
                               1359                 :                :     {
                               1360                 :                :         /* merging and deduplication are both unnecessary */
 7164 tgl@sss.pgh.pa.us        1361                 :        3357179 :         while ((itup = tuplesort_getindextuple(btspool->sortstate,
 3190 rhaas@postgresql.org     1362         [ +  + ]:        3357179 :                                                true)) != NULL)
                               1363                 :                :         {
                               1364                 :                :             /* When we see first tuple, create first index page */
 9158 inoue@tpf.co.jp          1365         [ +  + ]:        3336582 :             if (state == NULL)
 7766 tgl@sss.pgh.pa.us        1366                 :           3843 :                 state = _bt_pagestate(wstate, 0);
                               1367                 :                : 
 2019 pg@bowt.ie               1368                 :        3336582 :             _bt_buildadd(wstate, state, itup, 0);
                               1369                 :                : 
                               1370                 :                :             /* Report progress */
 2349 alvherre@alvh.no-ip.     1371                 :        3336582 :             pgstat_progress_update_param(PROGRESS_CREATEIDX_TUPLES_DONE,
                               1372                 :                :                                          ++tuples_done);
                               1373                 :                :         }
                               1374                 :                :     }
                               1375                 :                : 
                               1376                 :                :     /* Close down final pages and write the metapage */
 7766 tgl@sss.pgh.pa.us        1377                 :          25025 :     _bt_uppershutdown(wstate, state);
  561 heikki.linnakangas@i     1378                 :          25025 :     smgr_bulk_finish(wstate->bulkstate);
10651 scrappy@hub.org          1379                 :          25025 : }
                               1380                 :                : 
                               1381                 :                : /*
                               1382                 :                :  * Create parallel context, and launch workers for leader.
                               1383                 :                :  *
                               1384                 :                :  * buildstate argument should be initialized (with the exception of the
                               1385                 :                :  * tuplesort state in spools, which may later be created based on shared
                               1386                 :                :  * state initially set up here).
                               1387                 :                :  *
                               1388                 :                :  * isconcurrent indicates if operation is CREATE INDEX CONCURRENTLY.
                               1389                 :                :  *
                               1390                 :                :  * request is the target number of parallel worker processes to launch.
                               1391                 :                :  *
                               1392                 :                :  * Sets buildstate's BTLeader, which caller must use to shut down parallel
                               1393                 :                :  * mode by passing it to _bt_end_parallel() at the very end of its index
                               1394                 :                :  * build.  If not even a single worker process can be launched, this is
                               1395                 :                :  * never set, and caller should proceed with a serial index build.
                               1396                 :                :  */
                               1397                 :                : static void
 2773 rhaas@postgresql.org     1398                 :             74 : _bt_begin_parallel(BTBuildState *buildstate, bool isconcurrent, int request)
                               1399                 :                : {
                               1400                 :                :     ParallelContext *pcxt;
                               1401                 :                :     int         scantuplesortstates;
                               1402                 :                :     Snapshot    snapshot;
                               1403                 :                :     Size        estbtshared;
                               1404                 :                :     Size        estsort;
                               1405                 :                :     BTShared   *btshared;
                               1406                 :                :     Sharedsort *sharedsort;
                               1407                 :                :     Sharedsort *sharedsort2;
                               1408                 :             74 :     BTSpool    *btspool = buildstate->spool;
                               1409                 :             74 :     BTLeader   *btleader = (BTLeader *) palloc0(sizeof(BTLeader));
                               1410                 :                :     WalUsage   *walusage;
                               1411                 :                :     BufferUsage *bufferusage;
                               1412                 :             74 :     bool        leaderparticipates = true;
                               1413                 :                :     int         querylen;
                               1414                 :                : 
                               1415                 :                : #ifdef DISABLE_LEADER_PARTICIPATION
                               1416                 :                :     leaderparticipates = false;
                               1417                 :                : #endif
                               1418                 :                : 
                               1419                 :                :     /*
                               1420                 :                :      * Enter parallel mode, and create context for parallel build of btree
                               1421                 :                :      * index
                               1422                 :                :      */
                               1423                 :             74 :     EnterParallelMode();
                               1424         [ -  + ]:             74 :     Assert(request > 0);
                               1425                 :             74 :     pcxt = CreateParallelContext("postgres", "_bt_parallel_build_main",
                               1426                 :                :                                  request);
                               1427                 :                : 
                               1428         [ +  - ]:             74 :     scantuplesortstates = leaderparticipates ? request + 1 : request;
                               1429                 :                : 
                               1430                 :                :     /*
                               1431                 :                :      * Prepare for scan of the base relation.  In a normal index build, we use
                               1432                 :                :      * SnapshotAny because we must retrieve all tuples and do our own time
                               1433                 :                :      * qual checks (because we have to index RECENTLY_DEAD tuples).  In a
                               1434                 :                :      * concurrent build, we take a regular MVCC snapshot and index whatever's
                               1435                 :                :      * live according to that.
                               1436                 :                :      */
                               1437         [ +  - ]:             74 :     if (!isconcurrent)
                               1438                 :             74 :         snapshot = SnapshotAny;
                               1439                 :                :     else
 2773 rhaas@postgresql.org     1440                 :UBC           0 :         snapshot = RegisterSnapshot(GetTransactionSnapshot());
                               1441                 :                : 
                               1442                 :                :     /*
                               1443                 :                :      * Estimate size for our own PARALLEL_KEY_BTREE_SHARED workspace, and
                               1444                 :                :      * PARALLEL_KEY_TUPLESORT tuplesort workspace
                               1445                 :                :      */
 2371 andres@anarazel.de       1446                 :CBC          74 :     estbtshared = _bt_parallel_estimate_shared(btspool->heap, snapshot);
 2773 rhaas@postgresql.org     1447                 :             74 :     shm_toc_estimate_chunk(&pcxt->estimator, estbtshared);
                               1448                 :             74 :     estsort = tuplesort_estimate_shared(scantuplesortstates);
                               1449                 :             74 :     shm_toc_estimate_chunk(&pcxt->estimator, estsort);
                               1450                 :                : 
                               1451                 :                :     /*
                               1452                 :                :      * Unique case requires a second spool, and so we may have to account for
                               1453                 :                :      * another shared workspace for that -- PARALLEL_KEY_TUPLESORT_SPOOL2
                               1454                 :                :      */
                               1455         [ +  + ]:             74 :     if (!btspool->isunique)
                               1456                 :             42 :         shm_toc_estimate_keys(&pcxt->estimator, 2);
                               1457                 :                :     else
                               1458                 :                :     {
                               1459                 :             32 :         shm_toc_estimate_chunk(&pcxt->estimator, estsort);
                               1460                 :             32 :         shm_toc_estimate_keys(&pcxt->estimator, 3);
                               1461                 :                :     }
                               1462                 :                : 
                               1463                 :                :     /*
                               1464                 :                :      * Estimate space for WalUsage and BufferUsage -- PARALLEL_KEY_WAL_USAGE
                               1465                 :                :      * and PARALLEL_KEY_BUFFER_USAGE.
                               1466                 :                :      *
                               1467                 :                :      * If there are no extensions loaded that care, we could skip this.  We
                               1468                 :                :      * have no way of knowing whether anyone's looking at pgWalUsage or
                               1469                 :                :      * pgBufferUsage, so do it unconditionally.
                               1470                 :                :      */
 1981 akapila@postgresql.o     1471                 :             74 :     shm_toc_estimate_chunk(&pcxt->estimator,
                               1472                 :                :                            mul_size(sizeof(WalUsage), pcxt->nworkers));
                               1473                 :             74 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
 1976                          1474                 :             74 :     shm_toc_estimate_chunk(&pcxt->estimator,
                               1475                 :                :                            mul_size(sizeof(BufferUsage), pcxt->nworkers));
                               1476                 :             74 :     shm_toc_estimate_keys(&pcxt->estimator, 1);
                               1477                 :                : 
                               1478                 :                :     /* Finally, estimate PARALLEL_KEY_QUERY_TEXT space */
 1771 noah@leadboat.com        1479         [ +  - ]:             74 :     if (debug_query_string)
                               1480                 :                :     {
                               1481                 :             74 :         querylen = strlen(debug_query_string);
                               1482                 :             74 :         shm_toc_estimate_chunk(&pcxt->estimator, querylen + 1);
                               1483                 :             74 :         shm_toc_estimate_keys(&pcxt->estimator, 1);
                               1484                 :                :     }
                               1485                 :                :     else
 1771 noah@leadboat.com        1486                 :UBC           0 :         querylen = 0;           /* keep compiler quiet */
                               1487                 :                : 
                               1488                 :                :     /* Everyone's had a chance to ask for space, so now create the DSM */
 2773 rhaas@postgresql.org     1489                 :CBC          74 :     InitializeParallelDSM(pcxt);
                               1490                 :                : 
                               1491                 :                :     /* If no DSM segment was available, back out (do serial build) */
 2040 tmunro@postgresql.or     1492         [ -  + ]:             74 :     if (pcxt->seg == NULL)
                               1493                 :                :     {
 2040 tmunro@postgresql.or     1494   [ #  #  #  # ]:UBC           0 :         if (IsMVCCSnapshot(snapshot))
                               1495                 :              0 :             UnregisterSnapshot(snapshot);
                               1496                 :              0 :         DestroyParallelContext(pcxt);
                               1497                 :              0 :         ExitParallelMode();
                               1498                 :              0 :         return;
                               1499                 :                :     }
                               1500                 :                : 
                               1501                 :                :     /* Store shared build state, for which we reserved space */
 2773 rhaas@postgresql.org     1502                 :CBC          74 :     btshared = (BTShared *) shm_toc_allocate(pcxt->toc, estbtshared);
                               1503                 :                :     /* Initialize immutable state */
                               1504                 :             74 :     btshared->heaprelid = RelationGetRelid(btspool->heap);
                               1505                 :             74 :     btshared->indexrelid = RelationGetRelid(btspool->index);
                               1506                 :             74 :     btshared->isunique = btspool->isunique;
 1311 peter@eisentraut.org     1507                 :             74 :     btshared->nulls_not_distinct = btspool->nulls_not_distinct;
 2773 rhaas@postgresql.org     1508                 :             74 :     btshared->isconcurrent = isconcurrent;
                               1509                 :             74 :     btshared->scantuplesortstates = scantuplesortstates;
  341 michael@paquier.xyz      1510                 :             74 :     btshared->queryid = pgstat_get_my_query_id();
 2773 rhaas@postgresql.org     1511                 :             74 :     ConditionVariableInit(&btshared->workersdonecv);
                               1512                 :             74 :     SpinLockInit(&btshared->mutex);
                               1513                 :                :     /* Initialize mutable state */
                               1514                 :             74 :     btshared->nparticipantsdone = 0;
                               1515                 :             74 :     btshared->reltuples = 0.0;
                               1516                 :             74 :     btshared->havedead = false;
                               1517                 :             74 :     btshared->indtuples = 0.0;
                               1518                 :             74 :     btshared->brokenhotchain = false;
 2371 andres@anarazel.de       1519                 :             74 :     table_parallelscan_initialize(btspool->heap,
                               1520                 :                :                                   ParallelTableScanFromBTShared(btshared),
                               1521                 :                :                                   snapshot);
                               1522                 :                : 
                               1523                 :                :     /*
                               1524                 :                :      * Store shared tuplesort-private state, for which we reserved space.
                               1525                 :                :      * Then, initialize opaque state using tuplesort routine.
                               1526                 :                :      */
 2773 rhaas@postgresql.org     1527                 :             74 :     sharedsort = (Sharedsort *) shm_toc_allocate(pcxt->toc, estsort);
                               1528                 :             74 :     tuplesort_initialize_shared(sharedsort, scantuplesortstates,
                               1529                 :                :                                 pcxt->seg);
                               1530                 :                : 
                               1531                 :             74 :     shm_toc_insert(pcxt->toc, PARALLEL_KEY_BTREE_SHARED, btshared);
                               1532                 :             74 :     shm_toc_insert(pcxt->toc, PARALLEL_KEY_TUPLESORT, sharedsort);
                               1533                 :                : 
                               1534                 :                :     /* Unique case requires a second spool, and associated shared state */
                               1535         [ +  + ]:             74 :     if (!btspool->isunique)
                               1536                 :             42 :         sharedsort2 = NULL;
                               1537                 :                :     else
                               1538                 :                :     {
                               1539                 :                :         /*
                               1540                 :                :          * Store additional shared tuplesort-private state, for which we
                               1541                 :                :          * reserved space.  Then, initialize opaque state using tuplesort
                               1542                 :                :          * routine.
                               1543                 :                :          */
                               1544                 :             32 :         sharedsort2 = (Sharedsort *) shm_toc_allocate(pcxt->toc, estsort);
                               1545                 :             32 :         tuplesort_initialize_shared(sharedsort2, scantuplesortstates,
                               1546                 :                :                                     pcxt->seg);
                               1547                 :                : 
                               1548                 :             32 :         shm_toc_insert(pcxt->toc, PARALLEL_KEY_TUPLESORT_SPOOL2, sharedsort2);
                               1549                 :                :     }
                               1550                 :                : 
                               1551                 :                :     /* Store query string for workers */
 1771 noah@leadboat.com        1552         [ +  - ]:             74 :     if (debug_query_string)
                               1553                 :                :     {
                               1554                 :                :         char       *sharedquery;
                               1555                 :                : 
                               1556                 :             74 :         sharedquery = (char *) shm_toc_allocate(pcxt->toc, querylen + 1);
                               1557                 :             74 :         memcpy(sharedquery, debug_query_string, querylen + 1);
                               1558                 :             74 :         shm_toc_insert(pcxt->toc, PARALLEL_KEY_QUERY_TEXT, sharedquery);
                               1559                 :                :     }
                               1560                 :                : 
                               1561                 :                :     /*
                               1562                 :                :      * Allocate space for each worker's WalUsage and BufferUsage; no need to
                               1563                 :                :      * initialize.
                               1564                 :                :      */
 1981 akapila@postgresql.o     1565                 :             74 :     walusage = shm_toc_allocate(pcxt->toc,
                               1566                 :             74 :                                 mul_size(sizeof(WalUsage), pcxt->nworkers));
                               1567                 :             74 :     shm_toc_insert(pcxt->toc, PARALLEL_KEY_WAL_USAGE, walusage);
 1976                          1568                 :             74 :     bufferusage = shm_toc_allocate(pcxt->toc,
                               1569                 :             74 :                                    mul_size(sizeof(BufferUsage), pcxt->nworkers));
                               1570                 :             74 :     shm_toc_insert(pcxt->toc, PARALLEL_KEY_BUFFER_USAGE, bufferusage);
                               1571                 :                : 
                               1572                 :                :     /* Launch workers, saving status for leader/caller */
 2773 rhaas@postgresql.org     1573                 :             74 :     LaunchParallelWorkers(pcxt);
                               1574                 :             74 :     btleader->pcxt = pcxt;
                               1575                 :             74 :     btleader->nparticipanttuplesorts = pcxt->nworkers_launched;
                               1576         [ +  - ]:             74 :     if (leaderparticipates)
                               1577                 :             74 :         btleader->nparticipanttuplesorts++;
                               1578                 :             74 :     btleader->btshared = btshared;
                               1579                 :             74 :     btleader->sharedsort = sharedsort;
                               1580                 :             74 :     btleader->sharedsort2 = sharedsort2;
                               1581                 :             74 :     btleader->snapshot = snapshot;
 1981 akapila@postgresql.o     1582                 :             74 :     btleader->walusage = walusage;
 1976                          1583                 :             74 :     btleader->bufferusage = bufferusage;
                               1584                 :                : 
                               1585                 :                :     /* If no workers were successfully launched, back out (do serial build) */
 2773 rhaas@postgresql.org     1586         [ -  + ]:             74 :     if (pcxt->nworkers_launched == 0)
                               1587                 :                :     {
 2773 rhaas@postgresql.org     1588                 :UBC           0 :         _bt_end_parallel(btleader);
                               1589                 :              0 :         return;
                               1590                 :                :     }
                               1591                 :                : 
                               1592                 :                :     /* Save leader state now that it's clear build will be parallel */
 2773 rhaas@postgresql.org     1593                 :CBC          74 :     buildstate->btleader = btleader;
                               1594                 :                : 
                               1595                 :                :     /* Join heap scan ourselves */
                               1596         [ +  - ]:             74 :     if (leaderparticipates)
                               1597                 :             74 :         _bt_leader_participate_as_worker(buildstate);
                               1598                 :                : 
                               1599                 :                :     /*
                               1600                 :                :      * Caller needs to wait for all launched workers when we return.  Make
                               1601                 :                :      * sure that the failure-to-start case will not hang forever.
                               1602                 :                :      */
                               1603                 :             74 :     WaitForParallelWorkersToAttach(pcxt);
                               1604                 :                : }
                               1605                 :                : 
                               1606                 :                : /*
                               1607                 :                :  * Shut down workers, destroy parallel context, and end parallel mode.
                               1608                 :                :  */
                               1609                 :                : static void
                               1610                 :             74 : _bt_end_parallel(BTLeader *btleader)
                               1611                 :                : {
                               1612                 :                :     int         i;
                               1613                 :                : 
                               1614                 :                :     /* Shutdown worker processes */
                               1615                 :             74 :     WaitForParallelWorkersToFinish(btleader->pcxt);
                               1616                 :                : 
                               1617                 :                :     /*
                               1618                 :                :      * Next, accumulate WAL usage.  (This must wait for the workers to finish,
                               1619                 :                :      * or we might get incomplete data.)
                               1620                 :                :      */
 1981 akapila@postgresql.o     1621         [ +  + ]:            148 :     for (i = 0; i < btleader->pcxt->nworkers_launched; i++)
 1976                          1622                 :             74 :         InstrAccumParallelQuery(&btleader->bufferusage[i], &btleader->walusage[i]);
                               1623                 :                : 
                               1624                 :                :     /* Free last reference to MVCC snapshot, if one was used */
 2773 rhaas@postgresql.org     1625   [ +  -  -  + ]:             74 :     if (IsMVCCSnapshot(btleader->snapshot))
 2773 rhaas@postgresql.org     1626                 :UBC           0 :         UnregisterSnapshot(btleader->snapshot);
 2773 rhaas@postgresql.org     1627                 :CBC          74 :     DestroyParallelContext(btleader->pcxt);
                               1628                 :             74 :     ExitParallelMode();
                               1629                 :             74 : }
                               1630                 :                : 
                               1631                 :                : /*
                               1632                 :                :  * Returns size of shared memory required to store state for a parallel
                               1633                 :                :  * btree index build based on the snapshot its parallel scan will use.
                               1634                 :                :  */
                               1635                 :                : static Size
 2371 andres@anarazel.de       1636                 :             74 : _bt_parallel_estimate_shared(Relation heap, Snapshot snapshot)
                               1637                 :                : {
                               1638                 :                :     /* c.f. shm_toc_allocate as to why BUFFERALIGN is used */
                               1639                 :             74 :     return add_size(BUFFERALIGN(sizeof(BTShared)),
                               1640                 :                :                     table_parallelscan_estimate(heap, snapshot));
                               1641                 :                : }
                               1642                 :                : 
                               1643                 :                : /*
                               1644                 :                :  * Within leader, wait for end of heap scan.
                               1645                 :                :  *
                               1646                 :                :  * When called, parallel heap scan started by _bt_begin_parallel() will
                               1647                 :                :  * already be underway within worker processes (when leader participates
                               1648                 :                :  * as a worker, we should end up here just as workers are finishing).
                               1649                 :                :  *
                               1650                 :                :  * Fills in fields needed for ambuild statistics, and lets caller set
                               1651                 :                :  * field indicating that some worker encountered a broken HOT chain.
                               1652                 :                :  *
                               1653                 :                :  * Returns the total number of heap tuples scanned.
                               1654                 :                :  */
                               1655                 :                : static double
 2773 rhaas@postgresql.org     1656                 :             74 : _bt_parallel_heapscan(BTBuildState *buildstate, bool *brokenhotchain)
                               1657                 :                : {
                               1658                 :             74 :     BTShared   *btshared = buildstate->btleader->btshared;
                               1659                 :                :     int         nparticipanttuplesorts;
                               1660                 :                :     double      reltuples;
                               1661                 :                : 
                               1662                 :             74 :     nparticipanttuplesorts = buildstate->btleader->nparticipanttuplesorts;
                               1663                 :                :     for (;;)
                               1664                 :                :     {
                               1665         [ -  + ]:            202 :         SpinLockAcquire(&btshared->mutex);
                               1666         [ +  + ]:            202 :         if (btshared->nparticipantsdone == nparticipanttuplesorts)
                               1667                 :                :         {
                               1668                 :             74 :             buildstate->havedead = btshared->havedead;
                               1669                 :             74 :             buildstate->indtuples = btshared->indtuples;
                               1670                 :             74 :             *brokenhotchain = btshared->brokenhotchain;
                               1671                 :             74 :             reltuples = btshared->reltuples;
                               1672                 :             74 :             SpinLockRelease(&btshared->mutex);
                               1673                 :             74 :             break;
                               1674                 :                :         }
                               1675                 :            128 :         SpinLockRelease(&btshared->mutex);
                               1676                 :                : 
                               1677                 :            128 :         ConditionVariableSleep(&btshared->workersdonecv,
                               1678                 :                :                                WAIT_EVENT_PARALLEL_CREATE_INDEX_SCAN);
                               1679                 :                :     }
                               1680                 :                : 
                               1681                 :             74 :     ConditionVariableCancelSleep();
                               1682                 :                : 
                               1683                 :             74 :     return reltuples;
                               1684                 :                : }
                               1685                 :                : 
                               1686                 :                : /*
                               1687                 :                :  * Within leader, participate as a parallel worker.
                               1688                 :                :  */
                               1689                 :                : static void
                               1690                 :             74 : _bt_leader_participate_as_worker(BTBuildState *buildstate)
                               1691                 :                : {
                               1692                 :             74 :     BTLeader   *btleader = buildstate->btleader;
                               1693                 :                :     BTSpool    *leaderworker;
                               1694                 :                :     BTSpool    *leaderworker2;
                               1695                 :                :     int         sortmem;
                               1696                 :                : 
                               1697                 :                :     /* Allocate memory and initialize private spool */
                               1698                 :             74 :     leaderworker = (BTSpool *) palloc0(sizeof(BTSpool));
                               1699                 :             74 :     leaderworker->heap = buildstate->spool->heap;
                               1700                 :             74 :     leaderworker->index = buildstate->spool->index;
                               1701                 :             74 :     leaderworker->isunique = buildstate->spool->isunique;
 1311 peter@eisentraut.org     1702                 :             74 :     leaderworker->nulls_not_distinct = buildstate->spool->nulls_not_distinct;
                               1703                 :                : 
                               1704                 :                :     /* Initialize second spool, if required */
 2773 rhaas@postgresql.org     1705         [ +  + ]:             74 :     if (!btleader->btshared->isunique)
                               1706                 :             42 :         leaderworker2 = NULL;
                               1707                 :                :     else
                               1708                 :                :     {
                               1709                 :                :         /* Allocate memory for worker's own private secondary spool */
                               1710                 :             32 :         leaderworker2 = (BTSpool *) palloc0(sizeof(BTSpool));
                               1711                 :                : 
                               1712                 :                :         /* Initialize worker's own secondary spool */
                               1713                 :             32 :         leaderworker2->heap = leaderworker->heap;
                               1714                 :             32 :         leaderworker2->index = leaderworker->index;
                               1715                 :             32 :         leaderworker2->isunique = false;
                               1716                 :                :     }
                               1717                 :                : 
                               1718                 :                :     /*
                               1719                 :                :      * Might as well use reliable figure when doling out maintenance_work_mem
                               1720                 :                :      * (when requested number of workers were not launched, this will be
                               1721                 :                :      * somewhat higher than it is for other workers).
                               1722                 :                :      */
                               1723                 :             74 :     sortmem = maintenance_work_mem / btleader->nparticipanttuplesorts;
                               1724                 :                : 
                               1725                 :                :     /* Perform work common to all participants */
                               1726                 :             74 :     _bt_parallel_scan_and_sort(leaderworker, leaderworker2, btleader->btshared,
                               1727                 :                :                                btleader->sharedsort, btleader->sharedsort2,
                               1728                 :                :                                sortmem, true);
                               1729                 :                : 
                               1730                 :                : #ifdef BTREE_BUILD_STATS
                               1731                 :                :     if (log_btree_build_stats)
                               1732                 :                :     {
                               1733                 :                :         ShowUsage("BTREE BUILD (Leader Partial Spool) STATISTICS");
                               1734                 :                :         ResetUsage();
                               1735                 :                :     }
                               1736                 :                : #endif                          /* BTREE_BUILD_STATS */
                               1737                 :             74 : }
                               1738                 :                : 
                               1739                 :                : /*
                               1740                 :                :  * Perform work within a launched parallel process.
                               1741                 :                :  */
                               1742                 :                : void
                               1743                 :             74 : _bt_parallel_build_main(dsm_segment *seg, shm_toc *toc)
                               1744                 :                : {
                               1745                 :                :     char       *sharedquery;
                               1746                 :                :     BTSpool    *btspool;
                               1747                 :                :     BTSpool    *btspool2;
                               1748                 :                :     BTShared   *btshared;
                               1749                 :                :     Sharedsort *sharedsort;
                               1750                 :                :     Sharedsort *sharedsort2;
                               1751                 :                :     Relation    heapRel;
                               1752                 :                :     Relation    indexRel;
                               1753                 :                :     LOCKMODE    heapLockmode;
                               1754                 :                :     LOCKMODE    indexLockmode;
                               1755                 :                :     WalUsage   *walusage;
                               1756                 :                :     BufferUsage *bufferusage;
                               1757                 :                :     int         sortmem;
                               1758                 :                : 
                               1759                 :                : #ifdef BTREE_BUILD_STATS
                               1760                 :                :     if (log_btree_build_stats)
                               1761                 :                :         ResetUsage();
                               1762                 :                : #endif                          /* BTREE_BUILD_STATS */
                               1763                 :                : 
                               1764                 :                :     /*
                               1765                 :                :      * The only possible status flag that can be set to the parallel worker is
                               1766                 :                :      * PROC_IN_SAFE_IC.
                               1767                 :                :      */
 1387 akapila@postgresql.o     1768   [ -  +  -  - ]:             74 :     Assert((MyProc->statusFlags == 0) ||
                               1769                 :                :            (MyProc->statusFlags == PROC_IN_SAFE_IC));
                               1770                 :                : 
                               1771                 :                :     /* Set debug_query_string for individual workers first */
 1771 noah@leadboat.com        1772                 :             74 :     sharedquery = shm_toc_lookup(toc, PARALLEL_KEY_QUERY_TEXT, true);
 2725 rhaas@postgresql.org     1773                 :             74 :     debug_query_string = sharedquery;
                               1774                 :                : 
                               1775                 :                :     /* Report the query string from leader */
                               1776                 :             74 :     pgstat_report_activity(STATE_RUNNING, debug_query_string);
                               1777                 :                : 
                               1778                 :                :     /* Look up nbtree shared state */
 2773                          1779                 :             74 :     btshared = shm_toc_lookup(toc, PARALLEL_KEY_BTREE_SHARED, false);
                               1780                 :                : 
                               1781                 :                :     /* Open relations using lock modes known to be obtained by index.c */
                               1782         [ +  - ]:             74 :     if (!btshared->isconcurrent)
                               1783                 :                :     {
                               1784                 :             74 :         heapLockmode = ShareLock;
                               1785                 :             74 :         indexLockmode = AccessExclusiveLock;
                               1786                 :                :     }
                               1787                 :                :     else
                               1788                 :                :     {
 2773 rhaas@postgresql.org     1789                 :UBC           0 :         heapLockmode = ShareUpdateExclusiveLock;
                               1790                 :              0 :         indexLockmode = RowExclusiveLock;
                               1791                 :                :     }
                               1792                 :                : 
                               1793                 :                :     /* Track query ID */
  341 michael@paquier.xyz      1794                 :CBC          74 :     pgstat_report_query_id(btshared->queryid, false);
                               1795                 :                : 
                               1796                 :                :     /* Open relations within worker */
 2420 andres@anarazel.de       1797                 :             74 :     heapRel = table_open(btshared->heaprelid, heapLockmode);
 2773 rhaas@postgresql.org     1798                 :             74 :     indexRel = index_open(btshared->indexrelid, indexLockmode);
                               1799                 :                : 
                               1800                 :                :     /* Initialize worker's own spool */
                               1801                 :             74 :     btspool = (BTSpool *) palloc0(sizeof(BTSpool));
                               1802                 :             74 :     btspool->heap = heapRel;
                               1803                 :             74 :     btspool->index = indexRel;
                               1804                 :             74 :     btspool->isunique = btshared->isunique;
 1311 peter@eisentraut.org     1805                 :             74 :     btspool->nulls_not_distinct = btshared->nulls_not_distinct;
                               1806                 :                : 
                               1807                 :                :     /* Look up shared state private to tuplesort.c */
 2773 rhaas@postgresql.org     1808                 :             74 :     sharedsort = shm_toc_lookup(toc, PARALLEL_KEY_TUPLESORT, false);
                               1809                 :             74 :     tuplesort_attach_shared(sharedsort, seg);
                               1810         [ +  + ]:             74 :     if (!btshared->isunique)
                               1811                 :                :     {
                               1812                 :             42 :         btspool2 = NULL;
                               1813                 :             42 :         sharedsort2 = NULL;
                               1814                 :                :     }
                               1815                 :                :     else
                               1816                 :                :     {
                               1817                 :                :         /* Allocate memory for worker's own private secondary spool */
                               1818                 :             32 :         btspool2 = (BTSpool *) palloc0(sizeof(BTSpool));
                               1819                 :                : 
                               1820                 :                :         /* Initialize worker's own secondary spool */
                               1821                 :             32 :         btspool2->heap = btspool->heap;
                               1822                 :             32 :         btspool2->index = btspool->index;
                               1823                 :             32 :         btspool2->isunique = false;
                               1824                 :                :         /* Look up shared state private to tuplesort.c */
                               1825                 :             32 :         sharedsort2 = shm_toc_lookup(toc, PARALLEL_KEY_TUPLESORT_SPOOL2, false);
                               1826                 :             32 :         tuplesort_attach_shared(sharedsort2, seg);
                               1827                 :                :     }
                               1828                 :                : 
                               1829                 :                :     /* Prepare to track buffer usage during parallel execution */
 1981 akapila@postgresql.o     1830                 :             74 :     InstrStartParallelQuery();
                               1831                 :                : 
                               1832                 :                :     /* Perform sorting of spool, and possibly a spool2 */
 2773 rhaas@postgresql.org     1833                 :             74 :     sortmem = maintenance_work_mem / btshared->scantuplesortstates;
                               1834                 :             74 :     _bt_parallel_scan_and_sort(btspool, btspool2, btshared, sharedsort,
                               1835                 :                :                                sharedsort2, sortmem, false);
                               1836                 :                : 
                               1837                 :                :     /* Report WAL/buffer usage during parallel execution */
 1976 akapila@postgresql.o     1838                 :             74 :     bufferusage = shm_toc_lookup(toc, PARALLEL_KEY_BUFFER_USAGE, false);
 1981                          1839                 :             74 :     walusage = shm_toc_lookup(toc, PARALLEL_KEY_WAL_USAGE, false);
 1976                          1840                 :             74 :     InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
                               1841                 :             74 :                           &walusage[ParallelWorkerNumber]);
                               1842                 :                : 
                               1843                 :                : #ifdef BTREE_BUILD_STATS
                               1844                 :                :     if (log_btree_build_stats)
                               1845                 :                :     {
                               1846                 :                :         ShowUsage("BTREE BUILD (Worker Partial Spool) STATISTICS");
                               1847                 :                :         ResetUsage();
                               1848                 :                :     }
                               1849                 :                : #endif                          /* BTREE_BUILD_STATS */
                               1850                 :                : 
 2773 rhaas@postgresql.org     1851                 :             74 :     index_close(indexRel, indexLockmode);
 2420 andres@anarazel.de       1852                 :             74 :     table_close(heapRel, heapLockmode);
 2773 rhaas@postgresql.org     1853                 :             74 : }
                               1854                 :                : 
                               1855                 :                : /*
                               1856                 :                :  * Perform a worker's portion of a parallel sort.
                               1857                 :                :  *
                               1858                 :                :  * This generates a tuplesort for passed btspool, and a second tuplesort
                               1859                 :                :  * state if a second btspool is need (i.e. for unique index builds).  All
                               1860                 :                :  * other spool fields should already be set when this is called.
                               1861                 :                :  *
                               1862                 :                :  * sortmem is the amount of working memory to use within each worker,
                               1863                 :                :  * expressed in KBs.
                               1864                 :                :  *
                               1865                 :                :  * When this returns, workers are done, and need only release resources.
                               1866                 :                :  */
                               1867                 :                : static void
                               1868                 :            148 : _bt_parallel_scan_and_sort(BTSpool *btspool, BTSpool *btspool2,
                               1869                 :                :                            BTShared *btshared, Sharedsort *sharedsort,
                               1870                 :                :                            Sharedsort *sharedsort2, int sortmem, bool progress)
                               1871                 :                : {
                               1872                 :                :     SortCoordinate coordinate;
                               1873                 :                :     BTBuildState buildstate;
                               1874                 :                :     TableScanDesc scan;
                               1875                 :                :     double      reltuples;
                               1876                 :                :     IndexInfo  *indexInfo;
                               1877                 :                : 
                               1878                 :                :     /* Initialize local tuplesort coordination state */
                               1879                 :            148 :     coordinate = palloc0(sizeof(SortCoordinateData));
                               1880                 :            148 :     coordinate->isWorker = true;
                               1881                 :            148 :     coordinate->nParticipants = -1;
                               1882                 :            148 :     coordinate->sharedsort = sharedsort;
                               1883                 :                : 
                               1884                 :                :     /* Begin "partial" tuplesort */
                               1885                 :            296 :     btspool->sortstate = tuplesort_begin_index_btree(btspool->heap,
                               1886                 :                :                                                      btspool->index,
                               1887                 :            148 :                                                      btspool->isunique,
 1311 peter@eisentraut.org     1888                 :            148 :                                                      btspool->nulls_not_distinct,
                               1889                 :                :                                                      sortmem, coordinate,
                               1890                 :                :                                                      TUPLESORT_NONE);
                               1891                 :                : 
                               1892                 :                :     /*
                               1893                 :                :      * Just as with serial case, there may be a second spool.  If so, a
                               1894                 :                :      * second, dedicated spool2 partial tuplesort is required.
                               1895                 :                :      */
 2773 rhaas@postgresql.org     1896         [ +  + ]:            148 :     if (btspool2)
                               1897                 :                :     {
                               1898                 :                :         SortCoordinate coordinate2;
                               1899                 :                : 
                               1900                 :                :         /*
                               1901                 :                :          * We expect that the second one (for dead tuples) won't get very
                               1902                 :                :          * full, so we give it only work_mem (unless sortmem is less for
                               1903                 :                :          * worker).  Worker processes are generally permitted to allocate
                               1904                 :                :          * work_mem independently.
                               1905                 :                :          */
                               1906                 :             64 :         coordinate2 = palloc0(sizeof(SortCoordinateData));
                               1907                 :             64 :         coordinate2->isWorker = true;
                               1908                 :             64 :         coordinate2->nParticipants = -1;
                               1909                 :             64 :         coordinate2->sharedsort = sharedsort2;
                               1910                 :             64 :         btspool2->sortstate =
 1311 peter@eisentraut.org     1911                 :             64 :             tuplesort_begin_index_btree(btspool->heap, btspool->index, false, false,
                               1912                 :                :                                         Min(sortmem, work_mem), coordinate2,
                               1913                 :                :                                         false);
                               1914                 :                :     }
                               1915                 :                : 
                               1916                 :                :     /* Fill in buildstate for _bt_build_callback() */
 2773 rhaas@postgresql.org     1917                 :            148 :     buildstate.isunique = btshared->isunique;
 1311 peter@eisentraut.org     1918                 :            148 :     buildstate.nulls_not_distinct = btshared->nulls_not_distinct;
 2773 rhaas@postgresql.org     1919                 :            148 :     buildstate.havedead = false;
                               1920                 :            148 :     buildstate.heap = btspool->heap;
                               1921                 :            148 :     buildstate.spool = btspool;
                               1922                 :            148 :     buildstate.spool2 = btspool2;
                               1923                 :            148 :     buildstate.indtuples = 0;
                               1924                 :            148 :     buildstate.btleader = NULL;
                               1925                 :                : 
                               1926                 :                :     /* Join parallel scan */
                               1927                 :            148 :     indexInfo = BuildIndexInfo(btspool->index);
                               1928                 :            148 :     indexInfo->ii_Concurrent = btshared->isconcurrent;
 2349 alvherre@alvh.no-ip.     1929                 :            148 :     scan = table_beginscan_parallel(btspool->heap,
                               1930                 :                :                                     ParallelTableScanFromBTShared(btshared));
 2355 andres@anarazel.de       1931                 :            148 :     reltuples = table_index_build_scan(btspool->heap, btspool->index, indexInfo,
                               1932                 :                :                                        true, progress, _bt_build_callback,
                               1933                 :                :                                        &buildstate, scan);
                               1934                 :                : 
                               1935                 :                :     /* Execute this worker's part of the sort */
 1548 alvherre@alvh.no-ip.     1936         [ +  + ]:            148 :     if (progress)
                               1937                 :             74 :         pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE,
                               1938                 :                :                                      PROGRESS_BTREE_PHASE_PERFORMSORT_1);
 2773 rhaas@postgresql.org     1939                 :            148 :     tuplesort_performsort(btspool->sortstate);
                               1940         [ +  + ]:            148 :     if (btspool2)
                               1941                 :                :     {
 1548 alvherre@alvh.no-ip.     1942         [ +  + ]:             64 :         if (progress)
                               1943                 :             32 :             pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE,
                               1944                 :                :                                          PROGRESS_BTREE_PHASE_PERFORMSORT_2);
 2773 rhaas@postgresql.org     1945                 :             64 :         tuplesort_performsort(btspool2->sortstate);
                               1946                 :                :     }
                               1947                 :                : 
                               1948                 :                :     /*
                               1949                 :                :      * Done.  Record ambuild statistics, and whether we encountered a broken
                               1950                 :                :      * HOT chain.
                               1951                 :                :      */
                               1952         [ -  + ]:            148 :     SpinLockAcquire(&btshared->mutex);
                               1953                 :            148 :     btshared->nparticipantsdone++;
                               1954                 :            148 :     btshared->reltuples += reltuples;
                               1955         [ -  + ]:            148 :     if (buildstate.havedead)
 2773 rhaas@postgresql.org     1956                 :UBC           0 :         btshared->havedead = true;
 2773 rhaas@postgresql.org     1957                 :CBC         148 :     btshared->indtuples += buildstate.indtuples;
                               1958         [ -  + ]:            148 :     if (indexInfo->ii_BrokenHotChain)
 2773 rhaas@postgresql.org     1959                 :UBC           0 :         btshared->brokenhotchain = true;
 2773 rhaas@postgresql.org     1960                 :CBC         148 :     SpinLockRelease(&btshared->mutex);
                               1961                 :                : 
                               1962                 :                :     /* Notify leader */
                               1963                 :            148 :     ConditionVariableSignal(&btshared->workersdonecv);
                               1964                 :                : 
                               1965                 :                :     /* We can end tuplesorts immediately */
                               1966                 :            148 :     tuplesort_end(btspool->sortstate);
                               1967         [ +  + ]:            148 :     if (btspool2)
                               1968                 :             64 :         tuplesort_end(btspool2->sortstate);
                               1969                 :            148 : }
        

Generated by: LCOV version 2.4-beta