From a52a74193015c8701bf40bb87321dfd56e0dab76 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 29 Oct 2018 10:14:15 -0700 Subject: [PATCH 1/2] WIP: global barriers This is a squash of three patches from Andres: * Use procsignal_sigusr1_handler for all shmem connected bgworkers. * Use procsignal_sigusr1_handler in all auxiliary processes. * WIP: global barriers. And one from Magnus: * Wait event for global barriers --- src/backend/postmaster/autovacuum.c | 3 +- src/backend/postmaster/bgworker.c | 31 +++++--- src/backend/postmaster/bgwriter.c | 24 ++---- src/backend/postmaster/checkpointer.c | 19 ++--- src/backend/postmaster/pgstat.c | 3 + src/backend/postmaster/startup.c | 18 ++--- src/backend/postmaster/walwriter.c | 17 +--- src/backend/replication/walreceiver.c | 20 +---- src/backend/storage/buffer/bufmgr.c | 4 + src/backend/storage/ipc/procsignal.c | 141 ++++++++++++++++++++++++++++++++++ src/backend/storage/lmgr/proc.c | 20 +++++ src/backend/tcop/postgres.c | 7 ++ src/include/pgstat.h | 1 + src/include/storage/proc.h | 9 +++ src/include/storage/procsignal.h | 23 +++++- 15 files changed, 255 insertions(+), 85 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 073f313337..24e28dd3a3 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -649,8 +649,9 @@ AutoVacLauncherMain(int argc, char *argv[]) ResetLatch(MyLatch); - /* Process sinval catchup interrupts that happened while sleeping */ + /* Process pending interrupts. */ ProcessCatchupInterrupt(); + ProcessGlobalBarrierIntterupt(); /* the normal shutdown case */ if (got_SIGTERM) diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index b66b517aca..f300f9285b 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -734,23 +734,32 @@ StartBackgroundWorker(void) /* * Set up signal handlers. */ + + + /* + * SIGINT is used to signal canceling the current action for processes + * able to run queries. + */ if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION) - { - /* - * SIGINT is used to signal canceling the current action - */ pqsignal(SIGINT, StatementCancelHandler); - pqsignal(SIGUSR1, procsignal_sigusr1_handler); - pqsignal(SIGFPE, FloatExceptionHandler); - - /* XXX Any other handlers needed here? */ - } else - { pqsignal(SIGINT, SIG_IGN); + + /* + * Everything with a PGPROC should be able to receive procsignal.h style + * signals. + */ + if (worker->bgw_flags & (BGWORKER_BACKEND_DATABASE_CONNECTION | + BGWORKER_SHMEM_ACCESS)) + pqsignal(SIGUSR1, procsignal_sigusr1_handler); + else pqsignal(SIGUSR1, bgworker_sigusr1_handler); + + if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION) + pqsignal(SIGFPE, FloatExceptionHandler); + else pqsignal(SIGFPE, SIG_IGN); - } + pqsignal(SIGTERM, bgworker_die); pqsignal(SIGHUP, SIG_IGN); diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 8ec16a3fb8..80a8e3cf4b 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -51,6 +51,7 @@ #include "storage/ipc.h" #include "storage/lwlock.h" #include "storage/proc.h" +#include "storage/procsignal.h" #include "storage/shmem.h" #include "storage/smgr.h" #include "storage/spin.h" @@ -97,7 +98,6 @@ static volatile sig_atomic_t shutdown_requested = false; static void bg_quickdie(SIGNAL_ARGS); static void BgSigHupHandler(SIGNAL_ARGS); static void ReqShutdownHandler(SIGNAL_ARGS); -static void bgwriter_sigusr1_handler(SIGNAL_ARGS); /* @@ -115,10 +115,7 @@ BackgroundWriterMain(void) WritebackContext wb_context; /* - * Properly accept or ignore signals the postmaster might send us. - * - * bgwriter doesn't participate in ProcSignal signalling, but a SIGUSR1 - * handler is still needed for latch wakeups. + * Properly accept or ignore signals that might be sent to us. */ pqsignal(SIGHUP, BgSigHupHandler); /* set flag to read config file */ pqsignal(SIGINT, SIG_IGN); @@ -126,7 +123,7 @@ BackgroundWriterMain(void) pqsignal(SIGQUIT, bg_quickdie); /* hard crash time */ pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, bgwriter_sigusr1_handler); + pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR2, SIG_IGN); /* @@ -261,6 +258,10 @@ BackgroundWriterMain(void) proc_exit(0); /* done */ } + /* Process all pending interrupts. */ + if (GlobalBarrierInterruptPending) + ProcessGlobalBarrierIntterupt(); + /* * Do one cycle of dirty-buffer writing. */ @@ -428,14 +429,3 @@ ReqShutdownHandler(SIGNAL_ARGS) errno = save_errno; } - -/* SIGUSR1: used for latch wakeups */ -static void -bgwriter_sigusr1_handler(SIGNAL_ARGS) -{ - int save_errno = errno; - - latch_sigusr1_handler(); - - errno = save_errno; -} diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 61544f65ad..def9aa87d8 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -54,6 +54,7 @@ #include "storage/ipc.h" #include "storage/lwlock.h" #include "storage/proc.h" +#include "storage/procsignal.h" #include "storage/shmem.h" #include "storage/smgr.h" #include "storage/spin.h" @@ -179,7 +180,6 @@ static void UpdateSharedMemoryConfig(void); static void chkpt_quickdie(SIGNAL_ARGS); static void ChkptSigHupHandler(SIGNAL_ARGS); static void ReqCheckpointHandler(SIGNAL_ARGS); -static void chkpt_sigusr1_handler(SIGNAL_ARGS); static void ReqShutdownHandler(SIGNAL_ARGS); @@ -211,7 +211,7 @@ CheckpointerMain(void) pqsignal(SIGQUIT, chkpt_quickdie); /* hard crash time */ pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, chkpt_sigusr1_handler); + pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR2, ReqShutdownHandler); /* request shutdown */ /* @@ -346,6 +346,10 @@ CheckpointerMain(void) /* Clear any already-pending wakeups */ ResetLatch(MyLatch); + /* Process all pending interrupts. */ + if (GlobalBarrierInterruptPending) + ProcessGlobalBarrierIntterupt(); + /* * Process any requests or signals received recently. */ @@ -853,17 +857,6 @@ ReqCheckpointHandler(SIGNAL_ARGS) errno = save_errno; } -/* SIGUSR1: used for latch wakeups */ -static void -chkpt_sigusr1_handler(SIGNAL_ARGS) -{ - int save_errno = errno; - - latch_sigusr1_handler(); - - errno = save_errno; -} - /* SIGUSR2: set flag to run a shutdown checkpoint and exit */ static void ReqShutdownHandler(SIGNAL_ARGS) diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 011076c3e3..819381a2ae 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -3765,6 +3765,9 @@ pgstat_get_wait_ipc(WaitEventIPC w) case WAIT_EVENT_EXECUTE_GATHER: event_name = "ExecuteGather"; break; + case WAIT_EVENT_GLOBAL_BARRIER: + event_name = "GlobalBarrier"; + break; case WAIT_EVENT_HASH_BATCH_ALLOCATING: event_name = "Hash/Batch/Allocating"; break; diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index 5048a2c2aa..da0a670bdf 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -30,6 +30,7 @@ #include "storage/ipc.h" #include "storage/latch.h" #include "storage/pmsignal.h" +#include "storage/procsignal.h" #include "storage/standby.h" #include "utils/guc.h" #include "utils/timeout.h" @@ -50,7 +51,6 @@ static volatile sig_atomic_t in_restore_command = false; /* Signal handlers */ static void startupproc_quickdie(SIGNAL_ARGS); -static void StartupProcSigUsr1Handler(SIGNAL_ARGS); static void StartupProcTriggerHandler(SIGNAL_ARGS); static void StartupProcSigHupHandler(SIGNAL_ARGS); @@ -87,17 +87,6 @@ startupproc_quickdie(SIGNAL_ARGS) } -/* SIGUSR1: let latch facility handle the signal */ -static void -StartupProcSigUsr1Handler(SIGNAL_ARGS) -{ - int save_errno = errno; - - latch_sigusr1_handler(); - - errno = save_errno; -} - /* SIGUSR2: set flag to finish recovery */ static void StartupProcTriggerHandler(SIGNAL_ARGS) @@ -162,6 +151,9 @@ HandleStartupProcInterrupts(void) */ if (IsUnderPostmaster && !PostmasterIsAlive()) exit(1); + + if (GlobalBarrierInterruptPending) + ProcessGlobalBarrierIntterupt(); } @@ -181,7 +173,7 @@ StartupProcessMain(void) pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */ InitializeTimeouts(); /* establishes SIGALRM handler */ pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, StartupProcSigUsr1Handler); + pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR2, StartupProcTriggerHandler); /* diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index a6fdba3f41..19120aa6e1 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -55,6 +55,7 @@ #include "storage/ipc.h" #include "storage/lwlock.h" #include "storage/proc.h" +#include "storage/procsignal.h" #include "storage/smgr.h" #include "utils/guc.h" #include "utils/hsearch.h" @@ -86,7 +87,6 @@ static volatile sig_atomic_t shutdown_requested = false; static void wal_quickdie(SIGNAL_ARGS); static void WalSigHupHandler(SIGNAL_ARGS); static void WalShutdownHandler(SIGNAL_ARGS); -static void walwriter_sigusr1_handler(SIGNAL_ARGS); /* * Main entry point for walwriter process @@ -114,7 +114,7 @@ WalWriterMain(void) pqsignal(SIGQUIT, wal_quickdie); /* hard crash time */ pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, walwriter_sigusr1_handler); + pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR2, SIG_IGN); /* not used */ /* @@ -255,6 +255,8 @@ WalWriterMain(void) /* Normal exit from the walwriter is here */ proc_exit(0); /* done */ } + if (GlobalBarrierInterruptPending) + ProcessGlobalBarrierIntterupt(); /* * Do what we're here for; then, if XLogBackgroundFlush() found useful @@ -337,14 +339,3 @@ WalShutdownHandler(SIGNAL_ARGS) errno = save_errno; } - -/* SIGUSR1: used for latch wakeups */ -static void -walwriter_sigusr1_handler(SIGNAL_ARGS) -{ - int save_errno = errno; - - latch_sigusr1_handler(); - - errno = save_errno; -} diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 6abc780778..9acdbdd7c9 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -63,6 +63,7 @@ #include "storage/ipc.h" #include "storage/pmsignal.h" #include "storage/procarray.h" +#include "storage/procsignal.h" #include "utils/builtins.h" #include "utils/guc.h" #include "utils/pg_lsn.h" @@ -125,7 +126,6 @@ static void ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime); /* Signal handlers */ static void WalRcvSigHupHandler(SIGNAL_ARGS); -static void WalRcvSigUsr1Handler(SIGNAL_ARGS); static void WalRcvShutdownHandler(SIGNAL_ARGS); static void WalRcvQuickDieHandler(SIGNAL_ARGS); @@ -147,9 +147,8 @@ void ProcessWalRcvInterrupts(void) { /* - * Although walreceiver interrupt handling doesn't use the same scheme as - * regular backends, call CHECK_FOR_INTERRUPTS() to make sure we receive - * any incoming signals on Win32. + * The CHECK_FOR_INTERRUPTS() call ensures global barriers are handled, + * and incoming signals on Win32 are received. */ CHECK_FOR_INTERRUPTS(); @@ -252,7 +251,7 @@ WalReceiverMain(void) pqsignal(SIGQUIT, WalRcvQuickDieHandler); /* hard crash time */ pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, WalRcvSigUsr1Handler); + pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR2, SIG_IGN); /* Reset some signals that are accepted by postmaster but not here */ @@ -766,17 +765,6 @@ WalRcvSigHupHandler(SIGNAL_ARGS) } -/* SIGUSR1: used by latch mechanism */ -static void -WalRcvSigUsr1Handler(SIGNAL_ARGS) -{ - int save_errno = errno; - - latch_sigusr1_handler(); - - errno = save_errno; -} - /* SIGTERM: set flag for ProcessWalRcvInterrupts */ static void WalRcvShutdownHandler(SIGNAL_ARGS) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 483f705305..c8c48d8497 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -1885,6 +1885,10 @@ BufferSync(int flags) cur_tsid = CkptBufferIds[i].tsId; + /* XXX: need a more principled approach here */ + if (GlobalBarrierInterruptPending) + ProcessGlobalBarrierIntterupt(); + /* * Grow array of per-tablespace status structs, every time a new * tablespace is found. diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 7605b2c367..9aed52df4a 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -18,8 +18,10 @@ #include #include "access/parallel.h" +#include "access/twophase.h" #include "commands/async.h" #include "miscadmin.h" +#include "pgstat.h" #include "replication/walsender.h" #include "storage/latch.h" #include "storage/ipc.h" @@ -62,9 +64,11 @@ typedef struct static ProcSignalSlot *ProcSignalSlots = NULL; static volatile ProcSignalSlot *MyProcSignalSlot = NULL; +volatile sig_atomic_t GlobalBarrierInterruptPending = false; static bool CheckProcSignal(ProcSignalReason reason); static void CleanupProcSignalState(int status, Datum arg); +static void HandleGlobalBarrierSignal(void); /* * ProcSignalShmemSize @@ -262,6 +266,8 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) { int save_errno = errno; + pg_read_barrier(); + if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT)) HandleCatchupInterrupt(); @@ -292,9 +298,144 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN)) RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); + if (CheckProcSignal(PROCSIG_GLOBAL_BARRIER)) + HandleGlobalBarrierSignal(); + SetLatch(MyLatch); latch_sigusr1_handler(); errno = save_errno; } + +/* + * + */ +uint64 +EmitGlobalBarrier(GlobalBarrierKind kind) +{ + uint64 generation; + + /* + * Broadcast flag, without incrementing generation. This ensures that all + * backends could know about this. + * + * It's OK if the to-be-signalled backend enters after our check here. A + * new backend should have current settings. + */ + for (int i = 0; i < (MaxBackends + max_prepared_xacts); i++) + { + PGPROC *proc = &ProcGlobal->allProcs[i]; + + if (proc->pid == 0) + continue; + + pg_atomic_fetch_or_u32(&proc->barrierFlags, (uint32) kind); + + elog(LOG, "setting flags for %u", proc->pid); + } + + /* + * Broadcast flag generation. If any backend joins after this, it's either + * going to be signalled below, or has read a new enough generation that + * WaitForGlobalBarrier() will not wait for it. + */ + generation = pg_atomic_add_fetch_u64(&ProcGlobal->globalBarrierGen, 1); + + /* Wake up each backend (including ours) */ + for (int i = 0; i < NumProcSignalSlots; i++) + { + ProcSignalSlot *slot = &ProcSignalSlots[i]; + + if (slot->pss_pid == 0) + continue; + + /* Atomically set the proper flag */ + slot->pss_signalFlags[PROCSIG_GLOBAL_BARRIER] = true; + + pg_write_barrier(); + + /* Send signal */ + kill(slot->pss_pid, SIGUSR1); + } + + return generation; +} + +/* + * Wait for all barriers to be absorbed. This guarantees that all changes + * requested by a specific EmitGlobalBarrier() have taken effect. + */ +void +WaitForGlobalBarrier(uint64 generation) +{ + pgstat_report_wait_start(WAIT_EVENT_GLOBAL_BARRIER); + for (int i = 0; i < (MaxBackends + max_prepared_xacts); i++) + { + PGPROC *proc = &ProcGlobal->allProcs[i]; + uint64 oldval; + + pg_memory_barrier(); + oldval = pg_atomic_read_u64(&proc->barrierGen); + + /* + * Unused proc slots get their barrierGen set to UINT64_MAX, so we + * need not care about that. + */ + while (oldval < generation) + { + CHECK_FOR_INTERRUPTS(); + pg_usleep(10000); + + pg_memory_barrier(); + oldval = pg_atomic_read_u64(&proc->barrierGen); + } + } + pgstat_report_wait_end(); +} + +/* + * Absorb the global barrier procsignal. + */ +static void +HandleGlobalBarrierSignal(void) +{ + InterruptPending = true; + GlobalBarrierInterruptPending = true; + SetLatch(MyLatch); +} + +/* + * Perform global barrier related interrupt checking. If CHECK_FOR_INTERRUPTS + * is used, it'll be called by that, if a backend type doesn't do so, it has + * to be called explicitly. + */ +void +ProcessGlobalBarrierIntterupt(void) +{ + if (GlobalBarrierInterruptPending) + { + uint64 generation; + uint32 flags; + + GlobalBarrierInterruptPending = false; + + generation = pg_atomic_read_u64(&ProcGlobal->globalBarrierGen); + pg_memory_barrier(); + flags = pg_atomic_exchange_u32(&MyProc->barrierFlags, 0); + pg_memory_barrier(); + + if (flags & GLOBBAR_CHECKSUM) + { + /* + * By virtue of getting here (i.e. interrupts being processed), we + * know that this backend won't have any in-progress writes (which + * might have missed the checksum change). + */ + } + + pg_atomic_write_u64(&MyProc->barrierGen, generation); + + elog(LOG, "processed interrupts for %u", MyProcPid); + } +} diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 498373fd0e..ae52b9e9ac 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -190,6 +190,7 @@ InitProcGlobal(void) ProcGlobal->checkpointerLatch = NULL; pg_atomic_init_u32(&ProcGlobal->procArrayGroupFirst, INVALID_PGPROCNO); pg_atomic_init_u32(&ProcGlobal->clogGroupFirst, INVALID_PGPROCNO); + pg_atomic_init_u64(&ProcGlobal->globalBarrierGen, 1); /* * Create and initialize all the PGPROC structures we'll need. There are @@ -284,6 +285,9 @@ InitProcGlobal(void) */ pg_atomic_init_u32(&(procs[i].procArrayGroupNext), INVALID_PGPROCNO); pg_atomic_init_u32(&(procs[i].clogGroupNext), INVALID_PGPROCNO); + + pg_atomic_init_u32(&procs[i].barrierFlags, 0); + pg_atomic_init_u64(&procs[i].barrierGen, PG_UINT64_MAX); } /* @@ -442,6 +446,12 @@ InitProcess(void) MyProc->clogGroupMemberLsn = InvalidXLogRecPtr; Assert(pg_atomic_read_u32(&MyProc->clogGroupNext) == INVALID_PGPROCNO); + /* pairs with globalBarrierGen increase */ + pg_memory_barrier(); + pg_atomic_write_u32(&MyProc->barrierFlags, 0); + pg_atomic_write_u64(&MyProc->barrierGen, + pg_atomic_read_u64(&ProcGlobal->globalBarrierGen)); + /* * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch * on it. That allows us to repoint the process latch, which so far @@ -585,6 +595,13 @@ InitAuxiliaryProcess(void) MyProc->lwWaitMode = 0; MyProc->waitLock = NULL; MyProc->waitProcLock = NULL; + + /* pairs with globalBarrierGen increase */ + pg_memory_barrier(); + pg_atomic_write_u32(&MyProc->barrierFlags, 0); + pg_atomic_write_u64(&MyProc->barrierGen, + pg_atomic_read_u64(&ProcGlobal->globalBarrierGen)); + #ifdef USE_ASSERT_CHECKING { int i; @@ -883,6 +900,9 @@ ProcKill(int code, Datum arg) LWLockRelease(leader_lwlock); } + pg_atomic_write_u32(&MyProc->barrierFlags, 0); + pg_atomic_write_u64(&MyProc->barrierGen, PG_UINT64_MAX); + /* * Reset MyLatch to the process local one. This is so that signal * handlers et al can continue using the latch after the shared latch diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index e8d8e6f828..976e966565 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -612,6 +612,10 @@ ProcessClientWriteInterrupt(bool blocked) SetLatch(MyLatch); } + /* safe to handle during client communication */ + if (GlobalBarrierInterruptPending) + ProcessGlobalBarrierIntterupt(); + errno = save_errno; } @@ -3159,6 +3163,9 @@ ProcessInterrupts(void) if (ParallelMessagePending) HandleParallelMessages(); + + if (GlobalBarrierInterruptPending) + ProcessGlobalBarrierIntterupt(); } diff --git a/src/include/pgstat.h b/src/include/pgstat.h index fe076d823d..c997add881 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -824,6 +824,7 @@ typedef enum WAIT_EVENT_CHECKPOINT_DONE, WAIT_EVENT_CHECKPOINT_START, WAIT_EVENT_EXECUTE_GATHER, + WAIT_EVENT_GLOBAL_BARRIER, WAIT_EVENT_HASH_BATCH_ALLOCATING, WAIT_EVENT_HASH_BATCH_ELECTING, WAIT_EVENT_HASH_BATCH_LOADING, diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 281e1db725..f108ac52c6 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -203,6 +203,13 @@ struct PGPROC PGPROC *lockGroupLeader; /* lock group leader, if I'm a member */ dlist_head lockGroupMembers; /* list of members, if I'm a leader */ dlist_node lockGroupLink; /* my member link, if I'm a member */ + + /* + * Support for "super barriers". These can be used to e.g. make sure that + * all backends have acknowledged a configuration change. + */ + pg_atomic_uint64 barrierGen; + pg_atomic_uint32 barrierFlags; }; /* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */ @@ -272,6 +279,8 @@ typedef struct PROC_HDR int startupProcPid; /* Buffer id of the buffer that Startup process waits for pin on, or -1 */ int startupBufferPinWaitBufId; + + pg_atomic_uint64 globalBarrierGen; } PROC_HDR; extern PGDLLIMPORT PROC_HDR *ProcGlobal; diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index 05b186a05c..a978db9b24 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -14,8 +14,9 @@ #ifndef PROCSIGNAL_H #define PROCSIGNAL_H -#include "storage/backendid.h" +#include +#include "storage/backendid.h" /* * Reasons for signalling a Postgres child process (a backend or an auxiliary @@ -42,6 +43,8 @@ typedef enum PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + PROCSIG_GLOBAL_BARRIER, + NUM_PROCSIGNALS /* Must be last! */ } ProcSignalReason; @@ -57,4 +60,22 @@ extern int SendProcSignal(pid_t pid, ProcSignalReason reason, extern void procsignal_sigusr1_handler(SIGNAL_ARGS); +/* + * These collapse. The flag values better be distinct bits. + */ +typedef enum GlobalBarrierKind +{ + /* + * Guarantee that all processes have the correct view of whether checksums + * enabled/disabled, and no writes are in-progress with previous value(s). + */ + GLOBBAR_CHECKSUM = 1 << 0 +} GlobalBarrierKind; + +extern uint64 EmitGlobalBarrier(GlobalBarrierKind kind); +extern void WaitForGlobalBarrier(uint64 generation); +extern void ProcessGlobalBarrierIntterupt(void); + +extern PGDLLIMPORT volatile sig_atomic_t GlobalBarrierInterruptPending; + #endif /* PROCSIGNAL_H */ -- 2.11.0