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
 

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 [6]
 
static DataChecksumsStateStructDataChecksumState
 
static volatile sig_atomic_t abort_requested = false
 
static volatile sig_atomic_t launcher_running = false
 
static DataChecksumsWorkerOperation operation
 
const ShmemCallbacks DataChecksumsShmemCallbacks
 

Typedef Documentation

◆ ChecksumBarrierCondition

◆ DataChecksumsStateStruct

◆ DataChecksumsWorkerDatabase

Function Documentation

◆ AbsorbDataChecksumsBarrier()

bool AbsorbDataChecksumsBarrier ( ProcSignalBarrierType  barrier)

Definition at line 411 of file datachecksum_state.c.

412{
414 int current = data_checksums;
415 bool found = false;
416
417 /*
418 * Translate the barrier condition to the target state, doing it here
419 * instead of in the procsignal code saves the latter from knowing about
420 * checksum states.
421 */
422 switch (barrier)
423 {
426 break;
429 break;
432 break;
435 break;
436 default:
437 elog(ERROR, "incorrect barrier \"%i\" received", barrier);
438 }
439
440 /*
441 * If the target state matches the current state then the barrier has been
442 * repeated.
443 */
444 if (current == target_state)
445 return true;
446
447 /*
448 * If the cluster is in recovery we skip the validation of current state
449 * since the replay is trusted.
450 */
451 if (RecoveryInProgress())
452 {
454 return true;
455 }
456
457 /*
458 * Find the barrier condition definition for the target state. Not finding
459 * a condition would be a grave programmer error as the states are a
460 * discrete set.
461 */
462 for (int i = 0; i < lengthof(checksum_barriers) && !found; i++)
463 {
464 if (checksum_barriers[i].from == current && checksum_barriers[i].to == target_state)
465 found = true;
466 }
467
468 /*
469 * If the relevant state criteria aren't satisfied, throw an error which
470 * will be caught by the procsignal machinery for a later retry.
471 */
472 if (!found)
475 errmsg("incorrect data checksum state %i for target state %i",
476 current, target_state));
477
479 return true;
480}
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[6]
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
#define ereport(elevel,...)
Definition elog.h:151
int i
Definition isn.c:77
static char * errmsg
static THREAD_BARRIER_T barrier
Definition pgbench.c:488
static int fb(int x)
@ PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_OFF
Definition procsignal.h:53
@ PROCSIGNAL_BARRIER_CHECKSUM_INPROGRESS_ON
Definition procsignal.h:52
@ PROCSIGNAL_BARRIER_CHECKSUM_ON
Definition procsignal.h:54
@ PROCSIGNAL_BARRIER_CHECKSUM_OFF
Definition procsignal.h:51
bool RecoveryInProgress(void)
Definition xlog.c:6830
void SetLocalDataChecksumState(uint32 data_checksum_version)
Definition xlog.c:4969
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 1322 of file datachecksum_state.c.

1323{
1325 Relation rel;
1326 TableScanDesc scan;
1327 HeapTuple tup;
1330
1332
1334 scan = table_beginscan_catalog(rel, 0, NULL);
1335
1337 {
1340
1342
1344
1345 db->dboid = pgdb->oid;
1346 db->dbname = pstrdup(NameStr(pgdb->datname));
1347
1349
1351 }
1352
1353 table_endscan(scan);
1355
1357
1358 return DatabaseList;
1359}
static dlist_head DatabaseList
Definition autovacuum.c:325
#define NameStr(name)
Definition c.h:835
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1421
#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:1781
void * palloc0(Size size)
Definition mcxt.c:1417
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
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:1056
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 1388 of file datachecksum_state.c.

