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]>
Mon, 1 Feb 2016 09:14:43 +0000 (10:14 +0100)
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 cbb7a190c4e08288d20ce44b691eced62283f17a..51d0caa61b2901b4eee843c62aee90b9b1110c83 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 0f8b5f9f06526598ba7fc9cb65c7a4a9954df5ad..a0d86b0784e323dc4bbdd6b8ada680082f4ccb2e 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 148d30b8ec09c6f2d6b6358faf574d08caec5789..0a20d1134b025356eff06b122029a44363d18ee1 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 2568d6d641c833a32a6913e870d3787aa8f259fb..f2fffaa6925ffe4f23b3068306360bf11f116f06 100644 (file)
@@ -187,3 +187,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;