PostgreSQL Source Code git master
Loading...
Searching...
No Matches
datachecksum_state.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "catalog/indexing.h"
#include "catalog/pg_class.h"
#include "catalog/pg_database.h"
#include "commands/progress.h"
#include "commands/vacuum.h"
#include "common/relpath.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgworker.h"
#include "postmaster/bgwriter.h"
#include "postmaster/datachecksum_state.h"
#include "storage/bufmgr.h"
#include "storage/checksum.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/lmgr.h"
#include "storage/lwlock.h"
#include "storage/procarray.h"
#include "storage/smgr.h"
#include "storage/subsystems.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/injection_point.h"
#include "utils/lsyscache.h"
#include "utils/ps_status.h"
#include "utils/syscache.h"
#include "utils/wait_event.h"
Include dependency graph for datachecksum_state.c:

Go to the source code of this file.

Data Structures

struct  ChecksumBarrierCondition
 
struct  DataChecksumsStateStruct
 
struct  DataChecksumsWorkerDatabase
 

Macros

#define CHECK_FOR_ABORT_REQUEST()
 

Typedefs

typedef struct ChecksumBarrierCondition ChecksumBarrierCondition
 
typedef struct DataChecksumsStateStruct DataChecksumsStateStruct
 
typedef struct DataChecksumsWorkerDatabase DataChecksumsWorkerDatabase
 

Functions

static void DataChecksumsShmemRequest (void *arg)
 
static bool DatabaseExists (Oid dboid)
 
static ListBuildDatabaseList (void)
 
static ListBuildRelationList (bool temp_relations, bool include_shared)
 
static void FreeDatabaseList (List *dblist)
 
static DataChecksumsWorkerResult ProcessDatabase (DataChecksumsWorkerDatabase *db)
 
static bool ProcessAllDatabases (void)
 
static bool ProcessSingleRelationFork (Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy)
 
static void launcher_cancel_handler (SIGNAL_ARGS)
 
static void WaitForAllTransactionsToFinish (void)
 
void EmitAndWaitDataChecksumsBarrier (uint32 state)
 
bool AbsorbDataChecksumsBarrier (ProcSignalBarrierType barrier)
 
Datum disable_data_checksums (PG_FUNCTION_ARGS)
 
Datum enable_data_checksums (PG_FUNCTION_ARGS)
 
void StartDataChecksumsWorkerLauncher (DataChecksumsWorkerOperation op, int cost_delay, int cost_limit)
 
static bool ProcessSingleRelationByOid (Oid relationId, BufferAccessStrategy strategy)
 
static void launcher_exit (int code, Datum arg)
 
void DataChecksumsWorkerLauncherMain (Datum arg)
 
void DataChecksumsWorkerMain (Datum arg)
 

Variables

static const ChecksumBarrierCondition checksum_barriers [9]
 
static DataChecksumsStateStructDataChecksumState
 
static volatile sig_atomic_t abort_requested = false
 
static volatile sig_atomic_t launcher_running = false
 
static DataChecksumsWorkerOperation operation
 
const ShmemCallbacks DataChecksumsShmemCallbacks
 

Macro Definition Documentation

◆ CHECK_FOR_ABORT_REQUEST

#define CHECK_FOR_ABORT_REQUEST ( )
Value:
do { \
} while (0)
static DataChecksumsStateStruct * DataChecksumState
static volatile sig_atomic_t abort_requested
static DataChecksumsWorkerOperation operation
@ LW_SHARED
Definition lwlock.h:105
static int fb(int x)
DataChecksumsWorkerOperation launch_operation

Definition at line 375 of file datachecksum_state.c.

Typedef Documentation

◆ ChecksumBarrierCondition

◆ DataChecksumsStateStruct

◆ DataChecksumsWorkerDatabase

Function Documentation

◆ AbsorbDataChecksumsBarrier()

bool AbsorbDataChecksumsBarrier ( ProcSignalBarrierType  barrier)

Definition at line 430 of file datachecksum_state.c.

431{
433 int current = data_checksums;
434 bool found = false;
435
436 /*
437 * Translate the barrier condition to the target state, doing it here
438 * instead of in the procsignal code saves the latter from knowing about
439 * checksum states.
440 */
441 switch (barrier)
442 {
445 break;
448 break;
451 break;
454 break;
455 default:
456 elog(ERROR, "incorrect barrier \"%i\" received", barrier);
457 }
458
459 /*
460 * If the target state matches the current state then the barrier has been
461 * repeated.
462 */
463 if (current == target_state)
464 return true;
465
466 /*
467 * If the cluster is in recovery we skip the validation of current state
468 * since the replay is trusted.
469 */
470 if (RecoveryInProgress())
471 {
473 return true;
474 }
475
476 /*
477 * Find the barrier condition definition for the target state. Not finding
478 * a condition would be a grave programmer error as the states are a
479 * discrete set.
480 */
481 for (int i = 0; i < lengthof(checksum_barriers) && !found; i++)
482 {
483 if (checksum_barriers[i].from == current && checksum_barriers[i].to == target_state)
484 found = true;
485 }
486
487 /*
488 * If the relevant state criteria aren't satisfied, throw an error which
489 * will be caught by the procsignal machinery for a later retry.
490 */
491 if (!found)
494 errmsg("incorrect data checksum state %i for target state %i",
495 current, target_state));
496
498 return true;
499}
uint32_t uint32
Definition c.h:624
#define lengthof(array)
Definition c.h:873
@ 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
static const ChecksumBarrierCondition checksum_barriers[9]
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
int i
Definition isn.c:77
static char * errmsg
static THREAD_BARRIER_T barrier
Definition pgbench.c:488
@ 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
bool RecoveryInProgress(void)
Definition xlog.c:6834
void SetLocalDataChecksumState(uint32 data_checksum_version)
Definition xlog.c:4970
int data_checksums
Definition xlog.c:683

References barrier, checksum_barriers, data_checksums, elog, ereport, errcode(), errmsg, ERROR, fb(), i, lengthof, PG_DATA_CHECKSUM_INPROGRESS_OFF, PG_DATA_CHECKSUM_INPROGRESS_ON, PG_DATA_CHECKSUM_OFF, PG_DATA_CHECKSUM_VERSION, PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_OFF, PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_ON, PROCSIGNAL_BARRIER_CHECKSUM_OFF, PROCSIGNAL_BARRIER_CHECKSUM_ON, RecoveryInProgress(), and SetLocalDataChecksumState().

Referenced by ProcessProcSignalBarrier().