1389{
1391 Relation rel;
1392 TableScanDesc scan;
1393 HeapTuple tup;
1396
1398
1400 scan = table_beginscan_catalog(rel, 0, NULL);
1401
1403 {
1405
1406 /* Only include temporary relations when explicitly asked to */
1407 if (pgc->relpersistence == RELPERSISTENCE_TEMP)
1408 {
1409 if (!temp_relations)
1410 continue;
1411 }
1412 else
1413 {
1414 /*
1415 * If we are only interested in temp relations then continue
1416 * immediately as the current relation isn't a temp relation.
1417 */
1418 if (temp_relations)
1419 continue;
1420
1421 if (!RELKIND_HAS_STORAGE(pgc->relkind))
1422 continue;
1423
1424 if (pgc->relisshared && !include_shared)
1425 continue;
1426 }
1427
1431 }
1432
1433 table_endscan(scan);
1435
1437
1438 return RelationList;
1439}
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 1284 of file datachecksum_state.c.

1285{
1286 Relation rel;
1288 SysScanDesc scan;
1289 bool found;
1290 HeapTuple tuple;
1291
1293
1298 dboid);
1300 1, &skey);
1301 tuple = systable_getnext(scan);
1302 found = HeapTupleIsValid(tuple);
1303
1304 systable_endscan(scan);
1306
1308
1309 return found;
1310}
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
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(), fb(), HeapTupleIsValid, 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 1269 of file datachecksum_state.c.

1270{
1271 ShmemRequestStruct(.name = "DataChecksumsWorker Data",
1272 .size = sizeof(DataChecksumsStateStruct),
1273 .ptr = (void **) &DataChecksumState,
1274 );
1275}
static DataChecksumsStateStruct * DataChecksumState
#define ShmemRequestStruct(...)
Definition shmem.h:176
const char * name

References DataChecksumState, name, and ShmemRequestStruct.

◆ DataChecksumsWorkerLauncherMain()

void DataChecksumsWorkerLauncherMain ( Datum  arg)

Definition at line 1013 of file datachecksum_state.c.

1014{
1016
1018 errmsg("background worker \"datachecksums launcher\" started"));
1019
1024
1026
1029
1030 INJECTION_POINT("datachecksumsworker-launcher-delay", NULL);
1031
1033
1035 {
1036 ereport(LOG,
1037 errmsg("background worker \"datachecksums launcher\" already running, exiting"));
1038 /* Launcher was already running, let it finish */
1040 return;
1041 }
1042
1043 launcher_running = true;
1044
1045 /* Initialize a connection to shared catalogs only */
1047
1054
1055 /*
1056 * The target state can change while we are busy enabling/disabling
1057 * checksums, if the user calls pg_disable/enable_data_checksums() before
1058 * we are finished with the previous request. In that case, we will loop
1059 * back here, to process the new request.
1060 */
1061again:
1062
1064 InvalidOid);
1065
1067 {
1068 /*
1069 * If we are asked to enable checksums in a cluster which already has
1070 * checksums enabled, exit immediately as there is nothing more to do.
1071 */
1073 goto done;
1074
1075 ereport(LOG,
1076 errmsg("enabling data checksums requested, starting data checksum calculation"));
1077
1078 /*
1079 * Set the state to inprogress-on and wait on the procsignal barrier.
1080 */
1084
1085 /*
1086 * All backends are now in inprogress-on state and are writing data
1087 * checksums. Start processing all data at rest.
1088 */
1089 if (!ProcessAllDatabases())
1090 {
1091 /*
1092 * If the target state changed during processing then it's not a
1093 * failure, so restart processing instead.
1094 */
1097 {
1099 goto done;
1100 }
1102 ereport(ERROR,
1104 errmsg("unable to enable data checksums in cluster"));
1105 }
1106
1107 /*
1108 * Data checksums have been set on all pages, set the state to on in
1109 * order to instruct backends to validate checksums on reading.
1110 */
1112
1113 ereport(LOG,
1114 errmsg("data checksums are now enabled"));
1115 }
1116 else if (operation == DISABLE_DATACHECKSUMS)
1117 {
1118 ereport(LOG,
1119 errmsg("disabling data checksums requested"));
1120
1124 ereport(LOG,
1125 errmsg("data checksums are now disabled"));
1126 }
1127 else
1128 Assert(false);
1129
1130done:
1131
1132 /*
1133 * This state will only be displayed for a fleeting moment, but for the
1134 * sake of correctness it is still added before ending the command.
1135 */
1138
1139 /*
1140 * All done. But before we exit, check if the target state was changed
1141 * while we were running. In that case we will have to start all over
1142 * again.
1143 */
1146 {
1152 goto again;
1153 }
1154
1155 /* Shut down progress reporting as we are done */
1157
1158 launcher_running = false;
1161}
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:944
void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
Definition bgworker.c:904
#define Assert(condition)
Definition c.h:943
static volatile sig_atomic_t launcher_running
static DataChecksumsWorkerOperation operation
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:31
#define DEBUG1
Definition elog.h:30
#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:370
BackendType MyBackendType
Definition miscinit.c:65
#define die(msg)
#define pqsignal
Definition port.h:547
#define InvalidOid
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition procsignal.c:686
#define PROGRESS_DATACHECKSUMS_PHASE_DONE
Definition progress.h:202
#define PROGRESS_DATACHECKSUMS_PHASE
Definition progress.h:189
#define PROGRESS_DATACHECKSUMS_PHASE_ENABLING
Definition progress.h:198
#define PROGRESS_DATACHECKSUMS_PHASE_DISABLING
Definition progress.h:199
void init_ps_display(const char *fixed_part)
Definition ps_status.c:286
DataChecksumsWorkerOperation launch_operation
DataChecksumsWorkerOperation operation
#define SIGUSR1
Definition win32_port.h:170
#define SIGUSR2
Definition win32_port.h:171
void SetDataChecksumsOff(void)
Definition xlog.c:4858
bool DataChecksumsNeedVerify(void)
Definition xlog.c:4706
void SetDataChecksumsOn(void)
Definition xlog.c:4786
void SetDataChecksumsOnInProgress(void)
Definition xlog.c:4722

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, 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 1453 of file datachecksum_state.c.

