Send shared invalidation messages to other backends upon completion of a
authorPavan Deolasee <pavan.deolasee@gmail.com>
Wed, 21 Dec 2016 17:24:58 +0000 (22:54 +0530)
committerPavan Deolasee <pavan.deolasee@gmail.com>
Wed, 21 Dec 2016 17:24:58 +0000 (22:54 +0530)
command.

Since multiple backends may cooperate in a distributed transaction, it's
important that when one of the backends make changes to catalogs, which
requires cache invalidation, the other cooperating backends see those changes
immediately instead of end-of-transaction.

Also ensure that invalidation messages are accepted even when a relation lock
was already held by the backend, if it's running in a distributed transaction.

src/backend/storage/lmgr/lmgr.c
src/backend/utils/cache/inval.c
src/test/regress/expected/xl_distributed_xact.out [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/xl_distributed_xact.sql [new file with mode: 0644]

index 763f1cfdce2661e282ce8ad24a49114ce29dd1b5..16b41ba7b628eae881ad49abeb72a45545246f09 100644 (file)
@@ -120,8 +120,18 @@ LockRelationOid(Oid relid, LOCKMODE lockmode)
         * relcache entry in an undesirable way.  (In the case where our own xact
         * modifies the rel, the relcache update happens via
         * CommandCounterIncrement, not here.)
+        *
+        * In Postgres-XL, multiple backends may run concurrently to serve a
+        * distributed transaction. In that case, a conflicting lock may be granted
+        * to another backend running the same distributed transaction. But it's
+        * important that such backends process invalidation messages to ensure
+        * that relcache entry modified by the other cooperating backend is truly
+        * reflected. For example, the other backend may TRUNCATE the table and
+        * change the relfilenode. So we must see that change and work with the new
+        * relfilenode.
         */
-       if (res != LOCKACQUIRE_ALREADY_HELD)
+       if ((res != LOCKACQUIRE_ALREADY_HELD) ||
+               (MyProc->coordPid && MyProc->coordId))
                AcceptInvalidationMessages();
 }
 
index 0ad4548fe15b96e2c2e5f8321d71f29fbc2cbba4..bdaf89adb62b8cd4a68f7be54dde8d916eb43a9b 100644 (file)
@@ -1070,6 +1070,20 @@ CommandEndInvalidationMessages(void)
 
        ProcessInvalidationMessages(&transInvalInfo->CurrentCmdInvalidMsgs,
                                                                LocalExecuteInvalidationMessage);
+
+       /*
+        * In Postgres-XL, multiple backends can work for a distributed
+        * transaction. When catalog changes are made by one backend, the other
+        * backend participating in the distributed transaction must also see the
+        * changes immediately. So send the messages using shared invalidation
+        *
+        * XXX We could investigate if this can cause performance problems and
+        * check if the messages can be sent only to participating backends
+        */
+       if (IS_PGXC_DATANODE)
+               ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs,
+                       SendSharedInvalidMessages);
+
        AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
                                                           &transInvalInfo->CurrentCmdInvalidMsgs);
 }