◆ BuildDatabaseList()

static List * BuildDatabaseList ( void  )
static

Definition at line 1373 of file datachecksum_state.c.

1374{
1376 Relation rel;
1377 TableScanDesc scan;
1378 HeapTuple tup;
1381
1383
1385 scan = table_beginscan_catalog(rel, 0, NULL);
1386
1388 {
1391
1393
1395
1396 db->dboid = pgdb->oid;
1397 db->dbname = pstrdup(NameStr(pgdb->datname));
1398
1400
1402 }
1403
1404 table_endscan(scan);
1406
1408
1409 return DatabaseList;
1410}
static dlist_head DatabaseList
Definition autovacuum.c:327
#define NameStr(name)
Definition c.h:835
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1435
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
List * lappend(List *list, void *datum)
Definition list.c:339
#define AccessShareLock
Definition lockdefs.h:36
char * pstrdup(const char *in)
Definition mcxt.c:1910
void * palloc0(Size size)
Definition mcxt.c:1420
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
END_CATALOG_STRUCT typedef FormData_pg_database * Form_pg_database
#define NIL
Definition pg_list.h:68
@ ForwardScanDirection
Definition sdir.h:28
Definition pg_list.h:54
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
void StartTransactionCommand(void)
Definition xact.c:3109
void CommitTransactionCommand(void)
Definition xact.c:3207

References AccessShareLock, CommitTransactionCommand(), CurrentMemoryContext, DatabaseList, DataChecksumsWorkerDatabase::dbname, DataChecksumsWorkerDatabase::dboid, fb(), Form_pg_database, ForwardScanDirection, GETSTRUCT(), heap_getnext(), HeapTupleIsValid, lappend(), MemoryContextSwitchTo(), NameStr, NIL, palloc0(), pstrdup(), StartTransactionCommand(), table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessAllDatabases().

◆ BuildRelationList()

static List * BuildRelationList ( bool  temp_relations,
bool  include_shared 
)
static

Definition at line 1439 of file datachecksum_state.c.

1440{
1442 Relation rel;
1443 TableScanDesc scan;
1444 HeapTuple tup;
1447
1449
1451 scan = table_beginscan_catalog(rel, 0, NULL);
1452
1454 {
1456
1457 /* Only include temporary relations when explicitly asked to */
1458 if (pgc->relpersistence == RELPERSISTENCE_TEMP)
1459 {
1460 if (!temp_relations)
1461 continue;
1462 }
1463 else
1464 {
1465 /*
1466 * If we are only interested in temp relations then continue
1467 * immediately as the current relation isn't a temp relation.
1468 */
1469 if (temp_relations)
1470 continue;
1471
1472 if (!RELKIND_HAS_STORAGE(pgc->relkind))
1473 continue;
1474
1475 if (pgc->relisshared && !include_shared)
1476 continue;
1477 }
1478
1482 }
1483
1484 table_endscan(scan);
1486
1488
1489 return RelationList;
1490}
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
FormData_pg_class * Form_pg_class
Definition pg_class.h:160

References AccessShareLock, CommitTransactionCommand(), CurrentMemoryContext, fb(), ForwardScanDirection, GETSTRUCT(), heap_getnext(), HeapTupleIsValid, lappend_oid(), MemoryContextSwitchTo(), NIL, StartTransactionCommand(), table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by DataChecksumsWorkerMain().

◆ DatabaseExists()

static bool DatabaseExists ( Oid  dboid)
static

Definition at line 1326 of file datachecksum_state.c.

1327{
1328 Relation rel;
1330 SysScanDesc scan;
1331 bool found;
1332 HeapTuple tuple;
1334
1336
1341 ObjectIdGetDatum(dboid));
1343 1, &skey);
1344 tuple = systable_getnext(scan);
1345 found = HeapTupleIsValid(tuple);
1346
1347 /* If the Oid exists, ensure that it's not partially dropped */
1348 if (found)
1349 {
1352 found = false;
1353 }
1354
1355 systable_endscan(scan);
1357
1359
1360 return found;
1361}
bool database_is_invalid_form(Form_pg_database datform)
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
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define SnapshotSelf
Definition snapmgr.h:32
#define BTEqualStrategyNumber
Definition stratnum.h:31

