1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-15 19:21:59 +03:00

Allow read only connections during recovery, known as Hot Standby.

Enabled by recovery_connections = on (default) and forcing archive recovery using a recovery.conf. Recovery processing now emulates the original transactions as they are replayed, providing full locking and MVCC behaviour for read only queries. Recovery must enter consistent state before connections are allowed, so there is a delay, typically short, before connections succeed. Replay of recovering transactions can conflict and in some cases deadlock with queries during recovery; these result in query cancellation after max_standby_delay seconds have expired. Infrastructure changes have minor effects on normal running, though introduce four new types of WAL record.

New test mode "make standbycheck" allows regression tests of static command behaviour on a standby server while in recovery. Typical and extreme dynamic behaviours have been checked via code inspection and manual testing. Few port specific behaviours have been utilised, though primary testing has been on Linux only so far.

This commit is the basic patch. Additional changes will follow in this release to enhance some aspects of behaviour, notably improved handling of conflicts, deadlock detection and query cancellation. Changes to VACUUM FULL are also required.

Simon Riggs, with significant and lengthy review by Heikki Linnakangas, including streamlined redesign of snapshot creation and two-phase commit.

Important contributions from Florian Pflug, Mark Kirkwood, Merlin Moncure, Greg Stark, Gianni Ciolli, Gabriele Bartolini, Hannu Krosing, Robert Haas, Tatsuo Ishii, Hiroyuki Yamada plus support and feedback from many other community members.
This commit is contained in:
Simon Riggs
2009-12-19 01:32:45 +00:00
parent 78a09145e0
commit efc16ea520
87 changed files with 6165 additions and 428 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.209 2009/08/31 19:41:00 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.210 2009/12/19 01:32:36 sriggs Exp $
*
*-------------------------------------------------------------------------
*/
@ -318,6 +318,7 @@ InitProcess(void)
MyProc->waitProcLock = NULL;
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
SHMQueueInit(&(MyProc->myProcLocks[i]));
MyProc->recoveryConflictMode = 0;
/*
* We might be reusing a semaphore that belonged to a failed process. So
@ -374,6 +375,11 @@ InitProcessPhase2(void)
* to the ProcArray or the sinval messaging mechanism, either. They also
* don't get a VXID assigned, since this is only useful when we actually
* hold lockmgr locks.
*
* Startup process however uses locks but never waits for them in the
* normal backend sense. Startup process also takes part in sinval messaging
* as a sendOnly process, so never reads messages from sinval queue. So
* Startup process does have a VXID and does show up in pg_locks.
*/
void
InitAuxiliaryProcess(void)
@ -461,6 +467,24 @@ InitAuxiliaryProcess(void)
on_shmem_exit(AuxiliaryProcKill, Int32GetDatum(proctype));
}
/*
* Record the PID and PGPROC structures for the Startup process, for use in
* ProcSendSignal(). See comments there for further explanation.
*/
void
PublishStartupProcessInformation(void)
{
/* use volatile pointer to prevent code rearrangement */
volatile PROC_HDR *procglobal = ProcGlobal;
SpinLockAcquire(ProcStructLock);
procglobal->startupProc = MyProc;
procglobal->startupProcPid = MyProcPid;
SpinLockRelease(ProcStructLock);
}
/*
* Check whether there are at least N free PGPROC objects.
*
@ -1289,7 +1313,31 @@ ProcWaitForSignal(void)
void
ProcSendSignal(int pid)
{
PGPROC *proc = BackendPidGetProc(pid);
PGPROC *proc = NULL;
if (RecoveryInProgress())
{
/* use volatile pointer to prevent code rearrangement */
volatile PROC_HDR *procglobal = ProcGlobal;
SpinLockAcquire(ProcStructLock);
/*
* Check to see whether it is the Startup process we wish to signal.
* This call is made by the buffer manager when it wishes to wake
* up a process that has been waiting for a pin in so it can obtain a
* cleanup lock using LockBufferForCleanup(). Startup is not a normal
* backend, so BackendPidGetProc() will not return any pid at all.
* So we remember the information for this special case.
*/
if (pid == procglobal->startupProcPid)
proc = procglobal->startupProc;
SpinLockRelease(ProcStructLock);
}
if (proc == NULL)
proc = BackendPidGetProc(pid);
if (proc != NULL)
PGSemaphoreUnlock(&proc->sem);