Обсуждение: termination of backend waiting for sync rep generates a junk log message

Поиск
Список
Период
Сортировка

termination of backend waiting for sync rep generates a junk log message

От
Fujii Masao
Дата:
Hi,

In 9.1, the following procedure writes a junk message into the server log;

$ initdb -D data
$ cat << EOF >> data/postgresql.conf
wal_level = hot_standby
max_wal_senders = 1
synchronous_standby_names = '*'
EOF
$ pg_ctl -D data start
$ psql -c "create table t (i int)" &
$ pg_ctl -D data -m fast stop

WARNING:  canceling the wait for synchronous replication and
terminating connection due to administrator command
DETAIL:  The transaction has already committed locally, but might not
have been replicated to the standby.
backend> FATAL:  terminating connection due to administrator command

The above is the server log messages that I got when I did the procedure.
"backend> " is a junk. If a backend is terminated while it's waiting for
synchronous replication, whereToSendOutput is set to DestNone. Then,
whereToSendOutput=DestNone makes ReadCommand() call
InteractiveBackend() which outputs "backend> ".

This junk message might mess up the server log monitoring tools. I think
it should be removed.

The simple fix is to change InteractiveBackend() so that it calls
CHECK_FOR_INTERRUPTS() before it outputs "backend> ". Thought?

Regards,

-- 
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center


Re: termination of backend waiting for sync rep generates a junk log message

От
Robert Haas
Дата:
On Mon, Oct 17, 2011 at 6:53 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
> WARNING:  canceling the wait for synchronous replication and
> terminating connection due to administrator command
> DETAIL:  The transaction has already committed locally, but might not
> have been replicated to the standby.
> backend> FATAL:  terminating connection due to administrator command
>
> The above is the server log messages that I got when I did the procedure.
> "backend> " is a junk. If a backend is terminated while it's waiting for
> synchronous replication, whereToSendOutput is set to DestNone. Then,
> whereToSendOutput=DestNone makes ReadCommand() call
> InteractiveBackend() which outputs "backend> ".
>
> This junk message might mess up the server log monitoring tools. I think
> it should be removed.
>
> The simple fix is to change InteractiveBackend() so that it calls
> CHECK_FOR_INTERRUPTS() before it outputs "backend> ". Thought?

I'm tempted to say we should do that in PostgresMain() instead, maybe
something like this:

diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 976a832..9e5557c 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -3769,6 +3769,8 @@ PostgresMain(int argc, char *argv[], const char *username)
MemoryContextSwitchTo(MessageContext);              MemoryContextResetAndDeleteChildren(MessageContext); 

