mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
postgres_fdw: Report warning when timeout expires while getting query result.
When aborting remote transaction or sending cancel request to a remote server, postgres_fdw calls pgfdw_get_cleanup_result() to wait for the result of transaction abort query or cancel request to arrive. It fails to get the result if the timeout expires or a connection trouble happens. Previously postgres_fdw reported no warning message even when the timeout expired or a connection trouble happened in pgfdw_get_cleanup_result(). This could make the troubleshooting harder when such an event occurred. This commit makes pgfdw_get_cleanup_result() tell its caller what trouble (timeout or connection error) occurred, on failure, and also makes its caller report the proper warning message based on that information. Author: Fujii Masao Reviewed-by: Bharath Rupireddy Discussion: https://postgr.es/m/15aa988c-722e-ad3e-c936-4420c5b2bfea@oss.nttdata.com
This commit is contained in:
parent
d6f96ed94e
commit
815d61fcd4
@ -104,7 +104,7 @@ static bool pgfdw_cancel_query(PGconn *conn);
|
|||||||
static bool pgfdw_exec_cleanup_query(PGconn *conn, const char *query,
|
static bool pgfdw_exec_cleanup_query(PGconn *conn, const char *query,
|
||||||
bool ignore_errors);
|
bool ignore_errors);
|
||||||
static bool pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime,
|
static bool pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime,
|
||||||
PGresult **result);
|
PGresult **result, bool *timed_out);
|
||||||
static void pgfdw_abort_cleanup(ConnCacheEntry *entry, const char *sql,
|
static void pgfdw_abort_cleanup(ConnCacheEntry *entry, const char *sql,
|
||||||
bool toplevel);
|
bool toplevel);
|
||||||
static bool UserMappingPasswordRequired(UserMapping *user);
|
static bool UserMappingPasswordRequired(UserMapping *user);
|
||||||
@ -1154,6 +1154,7 @@ pgfdw_cancel_query(PGconn *conn)
|
|||||||
char errbuf[256];
|
char errbuf[256];
|
||||||
PGresult *result = NULL;
|
PGresult *result = NULL;
|
||||||
TimestampTz endtime;
|
TimestampTz endtime;
|
||||||
|
bool timed_out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it takes too long to cancel the query and discard the result, assume
|
* If it takes too long to cancel the query and discard the result, assume
|
||||||
@ -1180,8 +1181,19 @@ pgfdw_cancel_query(PGconn *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get and discard the result of the query. */
|
/* Get and discard the result of the query. */
|
||||||
if (pgfdw_get_cleanup_result(conn, endtime, &result))
|
if (pgfdw_get_cleanup_result(conn, endtime, &result, &timed_out))
|
||||||
|
{
|
||||||
|
if (timed_out)
|
||||||
|
ereport(WARNING,
|
||||||
|
(errmsg("could not get result of cancel request due to timeout")));
|
||||||
|
else
|
||||||
|
ereport(WARNING,
|
||||||
|
(errcode(ERRCODE_CONNECTION_FAILURE),
|
||||||
|
errmsg("could not get result of cancel request: %s",
|
||||||
|
pchomp(PQerrorMessage(conn)))));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1204,6 +1216,7 @@ pgfdw_exec_cleanup_query(PGconn *conn, const char *query, bool ignore_errors)
|
|||||||
{
|
{
|
||||||
PGresult *result = NULL;
|
PGresult *result = NULL;
|
||||||
TimestampTz endtime;
|
TimestampTz endtime;
|
||||||
|
bool timed_out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it takes too long to execute a cleanup query, assume the connection
|
* If it takes too long to execute a cleanup query, assume the connection
|
||||||
@ -1224,8 +1237,17 @@ pgfdw_exec_cleanup_query(PGconn *conn, const char *query, bool ignore_errors)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get the result of the query. */
|
/* Get the result of the query. */
|
||||||
if (pgfdw_get_cleanup_result(conn, endtime, &result))
|
if (pgfdw_get_cleanup_result(conn, endtime, &result, &timed_out))
|
||||||
|
{
|
||||||
|
if (timed_out)
|
||||||
|
ereport(WARNING,
|
||||||
|
(errmsg("could not get query result due to timeout"),
|
||||||
|
query ? errcontext("remote SQL command: %s", query) : 0));
|
||||||
|
else
|
||||||
|
pgfdw_report_error(WARNING, NULL, conn, false, query);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Issue a warning if not successful. */
|
/* Issue a warning if not successful. */
|
||||||
if (PQresultStatus(result) != PGRES_COMMAND_OK)
|
if (PQresultStatus(result) != PGRES_COMMAND_OK)
|
||||||
@ -1245,15 +1267,19 @@ pgfdw_exec_cleanup_query(PGconn *conn, const char *query, bool ignore_errors)
|
|||||||
* side back to the appropriate state.
|
* side back to the appropriate state.
|
||||||
*
|
*
|
||||||
* endtime is the time at which we should give up and assume the remote
|
* endtime is the time at which we should give up and assume the remote
|
||||||
* side is dead. Returns true if the timeout expired, otherwise false.
|
* side is dead. Returns true if the timeout expired or connection trouble
|
||||||
* Sets *result except in case of a timeout.
|
* occurred, false otherwise. Sets *result except in case of a timeout.
|
||||||
|
* Sets timed_out to true only when the timeout expired.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
|
pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result,
|
||||||
|
bool *timed_out)
|
||||||
{
|
{
|
||||||
volatile bool timed_out = false;
|
volatile bool failed = false;
|
||||||
PGresult *volatile last_res = NULL;
|
PGresult *volatile last_res = NULL;
|
||||||
|
|
||||||
|
*timed_out = false;
|
||||||
|
|
||||||
/* In what follows, do not leak any PGresults on an error. */
|
/* In what follows, do not leak any PGresults on an error. */
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
@ -1271,7 +1297,8 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
|
|||||||
cur_timeout = TimestampDifferenceMilliseconds(now, endtime);
|
cur_timeout = TimestampDifferenceMilliseconds(now, endtime);
|
||||||
if (cur_timeout <= 0)
|
if (cur_timeout <= 0)
|
||||||
{
|
{
|
||||||
timed_out = true;
|
*timed_out = true;
|
||||||
|
failed = true;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1290,8 +1317,8 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
|
|||||||
{
|
{
|
||||||
if (!PQconsumeInput(conn))
|
if (!PQconsumeInput(conn))
|
||||||
{
|
{
|
||||||
/* connection trouble; treat the same as a timeout */
|
/* connection trouble */
|
||||||
timed_out = true;
|
failed = true;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1313,11 +1340,11 @@ exit: ;
|
|||||||
}
|
}
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
|
|
||||||
if (timed_out)
|
if (failed)
|
||||||
PQclear(last_res);
|
PQclear(last_res);
|
||||||
else
|
else
|
||||||
*result = last_res;
|
*result = last_res;
|
||||||
return timed_out;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user