Client Server data inconsistency (after pg_ctl stop -m fast)

Hello

I found a problem when stopping the database with

pg_ctl stop -D /rt_global/testdb/data -m fast

bash-4.1$ pg_ctl --version : pg_ctl (PostgreSQL) 9.6.0


The problem is:

  • The client (used libpq in c++ or also psql in a perl) tries to insert a counter into testtable
  • Whenever an error is returned to the client, the client tries is to write it again

Problem:

  • the psql client receives an error but the record was inserted into the table!
  • So the record is finally insertet twice


    The postgres log shows this:

< 2017-01-24 06:35:39.825 CET > LOG: duration: 1.345 ms statement: select * from insert_testtable(66705);
< 2017-01-24 06:35:39.825 CET > FATAL: terminating connection due to administrator command
< 2017-01-24 06:35:39.825 CET > STATEMENT: select * from insert_testtable(66705);

… Note: this record was inserted (see table below) and client got error

< 2017-01-24 06:35:39.826 CET > LOG: shutting down
< 2017-01-24 06:35:39.831 CET > LOG: database system is shut down
< 2017-01-24 06:35:45.887 CET > LOG: database system was shut down at 2017-01-24 06:35:39 CET
< 2017-01-24 06:35:45.887 CET > FATAL: the database system is starting up
< 2017-01-24 06:35:45.887 CET > LOG: MultiXact member wraparound protections are now enabled
< 2017-01-24 06:35:45.888 CET > LOG: autovacuum launcher started
< 2017-01-24 06:35:45.888 CET > LOG: database system is ready to accept connections
< 2017-01-24 06:35:45.895 CET > LOG: duration: 1.628 ms statement: select * from insert_testtable(66705);


Duplicate record was inserted:

db1=# select * from testtable where counter = 66705;
counter | insert_time
---------±---------------------------
66705 | 2017-01-24 06:35:39.823853 … inserted but application got error
66705 | 2017-01-24 06:35:45.893446 … application retried to insert it after restart of postmaster
(2 rows)

Question: Can anybody tell how to avoid this problem?

Note: I have expected e.g. that a pg_terminate_backend makes it consistent but my tests showed it makes same problem
as with simple pg_ctl stop -m fast

Is there such a “graceful stop” method ?

  • to rollback a transation and to send error to client
  • or to finish the transaction and send ok to client
    (but should never finish the transaction and send error to client)

best regards

you can avoid duplicate entries with proper indexes.

it seems to me that the transaction was successful, but in fast-mode (pg_ctl -m fast) client-connections are immediately canceled. So, only the connection is down, but the row is successful inserted. Additionaly, the log line

LOG: duration: 1.345 ms statement: select * from insert_testtable(66705);

shows that the transaction was successful. So, i can’t see an error here. A ‘greaceful’ shurdown is possible with pg_ctl -m smart, in this case no connections are droped, instead of the database waits for all active clients to disconnect.


This is a german speaking forum, can we switch to german?

Danke für die rasche Antwort.

Ja, das im Falle von inserts kann man mit indices am Client feststellen, ob die row schon enthalten ist
(da muss aber der Client auch irgendeinen eindeutigen Schlüssel (Id) generieren)

Aber wir haben meistens updates verwendet wo keine Indexänderung stattfindet.

Anmerkung: wir verwenden Connection-Pools womit ein pg_ctl ohne “fast” nicht zum Stop führt

Meine Erwartung wäre gewesen, dass ein pg_terminate_backup oder ähnlich (vermutlich verwendet bei pg_ctl stop -m fast)
dem Client zuverlässig den Status der transaction mitteilt:
das heißt, dass nur eine Fehler zum client geschickt wird, wenn die transaction fehlgeschlagen ist.

Ein pg_cancel_backend könnte das eventuell gewährleisten, aber davor müsste es noch eine Methode geben,
um einen neuerlichen Request (auf bestehender Connection - weil Connection pool)
vom client zu verhindern (dass gar keine neue Transaktion gestartet werden kann)

Gibt es größere Foren, wo ich nach ähnlichen Problemberichten suchen kann?

Hallo
Meine Anmerkung “Index nicht aktualisiert” war mißverständlich, sorry
(ich meinte eigentlich beim update wird der key in der Tabelle ja nicht modifiziert,
(eg update table set Value1=1 where Id=2244) damit keine änderung am Index (mit Id)

Es geht nicht um indices sondern darum, wie man den server “sauber stoppt”
und der client zuverlässig den richtigen Status der “abgebrochenen” transaction bekommt
Habe das auch versucht mit pg_ctl stop -m smart:

  • dabei werden zwar keine neuen Connections erlaubt
  • aber dennoch können bestehende transaction (wegen connection pool) weiterhin “schreiben”
    … Also ist dennoch ein stop -m fast notwendig, der wieder eine aktive transaction abbricht.