LCOV - differential code coverage report
Current view: top level - src/backend/postmaster - datachecksum_state.c (source / functions) Coverage Total Hit UNC LBC UBC GNC CBC DCB
Current: 77aeca80249c9e640c811e80633a2e334a9320de vs 38afc3dcb25c45b744d4025029ce0a6c90b7059f Lines: 75.5 % 511 386 125 2 384 2
Current Date: 2026-07-25 19:08:27 +0900 Functions: 90.0 % 20 18 2 2 16
Baseline: lcov-20260725-baseline Branches: 50.0 % 322 161 1 1 159 5 156
Baseline Date: 2026-07-25 19:09:19 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 94.4 % 18 17 1 2 15
(30,360] days: 74.8 % 493 369 124 369
Function coverage date bins:
(7,30] days: 100.0 % 1 1 1
(30,360] days: 89.5 % 19 17 2 1 16
Branch coverage date bins:
(7,30] days: 77.8 % 18 14 1 3 5 9
(30,360] days: 48.4 % 304 147 1 156 147

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * datachecksum_state.c
                                  4                 :                :  *    Background worker for enabling or disabling data checksums online as
                                  5                 :                :  *    well as functionality for manipulating data checksum state
                                  6                 :                :  *
                                  7                 :                :  * When enabling data checksums on a cluster at initdb time or when shut down
                                  8                 :                :  * with pg_checksums, no extra process is required as each page is checksummed,
                                  9                 :                :  * and verified, when accessed.  When enabling checksums on an already running
                                 10                 :                :  * cluster, this worker will ensure that all pages are checksummed before
                                 11                 :                :  * verification of the checksums is turned on. In the case of disabling
                                 12                 :                :  * checksums, the state transition is performed only in the control file, no
                                 13                 :                :  * changes are performed on the data pages.
                                 14                 :                :  *
                                 15                 :                :  * Checksums can be either enabled or disabled cluster-wide, with on/off being
                                 16                 :                :  * the end state for data_checksums.
                                 17                 :                :  *
                                 18                 :                :  * 1. Enabling checksums
                                 19                 :                :  * ---------------------
                                 20                 :                :  * When enabling checksums in an online cluster, data_checksums will be set to
                                 21                 :                :  * "inprogress-on" which signals that write operations MUST compute and write
                                 22                 :                :  * the checksum on the data page, but during reading the checksum SHALL NOT be
                                 23                 :                :  * verified. This ensures that all objects created while checksums are being
                                 24                 :                :  * enabled will have checksums set, but reads won't fail due to missing or
                                 25                 :                :  * invalid checksums. Invalid checksums can be present in case the cluster had
                                 26                 :                :  * checksums enabled, then disabled them and updated the page while they were
                                 27                 :                :  * disabled.
                                 28                 :                :  *
                                 29                 :                :  * The DataChecksumsWorker will compile a list of all databases at the start,
                                 30                 :                :  * any databases created concurrently will see the in-progress state and will
                                 31                 :                :  * be checksummed automatically.  All databases from the original list MUST BE
                                 32                 :                :  * successfully processed in order for data checksums to be enabled, the only
                                 33                 :                :  * exception are databases which are dropped before having been processed.
                                 34                 :                :  *
                                 35                 :                :  * For each database, all relations which have storage are read and every data
                                 36                 :                :  * page is marked dirty to force a write with the checksum. This will generate
                                 37                 :                :  * a lot of WAL as the entire database is read and written.
                                 38                 :                :  *
                                 39                 :                :  * If the processing is interrupted by a cluster crash or restart, it needs to
                                 40                 :                :  * be restarted from the beginning again as state isn't persisted.
                                 41                 :                :  *
                                 42                 :                :  * 2. Disabling checksums
                                 43                 :                :  * ----------------------
                                 44                 :                :  * When disabling checksums, data_checksums will be set to "inprogress-off"
                                 45                 :                :  * which signals that checksums are written but no longer need to be verified.
                                 46                 :                :  * This ensures that backends which have not yet transitioned to the
                                 47                 :                :  * "inprogress-off" state will still see valid checksums on pages.
                                 48                 :                :  *
                                 49                 :                :  * 3. Synchronization and Correctness
                                 50                 :                :  * ----------------------------------
                                 51                 :                :  * The processes involved in enabling or disabling data checksums in an
                                 52                 :                :  * online cluster must be properly synchronized with the normal backends
                                 53                 :                :  * serving concurrent queries to ensure correctness. Correctness is defined
                                 54                 :                :  * as the following:
                                 55                 :                :  *
                                 56                 :                :  *    - Backends SHALL NOT violate the data_checksums state they have agreed to
                                 57                 :                :  *      by acknowledging the procsignalbarrier:  This means that all backends
                                 58                 :                :  *      MUST calculate and write data checksums during all states except off;
                                 59                 :                :  *      MUST validate checksums only in the 'on' state.
                                 60                 :                :  *    - Data checksums SHALL NOT be considered enabled cluster-wide until all
                                 61                 :                :  *      currently connected backends have state "on": This means that all
                                 62                 :                :  *      backends must wait on the procsignalbarrier to be acknowledged by all
                                 63                 :                :  *      before proceeding to validate data checksums.
                                 64                 :                :  *
                                 65                 :                :  * There are two steps of synchronization required for changing data_checksums
                                 66                 :                :  * in an online cluster: (i) changing state in the active backends ("on",
                                 67                 :                :  * "off", "inprogress-on" and "inprogress-off"), and (ii) ensuring no
                                 68                 :                :  * incompatible objects and processes are left in a database when workers end.
                                 69                 :                :  * The former deals with cluster-wide agreement on data checksum state and the
                                 70                 :                :  * latter with ensuring that any concurrent activity cannot break the data
                                 71                 :                :  * checksum contract during processing.
                                 72                 :                :  *
                                 73                 :                :  * Synchronizing the state change is done with procsignal barriers. Before
                                 74                 :                :  * updating the data_checksums state in the control file, all other backends must absorb the
                                 75                 :                :  * barrier.  Barrier absorption will happen during interrupt processing, which
                                 76                 :                :  * means that connected backends will change state at different times.  If
                                 77                 :                :  * waiting for a barrier is done during startup, for example during replay, it
                                 78                 :                :  * is important to realize that any locks held by the startup process might
                                 79                 :                :  * cause deadlocks if backends end up waiting for those locks while startup
                                 80                 :                :  * is waiting for a procsignalbarrier.
                                 81                 :                :  *
                                 82                 :                :  * 3.1 When Enabling Data Checksums
                                 83                 :                :  * --------------------------------
                                 84                 :                :  * A process which fails to observe data checksums being enabled can induce two
                                 85                 :                :  * types of errors: failing to write the checksum when modifying the page and
                                 86                 :                :  * failing to validate the data checksum on the page when reading it.
                                 87                 :                :  *
                                 88                 :                :  * When processing starts all backends belong to one of the below sets, with
                                 89                 :                :  * one of Bd and Bi being empty:
                                 90                 :                :  *
                                 91                 :                :  * Bg: Backend updating the global state and emitting the procsignalbarrier
                                 92                 :                :  * Bd: Backends in "off" state
                                 93                 :                :  * Bi: Backends in "inprogress-on" state
                                 94                 :                :  *
                                 95                 :                :  * If processing is started in an online cluster then all backends are in Bd.
                                 96                 :                :  * If processing was halted by the cluster shutting down (due to a crash or
                                 97                 :                :  * intentional restart), the controlfile state "inprogress-on" will be observed
                                 98                 :                :  * on system startup and all backends will be placed in Bd. The controlfile
                                 99                 :                :  * state will also be set to "off".
                                100                 :                :  *
                                101                 :                :  * Backends transition Bd -> Bi via a procsignalbarrier which is emitted by the
                                102                 :                :  * DataChecksumsWorkerLauncherMain.  When all backends have acknowledged the
                                103                 :                :  * barrier then Bd will be empty and the next phase can begin: calculating and
                                104                 :                :  * writing data checksums with DataChecksumsWorkers.  When the
                                105                 :                :  * DataChecksumsWorker processes have finished writing checksums on all pages,
                                106                 :                :  * data checksums are enabled cluster-wide via another procsignalbarrier.
                                107                 :                :  * There are four sets of backends where Bd shall be an empty set:
                                108                 :                :  *
                                109                 :                :  * Bg: Backend updating the global state and emitting the procsignalbarrier
                                110                 :                :  * Bd: Backends in "off" state
                                111                 :                :  * Be: Backends in "on" state
                                112                 :                :  * Bi: Backends in "inprogress-on" state
                                113                 :                :  *
                                114                 :                :  * Backends in Bi and Be will write checksums when modifying a page, but only
                                115                 :                :  * backends in Be will verify the checksum during reading. The Bg backend is
                                116                 :                :  * blocked waiting for all backends in Bi to process interrupts and move to
                                117                 :                :  * Be. Any backend starting while Bg is waiting on the procsignalbarrier will
                                118                 :                :  * observe the global state being "on" and will thus automatically belong to
                                119                 :                :  * Be.  Checksums are enabled cluster-wide when Bi is an empty set. Bi and Be
                                120                 :                :  * are compatible sets while still operating based on their local state as
                                121                 :                :  * both write data checksums.
                                122                 :                :  *
                                123                 :                :  * 3.2 When Disabling Data Checksums
                                124                 :                :  * ---------------------------------
                                125                 :                :  * A process which fails to observe that data checksums have been disabled
                                126                 :                :  * can induce two types of errors: writing the checksum when modifying the
                                127                 :                :  * page and validating a data checksum which is no longer correct due to
                                128                 :                :  * modifications to the page. The former is not an error per se as data
                                129                 :                :  * integrity is maintained, but it is wasteful.  The latter will cause errors
                                130                 :                :  * in user operations.  Assuming the following sets of backends:
                                131                 :                :  *
                                132                 :                :  * Bg: Backend updating the global state and emitting the procsignalbarrier
                                133                 :                :  * Bd: Backends in "off" state
                                134                 :                :  * Be: Backends in "on" state
                                135                 :                :  * Bo: Backends in "inprogress-off" state
                                136                 :                :  * Bi: Backends in "inprogress-on" state
                                137                 :                :  *
                                138                 :                :  * Backends transition from the Be state to Bd like so: Be -> Bo -> Bd.  From
                                139                 :                :  * all other states, the transition can be straight to Bd.
                                140                 :                :  *
                                141                 :                :  * The goal is to transition all backends to Bd making the others empty sets.
                                142                 :                :  * Backends in Bo write data checksums, but don't validate them, such that
                                143                 :                :  * backends still in Be can continue to validate pages until the barrier has
                                144                 :                :  * been absorbed such that they are in Bo. Once all backends are in Bo, the
                                145                 :                :  * barrier to transition to "off" can be raised and all backends can safely
                                146                 :                :  * stop writing data checksums as no backend is enforcing data checksum
                                147                 :                :  * validation any longer.
                                148                 :                :  *
                                149                 :                :  * 4. Future opportunities for optimizations
                                150                 :                :  * -----------------------------------------
                                151                 :                :  * Below are some potential optimizations and improvements which were brought
                                152                 :                :  * up during reviews of this feature, but which weren't implemented in the
                                153                 :                :  * initial version. These are ideas listed without any validation on their
                                154                 :                :  * feasibility or potential payoff. More discussion on (most of) these can be
                                155                 :                :  * found on the -hackers threads linked to in the commit message of this
                                156                 :                :  * feature.
                                157                 :                :  *
                                158                 :                :  *   * Launching datachecksumsworker for resuming operation from the startup
                                159                 :                :  *     process: Currently users have to restart processing manually after a
                                160                 :                :  *     restart since dynamic background worker cannot be started from the
                                161                 :                :  *     postmaster. Changing the startup process could make restarting the
                                162                 :                :  *     processing automatic on cluster restart.
                                163                 :                :  *   * Avoid dirtying the page when checksums already match: Iff the checksum
                                164                 :                :  *     on the page happens to already match we still dirty the page. It should
                                165                 :                :  *     be enough to only do the log_newpage_buffer() call in that case.
                                166                 :                :  *   * Teach pg_checksums to avoid checksummed pages when pg_checksums is used
                                167                 :                :  *     to enable checksums on a cluster which is in inprogress-on state and
                                168                 :                :  *     may have checksummed pages (make pg_checksums be able to resume an
                                169                 :                :  *     online operation). This should only be attempted for wal_level minimal.
                                170                 :                :  *   * Restartability (not necessarily with page granularity).
                                171                 :                :  *   * Avoid processing databases which were created during inprogress-on.
                                172                 :                :  *     Right now all databases are processed regardless to be safe.
                                173                 :                :  *   * Teach CREATE DATABASE to calculate checksums for databases created
                                174                 :                :  *     during inprogress-on with a template database which has yet to be
                                175                 :                :  *     processed.
                                176                 :                :  *
                                177                 :                :  *
                                178                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                179                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                180                 :                :  *
                                181                 :                :  *
                                182                 :                :  * IDENTIFICATION
                                183                 :                :  *    src/backend/postmaster/datachecksum_state.c
                                184                 :                :  *
                                185                 :                :  *-------------------------------------------------------------------------
                                186                 :                :  */
                                187                 :                : #include "postgres.h"
                                188                 :                : 
                                189                 :                : #include "access/genam.h"
                                190                 :                : #include "access/heapam.h"
                                191                 :                : #include "access/htup_details.h"
                                192                 :                : #include "access/xact.h"
                                193                 :                : #include "access/xlog.h"
                                194                 :                : #include "access/xloginsert.h"
                                195                 :                : #include "catalog/indexing.h"
                                196                 :                : #include "catalog/pg_class.h"
                                197                 :                : #include "catalog/pg_database.h"
                                198                 :                : #include "commands/progress.h"
                                199                 :                : #include "commands/vacuum.h"
                                200                 :                : #include "common/relpath.h"
                                201                 :                : #include "miscadmin.h"
                                202                 :                : #include "pgstat.h"
                                203                 :                : #include "postmaster/bgworker.h"
                                204                 :                : #include "postmaster/bgwriter.h"
                                205                 :                : #include "postmaster/datachecksum_state.h"
                                206                 :                : #include "storage/bufmgr.h"
                                207                 :                : #include "storage/checksum.h"
                                208                 :                : #include "storage/ipc.h"
                                209                 :                : #include "storage/latch.h"
                                210                 :                : #include "storage/lmgr.h"
                                211                 :                : #include "storage/lwlock.h"
                                212                 :                : #include "storage/procarray.h"
                                213                 :                : #include "storage/smgr.h"
                                214                 :                : #include "storage/subsystems.h"
                                215                 :                : #include "tcop/tcopprot.h"
                                216                 :                : #include "utils/builtins.h"
                                217                 :                : #include "utils/fmgroids.h"
                                218                 :                : #include "utils/injection_point.h"
                                219                 :                : #include "utils/lsyscache.h"
                                220                 :                : #include "utils/ps_status.h"
                                221                 :                : #include "utils/syscache.h"
                                222                 :                : #include "utils/wait_event.h"
                                223                 :                : 
                                224                 :                : /*
                                225                 :                :  * Configuration of conditions which must match when absorbing a procsignal
                                226                 :                :  * barrier during data checksum enable/disable operations.  A single function
                                227                 :                :  * is used for absorbing all barriers, and the current and target states must
                                228                 :                :  * be defined as a from/to tuple in the checksum_barriers struct.
                                229                 :                :  */
                                230                 :                : typedef struct ChecksumBarrierCondition
                                231                 :                : {
                                232                 :                :     /* Current state of data checksums */
                                233                 :                :     int         from;
                                234                 :                :     /* Target state for data checksums */
                                235                 :                :     int         to;
                                236                 :                : } ChecksumBarrierCondition;
                                237                 :                : 
                                238                 :                : static const ChecksumBarrierCondition checksum_barriers[9] =
                                239                 :                : {
                                240                 :                :     /*
                                241                 :                :      * Disabling checksums: If checksums are currently enabled, disabling must
                                242                 :                :      * go through the 'inprogress-off' state.
                                243                 :                :      */
                                244                 :                :     {PG_DATA_CHECKSUM_VERSION, PG_DATA_CHECKSUM_INPROGRESS_OFF},
                                245                 :                :     {PG_DATA_CHECKSUM_INPROGRESS_OFF, PG_DATA_CHECKSUM_OFF},
                                246                 :                : 
                                247                 :                :     /*
                                248                 :                :      * If checksums are in the process of being enabled, but are not yet being
                                249                 :                :      * verified, we can abort by going back to 'off' state.
                                250                 :                :      */
                                251                 :                :     {PG_DATA_CHECKSUM_INPROGRESS_ON, PG_DATA_CHECKSUM_OFF},
                                252                 :                : 
                                253                 :                :     /*
                                254                 :                :      * Enabling checksums must normally go through the 'inprogress-on' state.
                                255                 :                :      */
                                256                 :                :     {PG_DATA_CHECKSUM_OFF, PG_DATA_CHECKSUM_INPROGRESS_ON},
                                257                 :                :     {PG_DATA_CHECKSUM_INPROGRESS_ON, PG_DATA_CHECKSUM_VERSION},
                                258                 :                : 
                                259                 :                :     /*
                                260                 :                :      * If checksums are being disabled but all backends are still computing
                                261                 :                :      * checksums, we can go straight back to 'on'
                                262                 :                :      */
                                263                 :                :     {PG_DATA_CHECKSUM_INPROGRESS_OFF, PG_DATA_CHECKSUM_VERSION},
                                264                 :                : 
                                265                 :                :     /*
                                266                 :                :      * If checksums are being enabled when launcher_exit is executed, state is
                                267                 :                :      * set to off since we cannot reach on at that point.
                                268                 :                :      */
                                269                 :                :     {PG_DATA_CHECKSUM_INPROGRESS_ON, PG_DATA_CHECKSUM_INPROGRESS_OFF},
                                270                 :                : 
                                271                 :                :     /*
                                272                 :                :      * Transitions that can happen when a new request is made while another is
                                273                 :                :      * currently being processed.
                                274                 :                :      */
                                275                 :                :     {PG_DATA_CHECKSUM_INPROGRESS_OFF, PG_DATA_CHECKSUM_INPROGRESS_ON},
                                276                 :                :     {PG_DATA_CHECKSUM_OFF, PG_DATA_CHECKSUM_INPROGRESS_OFF},
                                277                 :                : };
                                278                 :                : 
                                279                 :                : /* Possible operations the DataChecksumsWorker can perform */
                                280                 :                : typedef enum DataChecksumsWorkerOperation
                                281                 :                : {
                                282                 :                :     ENABLE_DATACHECKSUMS,
                                283                 :                :     DISABLE_DATACHECKSUMS,
                                284                 :                : } DataChecksumsWorkerOperation;
                                285                 :                : 
                                286                 :                : /* Possible states for a database entry which has been processed */
                                287                 :                : typedef enum
                                288                 :                : {
                                289                 :                :     DATACHECKSUMSWORKER_SUCCESSFUL = 0,
                                290                 :                :     DATACHECKSUMSWORKER_ABORTED,
                                291                 :                :     DATACHECKSUMSWORKER_FAILED,
                                292                 :                :     DATACHECKSUMSWORKER_DROPDB,
                                293                 :                : } DataChecksumsWorkerResult;
                                294                 :                : 
                                295                 :                : /*
                                296                 :                :  * Signaling between backends calling pg_enable/disable_data_checksums, the
                                297                 :                :  * checksums launcher process, and the checksums worker process.
                                298                 :                :  *
                                299                 :                :  * This struct is protected by DataChecksumsWorkerLock
                                300                 :                :  */
                                301                 :                : typedef struct DataChecksumsStateStruct
                                302                 :                : {
                                303                 :                :     /*
                                304                 :                :      * These are set by pg_{enable|disable}_data_checksums, to tell the
                                305                 :                :      * launcher what the target state is.
                                306                 :                :      */
                                307                 :                :     DataChecksumsWorkerOperation launch_operation;
                                308                 :                :     int         launch_cost_delay;
                                309                 :                :     int         launch_cost_limit;
                                310                 :                : 
                                311                 :                :     /*
                                312                 :                :      * Is a launcher process currently running?  This is set by the main
                                313                 :                :      * launcher process, after it has read the above launch_* parameters.
                                314                 :                :      */
                                315                 :                :     bool        launcher_running;
                                316                 :                : 
                                317                 :                :     /*
                                318                 :                :      * Every time a new worker is launched, it's assigned a unique invocation
                                319                 :                :      * number by incrementing this counter.
                                320                 :                :      */
                                321                 :                :     uint64      worker_invocation_counter;
                                322                 :                : 
                                323                 :                :     /*
                                324                 :                :      * Information about the current worker, if it's currently running.  These
                                325                 :                :      * are set by the worker launcher.
                                326                 :                :      */
                                327                 :                :     uint64      worker_invocation;  /* unique invocation number */
                                328                 :                :     Oid         database_oid;   /* database it's processing */
                                329                 :                :     pid_t       worker_pid;     /* worker process's PID */
                                330                 :                : 
                                331                 :                :     /*
                                332                 :                :      * These fields indicate the target state that the worker is currently
                                333                 :                :      * running with.  They can be different from the corresponding launch_*
                                334                 :                :      * fields, if a new pg_enable/disable_data_checksums() call was made while
                                335                 :                :      * the launcher/worker was already running.  The worker will periodically
                                336                 :                :      * check if new cost settings have been requested, and if so will copy
                                337                 :                :      * them from the launch_* fields and reset cost throttling to match the
                                338                 :                :      * new values.
                                339                 :                :      */
                                340                 :                :     DataChecksumsWorkerOperation operation;
                                341                 :                :     int         cost_delay;
                                342                 :                :     int         cost_limit;
                                343                 :                : 
                                344                 :                :     /*
                                345                 :                :      * Signaling between the launcher and the worker process. Protected by
                                346                 :                :      * DataChecksumsWorkerLock.
                                347                 :                :      */
                                348                 :                : 
                                349                 :                :     /* result, set by worker before exiting */
                                350                 :                :     DataChecksumsWorkerResult worker_result;
                                351                 :                : 
                                352                 :                :     /*
                                353                 :                :      * Tells the worker process whether it should also process the shared
                                354                 :                :      * catalogs
                                355                 :                :      */
                                356                 :                :     bool        process_shared_catalogs;
                                357                 :                : } DataChecksumsStateStruct;
                                358                 :                : 
                                359                 :                : /* Shared memory segment for datachecksumsworker */
                                360                 :                : static DataChecksumsStateStruct *DataChecksumState;
                                361                 :                : 
                                362                 :                : typedef struct DataChecksumsWorkerDatabase
                                363                 :                : {
                                364                 :                :     Oid         dboid;
                                365                 :                :     char       *dbname;
                                366                 :                : } DataChecksumsWorkerDatabase;
                                367                 :                : 
                                368                 :                : /* Flag set by the interrupt handler */
                                369                 :                : static volatile sig_atomic_t abort_requested = false;
                                370                 :                : 
                                371                 :                : static uint64 worker_invocation;
                                372                 :                : 
                                373                 :                : /*
                                374                 :                :  * Have we set the DataChecksumsStateStruct->launcher_running flag?
                                375                 :                :  * If we have, we need to clear it before exiting!
                                376                 :                :  */
                                377                 :                : static volatile sig_atomic_t launcher_running = false;
                                378                 :                : 
                                379                 :                : /* Are we enabling data checksums, or disabling them? */
                                380                 :                : static DataChecksumsWorkerOperation operation;
                                381                 :                : 
                                382                 :                : /* Prototypes */
                                383                 :                : static void StartDataChecksumsWorkerLauncher(DataChecksumsWorkerOperation op,
                                384                 :                :                                              int cost_delay,
                                385                 :                :                                              int cost_limit);
                                386                 :                : static void DataChecksumsShmemRequest(void *arg);
                                387                 :                : static bool DatabaseExists(Oid dboid);
                                388                 :                : static List *BuildDatabaseList(void);
                                389                 :                : static List *BuildRelationList(bool temp_relations, bool include_shared);
                                390                 :                : static void FreeDatabaseList(List *dblist);
                                391                 :                : static DataChecksumsWorkerResult ProcessDatabase(DataChecksumsWorkerDatabase *db);
                                392                 :                : static bool ProcessAllDatabases(void);
                                393                 :                : static bool ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy);
                                394                 :                : static void ResetDataChecksumsProgressCounters(void);
                                395                 :                : static void launcher_cancel_handler(SIGNAL_ARGS);
                                396                 :                : static void WaitForAllTransactionsToFinish(void);
                                397                 :                : 
                                398                 :                : const ShmemCallbacks DataChecksumsShmemCallbacks = {
                                399                 :                :     .request_fn = DataChecksumsShmemRequest,
                                400                 :                : };
                                401                 :                : 
                                402                 :                : #define CHECK_FOR_LAUNCHER_ABORT_REQUEST() \
                                403                 :                :     do {                                                            \
                                404                 :                :         Assert(MyBackendType == B_DATACHECKSUMSWORKER_LAUNCHER);    \
                                405                 :                :         LWLockAcquire(DataChecksumsWorkerLock, LW_SHARED);          \
                                406                 :                :         if (DataChecksumState->launch_operation != operation)        \
                                407                 :                :             abort_requested = true;                                 \
                                408                 :                :         LWLockRelease(DataChecksumsWorkerLock);                     \
                                409                 :                :     } while (0)
                                410                 :                : 
                                411                 :                : #define CHECK_FOR_WORKER_ABORT_REQUEST() \
                                412                 :                :     do {                                                            \
                                413                 :                :         Assert(MyBackendType == B_DATACHECKSUMSWORKER_WORKER);      \
                                414                 :                :         LWLockAcquire(DataChecksumsWorkerLock, LW_SHARED);          \
                                415                 :                :         if (DataChecksumState->worker_invocation != worker_invocation || \
                                416                 :                :             DataChecksumState->launch_operation != operation)        \
                                417                 :                :             abort_requested = true;                                 \
                                418                 :                :         LWLockRelease(DataChecksumsWorkerLock);                     \
                                419                 :                :     } while (0)
                                420                 :                : 
                                421                 :                : 
                                422                 :                : /*****************************************************************************
                                423                 :                :  * Functionality for manipulating the data checksum state in the cluster
                                424                 :                :  */
                                425                 :                : 
                                426                 :                : void
  113 dgustafsson@postgres      427                 :CBC           8 : EmitAndWaitDataChecksumsBarrier(uint32 state)
                                428                 :                : {
                                429                 :                :     uint64      barrier;
                                430                 :                : 
                                431   [ +  +  +  +  :              8 :     switch (state)
                                                 - ]
                                432                 :                :     {
                                433                 :              3 :         case PG_DATA_CHECKSUM_INPROGRESS_ON:
                                434                 :              3 :             barrier = EmitProcSignalBarrier(PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_ON);
                                435                 :              3 :             WaitForProcSignalBarrier(barrier);
                                436                 :              3 :             break;
                                437                 :                : 
                                438                 :              1 :         case PG_DATA_CHECKSUM_INPROGRESS_OFF:
                                439                 :              1 :             barrier = EmitProcSignalBarrier(PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_OFF);
                                440                 :              1 :             WaitForProcSignalBarrier(barrier);
                                441                 :              1 :             break;
                                442                 :                : 
                                443                 :              2 :         case PG_DATA_CHECKSUM_VERSION:
                                444                 :              2 :             barrier = EmitProcSignalBarrier(PROCSIGNAL_BARRIER_CHECKSUM_ON);
                                445                 :              2 :             WaitForProcSignalBarrier(barrier);
                                446                 :              2 :             break;
                                447                 :                : 
                                448                 :              2 :         case PG_DATA_CHECKSUM_OFF:
                                449                 :              2 :             barrier = EmitProcSignalBarrier(PROCSIGNAL_BARRIER_CHECKSUM_OFF);
                                450                 :              2 :             WaitForProcSignalBarrier(barrier);
                                451                 :              2 :             break;
                                452                 :                : 
  113 dgustafsson@postgres      453                 :UBC           0 :         default:
                                454                 :              0 :             Assert(false);
                                455                 :                :     }
  113 dgustafsson@postgres      456                 :CBC           8 : }
                                457                 :                : 
                                458                 :                : /*
                                459                 :                :  * AbsorbDataChecksumsBarrier
                                460                 :                :  *      Generic function for absorbing data checksum state changes
                                461                 :                :  *
                                462                 :                :  * All procsignalbarriers regarding data checksum state changes are absorbed
                                463                 :                :  * with this function.  The set of conditions required for the state change to
                                464                 :                :  * be accepted are listed in the checksum_barriers struct, target_state is
                                465                 :                :  * used to look up the relevant entry.
                                466                 :                :  */
                                467                 :                : bool
                                468                 :            275 : AbsorbDataChecksumsBarrier(ProcSignalBarrierType barrier)
                                469                 :                : {
                                470                 :                :     uint32      target_state;
                                471                 :            275 :     int         current = data_checksums;
                                472                 :            275 :     bool        found = false;
                                473                 :                : 
                                474                 :                :     /*
                                475                 :                :      * Translate the barrier condition to the target state, doing it here
                                476                 :                :      * instead of in the procsignal code saves the latter from knowing about
                                477                 :                :      * checksum states.
                                478                 :                :      */
                                479   [ +  +  +  +  :            275 :     switch (barrier)
                                                 - ]
                                480                 :                :     {
                                481                 :             94 :         case PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_ON:
                                482                 :             94 :             target_state = PG_DATA_CHECKSUM_INPROGRESS_ON;
                                483                 :             94 :             break;
                                484                 :             71 :         case PROCSIGNAL_BARRIER_CHECKSUM_ON:
                                485                 :             71 :             target_state = PG_DATA_CHECKSUM_VERSION;
                                486                 :             71 :             break;
                                487                 :             53 :         case PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_OFF:
                                488                 :             53 :             target_state = PG_DATA_CHECKSUM_INPROGRESS_OFF;
                                489                 :             53 :             break;
                                490                 :             57 :         case PROCSIGNAL_BARRIER_CHECKSUM_OFF:
                                491                 :             57 :             target_state = PG_DATA_CHECKSUM_OFF;
                                492                 :             57 :             break;
  113 dgustafsson@postgres      493                 :UBC           0 :         default:
                                494         [ #  # ]:              0 :             elog(ERROR, "incorrect barrier \"%i\" received", barrier);
                                495                 :                :     }
                                496                 :                : 
                                497                 :                :     /*
                                498                 :                :      * If the target state matches the current state then the barrier has been
                                499                 :                :      * repeated.
                                500                 :                :      */
  113 dgustafsson@postgres      501         [ +  + ]:CBC         275 :     if (current == target_state)
                                502                 :              1 :         return true;
                                503                 :                : 
                                504                 :                :     /*
                                505                 :                :      * If the cluster is in recovery we skip the validation of current state
                                506                 :                :      * since the replay is trusted.
                                507                 :                :      */
                                508         [ +  + ]:            274 :     if (RecoveryInProgress())
                                509                 :                :     {
                                510                 :             48 :         SetLocalDataChecksumState(target_state);
                                511                 :             48 :         return true;
                                512                 :                :     }
                                513                 :                : 
                                514                 :                :     /*
                                515                 :                :      * Find the barrier condition definition for the target state. Not finding
                                516                 :                :      * a condition would be a grave programmer error as the states are a
                                517                 :                :      * discrete set.
                                518                 :                :      */
   14 peter@eisentraut.org      519   [ +  -  +  + ]:GNC        1036 :     for (size_t i = 0; i < lengthof(checksum_barriers) && !found; i++)
                                520                 :                :     {
  113 dgustafsson@postgres      521   [ +  +  +  + ]:CBC         810 :         if (checksum_barriers[i].from == current && checksum_barriers[i].to == target_state)
                                522                 :            226 :             found = true;
                                523                 :                :     }
                                524                 :                : 
                                525                 :                :     /*
                                526                 :                :      * If the relevant state criteria aren't satisfied, throw an error which
                                527                 :                :      * will be caught by the procsignal machinery for a later retry.
                                528                 :                :      */
                                529         [ -  + ]:            226 :     if (!found)
  113 dgustafsson@postgres      530         [ #  # ]:UBC           0 :         ereport(ERROR,
                                531                 :                :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                532                 :                :                 errmsg("incorrect data checksum state %i for target state %i",
                                533                 :                :                        current, target_state));
                                534                 :                : 
  113 dgustafsson@postgres      535                 :CBC         226 :     SetLocalDataChecksumState(target_state);
                                536                 :            226 :     return true;
                                537                 :                : }
                                538                 :                : 
                                539                 :                : 
                                540                 :                : /*
                                541                 :                :  * Disables data checksums for the cluster, if applicable. Starts a background
                                542                 :                :  * worker which turns off the data checksums.
                                543                 :                :  */
                                544                 :                : Datum
                                545                 :              7 : disable_data_checksums(PG_FUNCTION_ARGS)
                                546                 :                : {
   86                           547                 :              7 :     PreventCommandDuringRecovery("pg_disable_data_checksums()");
                                548                 :                : 
  113                           549         [ -  + ]:              7 :     if (!superuser())
  113 dgustafsson@postgres      550         [ #  # ]:UBC           0 :         ereport(ERROR,
                                551                 :                :                 errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                552                 :                :                 errmsg("must be superuser to change data checksum state"));
                                553                 :                : 
  113 dgustafsson@postgres      554                 :CBC           7 :     StartDataChecksumsWorkerLauncher(DISABLE_DATACHECKSUMS, 0, 0);
                                555                 :              7 :     PG_RETURN_VOID();
                                556                 :                : }
                                557                 :                : 
                                558                 :                : /*
                                559                 :                :  * Enables data checksums for the cluster, if applicable.  Supports vacuum-
                                560                 :                :  * like cost based throttling to limit system load. Starts a background worker
                                561                 :                :  * which updates data checksums on existing data.
                                562                 :                :  */
                                563                 :                : Datum
                                564                 :             11 : enable_data_checksums(PG_FUNCTION_ARGS)
                                565                 :                : {
                                566                 :             11 :     int         cost_delay = PG_GETARG_INT32(0);
                                567                 :             11 :     int         cost_limit = PG_GETARG_INT32(1);
                                568                 :                : 
   86                           569                 :             11 :     PreventCommandDuringRecovery("pg_enable_data_checksums()");
                                570                 :                : 
  113                           571         [ -  + ]:             11 :     if (!superuser())
  113 dgustafsson@postgres      572         [ #  # ]:UBC           0 :         ereport(ERROR,
                                573                 :                :                 errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                574                 :                :                 errmsg("must be superuser to change data checksum state"));
                                575                 :                : 
  113 dgustafsson@postgres      576         [ -  + ]:CBC          11 :     if (cost_delay < 0)
  113 dgustafsson@postgres      577         [ #  # ]:UBC           0 :         ereport(ERROR,
                                578                 :                :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                579                 :                :                 errmsg("cost delay cannot be a negative value"));
                                580                 :                : 
  113 dgustafsson@postgres      581         [ -  + ]:CBC          11 :     if (cost_limit <= 0)
  113 dgustafsson@postgres      582         [ #  # ]:UBC           0 :         ereport(ERROR,
                                583                 :                :                 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                584                 :                :                 errmsg("cost limit must be greater than zero"));
                                585                 :                : 
  113 dgustafsson@postgres      586                 :CBC          11 :     StartDataChecksumsWorkerLauncher(ENABLE_DATACHECKSUMS, cost_delay, cost_limit);
                                587                 :                : 
                                588                 :             11 :     PG_RETURN_VOID();
                                589                 :                : }
                                590                 :                : 
                                591                 :                : 
                                592                 :                : /*****************************************************************************
                                593                 :                :  * Functionality for running the datachecksumsworker and associated launcher
                                594                 :                :  */
                                595                 :                : 
                                596                 :                : /*
                                597                 :                :  * StartDataChecksumsWorkerLauncher
                                598                 :                :  *      Start the datachecksumsworker launcher process, if not running yet
                                599                 :                :  *
                                600                 :                :  * This is called to start data checksums processing for enabling as well as
                                601                 :                :  * disabling.
                                602                 :                :  */
                                603                 :                : static void
                                604                 :             18 : StartDataChecksumsWorkerLauncher(DataChecksumsWorkerOperation op,
                                605                 :                :                                  int cost_delay,
                                606                 :                :                                  int cost_limit)
                                607                 :                : {
                                608                 :                :     BackgroundWorker bgw;
                                609                 :                :     BackgroundWorkerHandle *bgw_handle;
                                610                 :                :     bool        running;
                                611                 :                : 
                                612                 :                : #ifdef USE_ASSERT_CHECKING
                                613                 :                :     /* The cost delay settings have no effect when disabling */
                                614         [ +  + ]:             18 :     if (op == DISABLE_DATACHECKSUMS)
                                615   [ +  -  -  + ]:              7 :         Assert(cost_delay == 0 && cost_limit == 0);
                                616                 :                : #endif
                                617                 :                : 
                                618                 :             18 :     INJECTION_POINT("datachecksumsworker-startup-delay", NULL);
                                619                 :                : 
                                620                 :                :     /* Store the desired state in shared memory */
                                621                 :             18 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
                                622                 :                : 
                                623                 :             18 :     DataChecksumState->launch_operation = op;
                                624                 :             18 :     DataChecksumState->launch_cost_delay = cost_delay;
                                625                 :             18 :     DataChecksumState->launch_cost_limit = cost_limit;
                                626                 :                : 
                                627                 :                :     /* Is the launcher already running? If so, what is it doing? */
   93 drowley@postgresql.o      628                 :             18 :     running = DataChecksumState->launcher_running;
                                629                 :                : 
  113 dgustafsson@postgres      630                 :             18 :     LWLockRelease(DataChecksumsWorkerLock);
                                631                 :                : 
                                632                 :                :     /*
                                633                 :                :      * Launch a new launcher process, if it's not running already.
                                634                 :                :      *
                                635                 :                :      * If the launcher is currently busy enabling the checksums, and we want
                                636                 :                :      * them disabled (or vice versa), the launcher will notice that at latest
                                637                 :                :      * when it's about to exit, and will loop back to process the new request.
                                638                 :                :      * So if the launcher is already running, we don't need to do anything
                                639                 :                :      * more here to abort it.
                                640                 :                :      *
                                641                 :                :      * If you call pg_enable/disable_data_checksums() twice in a row, before
                                642                 :                :      * the launcher has had a chance to start up, we still end up launching it
                                643                 :                :      * twice.  That's OK, the second invocation will see that a launcher is
                                644                 :                :      * already running and exit quickly.
                                645                 :                :      */
   93 drowley@postgresql.o      646         [ +  - ]:             18 :     if (!running)
                                647                 :                :     {
   86 dgustafsson@postgres      648   [ +  +  +  +  :             18 :         if ((op == ENABLE_DATACHECKSUMS && DataChecksumsOn()) ||
                                              +  + ]
                                649         [ +  + ]:              7 :             (op == DISABLE_DATACHECKSUMS && DataChecksumsOff()))
                                650                 :                :         {
                                651         [ +  - ]:              3 :             ereport(LOG,
                                652                 :                :                     errmsg("data checksums already in desired state, exiting"));
                                653                 :              3 :             return;
                                654                 :                :         }
                                655                 :                : 
                                656                 :                :         /*
                                657                 :                :          * Prepare the BackgroundWorker and launch it.
                                658                 :                :          */
  113                           659                 :             15 :         memset(&bgw, 0, sizeof(bgw));
                                660                 :             15 :         bgw.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION;
                                661                 :             15 :         bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
                                662                 :             15 :         snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
                                663                 :             15 :         snprintf(bgw.bgw_function_name, BGW_MAXLEN, "DataChecksumsWorkerLauncherMain");
   57                           664                 :             15 :         snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksums launcher");
                                665                 :             15 :         snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksums launcher");
  113                           666                 :             15 :         bgw.bgw_restart_time = BGW_NEVER_RESTART;
                                667                 :             15 :         bgw.bgw_notify_pid = MyProcPid;
                                668                 :             15 :         bgw.bgw_main_arg = (Datum) 0;
                                669                 :                : 
                                670         [ -  + ]:             15 :         if (!RegisterDynamicBackgroundWorker(&bgw, &bgw_handle))
  113 dgustafsson@postgres      671         [ #  # ]:UBC           0 :             ereport(ERROR,
                                672                 :                :                     errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                                673                 :                :                     errmsg("failed to start background worker to process data checksums"));
                                674                 :                :     }
                                675                 :                :     else
                                676                 :                :     {
   86                           677         [ #  # ]:              0 :         ereport(LOG,
                                678                 :                :                 errmsg("data checksum processing already running"));
                                679                 :                :     }
                                680                 :                : }
                                681                 :                : 
                                682                 :                : /*
                                683                 :                :  * ProcessSingleRelationFork
                                684                 :                :  *      Enable data checksums in a single relation/fork.
                                685                 :                :  *
                                686                 :                :  * Returns true if successful, and false if *aborted*. On error, an actual
                                687                 :                :  * error is raised in the lower levels.
                                688                 :                :  */
                                689                 :                : static bool
  113 dgustafsson@postgres      690                 :CBC        7573 : ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy)
                                691                 :                : {
                                692                 :           7573 :     BlockNumber numblocks = RelationGetNumberOfBlocksInFork(reln, forkNum);
                                693                 :                :     char        activity[NAMEDATALEN * 2 + 128];
                                694                 :                :     char       *relns;
                                695                 :                : 
                                696                 :           7573 :     relns = get_namespace_name(RelationGetNamespace(reln));
                                697                 :                : 
                                698                 :                :     /* Report the current relation to pg_stat_activity */
                                699                 :           7573 :     snprintf(activity, sizeof(activity) - 1, "processing: %s.%s (%s, %u blocks)",
                                700         [ +  - ]:           7573 :              (relns ? relns : ""), RelationGetRelationName(reln), forkNames[forkNum], numblocks);
                                701                 :           7573 :     pgstat_report_activity(STATE_RUNNING, activity);
                                702                 :                :     {
   15 fujii@postgresql.org      703                 :           7573 :         const int   index[] = {
                                704                 :                :             PROGRESS_DATACHECKSUMS_BLOCKS_TOTAL,
                                705                 :                :             PROGRESS_DATACHECKSUMS_BLOCKS_DONE
                                706                 :                :         };
                                707                 :                : 
                                708                 :                :         int64       vals[2];
                                709                 :                : 
                                710                 :           7573 :         vals[0] = numblocks;
                                711                 :           7573 :         vals[1] = 0;
                                712                 :                : 
                                713                 :           7573 :         pgstat_progress_update_multi_param(2, index, vals);
                                714                 :                :     }
  113 dgustafsson@postgres      715         [ +  - ]:           7573 :     if (relns)
                                716                 :           7573 :         pfree(relns);
                                717                 :                : 
                                718                 :                :     /*
                                719                 :                :      * We are looping over the blocks which existed at the time of process
                                720                 :                :      * start, which is safe since new blocks are created with checksums set
                                721                 :                :      * already due to the state being "inprogress-on".
                                722                 :                :      */
                                723         [ +  + ]:          47578 :     for (BlockNumber blknum = 0; blknum < numblocks; blknum++)
                                724                 :                :     {
                                725                 :          40006 :         Buffer      buf = ReadBufferExtended(reln, forkNum, blknum, RBM_NORMAL, strategy);
                                726                 :                : 
                                727                 :                :         /* Need to get an exclusive lock to mark the buffer as dirty */
                                728                 :          40006 :         LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
                                729                 :                : 
                                730                 :                :         /*
                                731                 :                :          * Mark the buffer as dirty and force a full page write.  We have to
                                732                 :                :          * re-write the page to WAL even if the checksum hasn't changed,
                                733                 :                :          * because if there is a replica it might have a slightly different
                                734                 :                :          * version of the page with an invalid checksum, caused by unlogged
                                735                 :                :          * changes (e.g. hint bits) on the primary happening while checksums
                                736                 :                :          * were off. This can happen if there was a valid checksum on the page
                                737                 :                :          * at one point in the past, so only when checksums are first on, then
                                738                 :                :          * off, and then turned on again.  TODO: investigate if this could be
                                739                 :                :          * avoided if the checksum is calculated to be correct and wal_level
                                740                 :                :          * is set to "minimal".
                                741                 :                :          *
                                742                 :                :          * Unlogged relations don't need WAL since they are reset to their
                                743                 :                :          * init fork on recovery.  We still dirty the buffer so that the
                                744                 :                :          * checksum is written to disk at the next checkpoint.
                                745                 :                :          *
                                746                 :                :          * The init fork is an exception: it is WAL-logged so the standby can
                                747                 :                :          * materialize the relation after promotion (see
                                748                 :                :          * ResetUnloggedRelations()).  Skipping it here would leave the
                                749                 :                :          * standby with a stale init fork that, once copied to the main fork
                                750                 :                :          * on promotion, would fail checksum verification on every read.
                                751                 :                :          */
                                752                 :          40006 :         START_CRIT_SECTION();
                                753                 :          40006 :         MarkBufferDirty(buf);
   80                           754   [ +  +  +  +  :          40006 :         if (RelationNeedsWAL(reln) || forkNum == INIT_FORKNUM)
                                     +  -  -  +  +  
                                                 + ]
                                755                 :          39972 :             log_newpage_buffer(buf, false);
  113                           756         [ -  + ]:          40006 :         END_CRIT_SECTION();
                                757                 :                : 
                                758                 :          40006 :         UnlockReleaseBuffer(buf);
                                759                 :                : 
                                760                 :                :         /* Check if we are asked to abort, the abortion will bubble up. */
                                761         [ -  + ]:          40006 :         Assert(operation == ENABLE_DATACHECKSUMS);
   31 heikki.linnakangas@i      762   [ -  +  +  -  :          40006 :         CHECK_FOR_WORKER_ABORT_REQUEST();
                                              -  + ]
  113 dgustafsson@postgres      763         [ -  + ]:          40006 :         if (abort_requested)
  113 dgustafsson@postgres      764                 :UBC           0 :             return false;
                                765                 :                : 
                                766                 :                :         /* update the block counter */
  113 dgustafsson@postgres      767                 :CBC       40006 :         pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_BLOCKS_DONE,
                                768                 :          40006 :                                      (blknum + 1));
                                769                 :                : 
                                770                 :                :         /*
                                771                 :                :          * Processing is re-using the vacuum cost delay for process
                                772                 :                :          * throttling, hence why we call vacuum APIs here.
                                773                 :                :          */
                                774                 :          40006 :         vacuum_delay_point(false);
                                775                 :                :     }
                                776                 :                : 
                                777                 :           7572 :     return true;
                                778                 :                : }
                                779                 :                : 
                                780                 :                : /*
                                781                 :                :  * Initialize all data checksum progress counters to be displayed as NULL.
                                782                 :                :  */
                                783                 :                : static void
   15 fujii@postgresql.org      784                 :             37 : ResetDataChecksumsProgressCounters(void)
                                785                 :                : {
                                786                 :             37 :     const int   index[] = {
                                787                 :                :         PROGRESS_DATACHECKSUMS_DBS_TOTAL,
                                788                 :                :         PROGRESS_DATACHECKSUMS_DBS_DONE,
                                789                 :                :         PROGRESS_DATACHECKSUMS_RELS_TOTAL,
                                790                 :                :         PROGRESS_DATACHECKSUMS_RELS_DONE,
                                791                 :                :         PROGRESS_DATACHECKSUMS_BLOCKS_TOTAL,
                                792                 :                :         PROGRESS_DATACHECKSUMS_BLOCKS_DONE,
                                793                 :                :     };
                                794                 :                : 
                                795                 :                :     int64       vals[lengthof(index)];
                                796                 :                : 
   14 peter@eisentraut.org      797         [ +  + ]:GNC         259 :     for (size_t i = 0; i < lengthof(index); i++)
   15 fujii@postgresql.org      798                 :CBC         222 :         vals[i] = -1;
                                799                 :                : 
                                800                 :             37 :     pgstat_progress_update_multi_param(lengthof(index), index, vals);
                                801                 :             37 : }
                                802                 :                : 
                                803                 :                : /*
                                804                 :                :  * ProcessSingleRelationByOid
                                805                 :                :  *      Process a single relation based on oid.
                                806                 :                :  *
                                807                 :                :  * Returns true if successful, and false if *aborted*. On error, an actual
                                808                 :                :  * error is raised in the lower levels.
                                809                 :                :  */
                                810                 :                : static bool
  113 dgustafsson@postgres      811                 :           5840 : ProcessSingleRelationByOid(Oid relationId, BufferAccessStrategy strategy)
                                812                 :                : {
                                813                 :                :     Relation    rel;
                                814                 :           5840 :     bool        aborted = false;
                                815                 :                : 
                                816                 :           5840 :     StartTransactionCommand();
                                817                 :                : 
                                818                 :           5840 :     rel = try_relation_open(relationId, AccessShareLock);
                                819         [ -  + ]:           5840 :     if (rel == NULL)
                                820                 :                :     {
                                821                 :                :         /*
                                822                 :                :          * Relation no longer exists. We don't consider this an error since
                                823                 :                :          * there are no pages in it that need data checksums, and thus return
                                824                 :                :          * true. The worker operates off a list of relations generated at the
                                825                 :                :          * start of processing, so relations being dropped in the meantime is
                                826                 :                :          * to be expected.
                                827                 :                :          */
  113 dgustafsson@postgres      828                 :UBC           0 :         CommitTransactionCommand();
                                829                 :              0 :         pgstat_report_activity(STATE_IDLE, NULL);
                                830                 :              0 :         return true;
                                831                 :                :     }
  113 dgustafsson@postgres      832                 :CBC        5840 :     RelationGetSmgr(rel);
                                833                 :                : 
                                834         [ +  + ]:          29196 :     for (ForkNumber fnum = 0; fnum <= MAX_FORKNUM; fnum++)
                                835                 :                :     {
                                836         [ +  + ]:          23357 :         if (smgrexists(rel->rd_smgr, fnum))
                                837                 :                :         {
                                838         [ -  + ]:           7573 :             if (!ProcessSingleRelationFork(rel, fnum, strategy))
                                839                 :                :             {
  113 dgustafsson@postgres      840                 :UBC           0 :                 aborted = true;
                                841                 :              0 :                 break;
                                842                 :                :             }
                                843                 :                :         }
                                844                 :                :     }
  113 dgustafsson@postgres      845                 :CBC        5839 :     relation_close(rel, AccessShareLock);
                                846                 :                : 
                                847                 :           5839 :     CommitTransactionCommand();
                                848                 :           5839 :     pgstat_report_activity(STATE_IDLE, NULL);
                                849                 :                : 
                                850                 :           5839 :     return !aborted;
                                851                 :                : }
                                852                 :                : 
                                853                 :                : /*
                                854                 :                :  * ProcessDatabase
                                855                 :                :  *      Enable data checksums in a single database.
                                856                 :                :  *
                                857                 :                :  * We do this by launching a dynamic background worker into this database, and
                                858                 :                :  * waiting for it to finish.  We have to do this in a separate worker, since
                                859                 :                :  * each process can only be connected to one database during its lifetime.
                                860                 :                :  */
                                861                 :                : static DataChecksumsWorkerResult
                                862                 :             23 : ProcessDatabase(DataChecksumsWorkerDatabase *db)
                                863                 :                : {
                                864                 :                :     BackgroundWorker bgw;
                                865                 :                :     BackgroundWorkerHandle *bgw_handle;
                                866                 :                :     BgwHandleStatus status;
                                867                 :                :     pid_t       pid;
                                868                 :                :     uint64      invocation;
                                869                 :                :     char        activity[NAMEDATALEN + 64];
                                870                 :                :     DataChecksumsWorkerResult result;
                                871                 :                : 
   31 heikki.linnakangas@i      872                 :             23 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
                                873                 :                : 
                                874                 :                :     /*
                                875                 :                :      * Initialize result to FAILED.  The worker will change it to SUCCESSFUL
                                876                 :                :      * if it completes successfully.
                                877                 :                :      */
                                878                 :             23 :     DataChecksumState->worker_result = DATACHECKSUMSWORKER_FAILED;
                                879                 :             23 :     DataChecksumState->worker_pid = InvalidPid;
                                880                 :                : 
                                881                 :             23 :     invocation = ++DataChecksumState->worker_invocation_counter;
                                882                 :             23 :     DataChecksumState->worker_invocation = invocation;
                                883                 :             23 :     DataChecksumState->database_oid = db->dboid;
                                884                 :                : 
   86 dgustafsson@postgres      885                 :             23 :     LWLockRelease(DataChecksumsWorkerLock);
                                886                 :                : 
  113                           887                 :             23 :     memset(&bgw, 0, sizeof(bgw));
                                888                 :             23 :     bgw.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION;
                                889                 :             23 :     bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
                                890                 :             23 :     snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
                                891                 :             23 :     snprintf(bgw.bgw_function_name, BGW_MAXLEN, "%s", "DataChecksumsWorkerMain");
   57                           892                 :             23 :     snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksums worker");
                                893                 :             23 :     snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksums worker");
  113                           894                 :             23 :     bgw.bgw_restart_time = BGW_NEVER_RESTART;
                                895                 :             23 :     bgw.bgw_notify_pid = MyProcPid;
                                896                 :                :     /* pass the invocation number to the worker process */
   31 heikki.linnakangas@i      897                 :             23 :     bgw.bgw_main_arg = UInt64GetDatum(invocation);
                                898                 :                : 
                                899                 :                :     /*
                                900                 :                :      * If there are no worker slots available, there is little we can do.  If
                                901                 :                :      * we retry in a bit it's still unlikely that the user has managed to
                                902                 :                :      * reconfigure in the meantime and we'd be run through retries fast.
                                903                 :                :      */
  113 dgustafsson@postgres      904         [ -  + ]:             23 :     if (!RegisterDynamicBackgroundWorker(&bgw, &bgw_handle))
                                905                 :                :     {
  113 dgustafsson@postgres      906         [ #  # ]:UBC           0 :         ereport(WARNING,
                                907                 :                :                 errmsg("could not start background worker for enabling data checksums in database \"%s\"",
                                908                 :                :                        db->dbname),
                                909                 :                :                 errhint("The \"%s\" setting might be too low.", "max_worker_processes"));
                                910                 :              0 :         return DATACHECKSUMSWORKER_FAILED;
                                911                 :                :     }
                                912                 :                : 
  113 dgustafsson@postgres      913                 :CBC          23 :     status = WaitForBackgroundWorkerStartup(bgw_handle, &pid);
                                914         [ -  + ]:             23 :     if (status == BGWH_STOPPED)
                                915                 :                :     {
                                916                 :                :         /*
                                917                 :                :          * If the worker managed to start, and stop, before we got to waiting
                                918                 :                :          * for it we can see a STOPPED status here without it being a failure.
                                919                 :                :          */
   86 dgustafsson@postgres      920                 :UBC           0 :         LWLockAcquire(DataChecksumsWorkerLock, LW_SHARED);
   31 heikki.linnakangas@i      921         [ #  # ]:              0 :         Assert(DataChecksumState->worker_invocation == invocation);
                                922         [ #  # ]:              0 :         if (DataChecksumState->worker_result == DATACHECKSUMSWORKER_SUCCESSFUL)
                                923                 :                :         {
   86 dgustafsson@postgres      924                 :              0 :             LWLockRelease(DataChecksumsWorkerLock);
  110                           925                 :              0 :             pgstat_report_activity(STATE_IDLE, NULL);
   31 heikki.linnakangas@i      926                 :              0 :             return DATACHECKSUMSWORKER_SUCCESSFUL;
                                927                 :                :         }
   86 dgustafsson@postgres      928                 :              0 :         LWLockRelease(DataChecksumsWorkerLock);
                                929                 :                : 
  113                           930         [ #  # ]:              0 :         ereport(WARNING,
                                931                 :                :                 errmsg("could not start background worker for enabling data checksums in database \"%s\"",
                                932                 :                :                        db->dbname),
                                933                 :                :                 errhint("More details on the error might be found in the server log."));
                                934                 :                : 
                                935                 :                :         /*
                                936                 :                :          * Heuristic to see if the database was dropped, and if it was we can
                                937                 :                :          * treat it as not an error, else treat as fatal and error out.
                                938                 :                :          */
                                939         [ #  # ]:              0 :         if (DatabaseExists(db->dboid))
                                940                 :              0 :             return DATACHECKSUMSWORKER_FAILED;
                                941                 :                :         else
                                942                 :              0 :             return DATACHECKSUMSWORKER_DROPDB;
                                943                 :                :     }
                                944                 :                : 
                                945                 :                :     /*
                                946                 :                :      * If the postmaster crashed we cannot end up with a processed database so
                                947                 :                :      * we have no alternative other than exiting. When enabling checksums we
                                948                 :                :      * won't at this time have changed the data checksums state in pg_control
                                949                 :                :      * to enabled so when the cluster comes back up processing will have to be
                                950                 :                :      * restarted.
                                951                 :                :      */
  113 dgustafsson@postgres      952         [ -  + ]:CBC          23 :     if (status == BGWH_POSTMASTER_DIED)
  113 dgustafsson@postgres      953         [ #  # ]:UBC           0 :         ereport(FATAL,
                                954                 :                :                 errcode(ERRCODE_ADMIN_SHUTDOWN),
                                955                 :                :                 errmsg("cannot enable data checksums without the postmaster process"),
                                956                 :                :                 errhint("Restart the database and restart data checksum processing by calling pg_enable_data_checksums()."));
                                957                 :                : 
  113 dgustafsson@postgres      958         [ -  + ]:CBC          23 :     Assert(status == BGWH_STARTED);
                                959         [ +  - ]:             23 :     ereport(LOG,
                                960                 :                :             errmsg("initiating data checksum processing in database \"%s\"",
                                961                 :                :                    db->dbname));
                                962                 :                : 
                                963                 :                :     /* Save the pid of the worker so we can signal it later */
                                964                 :             23 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
   31 heikki.linnakangas@i      965         [ -  + ]:             23 :     Assert(DataChecksumState->worker_invocation == invocation);
  113 dgustafsson@postgres      966                 :             23 :     DataChecksumState->worker_pid = pid;
                                967                 :             23 :     LWLockRelease(DataChecksumsWorkerLock);
                                968                 :                : 
                                969                 :             23 :     snprintf(activity, sizeof(activity) - 1,
                                970                 :                :              "Waiting for worker in database %s (pid %ld)", db->dbname, (long) pid);
                                971                 :             23 :     pgstat_report_activity(STATE_RUNNING, activity);
                                972                 :                : 
                                973                 :             23 :     status = WaitForBackgroundWorkerShutdown(bgw_handle);
                                974         [ -  + ]:             22 :     if (status == BGWH_POSTMASTER_DIED)
  113 dgustafsson@postgres      975         [ #  # ]:UBC           0 :         ereport(FATAL,
                                976                 :                :                 errcode(ERRCODE_ADMIN_SHUTDOWN),
                                977                 :                :                 errmsg("postmaster exited during data checksum processing in \"%s\"",
                                978                 :                :                        db->dbname),
                                979                 :                :                 errhint("Restart the database and restart data checksum processing by calling pg_enable_data_checksums()."));
                                980                 :                : 
  113 dgustafsson@postgres      981                 :CBC          22 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
   31 heikki.linnakangas@i      982         [ -  + ]:             22 :     Assert(DataChecksumState->worker_invocation == invocation);
                                983                 :             22 :     result = DataChecksumState->worker_result;
  113 dgustafsson@postgres      984                 :             22 :     DataChecksumState->worker_pid = InvalidPid;
                                985                 :             22 :     LWLockRelease(DataChecksumsWorkerLock);
                                986                 :                : 
   31 heikki.linnakangas@i      987         [ -  + ]:             22 :     if (result == DATACHECKSUMSWORKER_ABORTED)
   31 heikki.linnakangas@i      988         [ #  # ]:UBC           0 :         ereport(LOG,
                                989                 :                :                 errmsg("data checksums processing was aborted in database \"%s\"",
                                990                 :                :                        db->dbname));
   31 heikki.linnakangas@i      991                 :CBC          22 :     pgstat_report_activity(STATE_IDLE, NULL);
                                992                 :             22 :     return result;
                                993                 :                : }
                                994                 :                : 
                                995                 :                : /*
                                996                 :                :  * launcher_exit
                                997                 :                :  *
                                998                 :                :  * Internal routine for cleaning up state when a launcher process which has
                                999                 :                :  * performed checksum operations exits. A launcher process which is exiting due
                               1000                 :                :  * to a duplicate started launcher does not need to perform any cleanup and
                               1001                 :                :  * this function should not be called. Otherwise, we need to clean up the abort
                               1002                 :                :  * flag to ensure that processing can be started again if it was previously
                               1003                 :                :  * aborted (note: started again, *not* restarted from where it left off).
                               1004                 :                :  */
                               1005                 :                : static void
  113 dgustafsson@postgres     1006                 :             14 : launcher_exit(int code, Datum arg)
                               1007                 :                : {
                               1008                 :             14 :     abort_requested = false;
                               1009                 :                : 
                               1010         [ +  + ]:             14 :     if (launcher_running)
                               1011                 :                :     {
                               1012                 :              2 :         LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
                               1013         [ +  + ]:              2 :         if (DataChecksumState->worker_pid != InvalidPid)
                               1014                 :                :         {
                               1015         [ +  - ]:              1 :             ereport(LOG,
                               1016                 :                :                     errmsg("data checksums launcher exiting while worker is still running, signalling worker"));
                               1017                 :              1 :             kill(DataChecksumState->worker_pid, SIGTERM);
   31 heikki.linnakangas@i     1018                 :              1 :             DataChecksumState->worker_pid = InvalidPid;
                               1019                 :                :         }
  113 dgustafsson@postgres     1020                 :              2 :         LWLockRelease(DataChecksumsWorkerLock);
                               1021                 :                :     }
                               1022                 :                : 
                               1023                 :                :     /*
                               1024                 :                :      * If the launcher is exiting before data checksums are enabled then set
                               1025                 :                :      * the state to off since processing cannot be resumed.
                               1026                 :                :      */
                               1027         [ +  + ]:             14 :     if (DataChecksumsInProgressOn())
                               1028                 :              1 :         SetDataChecksumsOff();
                               1029                 :                : 
                               1030                 :             14 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
                               1031                 :             14 :     launcher_running = false;
                               1032                 :             14 :     DataChecksumState->launcher_running = false;
                               1033                 :             14 :     LWLockRelease(DataChecksumsWorkerLock);
                               1034                 :             14 : }
                               1035                 :                : 
                               1036                 :                : /*
                               1037                 :                :  * launcher_cancel_handler
                               1038                 :                :  *
                               1039                 :                :  * Internal routine for reacting to SIGINT and flagging the worker to abort.
                               1040                 :                :  * The worker won't be interrupted immediately but will check for abort flag
                               1041                 :                :  * between each block in a relation.
                               1042                 :                :  */
                               1043                 :                : static void
  113 dgustafsson@postgres     1044                 :UBC           0 : launcher_cancel_handler(SIGNAL_ARGS)
                               1045                 :                : {
                               1046                 :              0 :     int         save_errno = errno;
                               1047                 :                : 
                               1048                 :              0 :     abort_requested = true;
                               1049                 :                : 
                               1050                 :                :     /*
                               1051                 :                :      * There is no sleeping in the main loop, the flag will be checked
                               1052                 :                :      * periodically in ProcessSingleRelationFork. The worker does however
                               1053                 :                :      * sleep when waiting for concurrent transactions to end so we still need
                               1054                 :                :      * to set the latch.
                               1055                 :                :      */
                               1056                 :              0 :     SetLatch(MyLatch);
                               1057                 :                : 
                               1058                 :              0 :     errno = save_errno;
                               1059                 :              0 : }
                               1060                 :                : 
                               1061                 :                : /*
                               1062                 :                :  * WaitForAllTransactionsToFinish
                               1063                 :                :  *      Blocks awaiting all current transactions to finish
                               1064                 :                :  *
                               1065                 :                :  * Returns when all transactions which are active at the call of the function
                               1066                 :                :  * have ended.
                               1067                 :                :  *
                               1068                 :                :  * NB: this will return early, if aborted by SIGINT or if the target state
                               1069                 :                :  * is changed while we're running.
                               1070                 :                :  */
                               1071                 :                : static void
  113 dgustafsson@postgres     1072                 :CBC           9 : WaitForAllTransactionsToFinish(void)
                               1073                 :                : {
                               1074                 :                :     TransactionId waitforxid;
                               1075                 :                : 
                               1076                 :              9 :     LWLockAcquire(XidGenLock, LW_SHARED);
                               1077                 :              9 :     waitforxid = XidFromFullTransactionId(TransamVariables->nextXid);
                               1078                 :              9 :     LWLockRelease(XidGenLock);
                               1079                 :                : 
                               1080         [ -  + ]:              9 :     while (TransactionIdPrecedes(GetOldestActiveTransactionId(false, true), waitforxid))
                               1081                 :                :     {
                               1082                 :                :         char        activity[64];
                               1083                 :                :         int         rc;
                               1084                 :                : 
                               1085                 :                :         /* Oldest running xid is older than us, so wait */
  113 dgustafsson@postgres     1086                 :UBC           0 :         snprintf(activity,
                               1087                 :                :                  sizeof(activity),
                               1088                 :                :                  "Waiting for transactions older than %u to end",
                               1089                 :                :                  waitforxid);
                               1090                 :              0 :         pgstat_report_activity(STATE_RUNNING, activity);
                               1091                 :                : 
                               1092                 :                :         /* Retry every 3 seconds */
                               1093                 :              0 :         ResetLatch(MyLatch);
                               1094                 :              0 :         rc = WaitLatch(MyLatch,
                               1095                 :                :                        WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
                               1096                 :                :                        3000,
                               1097                 :                :                        WAIT_EVENT_CHECKSUM_ENABLE_STARTCONDITION);
                               1098                 :                : 
                               1099                 :                :         /*
                               1100                 :                :          * If the postmaster died, bail out.  But first print a log message to
                               1101                 :                :          * note that the checksumming didn't complete.
                               1102                 :                :          */
                               1103         [ #  # ]:              0 :         if (rc & WL_POSTMASTER_DEATH)
                               1104         [ #  # ]:              0 :             ereport(FATAL,
                               1105                 :                :                     errcode(ERRCODE_ADMIN_SHUTDOWN),
                               1106                 :                :                     errmsg("postmaster exited during data checksums processing"),
                               1107                 :                :                     errhint("Data checksums processing must be restarted manually after cluster restart."));
                               1108                 :                : 
                               1109         [ #  # ]:              0 :         CHECK_FOR_INTERRUPTS();
   31 heikki.linnakangas@i     1110   [ #  #  #  # ]:              0 :         CHECK_FOR_LAUNCHER_ABORT_REQUEST();
                               1111                 :                : 
  113 dgustafsson@postgres     1112         [ #  # ]:              0 :         if (abort_requested)
                               1113                 :              0 :             break;
                               1114                 :                :     }
                               1115                 :                : 
  113 dgustafsson@postgres     1116                 :CBC           9 :     pgstat_report_activity(STATE_IDLE, NULL);
                               1117                 :              9 :     return;
                               1118                 :                : }
                               1119                 :                : 
                               1120                 :                : /*
                               1121                 :                :  * DataChecksumsWorkerLauncherMain
                               1122                 :                :  *
                               1123                 :                :  * Main function for launching dynamic background workers for processing data
                               1124                 :                :  * checksums in databases. This function has the bgworker management, with
                               1125                 :                :  * ProcessAllDatabases being responsible for looping over the databases and
                               1126                 :                :  * initiating processing.
                               1127                 :                :  */
                               1128                 :                : void
                               1129                 :             14 : DataChecksumsWorkerLauncherMain(Datum arg)
                               1130                 :                : {
                               1131                 :                : 
                               1132         [ -  + ]:             14 :     ereport(DEBUG1,
                               1133                 :                :             errmsg("background worker \"datachecksums launcher\" started"));
                               1134                 :                : 
                               1135                 :             14 :     pqsignal(SIGTERM, die);
                               1136                 :             14 :     pqsignal(SIGINT, launcher_cancel_handler);
                               1137                 :             14 :     pqsignal(SIGUSR1, procsignal_sigusr1_handler);
  102 andrew@dunslane.net      1138                 :             14 :     pqsignal(SIGUSR2, PG_SIG_IGN);
                               1139                 :                : 
  113 dgustafsson@postgres     1140                 :             14 :     BackgroundWorkerUnblockSignals();
                               1141                 :                : 
                               1142                 :             14 :     MyBackendType = B_DATACHECKSUMSWORKER_LAUNCHER;
                               1143                 :             14 :     init_ps_display(NULL);
                               1144                 :                : 
                               1145                 :             14 :     INJECTION_POINT("datachecksumsworker-launcher-delay", NULL);
                               1146                 :                : 
                               1147                 :             14 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
                               1148                 :                : 
                               1149         [ -  + ]:             14 :     if (DataChecksumState->launcher_running)
                               1150                 :                :     {
  113 dgustafsson@postgres     1151         [ #  # ]:UBC           0 :         ereport(LOG,
                               1152                 :                :                 errmsg("background worker \"datachecksums launcher\" already running, exiting"));
                               1153                 :                :         /* Launcher was already running, let it finish */
                               1154                 :              0 :         LWLockRelease(DataChecksumsWorkerLock);
                               1155                 :              0 :         return;
                               1156                 :                :     }
                               1157                 :                : 
   86 dgustafsson@postgres     1158                 :CBC          14 :     on_shmem_exit(launcher_exit, 0);
  113                          1159                 :             14 :     launcher_running = true;
                               1160                 :                : 
                               1161                 :                :     /* Initialize a connection to shared catalogs only */
                               1162                 :             14 :     BackgroundWorkerInitializeConnectionByOid(InvalidOid, InvalidOid, 0);
                               1163                 :                : 
                               1164                 :             14 :     operation = DataChecksumState->launch_operation;
                               1165                 :             14 :     DataChecksumState->launcher_running = true;
                               1166                 :             14 :     DataChecksumState->operation = operation;
                               1167                 :             14 :     DataChecksumState->cost_delay = DataChecksumState->launch_cost_delay;
                               1168                 :             14 :     DataChecksumState->cost_limit = DataChecksumState->launch_cost_limit;
                               1169                 :             14 :     LWLockRelease(DataChecksumsWorkerLock);
                               1170                 :                : 
                               1171                 :                :     /*
                               1172                 :                :      * The target state can change while we are busy enabling/disabling
                               1173                 :                :      * checksums, if the user calls pg_disable/enable_data_checksums() before
                               1174                 :                :      * we are finished with the previous request. In that case, we will loop
                               1175                 :                :      * back here, to process the new request.
                               1176                 :                :      */
                               1177                 :             14 : again:
                               1178                 :                : 
                               1179                 :             14 :     pgstat_progress_start_command(PROGRESS_COMMAND_DATACHECKSUMS,
                               1180                 :                :                                   InvalidOid);
   15 fujii@postgresql.org     1181                 :             14 :     ResetDataChecksumsProgressCounters();
                               1182                 :                : 
  113 dgustafsson@postgres     1183         [ +  + ]:             14 :     if (operation == ENABLE_DATACHECKSUMS)
                               1184                 :                :     {
                               1185                 :                :         /*
                               1186                 :                :          * If we are asked to enable checksums in a cluster which already has
                               1187                 :                :          * checksums enabled, exit immediately as there is nothing more to do.
                               1188                 :                :          */
                               1189         [ -  + ]:              9 :         if (DataChecksumsNeedVerify())
  113 dgustafsson@postgres     1190                 :UBC           0 :             goto done;
                               1191                 :                : 
  113 dgustafsson@postgres     1192         [ +  - ]:CBC           9 :         ereport(LOG,
                               1193                 :                :                 errmsg("enabling data checksums requested, starting data checksum calculation"));
                               1194                 :                : 
                               1195                 :                :         /*
                               1196                 :                :          * Set the state to inprogress-on and wait on the procsignal barrier.
                               1197                 :                :          */
                               1198                 :              9 :         pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_PHASE,
                               1199                 :                :                                      PROGRESS_DATACHECKSUMS_PHASE_ENABLING);
                               1200                 :              9 :         SetDataChecksumsOnInProgress();
                               1201                 :                : 
                               1202                 :                :         /*
                               1203                 :                :          * All backends are now in inprogress-on state and are writing data
                               1204                 :                :          * checksums.  Start processing all data at rest.
                               1205                 :                :          */
                               1206         [ -  + ]:              9 :         if (!ProcessAllDatabases())
                               1207                 :                :         {
                               1208                 :                :             /*
                               1209                 :                :              * If the target state changed during processing then it's not a
                               1210                 :                :              * failure, so restart processing instead.
                               1211                 :                :              */
   31 heikki.linnakangas@i     1212   [ #  #  #  # ]:UBC           0 :             CHECK_FOR_LAUNCHER_ABORT_REQUEST();
                               1213         [ #  # ]:              0 :             if (abort_requested)
  113 dgustafsson@postgres     1214                 :              0 :                 goto done;
                               1215         [ #  # ]:              0 :             ereport(ERROR,
                               1216                 :                :                     errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                               1217                 :                :                     errmsg("unable to enable data checksums in cluster"));
                               1218                 :                :         }
                               1219                 :                : 
                               1220                 :                :         /*
                               1221                 :                :          * Data checksums have been set on all pages, set the state to on in
                               1222                 :                :          * order to instruct backends to validate checksums on reading.
                               1223                 :                :          */
  113 dgustafsson@postgres     1224                 :CBC           7 :         SetDataChecksumsOn();
                               1225                 :                : 
                               1226         [ +  - ]:              7 :         ereport(LOG,
                               1227                 :                :                 errmsg("data checksums are now enabled"));
                               1228                 :                :     }
                               1229         [ +  - ]:              5 :     else if (operation == DISABLE_DATACHECKSUMS)
                               1230                 :                :     {
                               1231         [ +  - ]:              5 :         ereport(LOG,
                               1232                 :                :                 errmsg("disabling data checksums requested"));
                               1233                 :                : 
                               1234                 :              5 :         pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_PHASE,
                               1235                 :                :                                      PROGRESS_DATACHECKSUMS_PHASE_DISABLING);
                               1236                 :              5 :         SetDataChecksumsOff();
                               1237         [ +  - ]:              5 :         ereport(LOG,
                               1238                 :                :                 errmsg("data checksums are now disabled"));
                               1239                 :                :     }
                               1240                 :                :     else
  113 dgustafsson@postgres     1241                 :UBC           0 :         Assert(false);
                               1242                 :                : 
  113 dgustafsson@postgres     1243                 :CBC          12 : done:
                               1244                 :                : 
                               1245                 :                :     /*
                               1246                 :                :      * This state will only be displayed for a fleeting moment, but for the
                               1247                 :                :      * sake of correctness it is still added before ending the command.
                               1248                 :                :      */
                               1249                 :             12 :     pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_PHASE,
                               1250                 :                :                                  PROGRESS_DATACHECKSUMS_PHASE_DONE);
                               1251                 :                : 
                               1252                 :                :     /*
                               1253                 :                :      * All done. But before we exit, check if the target state was changed
                               1254                 :                :      * while we were running. In that case we will have to start all over
                               1255                 :                :      * again.
                               1256                 :                :      */
                               1257                 :             12 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
                               1258         [ -  + ]:             12 :     if (DataChecksumState->launch_operation != operation)
                               1259                 :                :     {
  113 dgustafsson@postgres     1260                 :UBC           0 :         DataChecksumState->operation = DataChecksumState->launch_operation;
                               1261                 :              0 :         operation = DataChecksumState->launch_operation;
                               1262                 :              0 :         DataChecksumState->cost_delay = DataChecksumState->launch_cost_delay;
                               1263                 :              0 :         DataChecksumState->cost_limit = DataChecksumState->launch_cost_limit;
                               1264                 :              0 :         LWLockRelease(DataChecksumsWorkerLock);
                               1265                 :              0 :         goto again;
                               1266                 :                :     }
                               1267                 :                : 
                               1268                 :                :     /* Shut down progress reporting as we are done */
  113 dgustafsson@postgres     1269                 :CBC          12 :     pgstat_progress_end_command();
                               1270                 :                : 
                               1271                 :             12 :     launcher_running = false;
                               1272                 :             12 :     DataChecksumState->launcher_running = false;
                               1273                 :             12 :     LWLockRelease(DataChecksumsWorkerLock);
                               1274                 :                : }
                               1275                 :                : 
                               1276                 :                : /*
                               1277                 :                :  * ProcessAllDatabases
                               1278                 :                :  *      Compute the list of all databases and process checksums in each
                               1279                 :                :  *
                               1280                 :                :  * This will generate a list of databases to process for enabling checksums.
                               1281                 :                :  * If a database encounters a failure then processing will end immediately and
                               1282                 :                :  * return an error.
                               1283                 :                :  */
                               1284                 :                : static bool
                               1285                 :              9 : ProcessAllDatabases(void)
                               1286                 :                : {
                               1287                 :                :     List       *DatabaseList;
                               1288                 :              9 :     int         cumulative_total = 0;
                               1289                 :                : 
                               1290                 :                :     /* Set up so first run processes shared catalogs, not once in every db */
   86                          1291                 :              9 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
  113                          1292                 :              9 :     DataChecksumState->process_shared_catalogs = true;
   86                          1293                 :              9 :     LWLockRelease(DataChecksumsWorkerLock);
                               1294                 :                : 
                               1295                 :                :     /* Get a list of all databases to process */
  113                          1296                 :              9 :     WaitForAllTransactionsToFinish();
                               1297                 :              9 :     DatabaseList = BuildDatabaseList();
                               1298                 :                : 
                               1299                 :                :     /*
                               1300                 :                :      * Update progress reporting with the total number of databases we need to
                               1301                 :                :      * process.  This number should not be changed during processing, the
                               1302                 :                :      * columns for processed databases is instead increased such that it can
                               1303                 :                :      * be compared against the total.
                               1304                 :                :      */
                               1305                 :                :     {
                               1306                 :              9 :         const int   index[] = {
                               1307                 :                :             PROGRESS_DATACHECKSUMS_DBS_TOTAL,
                               1308                 :                :             PROGRESS_DATACHECKSUMS_DBS_DONE,
                               1309                 :                :         };
                               1310                 :                : 
                               1311                 :                :         int64       vals[2];
                               1312                 :                : 
                               1313                 :              9 :         vals[0] = list_length(DatabaseList);
                               1314                 :              9 :         vals[1] = 0;
                               1315                 :                : 
   15 fujii@postgresql.org     1316                 :              9 :         pgstat_progress_update_multi_param(2, index, vals);
                               1317                 :                :     }
                               1318                 :                : 
  113 dgustafsson@postgres     1319   [ +  -  +  +  :             37 :     foreach_ptr(DataChecksumsWorkerDatabase, db, DatabaseList)
                                              +  + ]
                               1320                 :                :     {
                               1321                 :                :         DataChecksumsWorkerResult result;
                               1322                 :                : 
                               1323                 :             23 :         result = ProcessDatabase(db);
                               1324                 :                : 
                               1325                 :                : #ifdef USE_INJECTION_POINTS
                               1326                 :                :         /* Allow a test process to alter the result of the operation */
  110                          1327         [ +  + ]:             22 :         if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fail-db-result"))
                               1328                 :                :         {
                               1329                 :              1 :             result = DATACHECKSUMSWORKER_FAILED;
                               1330                 :              1 :             INJECTION_POINT_CACHED("datachecksumsworker-fail-db-result",
                               1331                 :                :                                    db->dbname);
                               1332                 :                :         }
                               1333                 :                : #endif
                               1334                 :                : 
  113                          1335                 :             22 :         pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_DBS_DONE,
                               1336                 :                :                                      ++cumulative_total);
                               1337                 :                : 
                               1338         [ +  + ]:             22 :         if (result == DATACHECKSUMSWORKER_FAILED)
                               1339                 :                :         {
                               1340                 :                :             /*
                               1341                 :                :              * Disable checksums on cluster, because we failed one of the
                               1342                 :                :              * databases and this is an all or nothing process.
                               1343                 :                :              */
                               1344                 :              1 :             SetDataChecksumsOff();
                               1345         [ +  - ]:              1 :             ereport(ERROR,
                               1346                 :                :                     errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                               1347                 :                :                     errmsg("data checksums failed to get enabled in all databases, aborting"),
                               1348                 :                :                     errhint("The server log might have more information on the cause of the error."));
                               1349                 :                :         }
                               1350   [ +  -  -  + ]:             21 :         else if (result == DATACHECKSUMSWORKER_ABORTED || abort_requested)
                               1351                 :                :         {
                               1352                 :                :             /* Abort flag set, so exit the whole process */
  113 dgustafsson@postgres     1353                 :UBC           0 :             return false;
                               1354                 :                :         }
   15 fujii@postgresql.org     1355         [ -  + ]:CBC          21 :         else if (result == DATACHECKSUMSWORKER_DROPDB)
                               1356                 :                :         {
                               1357                 :                :             /*
                               1358                 :                :              * Ignore databases that were dropped before their worker could
                               1359                 :                :              * process them, and continue with the remaining databases.
                               1360                 :                :              */
   15 fujii@postgresql.org     1361                 :UBC           0 :             continue;
                               1362                 :                :         }
                               1363                 :                : 
                               1364                 :                :         /*
                               1365                 :                :          * When one database has completed, it will have done shared catalogs
                               1366                 :                :          * so we don't have to process them again.
                               1367                 :                :          */
   86 dgustafsson@postgres     1368                 :CBC          21 :         LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
  113                          1369                 :             21 :         DataChecksumState->process_shared_catalogs = false;
   86                          1370                 :             21 :         LWLockRelease(DataChecksumsWorkerLock);
                               1371                 :                :     }
                               1372                 :                : 
  113                          1373                 :              7 :     FreeDatabaseList(DatabaseList);
                               1374                 :                : 
                               1375                 :              7 :     pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_PHASE,
                               1376                 :                :                                  PROGRESS_DATACHECKSUMS_PHASE_WAITING_BARRIER);
                               1377                 :              7 :     return true;
                               1378                 :                : }
                               1379                 :                : 
                               1380                 :                : /*
                               1381                 :                :  * DataChecksumsShmemRequest
                               1382                 :                :  *      Request datachecksumsworker-related shared memory
                               1383                 :                :  */
                               1384                 :                : static void
  110 heikki.linnakangas@i     1385                 :           1225 : DataChecksumsShmemRequest(void *arg)
                               1386                 :                : {
                               1387                 :           1225 :     ShmemRequestStruct(.name = "DataChecksumsWorker Data",
                               1388                 :                :                        .size = sizeof(DataChecksumsStateStruct),
                               1389                 :                :                        .ptr = (void **) &DataChecksumState,
                               1390                 :                :         );
  113 dgustafsson@postgres     1391                 :           1225 : }
                               1392                 :                : 
                               1393                 :                : /*
                               1394                 :                :  * DatabaseExists
                               1395                 :                :  *
                               1396                 :                :  * Scans the system catalog to check if a database with the given Oid exists
                               1397                 :                :  * and returns true if it is found and valid, else false. Note, we cannot use
                               1398                 :                :  * database_is_invalid_oid here as it will ERROR out, and we want to gracefully
                               1399                 :                :  * handle errors.
                               1400                 :                :  */
                               1401                 :                : static bool
  113 dgustafsson@postgres     1402                 :UBC           0 : DatabaseExists(Oid dboid)
                               1403                 :                : {
                               1404                 :                :     Relation    rel;
                               1405                 :                :     ScanKeyData skey;
                               1406                 :                :     SysScanDesc scan;
                               1407                 :                :     bool        found;
                               1408                 :                :     HeapTuple   tuple;
                               1409                 :                :     Form_pg_database pg_database_tuple;
                               1410                 :                : 
                               1411                 :              0 :     StartTransactionCommand();
                               1412                 :                : 
                               1413                 :              0 :     rel = table_open(DatabaseRelationId, AccessShareLock);
                               1414                 :              0 :     ScanKeyInit(&skey,
                               1415                 :                :                 Anum_pg_database_oid,
                               1416                 :                :                 BTEqualStrategyNumber, F_OIDEQ,
                               1417                 :                :                 ObjectIdGetDatum(dboid));
                               1418                 :              0 :     scan = systable_beginscan(rel, DatabaseOidIndexId, true, SnapshotSelf,
                               1419                 :                :                               1, &skey);
                               1420                 :              0 :     tuple = systable_getnext(scan);
                               1421                 :              0 :     found = HeapTupleIsValid(tuple);
                               1422                 :                : 
                               1423                 :                :     /* If the Oid exists, ensure that it's not partially dropped */
   86                          1424         [ #  # ]:              0 :     if (found)
                               1425                 :                :     {
                               1426                 :              0 :         pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
                               1427         [ #  # ]:              0 :         if (database_is_invalid_form(pg_database_tuple))
                               1428                 :              0 :             found = false;
                               1429                 :                :     }
                               1430                 :                : 
  113                          1431                 :              0 :     systable_endscan(scan);
                               1432                 :              0 :     table_close(rel, AccessShareLock);
                               1433                 :                : 
                               1434                 :              0 :     CommitTransactionCommand();
                               1435                 :                : 
                               1436                 :              0 :     return found;
                               1437                 :                : }
                               1438                 :                : 
                               1439                 :                : /*
                               1440                 :                :  * BuildDatabaseList
                               1441                 :                :  *      Compile a list of all currently available databases in the cluster
                               1442                 :                :  *
                               1443                 :                :  * This creates the list of databases for the datachecksumsworker workers to
                               1444                 :                :  * add checksums to. If the caller wants to ensure that no concurrently
                               1445                 :                :  * running CREATE DATABASE calls exist, this needs to be preceded by a call
                               1446                 :                :  * to WaitForAllTransactionsToFinish().
                               1447                 :                :  */
                               1448                 :                : static List *
  113 dgustafsson@postgres     1449                 :CBC           9 : BuildDatabaseList(void)
                               1450                 :                : {
                               1451                 :              9 :     List       *DatabaseList = NIL;
                               1452                 :                :     Relation    rel;
                               1453                 :                :     TableScanDesc scan;
                               1454                 :                :     HeapTuple   tup;
                               1455                 :              9 :     MemoryContext ctx = CurrentMemoryContext;
                               1456                 :                :     MemoryContext oldctx;
                               1457                 :                : 
                               1458                 :              9 :     StartTransactionCommand();
                               1459                 :                : 
                               1460                 :              9 :     rel = table_open(DatabaseRelationId, AccessShareLock);
                               1461                 :              9 :     scan = table_beginscan_catalog(rel, 0, NULL);
                               1462                 :                : 
                               1463         [ +  + ]:             36 :     while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
                               1464                 :                :     {
                               1465                 :             27 :         Form_pg_database pgdb = (Form_pg_database) GETSTRUCT(tup);
                               1466                 :                :         DataChecksumsWorkerDatabase *db;
                               1467                 :                : 
                               1468                 :             27 :         oldctx = MemoryContextSwitchTo(ctx);
                               1469                 :                : 
                               1470                 :             27 :         db = (DataChecksumsWorkerDatabase *) palloc0(sizeof(DataChecksumsWorkerDatabase));
                               1471                 :                : 
                               1472                 :             27 :         db->dboid = pgdb->oid;
                               1473                 :             27 :         db->dbname = pstrdup(NameStr(pgdb->datname));
                               1474                 :                : 
                               1475                 :             27 :         DatabaseList = lappend(DatabaseList, db);
                               1476                 :                : 
                               1477                 :             27 :         MemoryContextSwitchTo(oldctx);
                               1478                 :                :     }
                               1479                 :                : 
                               1480                 :              9 :     table_endscan(scan);
                               1481                 :              9 :     table_close(rel, AccessShareLock);
                               1482                 :                : 
                               1483                 :              9 :     CommitTransactionCommand();
                               1484                 :                : 
                               1485                 :              9 :     return DatabaseList;
                               1486                 :                : }
                               1487                 :                : 
                               1488                 :                : static void
                               1489                 :              7 : FreeDatabaseList(List *dblist)
                               1490                 :                : {
                               1491         [ -  + ]:              7 :     if (!dblist)
  113 dgustafsson@postgres     1492                 :UBC           0 :         return;
                               1493                 :                : 
  113 dgustafsson@postgres     1494   [ +  -  +  +  :CBC          35 :     foreach_ptr(DataChecksumsWorkerDatabase, db, dblist)
                                              +  + ]
                               1495                 :                :     {
                               1496         [ +  - ]:             21 :         if (db->dbname != NULL)
                               1497                 :             21 :             pfree(db->dbname);
                               1498                 :                :     }
                               1499                 :                : 
                               1500                 :              7 :     list_free_deep(dblist);
                               1501                 :                : }
                               1502                 :                : 
                               1503                 :                : /*
                               1504                 :                :  * BuildRelationList
                               1505                 :                :  *      Compile a list of relations in the database
                               1506                 :                :  *
                               1507                 :                :  * Returns a list of OIDs for the requested relation types. If temp_relations
                               1508                 :                :  * is True then only temporary relations with storage are returned.  If
                               1509                 :                :  * temp_relations is False then non-temporary relations with storage are
                               1510                 :                :  * returned.  If include_shared is True then shared relations are included as
                               1511                 :                :  * well in a non-temporary list. include_shared has no relevance when building
                               1512                 :                :  * a list of temporary relations.
                               1513                 :                :  */
                               1514                 :                : static List *
                               1515                 :             68 : BuildRelationList(bool temp_relations, bool include_shared)
                               1516                 :                : {
                               1517                 :             68 :     List       *RelationList = NIL;
                               1518                 :                :     Relation    rel;
                               1519                 :                :     TableScanDesc scan;
                               1520                 :                :     HeapTuple   tup;
                               1521                 :             68 :     MemoryContext ctx = CurrentMemoryContext;
                               1522                 :                :     MemoryContext oldctx;
                               1523                 :                : 
                               1524                 :             68 :     StartTransactionCommand();
                               1525                 :                : 
                               1526                 :             68 :     rel = table_open(RelationRelationId, AccessShareLock);
                               1527                 :             68 :     scan = table_beginscan_catalog(rel, 0, NULL);
                               1528                 :                : 
                               1529         [ +  + ]:          30915 :     while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
                               1530                 :                :     {
                               1531                 :          30847 :         Form_pg_class pgc = (Form_pg_class) GETSTRUCT(tup);
                               1532                 :                : 
   15 fujii@postgresql.org     1533   [ +  +  +  +  :          30847 :         if (!RELKIND_HAS_STORAGE(pgc->relkind))
                                     +  -  +  +  +  
                                                 - ]
                               1534                 :          11084 :             continue;
                               1535                 :                : 
                               1536                 :                :         /* Only include temporary relations when explicitly asked to */
  113 dgustafsson@postgres     1537         [ +  + ]:          19763 :         if (pgc->relpersistence == RELPERSISTENCE_TEMP)
                               1538                 :                :         {
                               1539         [ +  + ]:              2 :             if (!temp_relations)
                               1540                 :              1 :                 continue;
                               1541                 :                :         }
                               1542                 :                :         else
                               1543                 :                :         {
                               1544                 :                :             /*
                               1545                 :                :              * If we are only interested in temp relations then continue
                               1546                 :                :              * immediately as the current relation isn't a temp relation.
                               1547                 :                :              */
                               1548         [ +  + ]:          19761 :             if (temp_relations)
                               1549                 :          13077 :                 continue;
                               1550                 :                : 
                               1551   [ +  +  +  + ]:           6684 :             if (pgc->relisshared && !include_shared)
                               1552                 :            644 :                 continue;
                               1553                 :                :         }
                               1554                 :                : 
                               1555                 :           6041 :         oldctx = MemoryContextSwitchTo(ctx);
                               1556                 :           6041 :         RelationList = lappend_oid(RelationList, pgc->oid);
                               1557                 :           6041 :         MemoryContextSwitchTo(oldctx);
                               1558                 :                :     }
                               1559                 :                : 
                               1560                 :             68 :     table_endscan(scan);
                               1561                 :             68 :     table_close(rel, AccessShareLock);
                               1562                 :                : 
                               1563                 :             68 :     CommitTransactionCommand();
                               1564                 :                : 
                               1565                 :             68 :     return RelationList;
                               1566                 :                : }
                               1567                 :                : 
                               1568                 :                : /*
                               1569                 :                :  * DataChecksumsWorkerMain
                               1570                 :                :  *
                               1571                 :                :  * Main function for enabling checksums in a single database. This is the
                               1572                 :                :  * function set as the bgw_function_name in the dynamic background worker
                               1573                 :                :  * process initiated for each database by the worker launcher. After enabling
                               1574                 :                :  * data checksums in each applicable relation in the database, it will wait for
                               1575                 :                :  * all temporary relations that were present when the function started to
                               1576                 :                :  * disappear before returning. This is required since we cannot rewrite
                               1577                 :                :  * existing temporary relations with data checksums.
                               1578                 :                :  */
                               1579                 :                : void
                               1580                 :             23 : DataChecksumsWorkerMain(Datum arg)
                               1581                 :                : {
                               1582                 :                :     Oid         dboid;
                               1583                 :             23 :     List       *RelationList = NIL;
                               1584                 :             23 :     List       *InitialTempTableList = NIL;
                               1585                 :                :     BufferAccessStrategy strategy;
                               1586                 :             23 :     bool        aborted = false;
                               1587                 :                :     int64       rels_done;
                               1588                 :                :     bool        process_shared;
                               1589                 :                : #ifdef USE_INJECTION_POINTS
  110                          1590                 :             23 :     bool        retried = false;
                               1591                 :                : #endif
                               1592                 :                : 
   31 heikki.linnakangas@i     1593                 :             23 :     worker_invocation = DatumGetUInt64(arg);
                               1594                 :                : 
  113 dgustafsson@postgres     1595                 :             23 :     operation = ENABLE_DATACHECKSUMS;
                               1596                 :                : 
                               1597                 :             23 :     pqsignal(SIGTERM, die);
                               1598                 :             23 :     pqsignal(SIGUSR1, procsignal_sigusr1_handler);
                               1599                 :                : 
                               1600                 :             23 :     BackgroundWorkerUnblockSignals();
                               1601                 :                : 
                               1602                 :             23 :     MyBackendType = B_DATACHECKSUMSWORKER_WORKER;
                               1603                 :             23 :     init_ps_display(NULL);
                               1604                 :                : 
   31 heikki.linnakangas@i     1605                 :             23 :     LWLockAcquire(DataChecksumsWorkerLock, LW_SHARED);
                               1606         [ -  + ]:             23 :     if (DataChecksumState->worker_invocation != worker_invocation)
                               1607                 :                :     {
   31 heikki.linnakangas@i     1608                 :UBC           0 :         LWLockRelease(DataChecksumsWorkerLock);
                               1609                 :              0 :         return;
                               1610                 :                :     }
   31 heikki.linnakangas@i     1611                 :CBC          23 :     dboid = DataChecksumState->database_oid;
                               1612                 :             23 :     LWLockRelease(DataChecksumsWorkerLock);
                               1613                 :                : 
  113 dgustafsson@postgres     1614                 :             23 :     BackgroundWorkerInitializeConnectionByOid(dboid, InvalidOid,
                               1615                 :                :                                               BGWORKER_BYPASS_ALLOWCONN);
                               1616                 :                : 
                               1617                 :                :     /* worker will have a separate entry in pg_stat_progress_data_checksums */
                               1618                 :             23 :     pgstat_progress_start_command(PROGRESS_COMMAND_DATACHECKSUMS,
                               1619                 :                :                                   InvalidOid);
   15 fujii@postgresql.org     1620                 :             23 :     ResetDataChecksumsProgressCounters();
                               1621                 :                : 
                               1622                 :                :     /*
                               1623                 :                :      * Get a list of all temp tables present as we start in this database. We
                               1624                 :                :      * need to wait until they are all gone before we exit.  For the list of
                               1625                 :                :      * relations to enable checksums in, check if shared catalogs have been
                               1626                 :                :      * processed already.
                               1627                 :                :      */
  113 dgustafsson@postgres     1628                 :             23 :     InitialTempTableList = BuildRelationList(true, false);
   37                          1629                 :             23 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
   31 heikki.linnakangas@i     1630         [ -  + ]:             23 :     if (DataChecksumState->worker_invocation != worker_invocation)
                               1631                 :                :     {
   31 heikki.linnakangas@i     1632                 :UBC           0 :         LWLockRelease(DataChecksumsWorkerLock);
                               1633                 :              0 :         return;
                               1634                 :                :     }
   37 dgustafsson@postgres     1635                 :CBC          23 :     process_shared = DataChecksumState->process_shared_catalogs;
                               1636                 :                : 
                               1637                 :                :     /*
                               1638                 :                :      * Enable vacuum cost delay, if any.  While this process isn't doing any
                               1639                 :                :      * vacuuming, we are re-using the infrastructure that vacuum cost delay
                               1640                 :                :      * provides rather than inventing something bespoke. This is an internal
                               1641                 :                :      * implementation detail and care should be taken to avoid it bleeding
                               1642                 :                :      * through to the user to avoid confusion.
                               1643                 :                :      *
                               1644                 :                :      * VacuumUpdateCosts() propagates the values to the variables actually
                               1645                 :                :      * read by vacuum_delay_point().
                               1646                 :                :      */
  113                          1647                 :             23 :     VacuumCostDelay = DataChecksumState->cost_delay;
                               1648                 :             23 :     VacuumCostLimit = DataChecksumState->cost_limit;
   37                          1649                 :             23 :     LWLockRelease(DataChecksumsWorkerLock);
   80                          1650                 :             23 :     VacuumUpdateCosts();
  113                          1651                 :             23 :     VacuumCostBalance = 0;
                               1652                 :                : 
                               1653                 :                :     /*
                               1654                 :                :      * Create and set the vacuum strategy as our buffer strategy.
                               1655                 :                :      */
                               1656                 :             23 :     strategy = GetAccessStrategy(BAS_VACUUM);
                               1657                 :                : 
   37                          1658                 :             23 :     RelationList = BuildRelationList(false, process_shared);
                               1659                 :                : 
                               1660                 :                :     /* Update the total number of relations to be processed in this DB. */
                               1661                 :                :     {
  113                          1662                 :             23 :         const int   index[] = {
                               1663                 :                :             PROGRESS_DATACHECKSUMS_RELS_TOTAL,
                               1664                 :                :             PROGRESS_DATACHECKSUMS_RELS_DONE
                               1665                 :                :         };
                               1666                 :                : 
                               1667                 :                :         int64       vals[2];
                               1668                 :                : 
                               1669                 :             23 :         vals[0] = list_length(RelationList);
                               1670                 :             23 :         vals[1] = 0;
                               1671                 :                : 
                               1672                 :             23 :         pgstat_progress_update_multi_param(2, index, vals);
                               1673                 :                :     }
                               1674                 :                : 
                               1675                 :                :     /* Process the relations */
                               1676                 :             23 :     rels_done = 0;
                               1677   [ +  -  +  +  :           5884 :     foreach_oid(reloid, RelationList)
                                              +  + ]
                               1678                 :                :     {
   86                          1679                 :           5840 :         bool        costs_updated = false;
                               1680                 :                : 
  113                          1681         [ -  + ]:           5840 :         if (!ProcessSingleRelationByOid(reloid, strategy))
                               1682                 :                :         {
  113 dgustafsson@postgres     1683                 :UBC           0 :             aborted = true;
                               1684                 :              0 :             break;
                               1685                 :                :         }
                               1686                 :                : 
  113 dgustafsson@postgres     1687                 :CBC        5839 :         pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_RELS_DONE,
                               1688                 :                :                                      ++rels_done);
   86                          1689         [ -  + ]:           5839 :         CHECK_FOR_INTERRUPTS();
   31 heikki.linnakangas@i     1690   [ -  +  +  -  :           5839 :         CHECK_FOR_WORKER_ABORT_REQUEST();
                                              -  + ]
                               1691                 :                : 
   86 dgustafsson@postgres     1692         [ -  + ]:           5839 :         if (abort_requested)
   86 dgustafsson@postgres     1693                 :UBC           0 :             break;
                               1694                 :                : 
                               1695                 :                :         /*
                               1696                 :                :          * Check if the cost settings changed during runtime and if so, update
                               1697                 :                :          * to reflect the new values and signal that the access strategy needs
                               1698                 :                :          * to be refreshed.
                               1699                 :                :          */
   86 dgustafsson@postgres     1700                 :CBC        5839 :         LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
   31 heikki.linnakangas@i     1701         [ -  + ]:           5839 :         if (DataChecksumState->worker_invocation != worker_invocation)
                               1702                 :                :         {
   31 heikki.linnakangas@i     1703                 :UBC           0 :             LWLockRelease(DataChecksumsWorkerLock);
                               1704                 :              0 :             break;
                               1705                 :                :         }
   86 dgustafsson@postgres     1706         [ +  - ]:CBC        5839 :         if ((DataChecksumState->launch_cost_delay != DataChecksumState->cost_delay)
                               1707         [ -  + ]:           5839 :             || (DataChecksumState->launch_cost_limit != DataChecksumState->cost_limit))
                               1708                 :                :         {
   86 dgustafsson@postgres     1709                 :UBC           0 :             costs_updated = true;
                               1710                 :              0 :             VacuumCostDelay = DataChecksumState->launch_cost_delay;
                               1711                 :              0 :             VacuumCostLimit = DataChecksumState->launch_cost_limit;
   80                          1712                 :              0 :             VacuumUpdateCosts();
                               1713                 :                : 
   86                          1714                 :              0 :             DataChecksumState->cost_delay = DataChecksumState->launch_cost_delay;
                               1715                 :              0 :             DataChecksumState->cost_limit = DataChecksumState->launch_cost_limit;
                               1716                 :                :         }
                               1717                 :                :         else
   86 dgustafsson@postgres     1718                 :CBC        5839 :             costs_updated = false;
                               1719                 :           5839 :         LWLockRelease(DataChecksumsWorkerLock);
                               1720                 :                : 
                               1721         [ -  + ]:           5839 :         if (costs_updated)
                               1722                 :                :         {
   86 dgustafsson@postgres     1723                 :UBC           0 :             FreeAccessStrategy(strategy);
                               1724                 :              0 :             strategy = GetAccessStrategy(BAS_VACUUM);
                               1725                 :                :         }
                               1726                 :                :     }
                               1727                 :                : 
  113 dgustafsson@postgres     1728                 :CBC          22 :     list_free(RelationList);
   86                          1729                 :             22 :     FreeAccessStrategy(strategy);
                               1730                 :                : 
                               1731   [ +  -  -  + ]:             22 :     if (aborted || abort_requested)
                               1732                 :                :     {
   86 dgustafsson@postgres     1733                 :UBC           0 :         LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
   31 heikki.linnakangas@i     1734         [ #  # ]:              0 :         if (DataChecksumState->worker_invocation == worker_invocation)
                               1735                 :              0 :             DataChecksumState->worker_result = DATACHECKSUMSWORKER_ABORTED;
   86 dgustafsson@postgres     1736                 :              0 :         LWLockRelease(DataChecksumsWorkerLock);
  113                          1737         [ #  # ]:              0 :         ereport(DEBUG1,
                               1738                 :                :                 errmsg("data checksum processing aborted in database OID %u",
                               1739                 :                :                        dboid));
                               1740                 :              0 :         return;
                               1741                 :                :     }
                               1742                 :                : 
                               1743                 :                :     /* The worker is about to wait for temporary tables to go away. */
  113 dgustafsson@postgres     1744                 :CBC          22 :     pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_PHASE,
                               1745                 :                :                                  PROGRESS_DATACHECKSUMS_PHASE_WAITING_TEMPREL);
                               1746                 :                : 
                               1747                 :                :     /*
                               1748                 :                :      * Wait for all temp tables that existed when we started to go away. This
                               1749                 :                :      * is necessary since we cannot "reach" them to enable checksums. Any temp
                               1750                 :                :      * tables created after we started will already have checksums in them
                               1751                 :                :      * (due to the "inprogress-on" state), so no need to wait for those.
                               1752                 :                :      */
                               1753                 :                :     for (;;)
  113 dgustafsson@postgres     1754                 :UBC           0 :     {
                               1755                 :                :         List       *CurrentTempTables;
                               1756                 :                :         int         numleft;
                               1757                 :                :         char        activity[64];
                               1758                 :                : 
  113 dgustafsson@postgres     1759                 :CBC          22 :         CurrentTempTables = BuildRelationList(true, false);
                               1760                 :             22 :         numleft = 0;
                               1761   [ -  +  -  -  :             44 :         foreach_oid(tmptbloid, InitialTempTableList)
                                              +  + ]
                               1762                 :                :         {
  113 dgustafsson@postgres     1763         [ #  # ]:UBC           0 :             if (list_member_oid(CurrentTempTables, tmptbloid))
                               1764                 :              0 :                 numleft++;
                               1765                 :                :         }
  113 dgustafsson@postgres     1766                 :CBC          22 :         list_free(CurrentTempTables);
                               1767                 :                : 
                               1768                 :                : #ifdef USE_INJECTION_POINTS
  110                          1769         [ -  + ]:             22 :         if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fake-temptable-wait"))
                               1770                 :                :         {
                               1771                 :                :             /* Make sure to just cause one retry */
  110 dgustafsson@postgres     1772   [ #  #  #  # ]:UBC           0 :             if (!retried && numleft == 0)
                               1773                 :                :             {
                               1774                 :              0 :                 numleft = 1;
                               1775                 :              0 :                 retried = true;
                               1776                 :                : 
                               1777                 :              0 :                 INJECTION_POINT_CACHED("datachecksumsworker-fake-temptable-wait", NULL);
                               1778                 :                :             }
                               1779                 :                :         }
                               1780                 :                : #endif
                               1781                 :                : 
  113 dgustafsson@postgres     1782         [ +  - ]:CBC          22 :         if (numleft == 0)
                               1783                 :             22 :             break;
                               1784                 :                : 
                               1785                 :                :         /*
                               1786                 :                :          * At least one temp table is left to wait for, indicate in pgstat
                               1787                 :                :          * activity and progress reporting.
                               1788                 :                :          */
  113 dgustafsson@postgres     1789                 :UBC           0 :         snprintf(activity,
                               1790                 :                :                  sizeof(activity),
                               1791                 :                :                  "Waiting for %d temp tables to be removed", numleft);
                               1792                 :              0 :         pgstat_report_activity(STATE_RUNNING, activity);
                               1793                 :                : 
                               1794                 :                :         /* Retry every 3 seconds */
                               1795                 :              0 :         ResetLatch(MyLatch);
                               1796                 :              0 :         (void) WaitLatch(MyLatch,
                               1797                 :                :                          WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
                               1798                 :                :                          3000,
                               1799                 :                :                          WAIT_EVENT_CHECKSUM_ENABLE_TEMPTABLE_WAIT);
                               1800                 :                : 
                               1801         [ #  # ]:              0 :         CHECK_FOR_INTERRUPTS();
   31 heikki.linnakangas@i     1802   [ #  #  #  #  :              0 :         CHECK_FOR_WORKER_ABORT_REQUEST();
                                              #  # ]
                               1803                 :                : 
  113 dgustafsson@postgres     1804   [ #  #  #  # ]:              0 :         if (aborted || abort_requested)
                               1805                 :                :         {
   86                          1806                 :              0 :             LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
   31 heikki.linnakangas@i     1807         [ #  # ]:              0 :             if (DataChecksumState->worker_invocation == worker_invocation)
                               1808                 :              0 :                 DataChecksumState->worker_result = DATACHECKSUMSWORKER_ABORTED;
   86 dgustafsson@postgres     1809                 :              0 :             LWLockRelease(DataChecksumsWorkerLock);
  113                          1810         [ #  # ]:              0 :             ereport(LOG,
                               1811                 :                :                     errmsg("data checksum processing aborted in database OID %u",
                               1812                 :                :                            dboid));
                               1813                 :              0 :             return;
                               1814                 :                :         }
                               1815                 :                :     }
                               1816                 :                : 
  113 dgustafsson@postgres     1817                 :CBC          22 :     list_free(InitialTempTableList);
                               1818                 :                : 
                               1819                 :                :     /* worker done */
                               1820                 :             22 :     pgstat_progress_end_command();
                               1821                 :                : 
  110                          1822                 :             22 :     LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
   31 heikki.linnakangas@i     1823         [ +  - ]:             22 :     if (DataChecksumState->worker_invocation == worker_invocation)
                               1824                 :             22 :         DataChecksumState->worker_result = DATACHECKSUMSWORKER_SUCCESSFUL;
  110 dgustafsson@postgres     1825                 :             22 :     LWLockRelease(DataChecksumsWorkerLock);
                               1826                 :                : }
        

Generated by: LCOV version 2.0-1