mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-01-31 09:24:07 +03:00
Drop ReplicationCursor.flush_feedback(), rectify pq_*_replication_*() interface.
This commit is contained in:
parent
dd6bcbd04f
commit
8b79bf43ac
|
@ -492,22 +492,6 @@ The individual messages in the replication stream are represented by
|
|||
This method can also be called with all default parameters' values to
|
||||
just send a keepalive message to the server.
|
||||
|
||||
If the feedback message could not be sent, updates the passed LSN
|
||||
positions in the cursor for a later call to `flush_feedback()` and
|
||||
returns `!False`, otherwise returns `!True`.
|
||||
|
||||
.. method:: flush_feedback(reply=False)
|
||||
|
||||
:param reply: request the server to send back a keepalive message immediately
|
||||
|
||||
This method tries to flush the latest replication feedback message
|
||||
that `send_feedback()` was trying to send but couldn't.
|
||||
|
||||
If *reply* is `!True` sends a keepalive message in either case.
|
||||
|
||||
Returns `!True` if the feedback message was sent successfully,
|
||||
`!False` otherwise.
|
||||
|
||||
Low-level replication cursor methods for :ref:`asynchronous connection
|
||||
<async-support>` operation.
|
||||
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
/* type and constant definitions from internal postgres includes not available otherwise */
|
||||
typedef unsigned PG_INT64_TYPE XLogRecPtr;
|
||||
|
||||
#define InvalidXLogRecPtr ((XLogRecPtr) 0)
|
||||
|
||||
/* have to use lowercase %x, as PyString_FromFormat can't do %X */
|
||||
#define XLOGFMTSTR "%x/%x"
|
||||
#define XLOGFMTARGS(x) ((uint32)((x) >> 32)), ((uint32)((x) & 0xFFFFFFFF))
|
||||
|
|
|
@ -1542,8 +1542,8 @@ exit:
|
|||
Any keepalive messages from the server are silently consumed and
|
||||
are never returned to the caller.
|
||||
*/
|
||||
PyObject *
|
||||
pq_read_replication_message(replicationCursorObject *repl)
|
||||
int
|
||||
pq_read_replication_message(replicationCursorObject *repl, replicationMessageObject **msg)
|
||||
{
|
||||
cursorObject *curs = &repl->cur;
|
||||
connectionObject *conn = curs->conn;
|
||||
|
@ -1553,18 +1553,21 @@ pq_read_replication_message(replicationCursorObject *repl)
|
|||
XLogRecPtr data_start, wal_end;
|
||||
pg_int64 send_time;
|
||||
PyObject *str = NULL, *result = NULL;
|
||||
replicationMessageObject *msg = NULL;
|
||||
int ret = -1;
|
||||
|
||||
Dprintf("pq_read_replication_message");
|
||||
|
||||
*msg = NULL;
|
||||
consumed = 0;
|
||||
|
||||
retry:
|
||||
len = PQgetCopyData(pgconn, &buffer, 1 /* async */);
|
||||
|
||||
if (len == 0) {
|
||||
/* If we've tried reading some data, but there was none, bail out. */
|
||||
if (consumed) {
|
||||
goto none;
|
||||
ret = 0;
|
||||
goto exit;
|
||||
}
|
||||
/* We should only try reading more data when there is nothing
|
||||
available at the moment. Otherwise, with a really highly loaded
|
||||
|
@ -1599,7 +1602,8 @@ retry:
|
|||
}
|
||||
|
||||
CLEARPGRES(curs->pgres);
|
||||
goto none;
|
||||
ret = 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* It also makes sense to set this flag here to make us return early in
|
||||
|
@ -1641,11 +1645,11 @@ retry:
|
|||
Py_DECREF(str);
|
||||
if (!result) { goto exit; }
|
||||
|
||||
msg = (replicationMessageObject *)result;
|
||||
msg->data_size = data_size;
|
||||
msg->data_start = data_start;
|
||||
msg->wal_end = wal_end;
|
||||
msg->send_time = send_time;
|
||||
*msg = (replicationMessageObject *)result;
|
||||
(*msg)->data_size = data_size;
|
||||
(*msg)->data_start = data_start;
|
||||
(*msg)->wal_end = wal_end;
|
||||
(*msg)->send_time = send_time;
|
||||
}
|
||||
else if (buffer[0] == 'k') {
|
||||
/* Primary keepalive message: msgtype(1), walEnd(8), sendTime(8), reply(1) */
|
||||
|
@ -1656,19 +1660,8 @@ retry:
|
|||
}
|
||||
|
||||
reply = buffer[hdr];
|
||||
if (reply) {
|
||||
if (!pq_send_replication_feedback(repl, 0)) {
|
||||
if (conn->async) {
|
||||
repl->feedback_pending = 1;
|
||||
} else {
|
||||
/* XXX not sure if this was a good idea after all */
|
||||
pq_raise(conn, curs, NULL);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else {
|
||||
gettimeofday(&repl->last_io, NULL);
|
||||
}
|
||||
if (reply && pq_send_replication_feedback(repl, 0) < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PQfreemem(buffer);
|
||||
|
@ -1680,24 +1673,22 @@ retry:
|
|||
goto exit;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit:
|
||||
if (buffer) {
|
||||
PQfreemem(buffer);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
none:
|
||||
result = Py_None;
|
||||
Py_INCREF(result);
|
||||
goto exit;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pq_send_replication_feedback(replicationCursorObject *repl, int reply_requested)
|
||||
{
|
||||
cursorObject *curs = &repl->cur;
|
||||
PGconn *pgconn = curs->conn->pgconn;
|
||||
connectionObject *conn = curs->conn;
|
||||
PGconn *pgconn = conn->pgconn;
|
||||
char replybuf[1 + 8 + 8 + 8 + 8 + 1];
|
||||
int len = 0;
|
||||
|
||||
|
@ -1714,11 +1705,12 @@ pq_send_replication_feedback(replicationCursorObject *repl, int reply_requested)
|
|||
replybuf[len] = reply_requested ? 1 : 0; len += 1;
|
||||
|
||||
if (PQputCopyData(pgconn, replybuf, len) <= 0 || PQflush(pgconn) != 0) {
|
||||
return 0;
|
||||
pq_raise(conn, curs, NULL);
|
||||
return -1;
|
||||
}
|
||||
gettimeofday(&repl->last_io, NULL);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calls pq_read_replication_message in an endless loop, until
|
||||
|
@ -1734,7 +1726,8 @@ pq_copy_both(replicationCursorObject *repl, PyObject *consume, double keepalive_
|
|||
cursorObject *curs = &repl->cur;
|
||||
connectionObject *conn = curs->conn;
|
||||
PGconn *pgconn = conn->pgconn;
|
||||
PyObject *msg, *tmp = NULL;
|
||||
replicationMessageObject *msg = NULL;
|
||||
PyObject *tmp = NULL;
|
||||
int fd, sel, ret = -1;
|
||||
fd_set fds;
|
||||
struct timeval keep_intr, curr_time, ping_time, timeout;
|
||||
|
@ -1750,13 +1743,10 @@ pq_copy_both(replicationCursorObject *repl, PyObject *consume, double keepalive_
|
|||
keep_intr.tv_usec = (keepalive_interval - keep_intr.tv_sec)*1.0e6;
|
||||
|
||||
while (1) {
|
||||
msg = pq_read_replication_message(repl);
|
||||
if (!msg) {
|
||||
if (pq_read_replication_message(repl, &msg) < 0) {
|
||||
goto exit;
|
||||
}
|
||||
else if (msg == Py_None) {
|
||||
Py_DECREF(msg);
|
||||
|
||||
else if (msg == NULL) {
|
||||
fd = PQsocket(pgconn);
|
||||
if (fd < 0) {
|
||||
pq_raise(conn, curs, NULL);
|
||||
|
@ -1793,8 +1783,7 @@ pq_copy_both(replicationCursorObject *repl, PyObject *consume, double keepalive_
|
|||
}
|
||||
|
||||
if (sel == 0) {
|
||||
if (!pq_send_replication_feedback(repl, 0)) {
|
||||
pq_raise(conn, curs, NULL);
|
||||
if (pq_send_replication_feedback(repl, 0) < 0) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,9 @@
|
|||
#define PSYCOPG_PQPATH_H 1
|
||||
|
||||
#include "psycopg/cursor.h"
|
||||
#include "psycopg/replication_cursor.h"
|
||||
#include "psycopg/connection.h"
|
||||
#include "psycopg/replication_cursor.h"
|
||||
#include "psycopg/replication_message.h"
|
||||
|
||||
/* macro to clean the pg result */
|
||||
#define CLEARPGRES(pgres) do { PQclear(pgres); pgres = NULL; } while (0)
|
||||
|
@ -76,7 +77,8 @@ RAISES HIDDEN void pq_complete_error(connectionObject *conn, PGresult **pgres,
|
|||
/* replication protocol support */
|
||||
HIDDEN int pq_copy_both(replicationCursorObject *repl, PyObject *consumer,
|
||||
double keepalive_interval);
|
||||
HIDDEN PyObject *pq_read_replication_message(replicationCursorObject *repl);
|
||||
HIDDEN int pq_read_replication_message(replicationCursorObject *repl,
|
||||
replicationMessageObject **msg);
|
||||
HIDDEN int pq_send_replication_feedback(replicationCursorObject *repl, int reply_requested);
|
||||
|
||||
#endif /* !defined(PSYCOPG_PQPATH_H) */
|
||||
|
|
|
@ -45,10 +45,9 @@ typedef struct replicationCursorObject {
|
|||
struct timeval last_io ; /* timestamp of the last exchange with the server */
|
||||
struct timeval keepalive_interval; /* interval for keepalive messages in replication mode */
|
||||
|
||||
XLogRecPtr write_lsn; /* LSN stats for replication feedback messages */
|
||||
XLogRecPtr write_lsn; /* LSNs for replication feedback messages */
|
||||
XLogRecPtr flush_lsn;
|
||||
XLogRecPtr apply_lsn;
|
||||
int feedback_pending; /* flag set when we couldn't send the feedback to the server */
|
||||
} replicationCursorObject;
|
||||
|
||||
|
||||
|
|
|
@ -130,28 +130,21 @@ static PyObject *
|
|||
psyco_repl_curs_read_message(replicationCursorObject *self)
|
||||
{
|
||||
cursorObject *curs = &self->cur;
|
||||
replicationMessageObject *msg = NULL;
|
||||
|
||||
EXC_IF_CURS_CLOSED(curs);
|
||||
EXC_IF_GREEN(read_message);
|
||||
EXC_IF_TPC_PREPARED(self->cur.conn, read_message);
|
||||
EXC_IF_NOT_REPLICATING(self, read_message);
|
||||
|
||||
return pq_read_replication_message(self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
repl_curs_flush_feedback(replicationCursorObject *self, int reply)
|
||||
{
|
||||
if (!(self->feedback_pending || reply))
|
||||
Py_RETURN_TRUE;
|
||||
|
||||
if (pq_send_replication_feedback(self, reply)) {
|
||||
self->feedback_pending = 0;
|
||||
Py_RETURN_TRUE;
|
||||
} else {
|
||||
self->feedback_pending = 1;
|
||||
Py_RETURN_FALSE;
|
||||
if (pq_read_replication_message(self, &msg) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (msg) {
|
||||
return (PyObject *)msg;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#define psyco_repl_curs_send_feedback_doc \
|
||||
|
@ -162,9 +155,7 @@ psyco_repl_curs_send_feedback(replicationCursorObject *self,
|
|||
PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
cursorObject *curs = &self->cur;
|
||||
XLogRecPtr write_lsn = InvalidXLogRecPtr,
|
||||
flush_lsn = InvalidXLogRecPtr,
|
||||
apply_lsn = InvalidXLogRecPtr;
|
||||
XLogRecPtr write_lsn = 0, flush_lsn = 0, apply_lsn = 0;
|
||||
int reply = 0;
|
||||
static char* kwlist[] = {"write_lsn", "flush_lsn", "apply_lsn", "reply", NULL};
|
||||
|
||||
|
@ -185,31 +176,11 @@ psyco_repl_curs_send_feedback(replicationCursorObject *self,
|
|||
if (apply_lsn > self->apply_lsn)
|
||||
self->apply_lsn = apply_lsn;
|
||||
|
||||
self->feedback_pending = 1;
|
||||
|
||||
return repl_curs_flush_feedback(self, reply);
|
||||
}
|
||||
|
||||
#define psyco_repl_curs_flush_feedback_doc \
|
||||
"flush_feedback(reply=False) -- Try flushing the latest pending replication feedback message to the server and optionally request a reply."
|
||||
|
||||
static PyObject *
|
||||
psyco_repl_curs_flush_feedback(replicationCursorObject *self,
|
||||
PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
cursorObject *curs = &self->cur;
|
||||
int reply = 0;
|
||||
static char *kwlist[] = {"reply", NULL};
|
||||
|
||||
EXC_IF_CURS_CLOSED(curs);
|
||||
EXC_IF_NOT_REPLICATING(self, flush_feedback);
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist,
|
||||
&reply)) {
|
||||
if (pq_send_replication_feedback(self, reply) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return repl_curs_flush_feedback(self, reply);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -260,8 +231,6 @@ static struct PyMethodDef replicationCursorObject_methods[] = {
|
|||
METH_NOARGS, psyco_repl_curs_read_message_doc},
|
||||
{"send_feedback", (PyCFunction)psyco_repl_curs_send_feedback,
|
||||
METH_VARARGS|METH_KEYWORDS, psyco_repl_curs_send_feedback_doc},
|
||||
{"flush_feedback", (PyCFunction)psyco_repl_curs_flush_feedback,
|
||||
METH_VARARGS|METH_KEYWORDS, psyco_repl_curs_flush_feedback_doc},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
@ -281,10 +250,9 @@ replicationCursor_setup(replicationCursorObject* self)
|
|||
self->consuming = 0;
|
||||
self->decode = 0;
|
||||
|
||||
self->write_lsn = InvalidXLogRecPtr;
|
||||
self->flush_lsn = InvalidXLogRecPtr;
|
||||
self->apply_lsn = InvalidXLogRecPtr;
|
||||
self->feedback_pending = 0;
|
||||
self->write_lsn = 0;
|
||||
self->flush_lsn = 0;
|
||||
self->apply_lsn = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ class AsyncReplicationTest(ReplicationTestCase):
|
|||
|
||||
self.msg_count += 1
|
||||
if self.msg_count > 3:
|
||||
cur.flush_feedback(reply=True)
|
||||
cur.send_feedback(reply=True)
|
||||
raise StopReplication()
|
||||
|
||||
cur.send_feedback(flush_lsn=msg.data_start)
|
||||
|
|
Loading…
Reference in New Issue
Block a user