References AccessShareLock, BTEqualStrategyNumber, CommitTransactionCommand(), database_is_invalid_form(), fb(), Form_pg_database, GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), ScanKeyInit(), SnapshotSelf, StartTransactionCommand(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ProcessDatabase().

◆ DataChecksumsShmemRequest()

static void DataChecksumsShmemRequest ( void arg)
static

Definition at line 1309 of file datachecksum_state.c.

1310{
1311 ShmemRequestStruct(.name = "DataChecksumsWorker Data",
1312 .size = sizeof(DataChecksumsStateStruct),
1313 .ptr = (void **) &DataChecksumState,
1314 );
1315}
#define ShmemRequestStruct(...)
Definition shmem.h:176
const char * name

References DataChecksumState, name, and ShmemRequestStruct.

◆ DataChecksumsWorkerLauncherMain()

void DataChecksumsWorkerLauncherMain ( Datum  arg)

Definition at line 1049 of file datachecksum_state.c.

1050{
1051
1053 errmsg("background worker \"datachecksums launcher\" started"));
1054
1059
1061
1064
1065 INJECTION_POINT("datachecksumsworker-launcher-delay", NULL);
1066
1068
1070 {
1071 ereport(LOG,
1072 errmsg("background worker \"datachecksums launcher\" already running, exiting"));
1073 /* Launcher was already running, let it finish */
1075 return;
1076 }
1077
1079 launcher_running = true;
1080
1081 /* Initialize a connection to shared catalogs only */
1083
1090
1091 /*
1092 * The target state can change while we are busy enabling/disabling
1093 * checksums, if the user calls pg_disable/enable_data_checksums() before
1094 * we are finished with the previous request. In that case, we will loop
1095 * back here, to process the new request.
1096 */
1097again:
1098
1100 InvalidOid);
1101
1103 {
1104 /*
1105 * If we are asked to enable checksums in a cluster which already has
1106 * checksums enabled, exit immediately as there is nothing more to do.
1107 */
1109 goto done;
1110
1111 ereport(LOG,
1112 errmsg("enabling data checksums requested, starting data checksum calculation"));
1113
1114 /*
1115 * Set the state to inprogress-on and wait on the procsignal barrier.
1116 */
1120
1121 /*
1122 * All backends are now in inprogress-on state and are writing data
1123 * checksums. Start processing all data at rest.
1124 */
1125 if (!ProcessAllDatabases())
1126 {
1127 /*
1128 * If the target state changed during processing then it's not a
1129 * failure, so restart processing instead.
1130 */
1133 {
1135 goto done;
1136 }
1138 ereport(ERROR,
1140 errmsg("unable to enable data checksums in cluster"));
1141 }
1142
1143 /*
1144 * Data checksums have been set on all pages, set the state to on in
1145 * order to instruct backends to validate checksums on reading.
1146 */
1148
1149 ereport(LOG,
1150 errmsg("data checksums are now enabled"));
1151 }
1152 else if (operation == DISABLE_DATACHECKSUMS)
1153 {
1154 ereport(LOG,
1155 errmsg("disabling data checksums requested"));
1156
1160 ereport(LOG,
1161 errmsg("data checksums are now disabled"));
1162 }
1163 else
1164 Assert(false);
1165
1166done:
1167
1168 /*
1169 * This state will only be displayed for a fleeting moment, but for the
1170 * sake of correctness it is still added before ending the command.
1171 */
1174
1175 /*
1176 * All done. But before we exit, check if the target state was changed
1177 * while we were running. In that case we will have to start all over
1178 * again.
1179 */
1182 {
1188 goto again;
1189 }
1190
1191 /* Shut down progress reporting as we are done */
1193
1194 launcher_running = false;
1197}
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_DATACHECKSUMS
void BackgroundWorkerUnblockSignals(void)
Definition bgworker.c:949
void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
Definition bgworker.c:909
#define Assert(condition)
Definition c.h:943
static volatile sig_atomic_t launcher_running
static void launcher_cancel_handler(SIGNAL_ARGS)
static bool ProcessAllDatabases(void)
static void launcher_exit(int code, Datum arg)
@ DISABLE_DATACHECKSUMS
@ ENABLE_DATACHECKSUMS
#define LOG
Definition elog.h:32
#define DEBUG1
Definition elog.h:31
#define INJECTION_POINT(name, arg)
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_EXCLUSIVE
Definition lwlock.h:104
@ B_DATACHECKSUMSWORKER_LAUNCHER
Definition miscadmin.h:373
BackendType MyBackendType
Definition miscinit.c:65
#define die(msg)
#define pqsignal
Definition port.h:548
#define PG_SIG_IGN
Definition port.h:552
#define InvalidOid
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition procsignal.c:696
#define PROGRESS_DATACHECKSUMS_PHASE_DONE
Definition progress.h:205
#define PROGRESS_DATACHECKSUMS_PHASE
Definition progress.h:192
#define PROGRESS_DATACHECKSUMS_PHASE_ENABLING
Definition progress.h:201
#define PROGRESS_DATACHECKSUMS_PHASE_DISABLING
Definition progress.h:202
void init_ps_display(const char *fixed_part)
Definition ps_status.c:286
DataChecksumsWorkerOperation operation
#define SIGUSR1
Definition win32_port.h:170
#define SIGUSR2
Definition win32_port.h:171
void SetDataChecksumsOff(void)
Definition xlog.c:4866
bool DataChecksumsNeedVerify(void)
Definition xlog.c:4733
void SetDataChecksumsOn(void)
Definition xlog.c:4802
void SetDataChecksumsOnInProgress(void)
Definition xlog.c:4749

References Assert, B_DATACHECKSUMSWORKER_LAUNCHER, BackgroundWorkerInitializeConnectionByOid(), BackgroundWorkerUnblockSignals(), DataChecksumsStateStruct::cost_delay, DataChecksumsStateStruct::cost_limit, DataChecksumsNeedVerify(), DataChecksumState, DEBUG1, die, DISABLE_DATACHECKSUMS, ENABLE_DATACHECKSUMS, ereport, errcode(), errmsg, ERROR, fb(), init_ps_display(), INJECTION_POINT, InvalidOid, DataChecksumsStateStruct::launch_cost_delay, DataChecksumsStateStruct::launch_cost_limit, DataChecksumsStateStruct::launch_operation, launcher_cancel_handler(), launcher_exit(), DataChecksumsStateStruct::launcher_running, launcher_running, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyBackendType, on_shmem_exit(), DataChecksumsStateStruct::operation, operation, PG_SIG_IGN, pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_param(), pqsignal, ProcessAllDatabases(), procsignal_sigusr1_handler(), PROGRESS_COMMAND_DATACHECKSUMS, PROGRESS_DATACHECKSUMS_PHASE, PROGRESS_DATACHECKSUMS_PHASE_DISABLING, PROGRESS_DATACHECKSUMS_PHASE_DONE, PROGRESS_DATACHECKSUMS_PHASE_ENABLING, SetDataChecksumsOff(), SetDataChecksumsOn(), SetDataChecksumsOnInProgress(), SIGUSR1, and SIGUSR2.

◆ DataChecksumsWorkerMain()

void DataChecksumsWorkerMain ( Datum  arg)

Definition at line 1504 of file datachecksum_state.c.

