Do not throw a FATAL error when SharedQ producer times out while waiting for
authorPavan Deolasee <[email protected]>
Sun, 31 Jan 2016 08:25:01 +0000 (13:55 +0530)
committerPavan Deolasee <[email protected]>
Tue, 18 Oct 2016 09:48:13 +0000 (15:18 +0530)
one or more consumers to finish.

We have seen bunch of cases where a consumer may never bind to the SharedQ and
rightfully so. For example, in a join between 3 tables which requires
redistribution of tuples, a consumer may not at all bind to the SharedQ because
it the top level outer side did not produce any tuples to join against the
redistributed inner node.

This patch avoids the unnecessary FATAL errors, but what we still do not do
nicely is to avoid the 10s timeout (as currently set for producer). So while
queries, as included in the test case, will finally return success, it will
unnecessarily add a 10s delay in the response time. This is a TODO.

src/backend/commands/portalcmds.c
src/backend/executor/producerReceiver.c
src/backend/pgxc/squeue/squeue.c
src/backend/tcop/pquery.c
src/include/pgxc/squeue.h
src/test/regress/expected/xl_join.out [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/xl_join.sql [new file with mode: 0644]

index 448e1ddce1d469f149794eba3290804aa9418eb7..8c84c812acdd8bd324c41cd07a886f9754c92d74 100644 (file)
@@ -322,7 +322,7 @@ PortalCleanup(Portal portal)
                                                         * consumers.
                                                         */
                                                        if (queryDesc->squeue)
-                                                               SharedQueueUnBind(queryDesc->squeue);
+                                                               SharedQueueUnBind(queryDesc->squeue, true);
                                                        FreeQueryDesc(queryDesc);
                                                }
                                        }
index b2d22e07d9116c79915866be1d1727cb100f0f15..145788a11b6f14f2c43d3008a85558b54a3f8f71 100644 (file)
@@ -174,7 +174,7 @@ producerDestroyReceiver(DestReceiver *self)
 
        /* wait while consumer are finishing and release shared resources */
        if (myState->squeue)
-               SharedQueueUnBind(myState->squeue);
+               SharedQueueUnBind(myState->squeue, false);
        myState->squeue = NULL;
 
        /* Release workspace if any */