1454{
1455 Oid dboid = DatumGetObjectId(arg);
1458 BufferAccessStrategy strategy;
1459 bool aborted = false;
1461#ifdef USE_INJECTION_POINTS
1462 bool retried = false;
1463#endif
1464
1466
1469
1471
1474
1477
1478 /* worker will have a separate entry in pg_stat_progress_data_checksums */
1480 InvalidOid);
1481
1482 /*
1483 * Get a list of all temp tables present as we start in this database. We
1484 * need to wait until they are all gone until we are done, since we cannot
1485 * access these relations and modify them.
1486 */
1488
1489 /*
1490 * Enable vacuum cost delay, if any. While this process isn't doing any
1491 * vacuuming, we are re-using the infrastructure that vacuum cost delay
1492 * provides rather than inventing something bespoke. This is an internal
1493 * implementation detail and care should be taken to avoid it bleeding
1494 * through to the user to avoid confusion.
1495 */
1504
1505 /*
1506 * Create and set the vacuum strategy as our buffer strategy.
1507 */
1508 strategy = GetAccessStrategy(BAS_VACUUM);
1509
1512
1513 /* Update the total number of relations to be processed in this DB. */
1514 {
1515 const int index[] = {
1518 };
1519
1520 int64 vals[2];
1521
1522 vals[0] = list_length(RelationList);
1523 vals[1] = 0;
1524
1526 }
1527
1528 /* Process the relations */
1529 rels_done = 0;
1530 foreach_oid(reloid, RelationList)
1531 {
1533
1534 if (!ProcessSingleRelationByOid(reloid, strategy))
1535 {
1536 aborted = true;
1537 break;
1538 }
1539
1541 ++rels_done);
1542 }
1544
1545 if (aborted)
1546 {
1549 errmsg("data checksum processing aborted in database OID %u",
1550 dboid));
1551 return;
1552 }
1553
1554 /* The worker is about to wait for temporary tables to go away. */
1557
1558 /*
1559 * Wait for all temp tables that existed when we started to go away. This
1560 * is necessary since we cannot "reach" them to enable checksums. Any temp
1561 * tables created after we started will already have checksums in them
1562 * (due to the "inprogress-on" state), so no need to wait for those.
1563 */
1564 for (;;)
1565 {
1567 int numleft;
1568 char activity[64];
1569
1570 CurrentTempTables = BuildRelationList(true, false);
1571 numleft = 0;
1573 {
1575 numleft++;
1576 }
1578
1579#ifdef USE_INJECTION_POINTS
1580 if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fake-temptable-wait"))
1581 {
1582 /* Make sure to just cause one retry */
1583 if (!retried && numleft == 0)
1584 {
1585 numleft = 1;
1586 retried = true;
1587
1588 INJECTION_POINT_CACHED("datachecksumsworker-fake-temptable-wait", NULL);
1589 }
1590 }
1591#endif
1592
1593 if (numleft == 0)
1594 break;
1595
1596 /*
1597 * At least one temp table is left to wait for, indicate in pgstat
1598 * activity and progress reporting.
1599 */
1601 sizeof(activity),
1602 "Waiting for %d temp tables to be removed", numleft);
1604
1605 /* Retry every 3 seconds */
1609 3000,
1611
1615
1617
1618 if (aborted || abort_requested)
1619 {
1621 ereport(LOG,
1622 errmsg("data checksum processing aborted in database OID %u",
1623 dboid));
1624 return;
1625 }
1626 }
1627
1629
1630 /* worker done */
1632
1636}
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 volatile sig_atomic_t abort_requested
static bool ProcessSingleRelationByOid(Oid relationId, BufferAccessStrategy strategy)
static List * BuildRelationList(bool temp_relations, bool include_shared)
@ DATACHECKSUMSWORKER_ABORTED
@ DATACHECKSUMSWORKER_SUCCESSFUL
Datum arg
Definition elog.c:1322
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition freelist.c:426
int VacuumCostLimit
Definition globals.c:154
int VacuumCostPageMiss
Definition globals.c:152
bool VacuumCostActive
Definition globals.c:158
int VacuumCostBalance
Definition globals.c:157
int VacuumCostPageDirty
Definition globals.c:153
int VacuumCostPageHit
Definition globals.c:151
struct Latch * MyLatch
Definition globals.c:63
double VacuumCostDelay
Definition globals.c:155
#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:123
@ B_DATACHECKSUMSWORKER_WORKER
Definition miscadmin.h:371
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:260
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
unsigned int Oid
#define PROGRESS_DATACHECKSUMS_RELS_TOTAL
Definition progress.h:192
#define PROGRESS_DATACHECKSUMS_PHASE_WAITING_TEMPREL
Definition progress.h:200
#define PROGRESS_DATACHECKSUMS_RELS_DONE
Definition progress.h:193
DataChecksumsWorkerResult success
Definition type.h:96
#define WL_TIMEOUT
#define WL_EXIT_ON_PM_DEATH
#define WL_LATCH_SET