1505{
1506 Oid dboid = DatumGetObjectId(arg);
1509 BufferAccessStrategy strategy;
1510 bool aborted = false;
1512#ifdef USE_INJECTION_POINTS
1513 bool retried = false;
1514#endif
1515
1517
1520
1522
1525
1528
1529 /* worker will have a separate entry in pg_stat_progress_data_checksums */
1531 InvalidOid);
1532
1533 /*
1534 * Get a list of all temp tables present as we start in this database. We
1535 * need to wait until they are all gone until we are done, since we cannot
1536 * access these relations and modify them.
1537 */
1539
1540 /*
1541 * Enable vacuum cost delay, if any. While this process isn't doing any
1542 * vacuuming, we are re-using the infrastructure that vacuum cost delay
1543 * provides rather than inventing something bespoke. This is an internal
1544 * implementation detail and care should be taken to avoid it bleeding
1545 * through to the user to avoid confusion.
1546 *
1547 * VacuumUpdateCosts() propagates the values to the variables actually
1548 * read by vacuum_delay_point().
1549 */
1554
1555 /*
1556 * Create and set the vacuum strategy as our buffer strategy.
1557 */
1558 strategy = GetAccessStrategy(BAS_VACUUM);
1559
1562
1563 /* Update the total number of relations to be processed in this DB. */
1564 {
1565 const int index[] = {
1568 };
1569
1570 int64 vals[2];
1571
1572 vals[0] = list_length(RelationList);
1573 vals[1] = 0;
1574
1576 }
1577
1578 /* Process the relations */
1579 rels_done = 0;
1580 foreach_oid(reloid, RelationList)
1581 {
1582 bool costs_updated = false;
1583
1584 if (!ProcessSingleRelationByOid(reloid, strategy))
1585 {
1586 aborted = true;
1587 break;
1588 }
1589
1591 ++rels_done);
1594
1595 if (abort_requested)
1596 break;
1597
1598 /*
1599 * Check if the cost settings changed during runtime and if so, update
1600 * to reflect the new values and signal that the access strategy needs
1601 * to be refreshed.
1602 */
1606 {
1607 costs_updated = true;
1611
1614 }
1615 else
1616 costs_updated = false;
1618
1619 if (costs_updated)
1620 {
1621 FreeAccessStrategy(strategy);
1622 strategy = GetAccessStrategy(BAS_VACUUM);
1623 }
1624 }
1625
1627 FreeAccessStrategy(strategy);
1628
1629 if (aborted || abort_requested)
1630 {
1635 errmsg("data checksum processing aborted in database OID %u",
1636 dboid));
1637 return;
1638 }
1639
1640 /* The worker is about to wait for temporary tables to go away. */
1643
1644 /*
1645 * Wait for all temp tables that existed when we started to go away. This
1646 * is necessary since we cannot "reach" them to enable checksums. Any temp
1647 * tables created after we started will already have checksums in them
1648 * (due to the "inprogress-on" state), so no need to wait for those.
1649 */
1650 for (;;)
1651 {
1653 int numleft;
1654 char activity[64];
1655
1656 CurrentTempTables = BuildRelationList(true, false);
1657 numleft = 0;
1659 {
1661 numleft++;
1662 }
1664
1665#ifdef USE_INJECTION_POINTS
1666 if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fake-temptable-wait"))
1667 {
1668 /* Make sure to just cause one retry */
1669 if (!retried && numleft == 0)
1670 {
1671 numleft = 1;
1672 retried = true;
1673
1674 INJECTION_POINT_CACHED("datachecksumsworker-fake-temptable-wait", NULL);
1675 }
1676 }
1677#endif
1678
1679 if (numleft == 0)
1680 break;
1681
1682 /*
1683 * At least one temp table is left to wait for, indicate in pgstat
1684 * activity and progress reporting.
1685 */
1687 sizeof(activity),
1688 "Waiting for %d temp tables to be removed", numleft);
1690
1691 /* Retry every 3 seconds */
1695 3000,
1697
1700
1701 if (aborted || abort_requested)
1702 {
1706 ereport(LOG,
1707 errmsg("data checksum processing aborted in database OID %u",
1708 dboid));
1709 return;
1710 }
1711 }
1712
1714
1715 /* worker done */
1717
1721}
void VacuumUpdateCosts(void)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
void pgstat_report_activity(BackendState state, const char *cmd_str)
@ STATE_RUNNING
#define BGWORKER_BYPASS_ALLOWCONN
Definition bgworker.h:166
@ BAS_VACUUM
Definition bufmgr.h:40
int64_t int64
Definition c.h:621
static bool ProcessSingleRelationByOid(Oid relationId, BufferAccessStrategy strategy)
#define CHECK_FOR_ABORT_REQUEST()
static List * BuildRelationList(bool temp_relations, bool include_shared)
@ DATACHECKSUMSWORKER_ABORTED
@ DATACHECKSUMSWORKER_SUCCESSFUL
Datum arg
Definition elog.c:1323
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition freelist.c:426
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition freelist.c:608
int VacuumCostLimit
Definition globals.c:157
int VacuumCostBalance
Definition globals.c:160
struct Latch * MyLatch
Definition globals.c:65
double VacuumCostDelay
Definition globals.c:158
#define IS_INJECTION_POINT_ATTACHED(name)
#define INJECTION_POINT_CACHED(name, arg)
void ResetLatch(Latch *latch)
Definition latch.c:374
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition latch.c:172
void list_free(List *list)
Definition list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
@ B_DATACHECKSUMSWORKER_WORKER
Definition miscadmin.h:374
static int list_length(const List *l)
Definition pg_list.h:152
#define foreach_oid(var, lst)
Definition pg_list.h:503
#define snprintf
Definition port.h:261
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
unsigned int Oid
#define PROGRESS_DATACHECKSUMS_RELS_TOTAL
Definition progress.h:195
#define PROGRESS_DATACHECKSUMS_PHASE_WAITING_TEMPREL
Definition progress.h:203
#define PROGRESS_DATACHECKSUMS_RELS_DONE
Definition progress.h:196
DataChecksumsWorkerResult success
Definition type.h:97
#define WL_TIMEOUT
#define WL_EXIT_ON_PM_DEATH
#define WL_LATCH_SET

References abort_requested, arg, B_DATACHECKSUMSWORKER_WORKER, BackgroundWorkerInitializeConnectionByOid(), BackgroundWorkerUnblockSignals(), BAS_VACUUM, BGWORKER_BYPASS_ALLOWCONN, BuildRelationList(), CHECK_FOR_ABORT_REQUEST, CHECK_FOR_INTERRUPTS, DataChecksumsStateStruct::cost_delay, DataChecksumsStateStruct::cost_limit, DataChecksumState, DATACHECKSUMSWORKER_ABORTED, DATACHECKSUMSWORKER_SUCCESSFUL, DatumGetObjectId(), DEBUG1, die, ENABLE_DATACHECKSUMS, ereport, errmsg, fb(), foreach_oid, FreeAccessStrategy(), GetAccessStrategy(), init_ps_display(), INJECTION_POINT_CACHED, InvalidOid, IS_INJECTION_POINT_ATTACHED, DataChecksumsStateStruct::launch_cost_delay, DataChecksumsStateStruct::launch_cost_limit, list_free(), list_length(), list_member_oid(), LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyBackendType, MyLatch, NIL, operation, pgstat_progress_end_command(), pgstat_progress_start_command(), pgstat_progress_update_multi_param(), pgstat_progress_update_param(), pgstat_report_activity(), pqsignal, DataChecksumsStateStruct::process_shared_catalogs, ProcessSingleRelationByOid(), procsignal_sigusr1_handler(), PROGRESS_COMMAND_DATACHECKSUMS, PROGRESS_DATACHECKSUMS_PHASE, PROGRESS_DATACHECKSUMS_PHASE_WAITING_TEMPREL, PROGRESS_DATACHECKSUMS_RELS_DONE, PROGRESS_DATACHECKSUMS_RELS_TOTAL, ResetLatch(), SIGUSR1, snprintf, STATE_RUNNING, DataChecksumsStateStruct::success, VacuumCostBalance, VacuumCostDelay, VacuumCostLimit, VacuumUpdateCosts(), WaitLatch(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and WL_TIMEOUT.

◆ disable_data_checksums()

Datum disable_data_checksums ( PG_FUNCTION_ARGS  )

Definition at line 507 of file datachecksum_state.c.

508{
509 PreventCommandDuringRecovery("pg_disable_data_checksums()");
510
511 if (!superuser())
514 errmsg("must be superuser to change data checksum state"));
515
518}
void StartDataChecksumsWorkerLauncher(DataChecksumsWorkerOperation op, int cost_delay, int cost_limit)
#define PG_RETURN_VOID()
Definition fmgr.h:350
bool superuser(void)
Definition superuser.c:47
void PreventCommandDuringRecovery(const char *cmdname)
Definition utility.c:446

