[Pgpool-general] node degeneration on INSERT

Toshihiro Kitagawa kitagawa at sraoss.co.jp
Mon Jul 4 10:57:43 UTC 2011


On Thu, 30 Jun 2011 11:12:55 +0200
Karsten Düsterloh <pgpool-general-ml at tal.de> wrote:

> Hi!
> 
> We're still experiencing node degeneration with certain INSERTs,
> but now (finally!) I have a testcase!
> 
> We're running pgpool-II 2.3.3 with two Postgresql 8.3.11 nodes.
> Certain tables sport an 'id' field, tied to a SEQUENCE as the default
> value. INSERT queries for these tables come in two flavours:
> - read next id from SEQUENCE and INSERT with that id explicitly set
> - INSERT without setting the id, let Postgresql set it automatically
> 
> This will occasionally fail with
> > ERROR:  kind mismatch among backends. Possible last query was: 
> > "INSERT INTO locktest(id, ts) VALUES(127, Now());" kind details are:
> > 0[C] 1[E: duplicate key value violates unique constraint
> > "locktest_pkey"]
> > HINT:  check data consistency among db nodes
> 
> We didn't test with pgpool-II 3. It'd be good to know if that'd be fixed
> there.
> 
> 
> 
> Testcase:
> 
> 1. Setup pgpool with two client nodes:
>  replication_mode = true
>  load_balance_mode = true
>  replication_stop_on_mismatch = true
>  failover_if_affected_tuples_mismatch = true
> 
> 2. Create the following table:
>  create table locktest(id SERIAL primary key, ts timestamptz);
> 
> 3. Create three small shell scripts in one directory:
> 
> test1_ex.sh:
> ============
> #!/bin/bash
> PSQL="/path/to/your/psql -your -access -options -Aqt -c"
> while true; do
>   TID=$($PSQL "SELECT nextval('locktest_id_seq');")
>   $PSQL "INSERT INTO locktest(id, ts) VALUES($TID, Now());"
> done
> 
> test1_im.sh:
> ============
> #!/bin/bash
> PSQL="/path/to/your/psql -your -access -options -Aqt -c"
> while true; do
>   $PSQL "INSERT INTO locktest(ts) VALUES(Now());"
> done
> 
> test1.sh:
> =========
> #!/bin/bash
> ./test1_ex.sh &
> ./test1_im.sh &
> 
> 4. Run test1.sh and wait for node degeneration.
> 
> Step 4 took less then 10 minutes for me until degeneration.
> 
> 
> 
> Analysis:
> 
> When inserting new rows, the *table* locktest will be locked so that
> both INSERTs can't disturb each other. But the dependend *sequence* will
> not be locked, hence the explicit call to nextval may happen while the
> table is already locked but the implicit nextval didn't happen yet:
> 
> Example: (LOCKs are generated by pgpool)
> 
> node 0:
> [im] LOCK
> [im] INSERT INTO locktest(ts) VALUES(Now());
> [ex] SELECT nextval('locktest_id_seq');
> [ex] LOCK
> [ex] INSERT INTO locktest(id, ts) VALUES(xxx, Now());
> 
> node 1:
> [im] LOCK
> [ex] SELECT nextval('locktest_id_seq');
> [im] INSERT INTO locktest(ts) VALUES(Now());
> [ex] LOCK
> [ex] INSERT INTO locktest(id, ts) VALUES(xxx, Now());
> 
> Maybe pgpool should/could LOCK implicitly used sequences as well?

I think it's a rare use case.
We cannot solve all problems such as this even if pgpool-II locks with
nextval. For example, if the sequence is not generated by the SERIAL
data types, pgpool-II cannot lock because lock target table does not
exist.

-- 
Toshihiro Kitagawa
SRA OSS, Inc. Japan



More information about the Pgpool-general mailing list