References abort_requested, arg, Assert, B_DATACHECKSUMSWORKER_WORKER, BackgroundWorkerInitializeConnectionByOid(), BackgroundWorkerUnblockSignals(), BAS_VACUUM, BGWORKER_BYPASS_ALLOWCONN, BuildRelationList(), CHECK_FOR_INTERRUPTS, DataChecksumsStateStruct::cost_delay, DataChecksumsStateStruct::cost_limit, DataChecksumState, DATACHECKSUMSWORKER_ABORTED, DATACHECKSUMSWORKER_SUCCESSFUL, DatumGetObjectId(), DEBUG1, die, ENABLE_DATACHECKSUMS, ereport, errmsg, fb(), foreach_oid, GetAccessStrategy(), init_ps_display(), INJECTION_POINT_CACHED, InvalidOid, IS_INJECTION_POINT_ATTACHED, DataChecksumsStateStruct::launch_operation, list_free(), list_length(), list_member_oid(), LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyBackendType, MyLatch, NIL, DataChecksumsStateStruct::operation, 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, VacuumCostActive, VacuumCostBalance, VacuumCostDelay, VacuumCostLimit, VacuumCostPageDirty, VacuumCostPageHit, VacuumCostPageMiss, 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 488 of file datachecksum_state.c.

489{
490 if (!superuser())
493 errmsg("must be superuser to change data checksum state"));
494
497}
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

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