+               CHECK_FOR_INTERRUPTS();
+               initStringInfo(&input_message);
               /*

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: termination of backend waiting for sync rep generates a junk log message

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> On Mon, Oct 17, 2011 at 6:53 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
>> The simple fix is to change InteractiveBackend() so that it calls
>> CHECK_FOR_INTERRUPTS() before it outputs "backend> ". Thought?

> I'm tempted to say we should do that in PostgresMain() instead, maybe
> something like this:

> diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
> index 976a832..9e5557c 100644
> --- a/src/backend/tcop/postgres.c
> +++ b/src/backend/tcop/postgres.c
> @@ -3769,6 +3769,8 @@ PostgresMain(int argc, char *argv[], const char *username)
>                 MemoryContextSwitchTo(MessageContext);
>                 MemoryContextResetAndDeleteChildren(MessageContext);

> +               CHECK_FOR_INTERRUPTS();
> +
>                 initStringInfo(&input_message);

>                 /*

I don't like putting a CHECK_FOR_INTERRUPTS there, because it's way too
late to throw an error for the previous query.

The real problem here is probably that we're overloading the meaning of
whereToSendOutput.  The reset of that variable during shutdown was only
ever meant to prevent output from being sent to a no-longer-present
client.  It should *not* result in trying to read a query from stdin.

Another question worth asking is how is it that we're getting to
ReadCommand at all, if we have already determined that the client is
gone.  Fixing that with an additional CHECK_FOR_INTERRUPTS seems like
a crock.
        regards, tom lane


Re: termination of backend waiting for sync rep generates a junk log message

От
Robert Haas
Дата:
On Tue, Oct 18, 2011 at 5:18 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Robert Haas <robertmhaas@gmail.com> writes:
>> On Mon, Oct 17, 2011 at 6:53 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
>>> The simple fix is to change InteractiveBackend() so that it calls
>>> CHECK_FOR_INTERRUPTS() before it outputs "backend> ". Thought?
>
>> I'm tempted to say we should do that in PostgresMain() instead, maybe
>> something like this:
>
>> diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
>> index 976a832..9e5557c 100644
>> --- a/src/backend/tcop/postgres.c
>> +++ b/src/backend/tcop/postgres.c
>> @@ -3769,6 +3769,8 @@ PostgresMain(int argc, char *argv[], const char *username)
>>                 MemoryContextSwitchTo(MessageContext);
>>                 MemoryContextResetAndDeleteChildren(MessageContext);
>
>> +               CHECK_FOR_INTERRUPTS();
>> +
>>                 initStringInfo(&input_message);
>
>>                 /*
>
> I don't like putting a CHECK_FOR_INTERRUPTS there, because it's way too
> late to throw an error for the previous query.
>
> The real problem here is probably that we're overloading the meaning of
> whereToSendOutput.  The reset of that variable during shutdown was only
> ever meant to prevent output from being sent to a no-longer-present
> client.  It should *not* result in trying to read a query from stdin.

I think you're right, but am not sure how to fix it.

> Another question worth asking is how is it that we're getting to
> ReadCommand at all, if we have already determined that the client is
> gone.  Fixing that with an additional CHECK_FOR_INTERRUPTS seems like
> a crock.

We haven't determined the client is gone; we're trying to close the
connection "unexpectedly".  As the comment in SyncRepWaitForLSN
explains:
               /*                * If a wait for synchronous replication is pending,
we can neither                * acknowledge the commit nor raise ERROR or FATAL.
The latter would                * lead the client to believe that that the
transaction aborted, which                * is not true: it's already committed locally. The
former is no good                * either: the client has requested synchronous
replication, and is                * entitled to assume that an acknowledged commit is
also replicated,                * which might not be true. So in this case we issue a
WARNING (which                * some clients may be able to interpret) and shut off
further output.                * We do NOT reset ProcDiePending, so that the process
will die after                * the commit is cleaned up.                */

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: termination of backend waiting for sync rep generates a junk log message

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> On Tue, Oct 18, 2011 at 5:18 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Another question worth asking is how is it that we're getting to
>> ReadCommand at all, if we have already determined that the client is
>> gone. �Fixing that with an additional CHECK_FOR_INTERRUPTS seems like
>> a crock.

> We haven't determined the client is gone; we're trying to close the
> connection "unexpectedly".  As the comment in SyncRepWaitForLSN
> explains:

>                 /*
>                  * If a wait for synchronous replication is pending,
> we can neither
>                  * acknowledge the commit nor raise ERROR or FATAL.
> The latter would
>                  * lead the client to believe that that the
> transaction aborted, which
>                  * is not true: it's already committed locally. The
> former is no good
>                  * either: the client has requested synchronous
> replication, and is
>                  * entitled to assume that an acknowledged commit is
> also replicated,
>                  * which might not be true. So in this case we issue a
> WARNING (which
>                  * some clients may be able to interpret) and shut off
> further output.
>                  * We do NOT reset ProcDiePending, so that the process
> will die after
>                  * the commit is cleaned up.
>                  */

Hmm.  Maybe the real answer is "this code is abusing whereToSendOutput"
(and about six other things besides).  I'll try to think of a better
solution, but not tonight.

One thing worth asking is why we're willing to violate half a dozen
different coding rules if we see ProcDiePending, yet we're perfectly
happy to rely on the client understanding a WARNING for the
QueryCancelPending case.  Another is whether this whole function isn't
complete BS in the first place, since it appears to be coded on the
obviously-false assumption that nothing it calls can throw elog(ERROR)
--- and of course, if any of those functions do throw ERROR, all the
argumentation here goes out the window.
        regards, tom lane


Re: termination of backend waiting for sync rep generates a junk log message

От
Robert Haas
Дата:
On Tue, Oct 18, 2011 at 11:27 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> One thing worth asking is why we're willing to violate half a dozen
> different coding rules if we see ProcDiePending, yet we're perfectly
> happy to rely on the client understanding a WARNING for the
> QueryCancelPending case.  Another is whether this whole function isn't
> complete BS in the first place, since it appears to be coded on the
> obviously-false assumption that nothing it calls can throw elog(ERROR)
> --- and of course, if any of those functions do throw ERROR, all the
> argumentation here goes out the window.

