[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [HACKERS] [OSSTEST PATCH 0/1] PostgreSQL db: Retry on constraint violation



Kevin Grittner writes ("Re: [HACKERS] [OSSTEST PATCH 0/1] PostgreSQL db: Retry 
on constraint violation"):
> If I recall correctly, the constraints for which there can be
> errors appearing due to concurrent transactions are primary key,
> unique, and foreign key constraints.  I don't remember seeing it
> happen, but it would not surprise me if an exclusion constraint can
> also cause an error due to a concurrent transaction's interaction
> with the transaction receiving the error.

Is it not in principle also possible to contrive a situation where
some set of (suitably weird) transactions will generate almost any
error, from the outer transaction ?

This is at the very least possible using pgsql's in-sql
exception-trapping facilities.  Such a construction might, in
principle, generate any error which can be conditionally generated at
query runtime.

ISTM that depending on the implementation arrangements (which I
frankly don't understand at all) there may be other constructions
which would give "impossible" answers.

Actually, now I come to think of it, the fact that pgsql has an in-sql
exception trapping facility means that the current situation is
clearly an actual bug, in the sense that the behaviour is contrary to
the documentation.  (And contrary to any reasonable thing that could
be written in the documentation.)

AIUI the documented behavour is that "every set of successful
transactions is serialisable".


But, consider the following scenario.

Context:

  CREATE OR REPLACE FUNCTION demo(nk TEXT, c INTEGER) RETURNS INTEGER AS $$
  BEGIN
    BEGIN
      INSERT INTO t (k,v) VALUES (nk, -1);
    EXCEPTION WHEN unique_violation THEN
      INSERT INTO c (k,v) VALUES (nk, c);
    END;
    RETURN 0;
  END;
  $$ LANGUAGE plpgsql;

  DROP TABLE IF EXISTS t;
  DROP TABLE IF EXISTS c;

  CREATE TABLE t (k TEXT PRIMARY KEY, v INTEGER NOT NULL);
  CREATE TABLE c (k TEXT PRIMARY KEY, v INTEGER NOT NULL);

Two identical transactions:

  BEGIN;
  SELECT count(*) FROM t WHERE k=1;   -- save value
                                      -- sleep to ensure conflict
  SELECT demo(1, ?);                  -- using value from SELECT
  COMMIT;

I have just tried this and got this result:

  osstestdb_test_iwj=> select * from t;
   k | v  
  ---+----
   1 | -1
  (1 row)

  osstestdb_test_iwj=> select * from c;
   k | v 
  ---+---
   1 | 0
  (1 row)

  osstestdb_test_iwj=> 

The row ('1',0) in table c is clearly wrong.  No rows with v=0 could
ever be inserted into c by this SQL code, unless the other
transaction is somehow interfering in the middle.

The perl program I used is below.  `csreadconfig' does nothing of
particular interest except obtaining the db connnection as $dbh_tests.

Ian.


#!/usr/bin/perl -w

use strict qw(vars);
use Osstest;
use Data::Dumper;
use Osstest::Executive;

csreadconfig();

if (!@ARGV) {
    $dbh_tests->do(<<'END');
  CREATE OR REPLACE FUNCTION demo(nk TEXT, c INTEGER) RETURNS INTEGER AS $$
  BEGIN
    BEGIN
      INSERT INTO t (k,v) VALUES (nk, -1);
    EXCEPTION WHEN unique_violation THEN
      INSERT INTO c (k,v) VALUES (nk, c);
    END;
    RETURN 0;
  END;
  $$ LANGUAGE plpgsql;

  DROP TABLE IF EXISTS t;
  DROP TABLE IF EXISTS c;

  CREATE TABLE t (k TEXT PRIMARY KEY, v INTEGER NOT NULL);
  CREATE TABLE c (k TEXT PRIMARY KEY, v INTEGER NOT NULL);
END
    exit 0;
}

our ($k,$v) = @ARGV;

$dbh_tests->begin_work;
$dbh_tests->do("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");

our ($conflictors)= $dbh_tests->selectrow_array(<<END, {}, $k);
    SELECT count(*) FROM t WHERE k=?
END

print STDERR "conflictors=$conflictors\n";
sleep 5;
print STDERR "continuing...\n";

$dbh_tests->do(<<END, {}, $k, $conflictors);
  SELECT demo(?,?);
END

$dbh_tests->commit;

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.