◆ EmitAndWaitDataChecksumsBarrier()

void EmitAndWaitDataChecksumsBarrier ( uint32  state)

◆ enable_data_checksums()

Datum enable_data_checksums ( PG_FUNCTION_ARGS  )

Definition at line 505 of file datachecksum_state.c.

506{
507 int cost_delay = PG_GETARG_INT32(0);
508 int cost_limit = PG_GETARG_INT32(1);
509
510 if (!superuser())
513 errmsg("must be superuser to change data checksum state"));
514
515 if (cost_delay < 0)
518 errmsg("cost delay cannot be a negative value"));
519
520 if (cost_limit <= 0)
523 errmsg("cost limit must be greater than zero"));
524
526
528}
#define PG_GETARG_INT32(n)
Definition fmgr.h:269

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

◆ FreeDatabaseList()

static void FreeDatabaseList ( List dblist)
static

Definition at line 1362 of file datachecksum_state.c.

1363{
1364 if (!dblist)
1365 return;
1366
1368 {
1369 if (db->dbname != NULL)
1370 pfree(db->dbname);
1371 }
1372
1374}
void list_free_deep(List *list)
Definition list.c:1560
void pfree(void *pointer)
Definition mcxt.c:1616
#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 923 of file datachecksum_state.c.

924{
925 int save_errno = errno;
926
927 abort_requested = true;
928
929 /*
930 * There is no sleeping in the main loop, the flag will be checked
931 * periodically in ProcessSingleRelationFork. The worker does however
932 * sleep when waiting for concurrent transactions to end so we still need
933 * to set the latch.
934 */
936
938}
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 886 of file datachecksum_state.c.

887{
888 abort_requested = false;
889
891 {
894 {
895 ereport(LOG,
896 errmsg("data checksums launcher exiting while worker is still running, signalling worker"));
898 }
900 }
901
902 /*
903 * If the launcher is exiting before data checksums are enabled then set
904 * the state to off since processing cannot be resumed.
905 */
908
910 launcher_running = false;
913}
#define InvalidPid
Definition miscadmin.h:32
#define kill(pid, sig)
Definition win32_port.h:490
bool DataChecksumsInProgressOn(void)
Definition xlog.c:4686

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 1172 of file datachecksum_state.c.