Well, there is a general problem that anything which throws an ERROR
too late in the commit path is Evil; and sync rep makes that worse to
the extent that it adds more stuff late in the commit path, but it
didn't invent the problem.  What it did do is add stuff late in the
commit path that can block for a potentially unbounded period of time,
and I don't see that there are any solutions to that problem that
aren't somewhat grotty.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: termination of backend waiting for sync rep generates a junk log message

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> On Tue, Oct 18, 2011 at 11:27 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> One thing worth asking is why we're willing to violate half a dozen
>> different coding rules if we see ProcDiePending, yet we're perfectly
>> happy to rely on the client understanding a WARNING for the
>> QueryCancelPending case. �Another is whether this whole function isn't
>> complete BS in the first place, since it appears to be coded on the
>> obviously-false assumption that nothing it calls can throw elog(ERROR)
>> --- and of course, if any of those functions do throw ERROR, all the
>> argumentation here goes out the window.

> Well, there is a general problem that anything which throws an ERROR
> too late in the commit path is Evil; and sync rep makes that worse to
> the extent that it adds more stuff late in the commit path, but it
> didn't invent the problem.  What it did do is add stuff late in the
> commit path that can block for a potentially unbounded period of time,
> and I don't see that there are any solutions to that problem that
> aren't somewhat grotty.

No doubt, but fantasizing about what you are or are not controlling
doesn't help ... and AFAICT this code is mostly fantasy.  Anyway,
I don't have a better proposal right offhand; will think about it.
        regards, tom lane


Re: termination of backend waiting for sync rep generates a junk log message

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> On Tue, Oct 18, 2011 at 11:27 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> One thing worth asking is why we're willing to violate half a dozen
>> different coding rules if we see ProcDiePending, yet we're perfectly
>> happy to rely on the client understanding a WARNING for the
>> QueryCancelPending case. �Another is whether this whole function isn't
>> complete BS in the first place, since it appears to be coded on the
>> obviously-false assumption that nothing it calls can throw elog(ERROR)
>> --- and of course, if any of those functions do throw ERROR, all the
>> argumentation here goes out the window.

> Well, there is a general problem that anything which throws an ERROR
> too late in the commit path is Evil; and sync rep makes that worse to
> the extent that it adds more stuff late in the commit path, but it
> didn't invent the problem.  What it did do is add stuff late in the
> commit path that can block for a potentially unbounded period of time,
> and I don't see that there are any solutions to that problem that
> aren't somewhat grotty.

After further reflection, you're right that all sync rep is really doing
is extending the time duration of the interval wherein clients will have
a hard time telling whether the commit occurred or not.  It's always
been the case that if a cancel/die interrupt occurs during
CommitTransaction, that will get serviced at the RESUME_INTERRUPTS call
at the end, and the client will see an apparent failure even though the
transaction was committed.  Even without that, an interrupt occurring
just after this code sequence, but before we reach the point of sending
a command-complete response message, is going to result in client
confusion, and there's very little we can do about that.

I think what we should do in SyncRepWaitForLSN is just send a warning
and abandon waiting.  Trying to fool with the interrupt response
behavior beyond that is simply broken, and it doesn't help any that we
chose to break it in two different, but equally indefensible, ways for
cancel versus die interrupts.

It would help BTW for the warning to have its own SQLSTATE, if we're
imagining that "some clients may be able to interpret" it.  Also, this
code is supposing that it must be called within a HOLD_INTERRUPTS
context, but it doesn't look to me like that is being done for the
various calls from twophase.c.
        regards, tom lane


Re: termination of backend waiting for sync rep generates a junk log message

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> Well, there is a general problem that anything which throws an ERROR
> too late in the commit path is Evil; and sync rep makes that worse to
> the extent that it adds more stuff late in the commit path, but it
> didn't invent the problem.

BTW, it strikes me that if we want to do something about that, it ought
to be possible; but it has to be built into error handling, not a
localized hack for sync rep.

Consider a design along these lines: we invent a global flag that gets
set at some appropriate point in RecordTransactionCommit (probably right
where we exit the commit critical section) and is not cleared until we
send a suitable message to the client --- I think either
command-complete or an error message would qualify, but that would have
to be analyzed more carefully than I've done so far.  If elog.c is told
to send an error message while this flag is set, then it does something
special to inform the client that this was a post-commit error and the
xact is in fact committed.