index 3d9b9100cf28097750842a129b1408fc24010121..56c91782e5bdcfc65817c5f95d0b5ab5fe97c0d5 100644 (file)
@@ -1200,7 +1200,7 @@ SharedQueueFinish(SharedQueue squeue, TupleDesc tupDesc,
  * set the tuplestore parameter to NULL.
  */
 void
-SharedQueueUnBind(SharedQueue squeue)
+SharedQueueUnBind(SharedQueue squeue, bool failed)
 {
        SQueueSync *sqsync = squeue->sq_sync;
        int                     wait_result = 0;
@@ -1216,6 +1216,7 @@ CHECK:
        {
                int i;
                int c_count = 0;
+               int unbound_count = 0;
 
                /* check queue states */
                for (i = 0; i < squeue->sq_nconsumers; i++)
@@ -1223,7 +1224,7 @@ CHECK:
                        ConsState *cstate = &squeue->sq_consumers[i];
                        LWLockAcquire(sqsync->sqs_consumer_sync[i].cs_lwlock, LW_EXCLUSIVE);
                        /* is consumer working yet ? */
-                       if (cstate->cs_status == CONSUMER_ACTIVE)
+                       if (cstate->cs_status == CONSUMER_ACTIVE && failed)
                                cstate->cs_status = CONSUMER_ERROR;
                        if (cstate->cs_status != CONSUMER_DONE)
                        {
@@ -1232,13 +1233,17 @@ CHECK:
                                SetLatch(&sqsync->sqs_consumer_sync[i].cs_latch);
                                /* producer will continue waiting */
                                ResetLatch(&sqsync->sqs_producer_latch);
+
+                               if (cstate->cs_pid == 0)
+                                       unbound_count++;
                        }
 
                        LWLockRelease(sqsync->sqs_consumer_sync[i].cs_lwlock);
                }
                if (c_count == 0)
                        break;
-               elog(DEBUG1, "Wait while %d squeue readers finishing", c_count);
+               elog(DEBUG1, "Wait while %d squeue readers finish, %d squeue readers "
+                               "not yet bound", c_count, unbound_count);
                /* wait for a notification */
                wait_result = WaitLatch(&sqsync->sqs_producer_latch,
                                                                WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT,
@@ -1294,7 +1299,7 @@ CHECK:
        LWLockRelease(SQueuesLock);
        elog(DEBUG1, "Finalized squeue");
        if (wait_result & WL_TIMEOUT)
-               elog(FATAL, "Timeout while waiting for Consumers finishing");
+               elog(WARNING, "Timeout while waiting for Consumers finishing");
 }
 
 
index 454f42721716c011d564daec33dbc9fa2d0a475f..6b749612e23dc05b9ce06a95599ad595eb669fc3 100644 (file)
@@ -714,7 +714,7 @@ PortalStart(Portal portal, ParamListInfo params,
                                                PG_CATCH();
                                                {
                                                        /* Ensure SharedQueue is released */
-                                                       SharedQueueUnBind(queryDesc->squeue);
+                                                       SharedQueueUnBind(queryDesc->squeue, true);
                                                        queryDesc->squeue = NULL;
                                                        PG_RE_THROW();
                                                }
index ad1873e0a089d3e4cd1fbdb2a50e9bf90bd5908f..c0a9807e43d71b4b5b0a6ee9e17206cb6e760030 100644 (file)
@@ -41,7 +41,7 @@ extern void SharedQueuesInit(void);
 extern void SharedQueueAcquire(const char *sqname, int ncons);
 extern SharedQueue SharedQueueBind(const char *sqname, List *consNodes,
                                List *distNodes, int *myindex, int *consMap);
-extern void SharedQueueUnBind(SharedQueue squeue);
+extern void SharedQueueUnBind(SharedQueue squeue, bool failed);
 extern void SharedQueueRelease(const char *sqname);
 extern void SharedQueuesCleanup(int code, Datum arg);
 
diff --git a/src/test/regress/expected/xl_join.out b/src/test/regress/expected/xl_join.out
new file mode 100644 (file)
index 0000000..7c70576
--- /dev/null
@@ -0,0 +1,40 @@
+CREATE TABLE xl_join_t1 (val1 int, val2 int);
+CREATE TABLE xl_join_t2 (val1 int, val2 int);
+CREATE TABLE xl_join_t3 (val1 int, val2 int);
+INSERT INTO xl_join_t1 VALUES (1,10),(2,20);
+INSERT INTO xl_join_t2 VALUES (3,30),(4,40);
+INSERT INTO xl_join_t3 VALUES (5,50),(6,60);
+EXPLAIN SELECT * FROM xl_join_t1
+       INNER JOIN xl_join_t2 ON xl_join_t1.val1 = xl_join_t2.val2 
+       INNER JOIN xl_join_t3 ON xl_join_t1.val1 = xl_join_t3.val1;
+                                                      QUERY PLAN                                                      
+----------------------------------------------------------------------------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)  (cost=475.52..5209.87 rows=288579 width=24)
+   ->  Merge Join  (cost=475.52..5209.87 rows=288579 width=24)
+         Merge Cond: (xl_join_t3.val1 = xl_join_t1.val1)
+         ->  Sort  (cost=158.51..164.16 rows=2260 width=8)
+               Sort Key: xl_join_t3.val1
+               ->  Seq Scan on xl_join_t3  (cost=0.00..32.60 rows=2260 width=8)
+         ->  Materialize  (cost=317.01..775.23 rows=25538 width=16)
+               ->  Merge Join  (cost=317.01..711.38 rows=25538 width=16)
+                     Merge Cond: (xl_join_t2.val2 = xl_join_t1.val1)
+                     ->  Remote Subquery Scan on all (datanode_1,datanode_2)  (cost=100.00..161.98 rows=2260 width=8)
+                           Distribute results by H: val2
+                           ->  Sort  (cost=287.89..293.54 rows=2260 width=8)
+                                 Sort Key: xl_join_t2.val2
+                                 ->  Seq Scan on xl_join_t2  (cost=0.00..32.60 rows=2260 width=8)
+                     ->  Sort  (cost=158.51..164.16 rows=2260 width=8)
+                           Sort Key: xl_join_t1.val1
+                           ->  Seq Scan on xl_join_t1  (cost=0.00..32.60 rows=2260 width=8)
+(17 rows)
+
+SELECT * FROM xl_join_t1
+       INNER JOIN xl_join_t2 ON xl_join_t1.val1 = xl_join_t2.val2 
+       INNER JOIN xl_join_t3 ON xl_join_t1.val1 = xl_join_t3.val1;
+ val1 | val2 | val1 | val2 | val1 | val2 
+------+------+------+------+------+------
+(0 rows)
+
+DROP TABLE xl_join_t1;
+DROP TABLE xl_join_t2;
+DROP TABLE xl_join_t3;
index 5169c3887d57d17c673cdb3f5988a061fcafb770..2bad0ff1a5d133f6385d06011babe2717d7012e6 100644 (file)
@@ -137,7 +137,7 @@ 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
+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
 
 #known bugs
 test: xl_known_bugs
index 59f4012a29a737943f572243f572c5569bc9f55f..f404c36b00dd2f975cd9983e29d96706f5bdef05 100644 (file)
@@ -185,3 +185,4 @@ test: xl_plan_pushdown
 test: xl_functions
 test: xl_limitations
 test: xl_user_defined_functions
+test: xl_join
diff --git a/src/test/regress/sql/xl_join.sql b/src/test/regress/sql/xl_join.sql
new file mode 100644 (file)
index 0000000..ed2829d
--- /dev/null
@@ -0,0 +1,20 @@
+
+CREATE TABLE xl_join_t1 (val1 int, val2 int);
+CREATE TABLE xl_join_t2 (val1 int, val2 int);
+CREATE TABLE xl_join_t3 (val1 int, val2 int);
+
+INSERT INTO xl_join_t1 VALUES (1,10),(2,20);
+INSERT INTO xl_join_t2 VALUES (3,30),(4,40);
+INSERT INTO xl_join_t3 VALUES (5,50),(6,60);
+
+EXPLAIN SELECT * FROM xl_join_t1
+       INNER JOIN xl_join_t2 ON xl_join_t1.val1 = xl_join_t2.val2 
+       INNER JOIN xl_join_t3 ON xl_join_t1.val1 = xl_join_t3.val1;
+
+SELECT * FROM xl_join_t1
+       INNER JOIN xl_join_t2 ON xl_join_t1.val1 = xl_join_t2.val2 
+       INNER JOIN xl_join_t3 ON xl_join_t1.val1 = xl_join_t3.val1;
+
+DROP TABLE xl_join_t1;
+DROP TABLE xl_join_t2;
+DROP TABLE xl_join_t3;