1173{
1175 int cumulative_total = 0;
1176
1177 /* Set up so first run processes shared catalogs, not once in every db */
1179
1180 /* Get a list of all databases to process */
1183
1184 /*
1185 * Update progress reporting with the total number of databases we need to
1186 * process. This number should not be changed during processing, the
1187 * columns for processed databases is instead increased such that it can
1188 * be compared against the total.
1189 */
1190 {
1191 const int index[] = {
1198 };
1199
1200 int64 vals[6];
1201
1202 vals[0] = list_length(DatabaseList);
1203 vals[1] = 0;
1204 /* translated to NULL */
1205 vals[2] = -1;
1206 vals[3] = -1;
1207 vals[4] = -1;
1208 vals[5] = -1;
1209
1211 }
1212
1214 {
1216
1217 result = ProcessDatabase(db);
1218
1219#ifdef USE_INJECTION_POINTS
1220 /* Allow a test process to alter the result of the operation */
1221 if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fail-db-result"))
1222 {
1224 INJECTION_POINT_CACHED("datachecksumsworker-fail-db-result",
1225 db->dbname);
1226 }
1227#endif
1228
1231
1233 {
1234 /*
1235 * Disable checksums on cluster, because we failed one of the
1236 * databases and this is an all or nothing process.
1237 */
1239 ereport(ERROR,
1241 errmsg("data checksums failed to get enabled in all databases, aborting"),
1242 errhint("The server log might have more information on the cause of the error."));
1243 }
1245 {
1246 /* Abort flag set, so exit the whole process */
1247 return false;
1248 }
1249
1250 /*
1251 * When one database has completed, it will have done shared catalogs
1252 * so we don't have to process them again.
1253 */
1255 }
1256
1258
1261 return true;
1262}
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:195
#define PROGRESS_DATACHECKSUMS_DBS_DONE
Definition progress.h:191
#define PROGRESS_DATACHECKSUMS_PHASE_WAITING_BARRIER
Definition progress.h:201
#define PROGRESS_DATACHECKSUMS_BLOCKS_TOTAL
Definition progress.h:194
#define PROGRESS_DATACHECKSUMS_DBS_TOTAL
Definition progress.h:190

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(), 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 762 of file datachecksum_state.c.

763{
766 BgwHandleStatus status;
767 pid_t pid;
768 char activity[NAMEDATALEN + 64];
769
771
772 memset(&bgw, 0, sizeof(bgw));
774 bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
775 snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
776 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "%s", "DataChecksumsWorkerMain");
777 snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksum worker");
778 snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksum worker");
779 bgw.bgw_restart_time = BGW_NEVER_RESTART;
780 bgw.bgw_notify_pid = MyProcPid;
781 bgw.bgw_main_arg = ObjectIdGetDatum(db->dboid);
782
783 /*
784 * If there are no worker slots available, there is little we can do. If
785 * we retry in a bit it's still unlikely that the user has managed to
786 * reconfigure in the meantime and we'd be run through retries fast.
787 */
789 {
791 errmsg("could not start background worker for enabling data checksums in database \"%s\"",
792 db->dbname),
793 errhint("The \"%s\" setting might be too low.", "max_worker_processes"));
795 }
796
798 if (status == BGWH_STOPPED)
799 {
800 /*
801 * If the worker managed to start, and stop, before we got to waiting
802 * for it we can se a STOPPED status here without it being a failure.
803 */
805 {
811 }
812
814 errmsg("could not start background worker for enabling data checksums in database \"%s\"",
815 db->dbname),
816 errhint("More details on the error might be found in the server log."));
817
818 /*
819 * Heuristic to see if the database was dropped, and if it was we can
820 * treat it as not an error, else treat as fatal and error out. TODO:
821 * this could probably be improved with a tighter check.
822 */
823 if (DatabaseExists(db->dboid))
825 else
827 }
828
829 /*
830 * If the postmaster crashed we cannot end up with a processed database so
831 * we have no alternative other than exiting. When enabling checksums we
832 * won't at this time have changed the data checksums state in pg_control
833 * to enabled so when the cluster comes back up processing will have to be
834 * restarted.
835 */
836 if (status == BGWH_POSTMASTER_DIED)
839 errmsg("cannot enable data checksums without the postmaster process"),
840 errhint("Restart the database and restart data checksum processing by calling pg_enable_data_checksums()."));
841
842 Assert(status == BGWH_STARTED);
843 ereport(LOG,
844 errmsg("initiating data checksum processing in database \"%s\"",
845 db->dbname));
846
847 /* Save the pid of the worker so we can signal it later */
851
852 snprintf(activity, sizeof(activity) - 1,
853 "Waiting for worker in database %s (pid %ld)", db->dbname, (long) pid);
855
857 if (status == BGWH_POSTMASTER_DIED)
860 errmsg("postmaster exited during data checksum processing in \"%s\"",
861 db->dbname),
862 errhint("Restart the database and restart data checksum processing by calling pg_enable_data_checksums()."));
863
865 ereport(LOG,
866 errmsg("data checksums processing was aborted in database \"%s\"",
867 db->dbname));
868
873
875}
@ STATE_IDLE
BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
Definition bgworker.c:1230
BgwHandleStatus WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle)
Definition bgworker.c:1275
bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle)
Definition bgworker.c:1063
#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:41
#define WARNING
Definition elog.h:36
int MyProcPid
Definition globals.c:47
#define NAMEDATALEN
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252

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, 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 711 of file datachecksum_state.c.