References DISABLE_DATACHECKSUMS, ereport, errcode(), errmsg, ERROR, fb(), PG_RETURN_VOID, PreventCommandDuringRecovery(), StartDataChecksumsWorkerLauncher(), and superuser().

◆ EmitAndWaitDataChecksumsBarrier()

void EmitAndWaitDataChecksumsBarrier ( uint32  state)

Definition at line 389 of file datachecksum_state.c.

390{
392
393 switch (state)
394 {
398 break;
399
403 break;
404
408 break;
409
413 break;
414
415 default:
416 Assert(false);
417 }
418}
uint64_t uint64
Definition c.h:625
void WaitForProcSignalBarrier(uint64 generation)
Definition procsignal.c:436
uint64 EmitProcSignalBarrier(ProcSignalBarrierType type)
Definition procsignal.c:368

References Assert, barrier, EmitProcSignalBarrier(), PG_DATA_CHECKSUM_INPROGRESS_OFF, PG_DATA_CHECKSUM_INPROGRESS_ON, PG_DATA_CHECKSUM_OFF, PG_DATA_CHECKSUM_VERSION, PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_OFF, PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_ON, PROCSIGNAL_BARRIER_CHECKSUM_OFF, PROCSIGNAL_BARRIER_CHECKSUM_ON, and WaitForProcSignalBarrier().

Referenced by StartupXLOG(), xlog2_redo(), and xlog_redo().

◆ enable_data_checksums()

Datum enable_data_checksums ( PG_FUNCTION_ARGS  )

Definition at line 526 of file datachecksum_state.c.

527{
528 int cost_delay = PG_GETARG_INT32(0);
529 int cost_limit = PG_GETARG_INT32(1);
530
531 PreventCommandDuringRecovery("pg_enable_data_checksums()");
532
533 if (!superuser())
536 errmsg("must be superuser to change data checksum state"));
537
538 if (cost_delay < 0)
541 errmsg("cost delay cannot be a negative value"));
542
543 if (cost_limit <= 0)
546 errmsg("cost limit must be greater than zero"));
547
549
551}
#define PG_GETARG_INT32(n)
Definition fmgr.h:269

References ENABLE_DATACHECKSUMS, ereport, errcode(), errmsg, ERROR, fb(), PG_GETARG_INT32, PG_RETURN_VOID, PreventCommandDuringRecovery(), StartDataChecksumsWorkerLauncher(), and superuser().

◆ FreeDatabaseList()

static void FreeDatabaseList ( List dblist)
static

Definition at line 1413 of file datachecksum_state.c.

1414{
1415 if (!dblist)
1416 return;
1417
1419 {
1420 if (db->dbname != NULL)
1421 pfree(db->dbname);
1422 }
1423
1425}
void list_free_deep(List *list)
Definition list.c:1560
void pfree(void *pointer)
Definition mcxt.c:1619
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
_stringlist * dblist
Definition pg_regress.c:99

References dblist, fb(), foreach_ptr, list_free_deep(), and pfree().

Referenced by ProcessAllDatabases().

◆ launcher_cancel_handler()

static void launcher_cancel_handler ( SIGNAL_ARGS  )
static

Definition at line 962 of file datachecksum_state.c.

963{
964 int save_errno = errno;
965
966 abort_requested = true;
967
968 /*
969 * There is no sleeping in the main loop, the flag will be checked
970 * periodically in ProcessSingleRelationFork. The worker does however
971 * sleep when waiting for concurrent transactions to end so we still need
972 * to set the latch.
973 */
975
977}
void SetLatch(Latch *latch)
Definition latch.c:290

References abort_requested, fb(), MyLatch, and SetLatch().

Referenced by DataChecksumsWorkerLauncherMain().

◆ launcher_exit()

static void launcher_exit ( int  code,
Datum  arg 
)
static

Definition at line 925 of file datachecksum_state.c.

926{
927 abort_requested = false;
928
930 {
933 {
934 ereport(LOG,
935 errmsg("data checksums launcher exiting while worker is still running, signalling worker"));
937 }
939 }
940
941 /*
942 * If the launcher is exiting before data checksums are enabled then set
943 * the state to off since processing cannot be resumed.
944 */
947
949 launcher_running = false;
952}
#define InvalidPid
Definition miscadmin.h:32
#define kill(pid, sig)
Definition win32_port.h:490
bool DataChecksumsInProgressOn(void)
Definition xlog.c:4707

References abort_requested, DataChecksumsInProgressOn(), DataChecksumState, ereport, errmsg, fb(), InvalidPid, kill, DataChecksumsStateStruct::launcher_running, launcher_running, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SetDataChecksumsOff(), and DataChecksumsStateStruct::worker_pid.

Referenced by DataChecksumsWorkerLauncherMain().

◆ ProcessAllDatabases()

static bool ProcessAllDatabases ( void  )
static

Definition at line 1208 of file datachecksum_state.c.

