From 9dfdbef345390124eaf993f6289e8ae796aa6918 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 19 Oct 2003 21:36:41 +0000 Subject: [PATCH] Adjust libpq to avoid deadlock when both client and server want to send data, and both have filled the transmission buffers. One scenario where this can happen was illustrated here: http://archives.postgresql.org/pgsql-hackers/2003-04/msg00979.php --- src/interfaces/libpq/fe-exec.c | 13 ++++++++++++- src/interfaces/libpq/fe-misc.c | 21 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 810a753ed3..1967d7429b 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.151 2003/10/04 21:05:21 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.152 2003/10/19 21:36:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1336,6 +1336,17 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes) libpq_gettext("no COPY in progress\n")); return -1; } + + /* + * Check for NOTICE messages coming back from the server. Since the + * server might generate multiple notices during the COPY, we have to + * consume those in a reasonably prompt fashion to prevent the comm + * buffers from filling up and possibly blocking the server. + */ + if (!PQconsumeInput(conn)) + return -1; /* I/O failure */ + parseInput(conn); + if (nbytes > 0) { /* diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index d71473d514..4349a4e05a 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -23,7 +23,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.102 2003/08/08 21:42:55 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.103 2003/10/19 21:36:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -828,7 +828,24 @@ pqSendSome(PGconn *conn, int len) break; } - if (pqWait(FALSE, TRUE, conn)) + /* + * There are scenarios in which we can't send data because the + * communications channel is full, but we cannot expect the server + * to clear the channel eventually because it's blocked trying to + * send data to us. (This can happen when we are sending a large + * amount of COPY data, and the server has generated lots of + * NOTICE responses.) To avoid a deadlock situation, we must be + * prepared to accept and buffer incoming data before we try + * again. Furthermore, it is possible that such incoming data + * might not arrive until after we've gone to sleep. Therefore, + * we wait for either read ready or write ready. + */ + if (pqReadData(conn) < 0) + { + result = -1; /* error message already set up */ + break; + } + if (pqWait(TRUE, TRUE, conn)) { result = -1; break; -- 2.40.0