712{
713 Relation rel;
714 bool aborted = false;
715
717
719 if (rel == NULL)
720 {
721 /*
722 * Relation no longer exists. We don't consider this an error since
723 * there are no pages in it that need data checksums, and thus return
724 * true. The worker operates off a list of relations generated at the
725 * start of processing, so relations being dropped in the meantime is
726 * to be expected.
727 */
730 return true;
731 }
732 RelationGetSmgr(rel);
733
734 for (ForkNumber fnum = 0; fnum <= MAX_FORKNUM; fnum++)
735 {
736 if (smgrexists(rel->rd_smgr, fnum))
737 {
738 if (!ProcessSingleRelationFork(rel, fnum, strategy))
739 {
740 aborted = true;
741 break;
742 }
743 }
744 }
746
749
750 return !aborted;
751}
static bool ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy)
static SMgrRelation RelationGetSmgr(Relation rel)
Definition rel.h:576
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 629 of file datachecksum_state.c.

630{
632 char activity[NAMEDATALEN * 2 + 128];
633 char *relns;
634
636
637 /* Report the current relation to pgstat_activity */
638 snprintf(activity, sizeof(activity) - 1, "processing: %s.%s (%s, %u blocks)",
642 if (relns)
643 pfree(relns);
644
645 /*
646 * We are looping over the blocks which existed at the time of process
647 * start, which is safe since new blocks are created with checksums set
648 * already due to the state being "inprogress-on".
649 */
651 {
652 Buffer buf = ReadBufferExtended(reln, forkNum, blknum, RBM_NORMAL, strategy);
653
654 /* Need to get an exclusive lock to mark the buffer as dirty */
656
657 /*
658 * Mark the buffer as dirty and force a full page write. We have to
659 * re-write the page to WAL even if the checksum hasn't changed,
660 * because if there is a replica it might have a slightly different
661 * version of the page with an invalid checksum, caused by unlogged
662 * changes (e.g. hintbits) on the primary happening while checksums
663 * were off. This can happen if there was a valid checksum on the page
664 * at one point in the past, so only when checksums are first on, then
665 * off, and then turned on again. TODO: investigate if this could be
666 * avoided if the checksum is calculated to be correct and wal_level
667 * is set to "minimal",
668 */
671 log_newpage_buffer(buf, false);
673
675
676 /*
677 * This is the only place where we check if we are asked to abort, the
678 * abortion will bubble up from here.
679 */
683 abort_requested = true;
685
686 if (abort_requested)
687 return false;
688
689 /* update the block counter */
691 (blknum + 1));
692
693 /*
694 * Processing is re-using the vacuum cost delay for process
695 * throttling, hence why we call vacuum APIs here.
696 */
697 vacuum_delay_point(false);
698 }
699
700 return true;
701}
uint32 BlockNumber
Definition block.h:31
int Buffer
Definition buf.h:23
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
Definition bufmgr.c:4645
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5603
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3147
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:3588
@ LW_SHARED
Definition lwlock.h:105
#define START_CRIT_SECTION()
Definition miscadmin.h:150
#define END_CRIT_SECTION()
Definition miscadmin.h:152
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RelationGetNamespace(relation)
Definition rel.h:555
const char *const forkNames[]
Definition relpath.c:33
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2431
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(), 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, 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 543 of file datachecksum_state.c.