1209{
1211 int cumulative_total = 0;
1212
1213 /* Set up so first run processes shared catalogs, not once in every db */
1217
1218 /* Get a list of all databases to process */
1221
1222 /*
1223 * Update progress reporting with the total number of databases we need to
1224 * process. This number should not be changed during processing, the
1225 * columns for processed databases is instead increased such that it can
1226 * be compared against the total.
1227 */
1228 {
1229 const int index[] = {
1236 };
1237
1238 int64 vals[6];
1239
1240 vals[0] = list_length(DatabaseList);
1241 vals[1] = 0;
1242 /* translated to NULL */
1243 vals[2] = -1;
1244 vals[3] = -1;
1245 vals[4] = -1;
1246 vals[5] = -1;
1247
1249 }
1250
1252 {
1254
1255 result = ProcessDatabase(db);
1256
1257#ifdef USE_INJECTION_POINTS
1258 /* Allow a test process to alter the result of the operation */
1259 if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fail-db-result"))
1260 {
1262 INJECTION_POINT_CACHED("datachecksumsworker-fail-db-result",
1263 db->dbname);
1264 }
1265#endif
1266
1269
1271 {
1272 /*
1273 * Disable checksums on cluster, because we failed one of the
1274 * databases and this is an all or nothing process.
1275 */
1277 ereport(ERROR,
1279 errmsg("data checksums failed to get enabled in all databases, aborting"),
1280 errhint("The server log might have more information on the cause of the error."));
1281 }
1283 {
1284 /* Abort flag set, so exit the whole process */
1285 return false;
1286 }
1287
1288 /*
1289 * When one database has completed, it will have done shared catalogs
1290 * so we don't have to process them again.
1291 */
1295 }
1296
1298
1301 return true;
1302}
uint32 result
static DataChecksumsWorkerResult ProcessDatabase(DataChecksumsWorkerDatabase *db)
static void FreeDatabaseList(List *dblist)
static List * BuildDatabaseList(void)
static void WaitForAllTransactionsToFinish(void)
DataChecksumsWorkerResult
@ DATACHECKSUMSWORKER_FAILED
int errhint(const char *fmt,...) pg_attribute_printf(1
#define PROGRESS_DATACHECKSUMS_BLOCKS_DONE
Definition progress.h:198
#define PROGRESS_DATACHECKSUMS_DBS_DONE
Definition progress.h:194
#define PROGRESS_DATACHECKSUMS_PHASE_WAITING_BARRIER
Definition progress.h:204
#define PROGRESS_DATACHECKSUMS_BLOCKS_TOTAL
Definition progress.h:197
#define PROGRESS_DATACHECKSUMS_DBS_TOTAL
Definition progress.h:193

References abort_requested, BuildDatabaseList(), DatabaseList, DataChecksumState, DATACHECKSUMSWORKER_ABORTED, DATACHECKSUMSWORKER_FAILED, ereport, errcode(), errhint(), errmsg, ERROR, fb(), foreach_ptr, FreeDatabaseList(), INJECTION_POINT_CACHED, IS_INJECTION_POINT_ATTACHED, list_length(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), pgstat_progress_update_multi_param(), pgstat_progress_update_param(), DataChecksumsStateStruct::process_shared_catalogs, ProcessDatabase(), PROGRESS_DATACHECKSUMS_BLOCKS_DONE, PROGRESS_DATACHECKSUMS_BLOCKS_TOTAL, PROGRESS_DATACHECKSUMS_DBS_DONE, PROGRESS_DATACHECKSUMS_DBS_TOTAL, PROGRESS_DATACHECKSUMS_PHASE, PROGRESS_DATACHECKSUMS_PHASE_WAITING_BARRIER, PROGRESS_DATACHECKSUMS_RELS_DONE, PROGRESS_DATACHECKSUMS_RELS_TOTAL, result, SetDataChecksumsOff(), and WaitForAllTransactionsToFinish().

Referenced by DataChecksumsWorkerLauncherMain().

◆ ProcessDatabase()

Definition at line 793 of file datachecksum_state.c.

794{
797 BgwHandleStatus status;
798 pid_t pid;
799 char activity[NAMEDATALEN + 64];
800
804
805 memset(&bgw, 0, sizeof(bgw));
807 bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
808 snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
809 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "%s", "DataChecksumsWorkerMain");
810 snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksums worker");
811 snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksums worker");
812 bgw.bgw_restart_time = BGW_NEVER_RESTART;
813 bgw.bgw_notify_pid = MyProcPid;
814 bgw.bgw_main_arg = ObjectIdGetDatum(db->dboid);
815
816 /*
817 * If there are no worker slots available, there is little we can do. If
818 * we retry in a bit it's still unlikely that the user has managed to
819 * reconfigure in the meantime and we'd be run through retries fast.
820 */
822 {
824 errmsg("could not start background worker for enabling data checksums in database \"%s\"",
825 db->dbname),
826 errhint("The \"%s\" setting might be too low.", "max_worker_processes"));
828 }
829
831 if (status == BGWH_STOPPED)
832 {
833 /*
834 * If the worker managed to start, and stop, before we got to waiting
835 * for it we can see a STOPPED status here without it being a failure.
836 */
839 {
846 }
848
850 errmsg("could not start background worker for enabling data checksums in database \"%s\"",
851 db->dbname),
852 errhint("More details on the error might be found in the server log."));
853
854 /*
855 * Heuristic to see if the database was dropped, and if it was we can
856 * treat it as not an error, else treat as fatal and error out.
857 */
858 if (DatabaseExists(db->dboid))
860 else
862 }
863
864 /*
865 * If the postmaster crashed we cannot end up with a processed database so
866 * we have no alternative other than exiting. When enabling checksums we
867 * won't at this time have changed the data checksums state in pg_control
868 * to enabled so when the cluster comes back up processing will have to be
869 * restarted.
870 */
871 if (status == BGWH_POSTMASTER_DIED)
874 errmsg("cannot enable data checksums without the postmaster process"),
875 errhint("Restart the database and restart data checksum processing by calling pg_enable_data_checksums()."));
876
877 Assert(status == BGWH_STARTED);
878 ereport(LOG,
879 errmsg("initiating data checksum processing in database \"%s\"",
880 db->dbname));
881
882 /* Save the pid of the worker so we can signal it later */
886
887 snprintf(activity, sizeof(activity) - 1,
888 "Waiting for worker in database %s (pid %ld)", db->dbname, (long) pid);
890
892 if (status == BGWH_POSTMASTER_DIED)
895 errmsg("postmaster exited during data checksum processing in \"%s\"",
896 db->dbname),
897 errhint("Restart the database and restart data checksum processing by calling pg_enable_data_checksums()."));
898
901 ereport(LOG,
902 errmsg("data checksums processing was aborted in database \"%s\"",
903 db->dbname));
905
910
912}
@ STATE_IDLE
BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
Definition bgworker.c:1235
BgwHandleStatus WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle)
Definition bgworker.c:1280
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_SHMEM_ACCESS
Definition bgworker.h:53
#define BGW_MAXLEN
Definition bgworker.h:93
static bool DatabaseExists(Oid dboid)
@ DATACHECKSUMSWORKER_DROPDB
#define FATAL
Definition elog.h:42
#define WARNING
Definition elog.h:37
int MyProcPid
Definition globals.c:49
#define NAMEDATALEN