My inclination for the "something special" would be to add a new error
message field, but that could be difficult for clients to examine
depending on what sort of driver infrastructure they're dealing with.
You could also imagine emitting a separate NOTICE or WARNING message,
which is analogous to the current hack in SyncRepWaitForLSN, but seems
pretty ugly because it requires clients to re-associate that event with
the later error message.  (But it might be worth doing anyway for human
users, even if we provide a different flag mechanism that is intended
for program consumption.)  Or maybe we could override the SQLSTATE with
some special value.  Or something else.

Given infrastructure like this, it would be reasonable for
SyncRepWaitForLSN to just throw an ERROR if it gets an interrupt,
instead of trying to kluge its own solution.
        regards, tom lane


Re: termination of backend waiting for sync rep generates a junk log message

От
Robert Haas
Дата:
On Mon, Oct 24, 2011 at 10:05 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> as it seems to me that any
>> client that is paranoid enough to care about sync rep had better
>> already be handling the case of a connection loss during commit.
>
> Agreed, but that is a problem that by definition we can't help with.
> Also, the issue with connection loss is that you really can't know
> whether your transaction got committed without reconnecting and looking
> for evidence.  There is no reason at all to inject such uncertainty
> into the cancel-SyncRepWaitForLSN case.  We know the transaction got
> committed,

I disagree.  The whole point of synchronous replication is that the
user is worried about the case where the primary goes away just after
the commit is acknowledged to the client.  Consider the following
scenario: Someone has determined that it can't be reached from 90% of
the corporate Internet, but the synchronous standby, which is
naturally on another network, still has connectivity.  So they log
into the master and perform a fast shutdown.  When they reconnect, the
connection pooler (or other mechanism) redirects their connection to
the standby, which has sense been promoted.  ISTM that the client had
darn well better go search for hard evidence about the transaction
state.

>> But I think that throwing an ERROR is likely to cause a LOT of client
>> breakage, even if you have some special (human-invisible?) flag that
>> indicates that you don't really mean it.  If we must do something
>> other than simulating a server disconnect, letting the command
>> completion message go through and annotating it with a NOTICE or
>> WARNING seems preferable.
>
> I think you're thinking narrowly of the SyncRepWaitForLSN case.  What
> I'm trying to point out is that there's a boatload of post-commit code
> which is capable of sometimes throwing errors, and that's not ever
> going to go away completely.
>
> It might be that it'd work to deal with this by reducing the reported
> strength of all such cases from ERROR to WARNING.  Not sure that that's
> a good idea, but it might work.

It's hard to be sure that a systematic approach will work.  For
example, if we fail to can't nuke a memory context for some reason, it
wouldn't be utterly crazy to just ignore the problem and try to
soldier on.  We've probably leaked some memory, but oh well.  If we've
failed to release a heavyweight lock we had better call
LockReleaseAll() somehow, but the details of what gets sent to the
client are negotiable and a WARNING is probably fine.  On the other
hand, if we experienced some failure that affects our ability to make
the transaction globally visible (like we wrote the commit record but
then fail trying to acquire ProcArrayLock to clear our xmin), it's
hard to believe that anything other than PANIC is enough.

Because of that and similar cases elsewhere, including for example
inside the lock manager, I've long been feeling grumpy about this:
       /* Ensure we will have room to remember the lock */       if (num_held_lwlocks >= MAX_SIMUL_LWLOCKS)
 elog(ERROR, "too many LWLocks taken"); 

It seems to me that the idea that the abort path is going to be able
to recover from that situation is wildly optimistic.  Fortunately, our
coding practices are good enough that I think it never happens anyway,
but if it does it should surely PANIC.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: termination of backend waiting for sync rep generates a junk log message

От
Robert Haas
Дата:
On Sun, Oct 23, 2011 at 6:34 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Robert Haas <robertmhaas@gmail.com> writes:
>> Well, there is a general problem that anything which throws an ERROR
>> too late in the commit path is Evil; and sync rep makes that worse to
>> the extent that it adds more stuff late in the commit path, but it
>> didn't invent the problem.
>
> BTW, it strikes me that if we want to do something about that, it ought
> to be possible; but it has to be built into error handling, not a
> localized hack for sync rep.
>
> Consider a design along these lines: we invent a global flag that gets
> set at some appropriate point in RecordTransactionCommit (probably right
> where we exit the commit critical section) and is not cleared until we
> send a suitable message to the client --- I think either
> command-complete or an error message would qualify, but that would have
> to be analyzed more carefully than I've done so far.  If elog.c is told
> to send an error message while this flag is set, then it does something
> special to inform the client that this was a post-commit error and the
> xact is in fact committed.
>
> My inclination for the "something special" would be to add a new error
> message field, but that could be difficult for clients to examine
> depending on what sort of driver infrastructure they're dealing with.
> You could also imagine emitting a separate NOTICE or WARNING message,
> which is analogous to the current hack in SyncRepWaitForLSN, but seems
> pretty ugly because it requires clients to re-associate that event with
> the later error message.  (But it might be worth doing anyway for human
> users, even if we provide a different flag mechanism that is intended
> for program consumption.)  Or maybe we could override the SQLSTATE with
> some special value.  Or something else.
>
> Given infrastructure like this, it would be reasonable for
> SyncRepWaitForLSN to just throw an ERROR if it gets an interrupt,
> instead of trying to kluge its own solution.