546{
549 bool launcher_running;
551
552#ifdef USE_ASSERT_CHECKING
553 /* The cost delay settings have no effect when disabling */
554 if (op == DISABLE_DATACHECKSUMS)
555 Assert(cost_delay == 0 && cost_limit == 0);
556#endif
557
558 INJECTION_POINT("datachecksumsworker-startup-delay", NULL);
559
560 /* Store the desired state in shared memory */
562
566
567 /* Is the launcher already running? If so, what is it doing? */
571
573
574 /*
575 * Launch a new launcher process, if it's not running already.
576 *
577 * If the launcher is currently busy enabling the checksums, and we want
578 * them disabled (or vice versa), the launcher will notice that at latest
579 * when it's about to exit, and will loop back process the new request. So
580 * if the launcher is already running, we don't need to do anything more
581 * here to abort it.
582 *
583 * If you call pg_enable/disable_data_checksums() twice in a row, before
584 * the launcher has had a chance to start up, we still end up launching it
585 * twice. That's OK, the second invocation will see that a launcher is
586 * already running and exit quickly.
587 *
588 * TODO: We could optimize here and skip launching the launcher, if we are
589 * already in the desired state, i.e. if the checksums are already enabled
590 * and you call pg_enable_data_checksums().
591 */
592 if (!launcher_running)
593 {
594 /*
595 * Prepare the BackgroundWorker and launch it.
596 */
597 memset(&bgw, 0, sizeof(bgw));
599 bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
600 snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
601 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "DataChecksumsWorkerLauncherMain");
602 snprintf(bgw.bgw_name, BGW_MAXLEN, "datachecksum launcher");
603 snprintf(bgw.bgw_type, BGW_MAXLEN, "datachecksum launcher");
604 bgw.bgw_restart_time = BGW_NEVER_RESTART;
605 bgw.bgw_notify_pid = MyProcPid;
606 bgw.bgw_main_arg = (Datum) 0;
607
611 errmsg("failed to start background worker to process data checksums"));
612 }
613 else
614 {
615 if (launcher_running_op == op)
617 errmsg("data checksum processing already running"));
618 }
619}
DataChecksumsWorkerOperation
uint64_t Datum
Definition postgres.h:70

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

Referenced by disable_data_checksums(), and enable_data_checksums().

◆ WaitForAllTransactionsToFinish()

static void WaitForAllTransactionsToFinish ( void  )
static

Definition at line 953 of file datachecksum_state.c.

954{
956
960
962 {
963 char activity[64];
964 int rc;
965
966 /* Oldest running xid is older than us, so wait */
968 sizeof(activity),
969 "Waiting for current transactions to finish (waiting for %u)",
970 waitforxid);
972
973 /* Retry every 3 seconds */
975 rc = WaitLatch(MyLatch,
977 3000,
979
980 /*
981 * If the postmaster died we won't be able to enable checksums
982 * cluster-wide so abort and hope to continue when restarted.
983 */
984 if (rc & WL_POSTMASTER_DEATH)
987 errmsg("postmaster exited during data checksums processing"),
988 errhint("Data checksums processing must be restarted manually after cluster restart."));
989
991
994 abort_requested = true;
996 if (abort_requested)
997 break;
998 }
999
1001 return;
1002}
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_INTERRUPTS, DataChecksumState, ereport, errcode(), errhint(), errmsg, FATAL, fb(), GetOldestActiveTransactionId(), DataChecksumsStateStruct::launch_operation, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyLatch, TransamVariablesData::nextXid, operation, 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[6]
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};

Referenced by AbsorbDataChecksumsBarrier().

◆ DataChecksumsShmemCallbacks

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

Definition at line 361 of file datachecksum_state.c.

361 {
362 .request_fn = DataChecksumsShmemRequest,
363};

◆ DataChecksumState

◆ launcher_running

◆ operation