References Assert, BGW_MAXLEN, BGW_NEVER_RESTART, BGWH_POSTMASTER_DIED, BGWH_STARTED, BGWH_STOPPED, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, BgWorkerStart_RecoveryFinished, DatabaseExists(), DataChecksumState, DATACHECKSUMSWORKER_ABORTED, DATACHECKSUMSWORKER_DROPDB, DATACHECKSUMSWORKER_FAILED, DATACHECKSUMSWORKER_SUCCESSFUL, DataChecksumsWorkerDatabase::dbname, DataChecksumsWorkerDatabase::dboid, ereport, errcode(), errhint(), errmsg, FATAL, fb(), InvalidPid, LOG, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyProcPid, NAMEDATALEN, ObjectIdGetDatum(), pgstat_report_activity(), RegisterDynamicBackgroundWorker(), snprintf, STATE_IDLE, STATE_RUNNING, DataChecksumsStateStruct::success, WaitForBackgroundWorkerShutdown(), WaitForBackgroundWorkerStartup(), WARNING, and DataChecksumsStateStruct::worker_pid.

Referenced by ProcessAllDatabases().

◆ ProcessSingleRelationByOid()

static bool ProcessSingleRelationByOid ( Oid  relationId,
BufferAccessStrategy  strategy 
)
static

Definition at line 742 of file datachecksum_state.c.

743{
744 Relation rel;
745 bool aborted = false;
746
748
750 if (rel == NULL)
751 {
752 /*
753 * Relation no longer exists. We don't consider this an error since
754 * there are no pages in it that need data checksums, and thus return
755 * true. The worker operates off a list of relations generated at the
756 * start of processing, so relations being dropped in the meantime is
757 * to be expected.
758 */
761 return true;
762 }
763 RelationGetSmgr(rel);
764
765 for (ForkNumber fnum = 0; fnum <= MAX_FORKNUM; fnum++)
766 {
767 if (smgrexists(rel->rd_smgr, fnum))
768 {
769 if (!ProcessSingleRelationFork(rel, fnum, strategy))
770 {
771 aborted = true;
772 break;
773 }
774 }
775 }
777
780
781 return !aborted;
782}
static bool ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy)
static SMgrRelation RelationGetSmgr(Relation rel)
Definition rel.h:578
ForkNumber
Definition relpath.h:56
#define MAX_FORKNUM
Definition relpath.h:70
bool smgrexists(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:462
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:89
SMgrRelation rd_smgr
Definition rel.h:58

References AccessShareLock, CommitTransactionCommand(), fb(), MAX_FORKNUM, pgstat_report_activity(), ProcessSingleRelationFork(), RelationData::rd_smgr, relation_close(), RelationGetSmgr(), smgrexists(), StartTransactionCommand(), STATE_IDLE, and try_relation_open().

Referenced by DataChecksumsWorkerMain().

◆ ProcessSingleRelationFork()

static bool ProcessSingleRelationFork ( Relation  reln,
ForkNumber  forkNum,
BufferAccessStrategy  strategy 
)
static

Definition at line 652 of file datachecksum_state.c.

653{
655 char activity[NAMEDATALEN * 2 + 128];
656 char *relns;
657
659
660 /* Report the current relation to pg_stat_activity */
661 snprintf(activity, sizeof(activity) - 1, "processing: %s.%s (%s, %u blocks)",
665 if (relns)
666 pfree(relns);
667
668 /*
669 * We are looping over the blocks which existed at the time of process
670 * start, which is safe since new blocks are created with checksums set
671 * already due to the state being "inprogress-on".
672 */
674 {
675 Buffer buf = ReadBufferExtended(reln, forkNum, blknum, RBM_NORMAL, strategy);
676
677 /* Need to get an exclusive lock to mark the buffer as dirty */
679
680 /*
681 * Mark the buffer as dirty and force a full page write. We have to
682 * re-write the page to WAL even if the checksum hasn't changed,
683 * because if there is a replica it might have a slightly different
684 * version of the page with an invalid checksum, caused by unlogged
685 * changes (e.g. hint bits) on the primary happening while checksums
686 * were off. This can happen if there was a valid checksum on the page
687 * at one point in the past, so only when checksums are first on, then
688 * off, and then turned on again. TODO: investigate if this could be
689 * avoided if the checksum is calculated to be correct and wal_level
690 * is set to "minimal".
691 *
692 * Unlogged relations don't need WAL since they are reset to their
693 * init fork on recovery. We still dirty the buffer so that the
694 * checksum is written to disk at the next checkpoint.
695 *
696 * The init fork is an exception: it is WAL-logged so the standby can
697 * materialize the relation after promotion (see
698 * ResetUnloggedRelations()). Skipping it here would leave the
699 * standby with a stale init fork that, once copied to the main fork
700 * on promotion, would fail checksum verification on every read.
701 */
704 if (RelationNeedsWAL(reln) || forkNum == INIT_FORKNUM)
705 log_newpage_buffer(buf, false);
707
709
710 /* Check if we are asked to abort, the abortion will bubble up. */
714 abort_requested = true;
716
717 if (abort_requested)
718 return false;
719
720 /* update the block counter */
722 (blknum + 1));
723
724 /*
725 * Processing is re-using the vacuum cost delay for process
726 * throttling, hence why we call vacuum APIs here.
727 */
728 vacuum_delay_point(false);
729 }
730
731 return true;
732}
uint32 BlockNumber
Definition block.h:31
int Buffer
Definition buf.h:23
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
Definition bufmgr.c:4654
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5612
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3156
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:926
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:222
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334
@ RBM_NORMAL
Definition bufmgr.h:46
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3599
#define START_CRIT_SECTION()
Definition miscadmin.h:152
#define END_CRIT_SECTION()
Definition miscadmin.h:154
static char buf[DEFAULT_XLOG_SEG_SIZE]
#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
@ INIT_FORKNUM
Definition relpath.h:61
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2438
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)