diff --git a/src/test/regress/expected/xl_distributed_xact.out b/src/test/regress/expected/xl_distributed_xact.out
new file mode 100644 (file)
index 0000000..0087690
--- /dev/null
@@ -0,0 +1,87 @@
+CREATE TABLE testr_x14 (a int, b int);
+CREATE TABLE testl_x14 (a int, b int);
+INSERT INTO testl_x14 SELECT generate_series(1,10000), generate_series(1,10000);
+CREATE TABLE testlr_x14 (al int, bl int, ar int, br int);
+-- Create a scenario where datanode-datanode connections are established and
+-- they access a relation, which is subsequently altered or modified by some
+-- other connections. As seen from a bug report, if cache invalidation is not
+-- done correctly, the datanode-datanode connections may use stale cached
+-- information, leading to many problems
+BEGIN;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+TRUNCATE testr_x14;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+     0
+(1 row)
+
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+ 10000
+(1 row)
+
+ROLLBACK;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+TRUNCATE testr_x14;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+     0
+(1 row)
+
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+ 10000
+(1 row)
+
+DROP TABLE testlr_x14, testr_x14, testl_x14;
+CREATE TABLE testr_x14 (a int, b int);
+CREATE TABLE testl_x14 (a int, b int);
+INSERT INTO testl_x14 SELECT generate_series(1,10000), generate_series(1,10000);
+CREATE TABLE testlr_x14 (al int, bl int, ar int, br int);
+BEGIN;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+ALTER TABLE testr_x14 ALTER COLUMN b SET DATA TYPE text;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+     0
+(1 row)
+
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT testr_x14.a, testr_x14.b::integer, testl_x14.* FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+ 10000
+(1 row)
+
+ROLLBACK;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+ALTER TABLE testr_x14 ALTER COLUMN b SET DATA TYPE text;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+     0
+(1 row)
+
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT testr_x14.a, testr_x14.b::integer, testl_x14.* FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ count 
+-------
+ 10000
+(1 row)
+
+DROP TABLE testlr_x14, testr_x14, testl_x14;
index e211237998e55493e1c2a6a050365a32fac9fa69..16f09d66c4e5c9398eaee601fdd72a82569e3692 100644 (file)
@@ -139,4 +139,4 @@ test: xc_prepared_xacts
 test: xc_notrans_block
 
 # This runs XL specific tests
-test: xl_primary_key xl_foreign_key xl_distribution_column_types xl_alter_table xl_distribution_column_types_modulo xl_plan_pushdown xl_functions xl_limitations xl_user_defined_functions xl_join
+test: xl_primary_key xl_foreign_key xl_distribution_column_types xl_alter_table xl_distribution_column_types_modulo xl_plan_pushdown xl_functions xl_limitations xl_user_defined_functions xl_join xl_distributed_xact
index 57034c61fcd21d41ccb92828aaa6f403de1549a1..376c5be7aa41a48289023446a0b8a0ce740f450c 100644 (file)
@@ -185,3 +185,4 @@ test: xl_functions
 test: xl_limitations
 test: xl_user_defined_functions
 test: xl_join
+test: xl_distributed_xact
diff --git a/src/test/regress/sql/xl_distributed_xact.sql b/src/test/regress/sql/xl_distributed_xact.sql
new file mode 100644 (file)
index 0000000..02ba65f
--- /dev/null
@@ -0,0 +1,58 @@
+
+CREATE TABLE testr_x14 (a int, b int);
+CREATE TABLE testl_x14 (a int, b int);
+INSERT INTO testl_x14 SELECT generate_series(1,10000), generate_series(1,10000);
+CREATE TABLE testlr_x14 (al int, bl int, ar int, br int);
+
+-- Create a scenario where datanode-datanode connections are established and
+-- they access a relation, which is subsequently altered or modified by some
+-- other connections. As seen from a bug report, if cache invalidation is not
+-- done correctly, the datanode-datanode connections may use stale cached
+-- information, leading to many problems
+
+BEGIN;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+TRUNCATE testr_x14;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ROLLBACK;
+
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+TRUNCATE testr_x14;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+
+DROP TABLE testlr_x14, testr_x14, testl_x14;
+
+
+CREATE TABLE testr_x14 (a int, b int);
+CREATE TABLE testl_x14 (a int, b int);
+INSERT INTO testl_x14 SELECT generate_series(1,10000), generate_series(1,10000);
+CREATE TABLE testlr_x14 (al int, bl int, ar int, br int);
+
+BEGIN;
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+ALTER TABLE testr_x14 ALTER COLUMN b SET DATA TYPE text;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT testr_x14.a, testr_x14.b::integer, testl_x14.* FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+ROLLBACK;
+
+INSERT INTO testlr_x14 SELECT * FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+ALTER TABLE testr_x14 ALTER COLUMN b SET DATA TYPE text;
+INSERT INTO testr_x14 SELECT * FROM testl_x14;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+TRUNCATE testlr_x14;
+INSERT INTO testlr_x14 SELECT testr_x14.a, testr_x14.b::integer, testl_x14.* FROM testr_x14 RIGHT OUTER JOIN testl_x14 ON testr_x14.a = testl_x14.b;
+SELECT count(*) FROM testlr_x14 WHERE al IS NOT NULL;
+
+DROP TABLE testlr_x14, testr_x14, testl_x14;
+