I actually think that emitting a NOTICE or WARNING and then slamming
the connection shut is quite elegant, as it seems to me that any
client that is paranoid enough to care about sync rep had better
already be handling the case of a connection loss during commit.  I
realize that handling query cancellation in a somewhat different way
is a wart, though, and I'm not necessarily opposed to changing the
behavior.

But I think that throwing an ERROR is likely to cause a LOT of client
breakage, even if you have some special (human-invisible?) flag that
indicates that you don't really mean it.  If we must do something
other than simulating a server disconnect, letting the command
completion message go through and annotating it with a NOTICE or
WARNING seems preferable.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: termination of backend waiting for sync rep generates a junk log message

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> On Sun, Oct 23, 2011 at 6:34 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> BTW, it strikes me that if we want to do something about that, it ought
>> to be possible; but it has to be built into error handling, not a
>> localized hack for sync rep.

> I actually think that emitting a NOTICE or WARNING and then slamming
> the connection shut is quite elegant,

No, it's a horrid crock, whose only saving grace is that it was
implementable with two or three lines localized to SyncRepWaitForLSN
... or at least, we thought that until Fujii-san started pointing out
the bugs in it.  It's not convenient for clients at all, it does not fit
well into the backend structure (which is the reason for the bugs), and
it forces session termination unnecessarily, or at least it would if
we'd been consistent and applied the method to query-cancel as well.

> as it seems to me that any
> client that is paranoid enough to care about sync rep had better
> already be handling the case of a connection loss during commit.

Agreed, but that is a problem that by definition we can't help with.
Also, the issue with connection loss is that you really can't know
whether your transaction got committed without reconnecting and looking
for evidence.  There is no reason at all to inject such uncertainty
into the cancel-SyncRepWaitForLSN case.  We know the transaction got
committed, and there's no reason to make the client guess about that,
nor to make it parse WARNING messages for which we didn't even get the
assignment of a unique SQLSTATE right (thus making the problem
insoluble anyhow).

> But I think that throwing an ERROR is likely to cause a LOT of client
> breakage, even if you have some special (human-invisible?) flag that
> indicates that you don't really mean it.  If we must do something
> other than simulating a server disconnect, letting the command
> completion message go through and annotating it with a NOTICE or
> WARNING seems preferable.

I think you're thinking narrowly of the SyncRepWaitForLSN case.  What
I'm trying to point out is that there's a boatload of post-commit code
which is capable of sometimes throwing errors, and that's not ever
going to go away completely.

It might be that it'd work to deal with this by reducing the reported
strength of all such cases from ERROR to WARNING.  Not sure that that's
a good idea, but it might work.
        regards, tom lane


Re: termination of backend waiting for sync rep generates a junk log message

От
"Kevin Grittner"
Дата:
Tom Lane <tgl@sss.pgh.pa.us> wrote:
> It might be that it'd work to deal with this by reducing the
> reported strength of all such cases from ERROR to WARNING.  Not
> sure that that's a good idea, but it might work.
Throwing an error on commit of a transaction when its work has
actually been persisted seems as bad as failing to persist the work
of a transaction when the commit appears successful.  If we know we
have met the persistence guarantees and some problem occurs after
that, then it seems to me we should issue a warning and indicate
success.  If we don't know whether the work will be persisted, it
seems to me we can block until we find out (if that's feasible) or
break the connection without indicating one way or the other.  The
work of the transaction must either all be persisted or not (I'm
assuming this isn't a problem here), and any user must be prepared
to deal with a broken connection before response on a commit
attempt.
I don't know whether changing all failures beyond the persistence
point in a commit to warnings is sufficient, but I think it is
required for anything which doesn't break the connection.
-Kevin