References abort_requested, Assert, buf, BUFFER_LOCK_EXCLUSIVE, DataChecksumState, DISABLE_DATACHECKSUMS, ENABLE_DATACHECKSUMS, END_CRIT_SECTION, fb(), forkNames, get_namespace_name(), INIT_FORKNUM, DataChecksumsStateStruct::launch_operation, LockBuffer(), log_newpage_buffer(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MarkBufferDirty(), NAMEDATALEN, operation, pfree(), pgstat_progress_update_param(), pgstat_report_activity(), PROGRESS_DATACHECKSUMS_BLOCKS_DONE, PROGRESS_DATACHECKSUMS_BLOCKS_TOTAL, RBM_NORMAL, ReadBufferExtended(), RelationGetNamespace, RelationGetNumberOfBlocksInFork(), RelationGetRelationName, RelationNeedsWAL, snprintf, START_CRIT_SECTION, STATE_RUNNING, UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ProcessSingleRelationByOid().

◆ StartDataChecksumsWorkerLauncher()

void StartDataChecksumsWorkerLauncher ( DataChecksumsWorkerOperation  op,
int  cost_delay,
int  cost_limit 
)

Definition at line 566 of file datachecksum_state.c.

569{
572 bool running;
573
574#ifdef USE_ASSERT_CHECKING
575 /* The cost delay settings have no effect when disabling */
576 if (op == DISABLE_DATACHECKSUMS)
577 Assert(cost_delay == 0 && cost_limit == 0);
578#endif
579
580 INJECTION_POINT("datachecksumsworker-startup-delay", NULL);
581
582 /* Store the desired state in shared memory */
584
588
589 /* Is the launcher already running? If so, what is it doing? */
591
593
594 /*
595 * Launch a new launcher process, if it's not running already.
596 *
597 * If the launcher is currently busy enabling the checksums, and we want
598 * them disabled (or vice versa), the launcher will notice that at latest
599 * when it's about to exit, and will loop back to process the new request.
600 * So if the launcher is already running, we don't need to do anything
601 * more here to abort it.
602 *
603 * If you call pg_enable/disable_data_checksums() twice in a row, before
604 * the launcher has had a chance to start up, we still end up launching it
605 * twice. That's OK, the second invocation will see that a launcher is
606 * already running and exit quickly.
607 */
608 if (!running)
609 {
610 if ((op == ENABLE_DATACHECKSUMS && DataChecksumsOn()) ||
612 {
613 ereport(LOG,
614 errmsg("data checksums already in desired state, exiting"));
615 return;
616 }
617
618 /*
619 * Prepare the BackgroundWorker and launch it.
620 */
621 memset(&bgw, 0, sizeof(bgw));
623 bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
624 snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
625 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "DataChecksumsWorkerLauncherMain");
626 snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksums launcher");
627 snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksums launcher");
628 bgw.bgw_restart_time = BGW_NEVER_RESTART;
629 bgw.bgw_notify_pid = MyProcPid;
630 bgw.bgw_main_arg = (Datum) 0;
631
635 errmsg("failed to start background worker to process data checksums"));
636 }
637 else
638 {
639 ereport(LOG,
640 errmsg("data checksum processing already running"));
641 }
642}
uint64_t Datum
Definition postgres.h:70
bool DataChecksumsOn(void)
Definition xlog.c:4695
bool DataChecksumsOff(void)
Definition xlog.c:4683

References Assert, BGW_MAXLEN, BGW_NEVER_RESTART, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, BgWorkerStart_RecoveryFinished, DataChecksumsOff(), DataChecksumsOn(), DataChecksumState, DISABLE_DATACHECKSUMS, ENABLE_DATACHECKSUMS, ereport, errcode(), errmsg, ERROR, fb(), INJECTION_POINT, DataChecksumsStateStruct::launch_cost_delay, DataChecksumsStateStruct::launch_cost_limit, DataChecksumsStateStruct::launch_operation, DataChecksumsStateStruct::launcher_running, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProcPid, RegisterDynamicBackgroundWorker(), and snprintf.

Referenced by disable_data_checksums(), and enable_data_checksums().

◆ WaitForAllTransactionsToFinish()

static void WaitForAllTransactionsToFinish ( void  )
static

Definition at line 992 of file datachecksum_state.c.

993{
995
999
1001 {
1002 char activity[64];
1003 int rc;
1004
1005 /* Oldest running xid is older than us, so wait */
1007 sizeof(activity),
1008 "Waiting for transactions older than %u to end",
1009 waitforxid);
1011
1012 /* Retry every 3 seconds */
1014 rc = WaitLatch(MyLatch,
1016 3000,
1018
1019 /*
1020 * If the postmaster died we won't be able to enable checksums
1021 * cluster-wide so abort and hope to continue when restarted.
1022 */
1023 if (rc & WL_POSTMASTER_DEATH)
1024 ereport(FATAL,
1026 errmsg("postmaster exited during data checksums processing"),
1027 errhint("Data checksums processing must be restarted manually after cluster restart."));
1028
1031
1032 if (abort_requested)
1033 break;
1034 }
1035
1037 return;
1038}
uint32 TransactionId
Definition c.h:736
TransactionId GetOldestActiveTransactionId(bool inCommitOnly, bool allDbs)
Definition procarray.c:2824
FullTransactionId nextXid
Definition transam.h:220
#define XidFromFullTransactionId(x)
Definition transam.h:48
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
TransamVariablesData * TransamVariables
Definition varsup.c:37
#define WL_POSTMASTER_DEATH

References abort_requested, CHECK_FOR_ABORT_REQUEST, CHECK_FOR_INTERRUPTS, ereport, errcode(), errhint(), errmsg, FATAL, fb(), GetOldestActiveTransactionId(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MyLatch, TransamVariablesData::nextXid, pgstat_report_activity(), ResetLatch(), snprintf, STATE_IDLE, STATE_RUNNING, TransactionIdPrecedes(), TransamVariables, WaitLatch(), WL_LATCH_SET, WL_POSTMASTER_DEATH, WL_TIMEOUT, and XidFromFullTransactionId.

Referenced by ProcessAllDatabases().

Variable Documentation

◆ abort_requested

◆ checksum_barriers

const ChecksumBarrierCondition checksum_barriers[9]
static
Initial value:

Definition at line 238 of file datachecksum_state.c.

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};

Referenced by AbsorbDataChecksumsBarrier().

◆ DataChecksumsShmemCallbacks

const ShmemCallbacks DataChecksumsShmemCallbacks
Initial value:
= {
}
static void DataChecksumsShmemRequest(void *arg)

Definition at line 371 of file datachecksum_state.c.

371 {
372 .request_fn = DataChecksumsShmemRequest,
373};

◆ DataChecksumState

◆ launcher_running

volatile sig_atomic_t launcher_running = false
static

Definition at line 354 of file datachecksum_state.c.

Referenced by DataChecksumsWorkerLauncherMain(), and launcher_exit().

◆ operation