Commit 78c8c814 authored by Peter Eisentraut's avatar Peter Eisentraut

Refactor libpqwalreceiver

The whole walreceiver API is now wrapped into a struct, like most of our
other loadable module APIs.  The libpq connection is no longer a global
variable in libpqwalreceiver.  Instead, it is encapsulated into a struct
that is passed around the functions.  This allows multiple walreceivers
to run at the same time.

Add some rudimentary support for logical replication connections to
libpqwalreceiver.

These changes are mostly cosmetic and are going to be useful for the
future logical replication patches.

From: Petr Jelinek <petr@2ndquadrant.com>
parent 597a87cc
...@@ -74,16 +74,9 @@ int wal_receiver_status_interval; ...@@ -74,16 +74,9 @@ int wal_receiver_status_interval;
int wal_receiver_timeout; int wal_receiver_timeout;
bool hot_standby_feedback; bool hot_standby_feedback;
/* libpqreceiver hooks to these when loaded */ /* libpqwalreceiver connection */
walrcv_connect_type walrcv_connect = NULL; static WalReceiverConn *wrconn = NULL;
walrcv_get_conninfo_type walrcv_get_conninfo = NULL; WalReceiverFunctionsType *WalReceiverFunctions = NULL;
walrcv_identify_system_type walrcv_identify_system = NULL;
walrcv_startstreaming_type walrcv_startstreaming = NULL;
walrcv_endstreaming_type walrcv_endstreaming = NULL;
walrcv_readtimelinehistoryfile_type walrcv_readtimelinehistoryfile = NULL;
walrcv_receive_type walrcv_receive = NULL;
walrcv_send_type walrcv_send = NULL;
walrcv_disconnect_type walrcv_disconnect = NULL;
#define NAPTIME_PER_CYCLE 100 /* max sleep time between cycles (100ms) */ #define NAPTIME_PER_CYCLE 100 /* max sleep time between cycles (100ms) */
...@@ -286,14 +279,7 @@ WalReceiverMain(void) ...@@ -286,14 +279,7 @@ WalReceiverMain(void)
/* Load the libpq-specific functions */ /* Load the libpq-specific functions */
load_file("libpqwalreceiver", false); load_file("libpqwalreceiver", false);
if (walrcv_connect == NULL || if (WalReceiverFunctions == NULL)
walrcv_get_conninfo == NULL ||
walrcv_startstreaming == NULL ||
walrcv_endstreaming == NULL ||
walrcv_identify_system == NULL ||
walrcv_readtimelinehistoryfile == NULL ||
walrcv_receive == NULL || walrcv_send == NULL ||
walrcv_disconnect == NULL)
elog(ERROR, "libpqwalreceiver didn't initialize correctly"); elog(ERROR, "libpqwalreceiver didn't initialize correctly");
/* /*
...@@ -307,14 +293,14 @@ WalReceiverMain(void) ...@@ -307,14 +293,14 @@ WalReceiverMain(void)
/* Establish the connection to the primary for XLOG streaming */ /* Establish the connection to the primary for XLOG streaming */
EnableWalRcvImmediateExit(); EnableWalRcvImmediateExit();
walrcv_connect(conninfo); wrconn = walrcv_connect(conninfo, false, "walreceiver");
DisableWalRcvImmediateExit(); DisableWalRcvImmediateExit();
/* /*
* Save user-visible connection string. This clobbers the original * Save user-visible connection string. This clobbers the original
* conninfo, for security. * conninfo, for security.
*/ */
tmp_conninfo = walrcv_get_conninfo(); tmp_conninfo = walrcv_get_conninfo(wrconn);
SpinLockAcquire(&walrcv->mutex); SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO); memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo) if (tmp_conninfo)
...@@ -328,12 +314,25 @@ WalReceiverMain(void) ...@@ -328,12 +314,25 @@ WalReceiverMain(void)
first_stream = true; first_stream = true;
for (;;) for (;;)
{ {
char *primary_sysid;
char standby_sysid[32];
/* /*
* Check that we're connected to a valid server using the * Check that we're connected to a valid server using the
* IDENTIFY_SYSTEM replication command, * IDENTIFY_SYSTEM replication command,
*/ */
EnableWalRcvImmediateExit(); EnableWalRcvImmediateExit();
walrcv_identify_system(&primaryTLI); primary_sysid = walrcv_identify_system(wrconn, &primaryTLI);
snprintf(standby_sysid, sizeof(standby_sysid), UINT64_FORMAT,
GetSystemIdentifier());
if (strcmp(primary_sysid, standby_sysid) != 0)
{
ereport(ERROR,
(errmsg("database system identifier differs between the primary and standby"),
errdetail("The primary's identifier is %s, the standby's identifier is %s.",
primary_sysid, standby_sysid)));
}
DisableWalRcvImmediateExit(); DisableWalRcvImmediateExit();
/* /*
...@@ -370,7 +369,7 @@ WalReceiverMain(void) ...@@ -370,7 +369,7 @@ WalReceiverMain(void)
* on the new timeline. * on the new timeline.
*/ */
ThisTimeLineID = startpointTLI; ThisTimeLineID = startpointTLI;
if (walrcv_startstreaming(startpointTLI, startpoint, if (walrcv_startstreaming(wrconn, startpointTLI, startpoint,
slotname[0] != '\0' ? slotname : NULL)) slotname[0] != '\0' ? slotname : NULL))
{ {
if (first_stream) if (first_stream)
...@@ -422,7 +421,7 @@ WalReceiverMain(void) ...@@ -422,7 +421,7 @@ WalReceiverMain(void)
} }
/* See if we can read data immediately */ /* See if we can read data immediately */
len = walrcv_receive(&buf, &wait_fd); len = walrcv_receive(wrconn, &buf, &wait_fd);
if (len != 0) if (len != 0)
{ {
/* /*
...@@ -453,7 +452,7 @@ WalReceiverMain(void) ...@@ -453,7 +452,7 @@ WalReceiverMain(void)
endofwal = true; endofwal = true;
break; break;
} }
len = walrcv_receive(&buf, &wait_fd); len = walrcv_receive(wrconn, &buf, &wait_fd);
} }
/* Let the master know that we received some data. */ /* Let the master know that we received some data. */
...@@ -570,7 +569,7 @@ WalReceiverMain(void) ...@@ -570,7 +569,7 @@ WalReceiverMain(void)
* our side, too. * our side, too.
*/ */
EnableWalRcvImmediateExit(); EnableWalRcvImmediateExit();
walrcv_endstreaming(&primaryTLI); walrcv_endstreaming(wrconn, &primaryTLI);
DisableWalRcvImmediateExit(); DisableWalRcvImmediateExit();
/* /*
...@@ -726,7 +725,7 @@ WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last) ...@@ -726,7 +725,7 @@ WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last)
tli))); tli)));
EnableWalRcvImmediateExit(); EnableWalRcvImmediateExit();
walrcv_readtimelinehistoryfile(tli, &fname, &content, &len); walrcv_readtimelinehistoryfile(wrconn, tli, &fname, &content, &len);
DisableWalRcvImmediateExit(); DisableWalRcvImmediateExit();
/* /*
...@@ -778,8 +777,8 @@ WalRcvDie(int code, Datum arg) ...@@ -778,8 +777,8 @@ WalRcvDie(int code, Datum arg)
SpinLockRelease(&walrcv->mutex); SpinLockRelease(&walrcv->mutex);
/* Terminate the connection gracefully. */ /* Terminate the connection gracefully. */
if (walrcv_disconnect != NULL) if (wrconn != NULL)
walrcv_disconnect(); walrcv_disconnect(wrconn);
/* Wake up the startup process to notice promptly that we're gone */ /* Wake up the startup process to notice promptly that we're gone */
WakeupRecovery(); WakeupRecovery();
...@@ -1150,7 +1149,7 @@ XLogWalRcvSendReply(bool force, bool requestReply) ...@@ -1150,7 +1149,7 @@ XLogWalRcvSendReply(bool force, bool requestReply)
(uint32) (applyPtr >> 32), (uint32) applyPtr, (uint32) (applyPtr >> 32), (uint32) applyPtr,
requestReply ? " (reply requested)" : ""); requestReply ? " (reply requested)" : "");
walrcv_send(reply_message.data, reply_message.len); walrcv_send(wrconn, reply_message.data, reply_message.len);
} }
/* /*
...@@ -1228,7 +1227,7 @@ XLogWalRcvSendHSFeedback(bool immed) ...@@ -1228,7 +1227,7 @@ XLogWalRcvSendHSFeedback(bool immed)
pq_sendint64(&reply_message, GetCurrentIntegerTimestamp()); pq_sendint64(&reply_message, GetCurrentIntegerTimestamp());
pq_sendint(&reply_message, xmin, 4); pq_sendint(&reply_message, xmin, 4);
pq_sendint(&reply_message, nextEpoch, 4); pq_sendint(&reply_message, nextEpoch, 4);
walrcv_send(reply_message.data, reply_message.len); walrcv_send(wrconn, reply_message.data, reply_message.len);
if (TransactionIdIsValid(xmin)) if (TransactionIdIsValid(xmin))
master_has_standby_xmin = true; master_has_standby_xmin = true;
else else
......
...@@ -134,33 +134,64 @@ typedef struct ...@@ -134,33 +134,64 @@ typedef struct
extern WalRcvData *WalRcv; extern WalRcvData *WalRcv;
/* libpqwalreceiver hooks */ struct WalReceiverConn;
typedef void (*walrcv_connect_type) (char *conninfo); typedef struct WalReceiverConn WalReceiverConn;
extern PGDLLIMPORT walrcv_connect_type walrcv_connect;
typedef char *(*walrcv_get_conninfo_type) (void);
extern PGDLLIMPORT walrcv_get_conninfo_type walrcv_get_conninfo;
typedef void (*walrcv_identify_system_type) (TimeLineID *primary_tli);
extern PGDLLIMPORT walrcv_identify_system_type walrcv_identify_system;
typedef void (*walrcv_readtimelinehistoryfile_type) (TimeLineID tli, char **filename, char **content, int *size);
extern PGDLLIMPORT walrcv_readtimelinehistoryfile_type walrcv_readtimelinehistoryfile;
typedef bool (*walrcv_startstreaming_type) (TimeLineID tli, XLogRecPtr startpoint, char *slotname);
extern PGDLLIMPORT walrcv_startstreaming_type walrcv_startstreaming;
typedef void (*walrcv_endstreaming_type) (TimeLineID *next_tli); /* libpqwalreceiver hooks */
extern PGDLLIMPORT walrcv_endstreaming_type walrcv_endstreaming; typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logical,
const char *appname);
typedef int (*walrcv_receive_type) (char **buffer, pgsocket *wait_fd); typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
extern PGDLLIMPORT walrcv_receive_type walrcv_receive; typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli);
typedef void (*walrcv_send_type) (const char *buffer, int nbytes); typedef void (*walrcv_readtimelinehistoryfile_fn) (WalReceiverConn *conn,
extern PGDLLIMPORT walrcv_send_type walrcv_send; TimeLineID tli,
char **filename,
typedef void (*walrcv_disconnect_type) (void); char **content, int *size);
extern PGDLLIMPORT walrcv_disconnect_type walrcv_disconnect; typedef bool (*walrcv_startstreaming_fn) (WalReceiverConn *conn,
TimeLineID tli,
XLogRecPtr startpoint,
const char *slotname);
typedef void (*walrcv_endstreaming_fn) (WalReceiverConn *conn,
TimeLineID *next_tli);
typedef int (*walrcv_receive_fn) (WalReceiverConn *conn, char **buffer,
pgsocket *wait_fd);
typedef void (*walrcv_send_fn) (WalReceiverConn *conn, const char *buffer,
int nbytes);
typedef void (*walrcv_disconnect_fn) (WalReceiverConn *conn);
typedef struct WalReceiverFunctionsType
{
walrcv_connect_fn connect;
walrcv_get_conninfo_fn get_conninfo;
walrcv_identify_system_fn identify_system;
walrcv_readtimelinehistoryfile_fn readtimelinehistoryfile;
walrcv_startstreaming_fn startstreaming;
walrcv_endstreaming_fn endstreaming;
walrcv_receive_fn receive;
walrcv_send_fn send;
walrcv_disconnect_fn disconnect;
} WalReceiverFunctionsType;
extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
#define walrcv_connect(conninfo, logical, appname) \
WalReceiverFunctions->connect(conninfo, logical, appname)
#define walrcv_get_conninfo(conn) \
WalReceiverFunctions->get_conninfo(conn)
#define walrcv_identify_system(conn, primary_tli) \
WalReceiverFunctions->identify_system(conn, primary_tli)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
WalReceiverFunctions->readtimelinehistoryfile(conn, tli, filename, content, size)
#define walrcv_startstreaming(conn, tli, startpoint, slotname) \
WalReceiverFunctions->startstreaming(conn, tli, startpoint, slotname)
#define walrcv_endstreaming(conn, next_tli) \
WalReceiverFunctions->endstreaming(conn, next_tli)
#define walrcv_receive(conn, buffer, wait_fd) \
WalReceiverFunctions->receive(conn, buffer, wait_fd)
#define walrcv_send(conn, buffer, nbytes) \
WalReceiverFunctions->send(conn, buffer, nbytes)
#define walrcv_disconnect(conn) \
WalReceiverFunctions->disconnect(conn)
/* prototypes for functions in walreceiver.c */ /* prototypes for functions in walreceiver.c */
extern void WalReceiverMain(void) pg_attribute_noreturn(); extern void WalReceiverMain(void) pg_attribute_noreturn();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment