PostgreSQL Source Code git master
Loading...
Searching...
No Matches
datachecksum_state.c
Go to the documentation of this file.
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"
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"
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 */
231{
232 /* Current state of data checksums */
233 int from;
234 /* Target state for data checksums */
235 int to;
237
239{
240 /*
241 * Disabling checksums: If checksums are currently enabled, disabling must
242 * go through the 'inprogress-off' state.
243 */
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 */
252
253 /*
254 * Enabling checksums must normally go through the 'inprogress-on' state.
255 */
258
259 /*
260 * If checksums are being disabled but all backends are still computing
261 * checksums, we can go straight back to 'on'
262 */
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 */
270
271 /*
272 * Transitions that can happen when a new request is made while another is
273 * currently being processed.
274 */
277};
278
279/* Possible operations the DataChecksumsWorker can perform */
285
286/* Possible states for a database entry which has been processed */
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 */
302{
303 /*
304 * These are set by pg_{enable|disable}_data_checksums, to tell the
305 * launcher what the target state is.
306 */
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 */
316
317 /*
318 * Every time a new worker is launched, it's assigned a unique invocation
319 * number by incrementing this counter.
320 */
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 */
343
344 /*
345 * Signaling between the launcher and the worker process. Protected by
346 * DataChecksumsWorkerLock.
347 */
348
349 /* result, set by worker before exiting */
351
352 /*
353 * Tells the worker process whether it should also process the shared
354 * catalogs
355 */
358
359/* Shared memory segment for datachecksumsworker */
361
367
368/* Flag set by the interrupt handler */
369static volatile sig_atomic_t abort_requested = false;
370
372
373/*
374 * Have we set the DataChecksumsStateStruct->launcher_running flag?
375 * If we have, we need to clear it before exiting!
376 */
377static volatile sig_atomic_t launcher_running = false;
378
379/* Are we enabling data checksums, or disabling them? */
381
382/* Prototypes */
384 int cost_delay,
385 int cost_limit);
386static void DataChecksumsShmemRequest(void *arg);
387static bool DatabaseExists(Oid dboid);
388static List *BuildDatabaseList(void);
390static void FreeDatabaseList(List *dblist);
392static bool ProcessAllDatabases(void);
394static void ResetDataChecksumsProgressCounters(void);
396static void WaitForAllTransactionsToFinish(void);
397
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
426void
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 */
467bool
469{
471 int current = data_checksums;
472 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 switch (barrier)
480 {
483 break;
486 break;
489 break;
492 break;
493 default:
494 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 */
501 if (current == target_state)
502 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 if (RecoveryInProgress())
509 {
511 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 */
519 for (size_t i = 0; i < lengthof(checksum_barriers) && !found; i++)
520 {
521 if (checksum_barriers[i].from == current && checksum_barriers[i].to == target_state)
522 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 if (!found)
532 errmsg("incorrect data checksum state %i for target state %i",
533 current, target_state));
534
536 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 */
544Datum
546{
547 PreventCommandDuringRecovery("pg_disable_data_checksums()");
548
549 if (!superuser())
552 errmsg("must be superuser to change data checksum state"));
553
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 */
563Datum
565{
566 int cost_delay = PG_GETARG_INT32(0);
567 int cost_limit = PG_GETARG_INT32(1);
568
569 PreventCommandDuringRecovery("pg_enable_data_checksums()");
570
571 if (!superuser())
574 errmsg("must be superuser to change data checksum state"));
575
576 if (cost_delay < 0)
579 errmsg("cost delay cannot be a negative value"));
580
581 if (cost_limit <= 0)
584 errmsg("cost limit must be greater than zero"));
585
587
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 */
603static void
605 int cost_delay,
606 int cost_limit)
607{
610 bool running;
611
612#ifdef USE_ASSERT_CHECKING
613 /* The cost delay settings have no effect when disabling */
614 if (op == DISABLE_DATACHECKSUMS)
615 Assert(cost_delay == 0 && cost_limit == 0);
616#endif
617
618 INJECTION_POINT("datachecksumsworker-startup-delay", NULL);
619
620 /* Store the desired state in shared memory */
622
626
627 /* Is the launcher already running? If so, what is it doing? */
629
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 */
646 if (!running)
647 {
648 if ((op == ENABLE_DATACHECKSUMS && DataChecksumsOn()) ||
650 {
651 ereport(LOG,
652 errmsg("data checksums already in desired state, exiting"));
653 return;
654 }
655
656 /*
657 * Prepare the BackgroundWorker and launch it.
658 */
659 memset(&bgw, 0, sizeof(bgw));
661 bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
662 snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
663 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "DataChecksumsWorkerLauncherMain");
664 snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksums launcher");
665 snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksums launcher");
666 bgw.bgw_restart_time = BGW_NEVER_RESTART;
667 bgw.bgw_notify_pid = MyProcPid;
668 bgw.bgw_main_arg = (Datum) 0;
669
673 errmsg("failed to start background worker to process data checksums"));
674 }
675 else
676 {
677 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 */
689static bool
691{
693 char activity[NAMEDATALEN * 2 + 128];
694 char *relns;
695
697
698 /* Report the current relation to pg_stat_activity */
699 snprintf(activity, sizeof(activity) - 1, "processing: %s.%s (%s, %u blocks)",
702 {
703 const int index[] = {
706 };
707
708 int64 vals[2];
709
710 vals[0] = numblocks;
711 vals[1] = 0;
712
714 }
715 if (relns)
716 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 */
724 {
725 Buffer buf = ReadBufferExtended(reln, forkNum, blknum, RBM_NORMAL, strategy);
726
727 /* Need to get an exclusive lock to mark the buffer as dirty */
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 */
754 if (RelationNeedsWAL(reln) || forkNum == INIT_FORKNUM)
755 log_newpage_buffer(buf, false);
757
759
760 /* Check if we are asked to abort, the abortion will bubble up. */
763 if (abort_requested)
764 return false;
765
766 /* update the block counter */
768 (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 vacuum_delay_point(false);
775 }
776
777 return true;
778}
779
780/*
781 * Initialize all data checksum progress counters to be displayed as NULL.
782 */
783static void
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 */
810static bool
812{
813 Relation rel;
814 bool aborted = false;
815
817
819 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 */
830 return true;
831 }
832 RelationGetSmgr(rel);
833
834 for (ForkNumber fnum = 0; fnum <= MAX_FORKNUM; fnum++)
835 {
836 if (smgrexists(rel->rd_smgr, fnum))
837 {
838 if (!ProcessSingleRelationFork(rel, fnum, strategy))
839 {
840 aborted = true;
841 break;
842 }
843 }
844 }
846
849
850 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 */
863{
866 BgwHandleStatus status;
867 pid_t pid;
869 char activity[NAMEDATALEN + 64];
871
873
874 /*
875 * Initialize result to FAILED. The worker will change it to SUCCESSFUL
876 * if it completes successfully.
877 */
880
884
886
887 memset(&bgw, 0, sizeof(bgw));
889 bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
890 snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
891 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "%s", "DataChecksumsWorkerMain");
892 snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksums worker");
893 snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksums worker");
894 bgw.bgw_restart_time = BGW_NEVER_RESTART;
895 bgw.bgw_notify_pid = MyProcPid;
896 /* pass the invocation number to the worker process */
897 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 */
905 {
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"));
911 }
912
914 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 */
923 {
927 }
929
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 if (DatabaseExists(db->dboid))
941 else
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 */
952 if (status == BGWH_POSTMASTER_DIED)
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
958 Assert(status == BGWH_STARTED);
959 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 */
968
969 snprintf(activity, sizeof(activity) - 1,
970 "Waiting for worker in database %s (pid %ld)", db->dbname, (long) pid);
972
974 if (status == BGWH_POSTMASTER_DIED)
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
986
988 ereport(LOG,
989 errmsg("data checksums processing was aborted in database \"%s\"",
990 db->dbname));
992 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 */
1005static void
1007{
1008 abort_requested = false;
1009
1010 if (launcher_running)
1011 {
1014 {
1015 ereport(LOG,
1016 errmsg("data checksums launcher exiting while worker is still running, signalling worker"));
1019 }
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 */
1029
1031 launcher_running = false;
1034}
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 */
1043static void
1045{
1046 int save_errno = errno;
1047
1048 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 */
1057
1058 errno = save_errno;
1059}
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 */
1071static void
1073{
1075
1079
1081 {
1082 char activity[64];
1083 int rc;
1084
1085 /* Oldest running xid is older than us, so wait */
1087 sizeof(activity),
1088 "Waiting for transactions older than %u to end",
1089 waitforxid);
1091
1092 /* Retry every 3 seconds */
1094 rc = WaitLatch(MyLatch,
1096 3000,
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 if (rc & WL_POSTMASTER_DEATH)
1104 ereport(FATAL,
1106 errmsg("postmaster exited during data checksums processing"),
1107 errhint("Data checksums processing must be restarted manually after cluster restart."));
1108
1111
1112 if (abort_requested)
1113 break;
1114 }
1115
1117 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 */
1128void
1130{
1131
1133 errmsg("background worker \"datachecksums launcher\" started"));
1134
1139
1141
1144
1145 INJECTION_POINT("datachecksumsworker-launcher-delay", NULL);
1146
1148
1150 {
1151 ereport(LOG,
1152 errmsg("background worker \"datachecksums launcher\" already running, exiting"));
1153 /* Launcher was already running, let it finish */
1155 return;
1156 }
1157
1159 launcher_running = true;
1160
1161 /* Initialize a connection to shared catalogs only */
1163
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 */
1177again:
1178
1180 InvalidOid);
1182
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 */
1190 goto done;
1191
1192 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 */
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 if (!ProcessAllDatabases())
1207 {
1208 /*
1209 * If the target state changed during processing then it's not a
1210 * failure, so restart processing instead.
1211 */
1213 if (abort_requested)
1214 goto done;
1215 ereport(ERROR,
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 */
1225
1226 ereport(LOG,
1227 errmsg("data checksums are now enabled"));
1228 }
1229 else if (operation == DISABLE_DATACHECKSUMS)
1230 {
1231 ereport(LOG,
1232 errmsg("disabling data checksums requested"));
1233
1237 ereport(LOG,
1238 errmsg("data checksums are now disabled"));
1239 }
1240 else
1241 Assert(false);
1242
1243done:
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 */
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 */
1259 {
1265 goto again;
1266 }
1267
1268 /* Shut down progress reporting as we are done */
1270
1271 launcher_running = false;
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 */
1284static bool
1286{
1288 int cumulative_total = 0;
1289
1290 /* Set up so first run processes shared catalogs, not once in every db */
1294
1295 /* Get a list of all databases to process */
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 const int index[] = {
1309 };
1310
1311 int64 vals[2];
1312
1313 vals[0] = list_length(DatabaseList);
1314 vals[1] = 0;
1315
1317 }
1318
1320 {
1322
1323 result = ProcessDatabase(db);
1324
1325#ifdef USE_INJECTION_POINTS
1326 /* Allow a test process to alter the result of the operation */
1327 if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fail-db-result"))
1328 {
1330 INJECTION_POINT_CACHED("datachecksumsworker-fail-db-result",
1331 db->dbname);
1332 }
1333#endif
1334
1337
1339 {
1340 /*
1341 * Disable checksums on cluster, because we failed one of the
1342 * databases and this is an all or nothing process.
1343 */
1345 ereport(ERROR,
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 }
1351 {
1352 /* Abort flag set, so exit the whole process */
1353 return false;
1354 }
1356 {
1357 /*
1358 * Ignore databases that were dropped before their worker could
1359 * process them, and continue with the remaining databases.
1360 */
1361 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 */
1371 }
1372
1374
1377 return true;
1378}
1379
1380/*
1381 * DataChecksumsShmemRequest
1382 * Request datachecksumsworker-related shared memory
1383 */
1384static void
1386{
1387 ShmemRequestStruct(.name = "DataChecksumsWorker Data",
1388 .size = sizeof(DataChecksumsStateStruct),
1389 .ptr = (void **) &DataChecksumState,
1390 );
1391}
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 */
1401static bool
1403{
1404 Relation rel;
1406 SysScanDesc scan;
1407 bool found;
1408 HeapTuple tuple;
1410
1412
1417 ObjectIdGetDatum(dboid));
1419 1, &skey);
1420 tuple = systable_getnext(scan);
1421 found = HeapTupleIsValid(tuple);
1422
1423 /* If the Oid exists, ensure that it's not partially dropped */
1424 if (found)
1425 {
1428 found = false;
1429 }
1430
1431 systable_endscan(scan);
1433
1435
1436 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 */
1448static List *
1450{
1452 Relation rel;
1453 TableScanDesc scan;
1454 HeapTuple tup;
1457
1459
1461 scan = table_beginscan_catalog(rel, 0, NULL);
1462
1464 {
1467
1469
1471
1472 db->dboid = pgdb->oid;
1473 db->dbname = pstrdup(NameStr(pgdb->datname));
1474
1476
1478 }
1479
1480 table_endscan(scan);
1482
1484
1485 return DatabaseList;
1486}
1487
1488static void
1490{
1491 if (!dblist)
1492 return;
1493
1495 {
1496 if (db->dbname != NULL)
1497 pfree(db->dbname);
1498 }
1499
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 */
1514static List *
1516{
1518 Relation rel;
1519 TableScanDesc scan;
1520 HeapTuple tup;
1523
1525
1527 scan = table_beginscan_catalog(rel, 0, NULL);
1528
1530 {
1532
1533 if (!RELKIND_HAS_STORAGE(pgc->relkind))
1534 continue;
1535
1536 /* Only include temporary relations when explicitly asked to */
1537 if (pgc->relpersistence == RELPERSISTENCE_TEMP)
1538 {
1539 if (!temp_relations)
1540 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 if (temp_relations)
1549 continue;
1550
1551 if (pgc->relisshared && !include_shared)
1552 continue;
1553 }
1554
1558 }
1559
1560 table_endscan(scan);
1562
1564
1565 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 */
1579void
1581{
1582 Oid dboid;
1585 BufferAccessStrategy strategy;
1586 bool aborted = false;
1588 bool process_shared;
1589#ifdef USE_INJECTION_POINTS
1590 bool retried = false;
1591#endif
1592
1594
1596
1599
1601
1604
1607 {
1609 return;
1610 }
1613
1616
1617 /* worker will have a separate entry in pg_stat_progress_data_checksums */
1619 InvalidOid);
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 */
1631 {
1633 return;
1634 }
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 */
1652
1653 /*
1654 * Create and set the vacuum strategy as our buffer strategy.
1655 */
1656 strategy = GetAccessStrategy(BAS_VACUUM);
1657
1659
1660 /* Update the total number of relations to be processed in this DB. */
1661 {
1662 const int index[] = {
1665 };
1666
1667 int64 vals[2];
1668
1669 vals[0] = list_length(RelationList);
1670 vals[1] = 0;
1671
1673 }
1674
1675 /* Process the relations */
1676 rels_done = 0;
1677 foreach_oid(reloid, RelationList)
1678 {
1679 bool costs_updated = false;
1680
1681 if (!ProcessSingleRelationByOid(reloid, strategy))
1682 {
1683 aborted = true;
1684 break;
1685 }
1686
1688 ++rels_done);
1691
1692 if (abort_requested)
1693 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 */
1702 {
1704 break;
1705 }
1708 {
1709 costs_updated = true;
1713
1716 }
1717 else
1718 costs_updated = false;
1720
1721 if (costs_updated)
1722 {
1723 FreeAccessStrategy(strategy);
1724 strategy = GetAccessStrategy(BAS_VACUUM);
1725 }
1726 }
1727
1729 FreeAccessStrategy(strategy);
1730
1731 if (aborted || abort_requested)
1732 {
1738 errmsg("data checksum processing aborted in database OID %u",
1739 dboid));
1740 return;
1741 }
1742
1743 /* The worker is about to wait for temporary tables to go away. */
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 (;;)
1754 {
1756 int numleft;
1757 char activity[64];
1758
1759 CurrentTempTables = BuildRelationList(true, false);
1760 numleft = 0;
1762 {
1764 numleft++;
1765 }
1767
1768#ifdef USE_INJECTION_POINTS
1769 if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fake-temptable-wait"))
1770 {
1771 /* Make sure to just cause one retry */
1772 if (!retried && numleft == 0)
1773 {
1774 numleft = 1;
1775 retried = true;
1776
1777 INJECTION_POINT_CACHED("datachecksumsworker-fake-temptable-wait", NULL);
1778 }
1779 }
1780#endif
1781
1782 if (numleft == 0)
1783 break;
1784
1785 /*
1786 * At least one temp table is left to wait for, indicate in pgstat
1787 * activity and progress reporting.
1788 */
1790 sizeof(activity),
1791 "Waiting for %d temp tables to be removed", numleft);
1793
1794 /* Retry every 3 seconds */
1798 3000,
1800
1803
1804 if (aborted || abort_requested)
1805 {
1810 ereport(LOG,
1811 errmsg("data checksum processing aborted in database OID %u",
1812 dboid));
1813 return;
1814 }
1815 }
1816
1818
1819 /* worker done */
1821
1826}
void VacuumUpdateCosts(void)
static dlist_head DatabaseList
Definition autovacuum.c:325
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_DATACHECKSUMS
void pgstat_report_activity(BackendState state, const char *cmd_str)
@ STATE_IDLE
@ STATE_RUNNING
BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
Definition bgworker.c:1235
BgwHandleStatus WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle)
Definition bgworker.c:1280
void BackgroundWorkerUnblockSignals(void)
Definition bgworker.c:949
void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
Definition bgworker.c:909
bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle)
Definition bgworker.c:1068
#define BGW_NEVER_RESTART
Definition bgworker.h:92
BgwHandleStatus
Definition bgworker.h:111
@ BGWH_POSTMASTER_DIED
Definition bgworker.h:115
@ BGWH_STARTED
Definition bgworker.h:112
@ BGWH_STOPPED
Definition bgworker.h:114
@ BgWorkerStart_RecoveryFinished
Definition bgworker.h:88
#define BGWORKER_BACKEND_DATABASE_CONNECTION
Definition bgworker.h:60
#define BGWORKER_BYPASS_ALLOWCONN
Definition bgworker.h:166
#define BGWORKER_SHMEM_ACCESS
Definition bgworker.h:53
#define BGW_MAXLEN
Definition bgworker.h:93
uint32 BlockNumber
Definition block.h:31
int Buffer
Definition buf.h:23
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
Definition bufmgr.c:4668
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5626
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3170
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:926
@ BAS_VACUUM
Definition bufmgr.h:40
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:222
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334
@ RBM_NORMAL
Definition bufmgr.h:46
#define NameStr(name)
Definition c.h:894
#define SIGNAL_ARGS
Definition c.h:1519
#define Assert(condition)
Definition c.h:1002
int64_t int64
Definition c.h:680
uint64_t uint64
Definition c.h:684
uint32_t uint32
Definition c.h:683
#define lengthof(array)
Definition c.h:932
uint32 TransactionId
Definition c.h:795
@ PG_DATA_CHECKSUM_VERSION
Definition checksum.h:29
@ PG_DATA_CHECKSUM_INPROGRESS_OFF
Definition checksum.h:30
@ PG_DATA_CHECKSUM_INPROGRESS_ON
Definition checksum.h:31
@ PG_DATA_CHECKSUM_OFF
Definition checksum.h:28
uint32 result
static void DataChecksumsShmemRequest(void *arg)
#define CHECK_FOR_WORKER_ABORT_REQUEST()
static const ChecksumBarrierCondition checksum_barriers[9]
static DataChecksumsStateStruct * DataChecksumState
static volatile sig_atomic_t launcher_running
static bool ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy)
void EmitAndWaitDataChecksumsBarrier(uint32 state)
static volatile sig_atomic_t abort_requested
static DataChecksumsWorkerOperation operation
static void ResetDataChecksumsProgressCounters(void)
static void launcher_cancel_handler(SIGNAL_ARGS)
static DataChecksumsWorkerResult ProcessDatabase(DataChecksumsWorkerDatabase *db)
void DataChecksumsWorkerMain(Datum arg)
#define CHECK_FOR_LAUNCHER_ABORT_REQUEST()
static void FreeDatabaseList(List *dblist)
static List * BuildDatabaseList(void)
static bool DatabaseExists(Oid dboid)
static bool ProcessAllDatabases(void)
void DataChecksumsWorkerLauncherMain(Datum arg)
DataChecksumsWorkerOperation
@ DISABLE_DATACHECKSUMS
@ ENABLE_DATACHECKSUMS
static void StartDataChecksumsWorkerLauncher(DataChecksumsWorkerOperation op, int cost_delay, int cost_limit)
static void launcher_exit(int code, Datum arg)
static bool ProcessSingleRelationByOid(Oid relationId, BufferAccessStrategy strategy)
bool AbsorbDataChecksumsBarrier(ProcSignalBarrierType barrier)
DataChecksumsWorkerResult
@ DATACHECKSUMSWORKER_ABORTED
@ DATACHECKSUMSWORKER_FAILED
@ DATACHECKSUMSWORKER_DROPDB
@ DATACHECKSUMSWORKER_SUCCESSFUL
const ShmemCallbacks DataChecksumsShmemCallbacks
static void WaitForAllTransactionsToFinish(void)
Datum disable_data_checksums(PG_FUNCTION_ARGS)
static uint64 worker_invocation
Datum enable_data_checksums(PG_FUNCTION_ARGS)
static List * BuildRelationList(bool temp_relations, bool include_shared)
bool database_is_invalid_form(Form_pg_database datform)
Datum arg
Definition elog.c:1323
int errcode(int sqlerrcode)
Definition elog.c:875
#define LOG
Definition elog.h:32
int errhint(const char *fmt,...) pg_attribute_printf(1
#define FATAL
Definition elog.h:42
#define WARNING
Definition elog.h:37
#define DEBUG1
Definition elog.h:31
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition freelist.c:426
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition freelist.c:608
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
int VacuumCostLimit
Definition globals.c:157
int MyProcPid
Definition globals.c:49
int VacuumCostBalance
Definition globals.c:160
struct Latch * MyLatch
Definition globals.c:65
double VacuumCostDelay
Definition globals.c:158
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1436
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define INJECTION_POINT(name, arg)
#define IS_INJECTION_POINT_ATTACHED(name)
#define INJECTION_POINT_CACHED(name, arg)
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
int i
Definition isn.c:77
void SetLatch(Latch *latch)
Definition latch.c:290
void ResetLatch(Latch *latch)
Definition latch.c:374
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition latch.c:172
List * lappend(List *list, void *datum)
Definition list.c:339
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
void list_free(List *list)
Definition list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
void list_free_deep(List *list)
Definition list.c:1560
#define AccessShareLock
Definition lockdefs.h:36
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_SHARED
Definition lwlock.h:105
@ LW_EXCLUSIVE
Definition lwlock.h:104
char * pstrdup(const char *in)
Definition mcxt.c:1910
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
#define START_CRIT_SECTION()
Definition miscadmin.h:152
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
@ B_DATACHECKSUMSWORKER_WORKER
Definition miscadmin.h:374
@ B_DATACHECKSUMSWORKER_LAUNCHER
Definition miscadmin.h:373
#define END_CRIT_SECTION()
Definition miscadmin.h:154
#define InvalidPid
Definition miscadmin.h:32
BackendType MyBackendType
Definition miscinit.c:65
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
#define NAMEDATALEN
END_CATALOG_STRUCT typedef FormData_pg_database * Form_pg_database
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
#define foreach_oid(var, lst)
Definition pg_list.h:503
_stringlist * dblist
Definition pg_regress.c:99
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define die(msg)
static THREAD_BARRIER_T barrier
Definition pgbench.c:488
#define pqsignal
Definition port.h:548
#define PG_SIG_IGN
Definition port.h:552
#define snprintf
Definition port.h:261
static uint64 DatumGetUInt64(Datum X)
Definition postgres.h:436
static Datum UInt64GetDatum(uint64 X)
Definition postgres.h:446
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
static int fb(int x)
TransactionId GetOldestActiveTransactionId(bool inCommitOnly, bool allDbs)
Definition procarray.c:2832
void WaitForProcSignalBarrier(uint64 generation)
Definition procsignal.c:436
uint64 EmitProcSignalBarrier(ProcSignalBarrierType type)
Definition procsignal.c:368
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition procsignal.c:696
ProcSignalBarrierType
Definition procsignal.h:49
@ PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_OFF
Definition procsignal.h:55
@ PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_ON
Definition procsignal.h:54
@ PROCSIGNAL_BARRIER_CHECKSUM_ON
Definition procsignal.h:56
@ PROCSIGNAL_BARRIER_CHECKSUM_OFF
Definition procsignal.h:53
#define PROGRESS_DATACHECKSUMS_PHASE_DONE
Definition progress.h:205
#define PROGRESS_DATACHECKSUMS_RELS_TOTAL
Definition progress.h:195
#define PROGRESS_DATACHECKSUMS_PHASE_WAITING_TEMPREL
Definition progress.h:203
#define PROGRESS_DATACHECKSUMS_BLOCKS_DONE
Definition progress.h:198
#define PROGRESS_DATACHECKSUMS_DBS_DONE
Definition progress.h:194
#define PROGRESS_DATACHECKSUMS_PHASE
Definition progress.h:192
#define PROGRESS_DATACHECKSUMS_PHASE_ENABLING
Definition progress.h:201
#define PROGRESS_DATACHECKSUMS_PHASE_WAITING_BARRIER
Definition progress.h:204
#define PROGRESS_DATACHECKSUMS_PHASE_DISABLING
Definition progress.h:202
#define PROGRESS_DATACHECKSUMS_BLOCKS_TOTAL
Definition progress.h:197
#define PROGRESS_DATACHECKSUMS_DBS_TOTAL
Definition progress.h:193
#define PROGRESS_DATACHECKSUMS_RELS_DONE
Definition progress.h:196
void init_ps_display(const char *fixed_part)
Definition ps_status.c:286
static SMgrRelation RelationGetSmgr(Relation rel)
Definition rel.h:578
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationNeedsWAL(relation)
Definition rel.h:639
#define RelationGetNamespace(relation)
Definition rel.h:557
const char *const forkNames[]
Definition relpath.c:33
ForkNumber
Definition relpath.h:56
@ INIT_FORKNUM
Definition relpath.h:61
#define MAX_FORKNUM
Definition relpath.h:70
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
@ ForwardScanDirection
Definition sdir.h:28
#define ShmemRequestStruct(...)
Definition shmem.h:176
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:462
#define SnapshotSelf
Definition snapmgr.h:32
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:89
#define BTEqualStrategyNumber
Definition stratnum.h:31
DataChecksumsWorkerResult worker_result
DataChecksumsWorkerOperation launch_operation
DataChecksumsWorkerOperation operation
Definition pg_list.h:54
SMgrRelation rd_smgr
Definition rel.h:58
ShmemRequestCallback request_fn
Definition shmem.h:133
FullTransactionId nextXid
Definition transam.h:220
Definition type.h:97
bool superuser(void)
Definition superuser.c:47
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
Definition tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition tableam.h:1061
#define XidFromFullTransactionId(x)
Definition transam.h:48
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
void PreventCommandDuringRecovery(const char *cmdname)
Definition utility.c:446
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2438
TransamVariablesData * TransamVariables
Definition varsup.c:37
const char * name
#define WL_TIMEOUT
#define WL_EXIT_ON_PM_DEATH
#define WL_LATCH_SET
#define WL_POSTMASTER_DEATH
#define kill(pid, sig)
Definition win32_port.h:507
#define SIGUSR1
Definition win32_port.h:170
#define SIGUSR2
Definition win32_port.h:171
void StartTransactionCommand(void)
Definition xact.c:3112
void CommitTransactionCommand(void)
Definition xact.c:3210
bool RecoveryInProgress(void)
Definition xlog.c:6835
void SetLocalDataChecksumState(uint32 data_checksum_version)
Definition xlog.c:4969
void SetDataChecksumsOff(void)
Definition xlog.c:4865
bool DataChecksumsNeedVerify(void)
Definition xlog.c:4732
void SetDataChecksumsOn(void)
Definition xlog.c:4801
bool DataChecksumsOn(void)
Definition xlog.c:4694
void SetDataChecksumsOnInProgress(void)
Definition xlog.c:4748
int data_checksums
Definition xlog.c:683
bool DataChecksumsOff(void)
Definition xlog.c:4682
bool DataChecksumsInProgressOn(void)
Definition xlog.c:4706
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)