mirror of
https://github.com/postgres/postgres.git
synced 2026-04-29 02:00:35 -04:00
In WAL receiver and WAL server, some accesses to their corresponding shared memory control structs were done without holding any kind of lock, which could lead to inconsistent and possibly insecure results. In walsender, fix by clarifying the locking rules and following them correctly, as documented in the new comment in walsender_private.h; namely that some members can be read in walsender itself without a lock, because the only writes occur in the same process. The rest of the struct requires spinlock for accesses, as usual. In walreceiver, fix by always holding spinlock while accessing the struct. While there is potentially a problem in all branches, it is minor in stable ones. This only became a real problem in pg10 because of quorum commit in synchronous replication (commit3901fd70cc), and a potential security problem in walreceiver because a superuser() check was removed by default monitoring roles (commit25fff40798). Thus, no backpatch. In passing, clean up some leftover braces which were used to create unconditional blocks. Once upon a time these were used for volatile-izing accesses to those shmem structs, which is no longer required. Many other occurrences of this pattern remain. Author: Michaël Paquier Reported-by: Michaël Paquier Reviewed-by: Masahiko Sawada, Kyotaro Horiguchi, Thomas Munro, Robert Haas Discussion: https://postgr.es/m/CAB7nPqTWYqtzD=LN_oDaf9r-hAjUEPAy0B9yRkhcsLdRN8fzrw@mail.gmail.com
124 lines
3.4 KiB
C
124 lines
3.4 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* walsender_private.h
|
|
* Private definitions from replication/walsender.c.
|
|
*
|
|
* Portions Copyright (c) 2010-2017, PostgreSQL Global Development Group
|
|
*
|
|
* src/include/replication/walsender_private.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef _WALSENDER_PRIVATE_H
|
|
#define _WALSENDER_PRIVATE_H
|
|
|
|
#include "access/xlog.h"
|
|
#include "nodes/nodes.h"
|
|
#include "replication/syncrep.h"
|
|
#include "storage/latch.h"
|
|
#include "storage/shmem.h"
|
|
#include "storage/spin.h"
|
|
|
|
typedef enum WalSndState
|
|
{
|
|
WALSNDSTATE_STARTUP = 0,
|
|
WALSNDSTATE_BACKUP,
|
|
WALSNDSTATE_CATCHUP,
|
|
WALSNDSTATE_STREAMING,
|
|
WALSNDSTATE_STOPPING
|
|
} WalSndState;
|
|
|
|
/*
|
|
* Each walsender has a WalSnd struct in shared memory.
|
|
*
|
|
* This struct is protected by 'mutex', with two exceptions: one is
|
|
* sync_standby_priority as noted below. The other exception is that some
|
|
* members are only written by the walsender process itself, and thus that
|
|
* process is free to read those members without holding spinlock. pid and
|
|
* needreload always require the spinlock to be held for all accesses.
|
|
*/
|
|
typedef struct WalSnd
|
|
{
|
|
pid_t pid; /* this walsender's PID, or 0 if not active */
|
|
|
|
WalSndState state; /* this walsender's state */
|
|
XLogRecPtr sentPtr; /* WAL has been sent up to this point */
|
|
bool needreload; /* does currently-open file need to be
|
|
* reloaded? */
|
|
|
|
/*
|
|
* The xlog locations that have been written, flushed, and applied by
|
|
* standby-side. These may be invalid if the standby-side has not offered
|
|
* values yet.
|
|
*/
|
|
XLogRecPtr write;
|
|
XLogRecPtr flush;
|
|
XLogRecPtr apply;
|
|
|
|
/* Measured lag times, or -1 for unknown/none. */
|
|
TimeOffset writeLag;
|
|
TimeOffset flushLag;
|
|
TimeOffset applyLag;
|
|
|
|
/* Protects shared variables shown above. */
|
|
slock_t mutex;
|
|
|
|
/*
|
|
* Pointer to the walsender's latch. Used by backends to wake up this
|
|
* walsender when it has work to do. NULL if the walsender isn't active.
|
|
*/
|
|
Latch *latch;
|
|
|
|
/*
|
|
* The priority order of the standby managed by this WALSender, as listed
|
|
* in synchronous_standby_names, or 0 if not-listed. Protected by
|
|
* SyncRepLock.
|
|
*/
|
|
int sync_standby_priority;
|
|
} WalSnd;
|
|
|
|
extern WalSnd *MyWalSnd;
|
|
|
|
/* There is one WalSndCtl struct for the whole database cluster */
|
|
typedef struct
|
|
{
|
|
/*
|
|
* Synchronous replication queue with one queue per request type.
|
|
* Protected by SyncRepLock.
|
|
*/
|
|
SHM_QUEUE SyncRepQueue[NUM_SYNC_REP_WAIT_MODE];
|
|
|
|
/*
|
|
* Current location of the head of the queue. All waiters should have a
|
|
* waitLSN that follows this value. Protected by SyncRepLock.
|
|
*/
|
|
XLogRecPtr lsn[NUM_SYNC_REP_WAIT_MODE];
|
|
|
|
/*
|
|
* Are any sync standbys defined? Waiting backends can't reload the
|
|
* config file safely, so checkpointer updates this value as needed.
|
|
* Protected by SyncRepLock.
|
|
*/
|
|
bool sync_standbys_defined;
|
|
|
|
WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER];
|
|
} WalSndCtlData;
|
|
|
|
extern WalSndCtlData *WalSndCtl;
|
|
|
|
|
|
extern void WalSndSetState(WalSndState state);
|
|
|
|
/*
|
|
* Internal functions for parsing the replication grammar, in repl_gram.y and
|
|
* repl_scanner.l
|
|
*/
|
|
extern int replication_yyparse(void);
|
|
extern int replication_yylex(void);
|
|
extern void replication_yyerror(const char *str) pg_attribute_noreturn();
|
|
extern void replication_scanner_init(const char *query_string);
|
|
extern void replication_scanner_finish(void);
|
|
|
|
extern Node *replication_parse_result;
|
|
|
|
#endif /* _WALSENDER_PRIVATE_H */
|