Parallel Index-only scan

Started by Rafia Sabihabout 9 years ago23 messages
#1Rafia Sabih
rafia.sabih@enterprisedb.com
1 attachment(s)

Hello all,
This is to propose a patch for enabling parallel index-only scans. With the
patch of parallel index scan around [1]/messages/by-id/CAOGQiiOneen9WEppO6V_myKpQ97CrjBQJ0Pv7ri0rxmMYvLcTg@mail.gmail.com -- Regards, Rafia Sabih EnterpriseDB: http://www.enterprisedb.com/, adding the mechanism for
parallelising index-only scans makes sense. Without this mechanism for the
queries preferring index-only scans, it is likely that at higher scale
parallel index or parallel seq scan serve as cheaper alternative to
index-only scans and then query performance might suffer because of the
added processing of index or seq scans.

Performance
-----------------
Consider the performance of a simple query on TPC-H schema,

explain analyse select count(*) from lineitem where l_shipdate < date
'1995-01-03';

Without parallel index-only scan, parallel seq scan got picked and it took
around 23 seconds for the query to execute,

Finalize Aggregate (cost=651586.63..651586.64 rows=1 width=8) (actual
time=22853.872..22853.873 rows=1 loops=1)
-> Gather (cost=651586.21..651586.62 rows=4 width=8) (actual
time=22853.684..22853.864 rows=5 loops=1)
Workers Planned: 4
Workers Launched: 4
-> Partial Aggregate (cost=650586.21..650586.22 rows=1 width=8)
(actual time=22850.489..22850.489 rows=1 loops=5)
-> Parallel Seq Scan on lineitem (cost=0.00..618021.73
rows=13025795 width=0) (actual time=0.035..20553.495 rows=10342437 loops=5)
Filter: (l_shipdate < '1995-01-03'::date)
Rows Removed by Filter: 13656485
Planning time: 0.225 ms
Execution time: 22855.196 ms

However, with parallel index-only scan, it took only 8.5 seconds,

Finalize Aggregate (cost=568883.69..568883.70 rows=1 width=8) (actual

time=8548.993..8548.993 rows=1 loops=1)
-> Gather (cost=568883.27..568883.68 rows=4 width=8) (actual
time=8548.789..8548.976 rows=5 loops=1)
Workers Planned: 4
Workers Launched: 4
-> Partial Aggregate (cost=567883.27..567883.28 rows=1 width=8)
(actual time=8541.929..8541.929 rows=1 loops=5)
-> Parallel Index Only Scan using idx_l_shipdate on
lineitem (cost=0.57..535318.78 rows=13025795 width=0) (actual
time=0.113..5866.729 rows=10342437 loops=5)
Index Cond: (l_shipdate < '1995-01-03'::date)
Heap Fetches: 0
Planning time: 0.266 ms
Execution time: 8569.735 ms

The effect of parallel index-only scan can be seen more in some more
complex queries where parallelism is enabled till top of the tree, e.g,
following query takes 118 ms on head,

explain analyse select sum(l_extendedprice * l_discount) as revenue,
avg(o_orderkey) from orders, lineitem where o_orderkey < 10000 and
o_orderkey = l_orderkey group by l_shipmode order by revenue

Sort (cost=24396.44..24396.45 rows=7 width=75) (actual

time=118.823..118.825 rows=7 loops=1)
Sort Key: (sum((lineitem.l_extendedprice * lineitem.l_discount)))
Sort Method: quicksort Memory: 25kB
-> HashAggregate (cost=24396.23..24396.34 rows=7 width=75) (actual
time=118.749..118.786 rows=7 loops=1)
Group Key: lineitem.l_shipmode
-> Nested Loop (cost=1.13..24293.11 rows=10312 width=27)
(actual time=0.096..73.198 rows=9965 loops=1)
-> Index Only Scan using orders_pkey on orders
(cost=0.56..46.48 rows=2578 width=4) (actual time=0.072..1.663 rows=2503
loops=1)
Index Cond: (o_orderkey < 10000)
Heap Fetches: 0
-> Index Scan using idx_lineitem_orderkey on lineitem
(cost=0.57..6.45 rows=296 width=31) (actual time=0.018..0.023 rows=4
loops=2503)
Index Cond: (l_orderkey = orders.o_orderkey)
Planning time: 1.062 ms
Execution time: 118.977 ms

With parallel index-only scan, the performance improves to 40 ms,

Sort (cost=7191.33..7191.35 rows=7 width=75) (actual time=40.475..40.476

rows=7 loops=1)
Sort Key: (sum((lineitem.l_extendedprice * lineitem.l_discount)))
Sort Method: quicksort Memory: 25kB
-> Finalize GroupAggregate (cost=7190.78..7191.23 rows=7 width=75)
(actual time=40.168..40.451 rows=7 loops=1)
Group Key: lineitem.l_shipmode
-> Sort (cost=7190.78..7190.85 rows=28 width=75) (actual
time=40.105..40.127 rows=35 loops=1)
Sort Key: lineitem.l_shipmode
Sort Method: quicksort Memory: 29kB
-> Gather (cost=7187.22..7190.11 rows=28 width=75)
(actual time=39.344..39.983 rows=35 loops=1)
Workers Planned: 4
Workers Launched: 4
-> Partial HashAggregate (cost=6187.22..6187.31
rows=7 width=75) (actual time=25.981..26.011 rows=7 loops=5)
Group Key: lineitem.l_shipmode
-> Nested Loop (cost=1.13..6084.10 rows=10312
width=27) (actual time=0.139..16.352 rows=1993 loops=5)
-> Parallel Index Only Scan using
orders_pkey on orders (cost=0.56..27.14 rows=644 width=4) (actual
time=0.082..0.366 rows=501 loops=5)
Index Cond: (o_orderkey < 10000)
Heap Fetches: 0
-> Index Scan using
idx_lineitem_orderkey on lineitem (cost=0.57..6.45 rows=296 width=31)
(actual time=0.020..0.025 rows=4 loops=2503)
Index Cond: (l_orderkey =
orders.o_orderkey)
Planning time: 1.170 ms
Execution time: 40.898 ms

Test configuration and machine detail:
--------------------------------------------------
TPC-H: scale facto : 20
work_mem : 64MB
shared buffer : 1GB
max_parallel_workers_per_gather : 4
Machine : IBM POWER, 4 socket
machine with 512 GB RAM.
random_page_cost = seq_page_cost = 0.1
We kept random and seq page cost same since warm cache environment was
ensured, thus, keeping a value of random_page_cost that is higher than
seq_page_cost doesn't makes much sense in this setup.
Also, some additional indexes were build, for lineitem table l_shipdate,
l_shipmode, and l_returnflag, on orders table index is added for o_comment
and o_orderdate individually.

The point to note here is that with parallel index-only scan, not only the
heap fetches are saved but also the aggregates/sort can be pushed down to
workers and thus the total time of query can be improved. Clearly, the
performance of queries improved significantly with this new operator and
considering the changes required after parallel index scan patches is less
if evaluated against the improvement in performance it offers.

Attached file:
------------------
1. parallel_index_only_v1.patch

This patch is to be applied over parallel index scan [1]/messages/by-id/CAOGQiiOneen9WEppO6V_myKpQ97CrjBQJ0Pv7ri0rxmMYvLcTg@mail.gmail.com -- Regards, Rafia Sabih EnterpriseDB: http://www.enterprisedb.com/.

* Thanks to my colleagues Dilip Kumar and Amit Kapila for their support and
feedback.

[1]: /messages/by-id/CAOGQiiOneen9WEppO6V_myKpQ97CrjBQJ0Pv7ri0rxmMYvLcTg@mail.gmail.com -- Regards, Rafia Sabih EnterpriseDB: http://www.enterprisedb.com/
/messages/by-id/CAOGQiiOneen9WEppO6V_myKpQ97CrjBQJ0Pv7ri0rxmMYvLcTg@mail.gmail.com
--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v1.patchapplication/octet-stream; name=parallel_index_only_v1.patchDownload
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 59dc394..34c569e 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -36,6 +36,8 @@
 #include "utils/resowner.h"
 #include "utils/snapmgr.h"
 
+#include "optimizer/cost.h"
+
 
 /*
  * We don't want to waste a lot of memory on an error queue which, most of
@@ -946,7 +948,11 @@ ParallelWorkerMain(Datum main_arg)
 	char	   *asnapspace;
 	char	   *tstatespace;
 	StringInfoData msgbuf;
-
+	int i =0;
+	while (i)
+	{
+		sleep(10);
+	}
 	/* Set flag to indicate that we're initializing a parallel worker. */
 	InitializingParallelWorker = true;
 
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index c55b7c4..08329b0 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -198,6 +198,11 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+									  e->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -254,6 +259,11 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+										   d->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -701,6 +711,10 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 45566bd..8257f43 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -276,7 +276,17 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
  */
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
-{
+{	
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * if we are here to just update the scan keys, then don't reset parallel
+	 * scan
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +306,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
+
+		index_rescan(node->ioss_ScanDesc,
+				 	node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+		if (reset_parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
 
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -534,33 +550,99 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	{
 		indexstate->ioss_RuntimeContext = NULL;
 	}
-
-	/*
-	 * Initialize scan descriptor.
-	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+	if (!node->scan.plan.parallel_aware)
+	{
+		/*
+	 	 * Initialize scan descriptor.
+	 	 */
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
 												indexstate->ioss_RelationDesc,
 												estate->es_snapshot, NULL,
 												indexstate->ioss_NumScanKeys,
 									 indexstate->ioss_NumOrderByKeys, false);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+		 * index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
 					 indexstate->ioss_ScanKeys,
 					 indexstate->ioss_NumScanKeys,
 					 indexstate->ioss_OrderByKeys,
 					 indexstate->ioss_NumOrderByKeys);
-
+	}
 	/*
 	 * all done.
 	 */
 	return indexstate;
 }
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+					  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+													 estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+						   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 54a8a2f..5d963f5 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1098,8 +1098,8 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 		 * If appropriate, consider parallel index scan.  We don't allow
 		 * parallel index scan for bitmap scans.
 		 */
-		if (index->amcanparallel &&
-			!index_only_scan &&
+		if ((index->amcanparallel ||
+			index_only_scan) &&
 			rel->consider_parallel &&
 			outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index d63d194..143d8cd 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -14,6 +14,7 @@
 #ifndef NODEINDEXONLYSCAN_H
 #define NODEINDEXONLYSCAN_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
@@ -23,4 +24,8 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 17d712a..b8f22da 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1397,6 +1397,8 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	/* This is needed for parallel index scan */
+	Size	ioss_PscanLen;
 } IndexOnlyScanState;
 
 /* ----------------
#2rafia.sabih
rafia.sabih@enterprisedb.com
In reply to: Rafia Sabih (#1)
Re: Parallel Index-only scan

Please find the attached file for the latest version of patch.

parallel_index_only_v2.patch
<http://postgresql.nabble.com/file/n5936010/parallel_index_only_v2.patch&gt;

--
View this message in context: http://postgresql.nabble.com/Parallel-Index-only-scan-tp5934352p5936010.html
Sent from the PostgreSQL - hackers mailing list archive at Nabble.com.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Robert Haas
robertmhaas@gmail.com
In reply to: rafia.sabih (#2)
Re: Parallel Index-only scan

On Fri, Dec 23, 2016 at 12:04 AM, rafia.sabih
<rafia.sabih@enterprisedb.com> wrote:

Please find the attached file for the latest version of patch.

parallel_index_only_v2.patch
<http://postgresql.nabble.com/file/n5936010/parallel_index_only_v2.patch&gt;

We want to have the patch actually attached, not just stored on nabble.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#3)
Re: Parallel Index-only scan

Robert Haas wrote:

On Fri, Dec 23, 2016 at 12:04 AM, rafia.sabih
<rafia.sabih@enterprisedb.com> wrote:

Please find the attached file for the latest version of patch.

parallel_index_only_v2.patch
<http://postgresql.nabble.com/file/n5936010/parallel_index_only_v2.patch&gt;

We want to have the patch actually attached, not just stored on nabble.

I think the problem is that Nabble removes the attachment before
resending the email to the list. The OP should be posting directly
instead of via Nabble.

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#3)
Re: Parallel Index-only scan

Robert Haas <robertmhaas@gmail.com> writes:

On Fri, Dec 23, 2016 at 12:04 AM, rafia.sabih
<rafia.sabih@enterprisedb.com> wrote:

Please find the attached file for the latest version of patch.
parallel_index_only_v2.patch
<http://postgresql.nabble.com/file/n5936010/parallel_index_only_v2.patch&gt;

We want to have the patch actually attached, not just stored on nabble.

Or in words of one syllable: please do not use nabble to post to the
community mailing lists. Their habit of stripping attachments is not
the only evil thing about them (although it's the only one I remember
details of ATM).

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#5)
Re: Parallel Index-only scan

On Fri, Dec 23, 2016 at 3:03 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Or in words of one syllable: please do not use nabble to post to the
community mailing lists.

Many of those words have two syllables, and one has four.

Anyhow, I think three castigating emails from committers in a span of
62 minutes is probably enough for the OP to get the point, unless
someone else REALLY feels the need to pile on.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Robert Haas (#6)
1 attachment(s)
Re: Parallel Index-only scan

Extremely sorry for the inconvenience caused, please find the attached file
for the latest version of the patch.

On Sat, Dec 24, 2016 at 1:41 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Dec 23, 2016 at 3:03 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Or in words of one syllable: please do not use nabble to post to the
community mailing lists.

Many of those words have two syllables, and one has four.

Anyhow, I think three castigating emails from committers in a span of
62 minutes is probably enough for the OP to get the point, unless
someone else REALLY feels the need to pile on.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v2.patchapplication/octet-stream; name=parallel_index_only_v2.patchDownload
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index baa69fc..79eaf79 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -1394,6 +1394,9 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
 			blkno = _bt_parallel_seize(scan, &status);
 			if (status == false)
 			{
+				/* release the previous buffer, if pinned */
+				BTScanPosUnpinIfPinned(so->currPos);
+
 				BTScanPosInvalidate(so->currPos);
 				return false;
 			}
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index c55b7c4..08329b0 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -198,6 +198,11 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+									  e->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -254,6 +259,11 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+										   d->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -701,6 +711,10 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 45566bd..78304d1 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -21,6 +21,9 @@
  *		ExecEndIndexOnlyScan		releases all storage.
  *		ExecIndexOnlyMarkPos		marks scan position.
  *		ExecIndexOnlyRestrPos		restores scan position.
+ *		ExecIndexOnlyScanEstimate		estimates DSM space needed for parallel index-only scan
+ *		ExecIndexOnlyScanInitializeDSM 		initialize DSM for parallel index-only scan
+ *		ExecIndexOnlyScanInitializeWorker 	attach to DSM info in parallel worker
  */
 #include "postgres.h"
 
@@ -277,6 +280,16 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * if we are here to just update the scan keys, then don't reset parallel
+	 * scan
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +309,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
+
+		index_rescan(node->ioss_ScanDesc,
+					node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+		if (reset_parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
 
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -534,33 +553,99 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	{
 		indexstate->ioss_RuntimeContext = NULL;
 	}
-
-	/*
-	 * Initialize scan descriptor.
-	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+	if (!node->scan.plan.parallel_aware)
+	{
+		/*
+		 * Initialize scan descriptor.
+		 */
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
 												indexstate->ioss_RelationDesc,
 												estate->es_snapshot, NULL,
 												indexstate->ioss_NumScanKeys,
 									 indexstate->ioss_NumOrderByKeys, false);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+		 * index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
 					 indexstate->ioss_ScanKeys,
 					 indexstate->ioss_NumScanKeys,
 					 indexstate->ioss_OrderByKeys,
 					 indexstate->ioss_NumOrderByKeys);
-
+	}
 	/*
 	 * all done.
 	 */
 	return indexstate;
 }
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+					  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+													 estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+						   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 54a8a2f..5d963f5 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1098,8 +1098,8 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 		 * If appropriate, consider parallel index scan.  We don't allow
 		 * parallel index scan for bitmap scans.
 		 */
-		if (index->amcanparallel &&
-			!index_only_scan &&
+		if ((index->amcanparallel ||
+			index_only_scan) &&
 			rel->consider_parallel &&
 			outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index d63d194..143d8cd 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -14,6 +14,7 @@
 #ifndef NODEINDEXONLYSCAN_H
 #define NODEINDEXONLYSCAN_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
@@ -23,4 +24,8 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 17d712a..b8f22da 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1397,6 +1397,8 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	/* This is needed for parallel index scan */
+	Size	ioss_PscanLen;
 } IndexOnlyScanState;
 
 /* ----------------
#8Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Rafia Sabih (#7)
1 attachment(s)
Re: Parallel Index-only scan

Rebased patch of parallel-index only scan based on the latest version of
parallel index scan [1]/messages/by-id/CAA4eK1LiNi7_Z1%25 2BPCV4y06o_v%3DZdZ1UThE%2BW9JhthX4B8uifnA%40mail.gmail.com is attached.

[1]: /messages/by-id/CAA4eK1LiNi7_Z1%25 2BPCV4y06o_v%3DZdZ1UThE%2BW9JhthX4B8uifnA%40mail.gmail.com
2BPCV4y06o_v%3DZdZ1UThE%2BW9JhthX4B8uifnA%40mail.gmail.com

On Sat, Dec 24, 2016 at 7:55 PM, Rafia Sabih <rafia.sabih@enterprisedb.com>
wrote:

Extremely sorry for the inconvenience caused, please find the attached
file for the latest version of the patch.

On Sat, Dec 24, 2016 at 1:41 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

On Fri, Dec 23, 2016 at 3:03 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Or in words of one syllable: please do not use nabble to post to the
community mailing lists.

Many of those words have two syllables, and one has four.

Anyhow, I think three castigating emails from committers in a span of
62 minutes is probably enough for the OP to get the point, unless
someone else REALLY feels the need to pile on.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v3.patchapplication/octet-stream; name=parallel_index_only_v3.patchDownload
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 3238cc7..a640c4b 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -29,6 +29,7 @@
 #include "executor/nodeForeignscan.h"
 #include "executor/nodeSeqscan.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeIndexonlyscan.h"
 #include "executor/tqueue.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
@@ -198,6 +199,11 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+									  e->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -254,6 +260,11 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+										   d->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -701,6 +712,10 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 45566bd..78304d1 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -21,6 +21,9 @@
  *		ExecEndIndexOnlyScan		releases all storage.
  *		ExecIndexOnlyMarkPos		marks scan position.
  *		ExecIndexOnlyRestrPos		restores scan position.
+ *		ExecIndexOnlyScanEstimate		estimates DSM space needed for parallel index-only scan
+ *		ExecIndexOnlyScanInitializeDSM 		initialize DSM for parallel index-only scan
+ *		ExecIndexOnlyScanInitializeWorker 	attach to DSM info in parallel worker
  */
 #include "postgres.h"
 
@@ -277,6 +280,16 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * if we are here to just update the scan keys, then don't reset parallel
+	 * scan
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +309,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
+
+		index_rescan(node->ioss_ScanDesc,
+					node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+		if (reset_parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
 
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -534,33 +553,99 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	{
 		indexstate->ioss_RuntimeContext = NULL;
 	}
-
-	/*
-	 * Initialize scan descriptor.
-	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+	if (!node->scan.plan.parallel_aware)
+	{
+		/*
+		 * Initialize scan descriptor.
+		 */
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
 												indexstate->ioss_RelationDesc,
 												estate->es_snapshot, NULL,
 												indexstate->ioss_NumScanKeys,
 									 indexstate->ioss_NumOrderByKeys, false);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+		 * index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
 					 indexstate->ioss_ScanKeys,
 					 indexstate->ioss_NumScanKeys,
 					 indexstate->ioss_OrderByKeys,
 					 indexstate->ioss_NumOrderByKeys);
-
+	}
 	/*
 	 * all done.
 	 */
 	return indexstate;
 }
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+					  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+													 estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+						   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 54a8a2f..5d963f5 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1098,8 +1098,8 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 		 * If appropriate, consider parallel index scan.  We don't allow
 		 * parallel index scan for bitmap scans.
 		 */
-		if (index->amcanparallel &&
-			!index_only_scan &&
+		if ((index->amcanparallel ||
+			index_only_scan) &&
 			rel->consider_parallel &&
 			outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index d63d194..143d8cd 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -14,6 +14,7 @@
 #ifndef NODEINDEXONLYSCAN_H
 #define NODEINDEXONLYSCAN_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
@@ -23,4 +24,8 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 4013986..a364cf0 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1397,6 +1397,8 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	/* This is needed for parallel index scan */
+	Size	ioss_PscanLen;
 } IndexOnlyScanState;
 
 /* ----------------
#9Amit Kapila
amit.kapila16@gmail.com
In reply to: Rafia Sabih (#8)
Re: Parallel Index-only scan

On Wed, Dec 28, 2016 at 12:18 PM, Rafia Sabih
<rafia.sabih@enterprisedb.com> wrote:

Rebased patch of parallel-index only scan based on the latest version of
parallel index scan [1] is attached.

[1]
/messages/by-id/CAA4eK1LiNi7_Z1+PCV4y06o_v=ZdZ1UThE+W9JhthX4B8uifnA@mail.gmail.com

The link for the latest version is wrong, the correct link is:
/messages/by-id/CAA4eK1KthrAvNjmB2cWuUHz+p3ZTTtbD7o2KUw49PC8HK4r1Wg@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Rahila Syed
rahilasyed90@gmail.com
In reply to: Amit Kapila (#9)
1 attachment(s)
Re: Parallel Index-only scan

Hello,

On applying the patch on latest master branch and running regression tests
following failure occurs.
I applied it on latest parallel index scan patches as given in the link
above.

***
/home/rahila/postgres/postgres/src/test/regress/expected/select_parallel.out
2017-01-03 14:06:29.122022780 +0530
---
/home/rahila/postgres/postgres/src/test/regress/results/select_parallel.out
2017-01-12 14:35:56.652712622 +0530
***************
*** 92,103 ****
explain (costs off)
select sum(parallel_restricted(unique1)) from tenk1
group by(parallel_restricted(unique1));
! QUERY PLAN
! ----------------------------------------------------
HashAggregate
Group Key: parallel_restricted(unique1)
! -> Index Only Scan using tenk1_unique1 on tenk1
! (3 rows)

  set force_parallel_mode=1;
  explain (costs off)
--- 92,105 ----
  explain (costs off)
    select  sum(parallel_restricted(unique1)) from tenk1
    group by(parallel_restricted(unique1));
!                             QUERY PLAN
! -------------------------------------------------------------------
   HashAggregate
     Group Key: parallel_restricted(unique1)
!    ->  Gather
!          Workers Planned: 4
!          ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
! (5 rows)

IIUC, parallel operation being performed here is fine as parallel
restricted function occurs above Gather node
and just the expected output needs to be changed.

Thank you,
Rahila Syed

Attachments:

regression.diffsapplication/octet-stream; name=regression.diffsDownload
*** /home/rahila/postgres/postgres/src/test/regress/expected/select_parallel.out	2017-01-03 14:06:29.122022780 +0530
--- /home/rahila/postgres/postgres/src/test/regress/results/select_parallel.out	2017-01-12 14:35:56.652712622 +0530
***************
*** 92,103 ****
  explain (costs off)
  	select  sum(parallel_restricted(unique1)) from tenk1
  	group by(parallel_restricted(unique1));
!                      QUERY PLAN                     
! ----------------------------------------------------
   HashAggregate
     Group Key: parallel_restricted(unique1)
!    ->  Index Only Scan using tenk1_unique1 on tenk1
! (3 rows)
  
  set force_parallel_mode=1;
  explain (costs off)
--- 92,105 ----
  explain (costs off)
  	select  sum(parallel_restricted(unique1)) from tenk1
  	group by(parallel_restricted(unique1));
!                             QUERY PLAN                             
! -------------------------------------------------------------------
   HashAggregate
     Group Key: parallel_restricted(unique1)
!    ->  Gather
!          Workers Planned: 4
!          ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
! (5 rows)
  
  set force_parallel_mode=1;
  explain (costs off)

======================================================================

#11Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Rahila Syed (#10)
1 attachment(s)
Re: Parallel Index-only scan

On Thu, Jan 12, 2017 at 5:39 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:

Hello,

On applying the patch on latest master branch and running regression tests
following failure occurs.
I applied it on latest parallel index scan patches as given in the link
above.

***
/home/rahila/postgres/postgres/src/test/regress/expected/select_parallel.out
2017-01-03 14:06:29.122022780 +0530
---
/home/rahila/postgres/postgres/src/test/regress/results/select_parallel.out
2017-01-12 14:35:56.652712622 +0530
***************
*** 92,103 ****
explain (costs off)
select sum(parallel_restricted(unique1)) from tenk1
group by(parallel_restricted(unique1));
! QUERY PLAN
! ----------------------------------------------------
HashAggregate
Group Key: parallel_restricted(unique1)
! -> Index Only Scan using tenk1_unique1 on tenk1
! (3 rows)

set force_parallel_mode=1;
explain (costs off)
--- 92,105 ----
explain (costs off)
select  sum(parallel_restricted(unique1)) from tenk1
group by(parallel_restricted(unique1));
!                             QUERY PLAN
! -------------------------------------------------------------------
HashAggregate
Group Key: parallel_restricted(unique1)
!    ->  Gather
!          Workers Planned: 4
!          ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
! (5 rows)

IIUC, parallel operation being performed here is fine as parallel restricted
function occurs above Gather node
and just the expected output needs to be changed.

True, fixed it, please find the attached file for the latest version.

Thank you,
Rahila Syed

Thanks a lot for the review Rahila.
--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v4.patchapplication/octet-stream; name=parallel_index_only_v4.patchDownload
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index a474970..0d00d2b 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -29,6 +29,7 @@
 #include "executor/nodeForeignscan.h"
 #include "executor/nodeSeqscan.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeIndexonlyscan.h"
 #include "executor/tqueue.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
@@ -200,6 +201,11 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+									  e->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -256,6 +262,11 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+										   d->pcxt);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -735,6 +746,10 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
+
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 55c27a8..15a73fd 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -21,6 +21,9 @@
  *		ExecEndIndexOnlyScan		releases all storage.
  *		ExecIndexOnlyMarkPos		marks scan position.
  *		ExecIndexOnlyRestrPos		restores scan position.
+ *		ExecIndexOnlyScanEstimate		estimates DSM space needed for parallel index-only scan
+ *		ExecIndexOnlyScanInitializeDSM 		initialize DSM for parallel index-only scan
+ *		ExecIndexOnlyScanInitializeWorker 	attach to DSM info in parallel worker
  */
 #include "postgres.h"
 
@@ -277,6 +280,16 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * if we are here to just update the scan keys, then don't reset parallel
+	 * scan
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +309,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
+
+		index_rescan(node->ioss_ScanDesc,
+					node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+		if (reset_parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
 
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -534,33 +553,99 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	{
 		indexstate->ioss_RuntimeContext = NULL;
 	}
-
-	/*
-	 * Initialize scan descriptor.
-	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+	if (!node->scan.plan.parallel_aware)
+	{
+		/*
+		 * Initialize scan descriptor.
+		 */
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
 												indexstate->ioss_RelationDesc,
 												estate->es_snapshot, NULL,
 												indexstate->ioss_NumScanKeys,
 									 indexstate->ioss_NumOrderByKeys, false);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+		 * index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
 					 indexstate->ioss_ScanKeys,
 					 indexstate->ioss_NumScanKeys,
 					 indexstate->ioss_OrderByKeys,
 					 indexstate->ioss_NumOrderByKeys);
-
+	}
 	/*
 	 * all done.
 	 */
 	return indexstate;
 }
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+					  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+													 estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+						   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 5380b87..59fb561 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1098,8 +1098,8 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 		 * If appropriate, consider parallel index scan.  We don't allow
 		 * parallel index scan for bitmap scans.
 		 */
-		if (index->amcanparallel &&
-			!index_only_scan &&
+		if ((index->amcanparallel ||
+			index_only_scan) &&
 			rel->consider_parallel &&
 			outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index 4018af2..524e13f 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -14,6 +14,7 @@
 #ifndef NODEINDEXONLYSCAN_H
 #define NODEINDEXONLYSCAN_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
@@ -23,4 +24,8 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 58ec9d2..cb441f2 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1418,6 +1418,8 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	/* This is needed for parallel index scan */
+	Size	ioss_PscanLen;
 } IndexOnlyScanState;
 
 /* ----------------
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 18e21b7..741e2bd 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -92,12 +92,14 @@ explain (costs off)
 explain (costs off)
 	select  sum(parallel_restricted(unique1)) from tenk1
 	group by(parallel_restricted(unique1));
-                     QUERY PLAN                     
-----------------------------------------------------
+                            QUERY PLAN                             
+-------------------------------------------------------------------
  HashAggregate
    Group Key: parallel_restricted(unique1)
-   ->  Index Only Scan using tenk1_unique1 on tenk1
-(3 rows)
+   ->  Gather
+         Workers Planned: 4
+         ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
+(5 rows)
 
 set force_parallel_mode=1;
 explain (costs off)
#12Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Rafia Sabih (#11)
1 attachment(s)
Re: Parallel Index-only scan

On Fri, Jan 13, 2017 at 2:19 PM, Rafia Sabih
<rafia.sabih@enterprisedb.com> wrote:

On Thu, Jan 12, 2017 at 5:39 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:

Hello,

On applying the patch on latest master branch and running regression tests
following failure occurs.
I applied it on latest parallel index scan patches as given in the link
above.

***
/home/rahila/postgres/postgres/src/test/regress/expected/select_parallel.out
2017-01-03 14:06:29.122022780 +0530
---
/home/rahila/postgres/postgres/src/test/regress/results/select_parallel.out
2017-01-12 14:35:56.652712622 +0530
***************
*** 92,103 ****
explain (costs off)
select sum(parallel_restricted(unique1)) from tenk1
group by(parallel_restricted(unique1));
! QUERY PLAN
! ----------------------------------------------------
HashAggregate
Group Key: parallel_restricted(unique1)
! -> Index Only Scan using tenk1_unique1 on tenk1
! (3 rows)

set force_parallel_mode=1;
explain (costs off)
--- 92,105 ----
explain (costs off)
select  sum(parallel_restricted(unique1)) from tenk1
group by(parallel_restricted(unique1));
!                             QUERY PLAN
! -------------------------------------------------------------------
HashAggregate
Group Key: parallel_restricted(unique1)
!    ->  Gather
!          Workers Planned: 4
!          ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
! (5 rows)

IIUC, parallel operation being performed here is fine as parallel restricted
function occurs above Gather node
and just the expected output needs to be changed.

True, fixed it, please find the attached file for the latest version.

Please find the attached file rebased patch of parallel index-only
scan on the latest Parallel index-scan patch [1]/messages/by-id/CAA4eK1L-gb0Fum3mQN4c5PWJXNE7xs7pzwMDWsrDYLucKqvJ2A@mail.gmail.com -- Regards, Rafia Sabih EnterpriseDB: http://www.enterprisedb.com/.

[1]: /messages/by-id/CAA4eK1L-gb0Fum3mQN4c5PWJXNE7xs7pzwMDWsrDYLucKqvJ2A@mail.gmail.com -- Regards, Rafia Sabih EnterpriseDB: http://www.enterprisedb.com/
--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v5.patchapplication/octet-stream; name=parallel_index_only_v5.patchDownload
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index cb91cc3..ea670ed 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -29,6 +29,7 @@
 #include "executor/nodeForeignscan.h"
 #include "executor/nodeSeqscan.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeIndexonlyscan.h"
 #include "executor/tqueue.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
@@ -202,6 +203,10 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+									  e->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -258,6 +263,10 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+										   d->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -737,6 +746,9 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index ddef3a4..9e65d06 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -21,6 +21,11 @@
  *		ExecEndIndexOnlyScan		releases all storage.
  *		ExecIndexOnlyMarkPos		marks scan position.
  *		ExecIndexOnlyRestrPos		restores scan position.
+ *		ExecIndexOnlyScanEstimate	estimates DSM space needed for
+ *						parallel index-only scan
+ *		ExecIndexOnlyScanInitializeDSM 	initialize DSM for parallel
+ *						index-only scan
+ *		ExecIndexOnlyScanInitializeWorker attach to DSM info in parallel worker
  */
 #include "postgres.h"
 
@@ -277,6 +282,15 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * if we are here to just update the scan keys, then don't reset parallel
+	 * scan
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +310,15 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
 
+		index_rescan(node->ioss_ScanDesc,
+					node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+		if (reset_parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -538,29 +557,121 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	/*
 	 * Initialize scan descriptor.
 	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+	if (!node->scan.plan.parallel_aware)
+	{
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
 												indexstate->ioss_RelationDesc,
 												estate->es_snapshot,
 												indexstate->ioss_NumScanKeys,
 											indexstate->ioss_NumOrderByKeys);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+		 * index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
 					 indexstate->ioss_ScanKeys,
 					 indexstate->ioss_NumScanKeys,
 					 indexstate->ioss_OrderByKeys,
 					 indexstate->ioss_NumOrderByKeys);
-
+	}
 	/*
 	 * all done.
 	 */
 	return indexstate;
+ }
+
+/* ----------------------------------------------------------------
+ *		Parallel Index-only Scan Support
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanEstimate
+ *
+ *	estimates the space required to serialize index-only scan node.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+					  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+											estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeDSM
+ *
+ *		Set up a parallel index-only scan descriptor.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+						   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeWorker
+ *
+ *		Copy relevant information from TOC into planstate.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
 }
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 1905917..6231774 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1050,8 +1050,8 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 		 * If appropriate, consider parallel index scan.  We don't allow
 		 * parallel index scan for bitmap scans.
 		 */
-		if (index->amcanparallel &&
-			!index_only_scan &&
+		if ((index->amcanparallel ||
+			index_only_scan) &&
 			rel->consider_parallel &&
 			outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index 4018af2..5bb44c2 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -15,6 +15,7 @@
 #define NODEINDEXONLYSCAN_H
 
 #include "nodes/execnodes.h"
+#include "access/parallel.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
@@ -23,4 +24,9 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+/* Support functions for parallel index-only scans */
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index b565f28..02a519c 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1418,6 +1418,7 @@ typedef struct IndexScanState
  *		ScanDesc		   index scan descriptor
  *		VMBuffer		   buffer in use for visibility map testing, if any
  *		HeapFetches		   number of tuples we were forced to fetch from heap
+ *		ioss_PscanLen		   This is needed for parallel index scan
  * ----------------
  */
 typedef struct IndexOnlyScanState
@@ -1436,6 +1437,7 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	Size	ioss_PscanLen;				/* This is needed for parallel index scan */
 } IndexOnlyScanState;
 
 /* ----------------
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 140fb3c..c919e59 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -92,12 +92,14 @@ explain (costs off)
 explain (costs off)
 	select  sum(parallel_restricted(unique1)) from tenk1
 	group by(parallel_restricted(unique1));
-                     QUERY PLAN                     
-----------------------------------------------------
+                            QUERY PLAN                             
+-------------------------------------------------------------------
  HashAggregate
    Group Key: parallel_restricted(unique1)
-   ->  Index Only Scan using tenk1_unique1 on tenk1
-(3 rows)
+   ->  Gather
+         Workers Planned: 4
+         ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
+(5 rows)
 
 -- test parallel index scans.
 set enable_seqscan to off;
#13tushar
tushar.ahuja@enterprisedb.com
In reply to: Rafia Sabih (#12)
3 attachment(s)
Re: Parallel Index-only scan

On 01/19/2017 05:37 PM, Rafia Sabih wrote:

Please find the attached file rebased patch of parallel index-only
scan on the latest Parallel index-scan patch [1].

We did some testing of this feature and written few testcases. PFA the
sql script(along with the expected .out files)

In addition we have generated the LCOV (code coverage) report and
compared the files which are changed for this.
You can see the numbers for "with_patch" V/s "with_patch+TestCases"
(.pdf file is attached)

--
regards,tushar
EnterpriseDB https://www.enterprisedb.com/
The Enterprise PostgreSQL Company

Attachments:

pios.pdfapplication/pdf; name=pios.pdfDownload
%PDF-1.4
% ����
4
0
obj
<<
/Type
/Catalog
/Names
<<
/JavaScript
3
0
R
>>
/PageLabels
<<
/Nums
[
0
<<
/S
/D
/St
1
>>
]
>>
/Outlines
2
0
R
/Pages
1
0
R
>>
endobj
5
0
obj
<<
/Creator
(��Google Sheets)
/Title
()
>>
endobj
6
0
obj
<<
/Type
/Page
/Parent
1
0
R
/MediaBox
[
0
0
792
612
]
/Contents
7
0
R
/Resources
8
0
R
/Annots
10
0
R
/Group
<<
/S
/Transparency
/CS
/DeviceRGB
>>
>>
endobj
7
0
obj
<<
/Filter
/FlateDecode
/Length
9
0
R
>>
stream
x��\]�����b�&�����CP$ErC���[8�N���G��q�Ix�&-��_�Rg(�]���q�<{�3G�p���y�^������0������~��+���r����Z���_P�@�����xC�����P�v�v?������;��\2^�H���ri����*���$e�d���lLE� vc�g���4���0@�f8����{NC��^�3��fY�S���`"�wQO��A��u_�������������u_Pr
t�;8P���������cv��9$E�#�����n�����R��z�:5��o��T��l�Q�S����!��5��5�H�
��mo��|)zqp9��#V�l��X������n|v?�>��������?1�Q����7~c�����%C�:�X
M�����y4�5~\��Y[�f���&���a���ph�[*�`|
�����]Wa����V0*���"`2]�� ��F�4IAh�+���3`�4J�f@
�uDAg���
W���X0��K3 �:���� ���.kq�r�F��H�nR ��*������4�"�'{W������f ����p���=\m�q���m�8��?�
����'pX��'�	�%2u���1`� �����4���G�N^o��
�a� ���AI���DI��*�"�=�l*#Q%!�zZ�����x��!~�dS94	9���(�������&8@Dy�S�K�&��{d�O�t��N����jS��������0r)i*"b��Aa@���7�9�`���L]'(
��ph ��D
d@IbQl�F���mK����34�������n�OE�U:h���i,�R�	�3[�����!C�
DB�H�(Yp�F����G����$4���-A����i���J����B��0���M���L��I
�fA�C98��!�����qA����"�H�������f�pLY��E�iH�A{��=�%��$\�<�X�t���Q�Enc��,��E'��6��N��DA�A@�$h��6��NP�!Dy��3�8D2�ddA�-SF%��kl��9����8t(����]���hy\��\�BY���&�gpV�<.�|@� � �@4dpV�<.�j�X	�P*J�:2	�QTE#��*%I&�6$�@�ddIH����${�Q��P�t�N���i�,	����G�gQMcB�����Xhp,l8R����JeTA�Y�I%�W �%�$�*�$�^���N���+�����	\B#�Z$��X�H���%!`�V�b1UaP����IK����@�L��V�%*�P�e:�D-bZ�,(��V����x��t��K��XU PCG���#J,�Ua�/��wep�t�2�b�(kQL���_"�2�$$��js�R�"�,����K��(S P�js���"�,����K��h[ P�ks���"�,=��c�/�b]�@���C���[��1�Q�DLK����9���"�Z��a�/�B-#KB��N����H�ulam�N�V�bZ��@������QfqL���_"����2S��cSP�0�j!��_"����2W���Q�"�N�Q�D�edIH����-1D�Y:����_"�E����#�ds@D��0��~�����U�K${�"�,��t�K��[ PVq8��a�(�a��_"����2W���Q�"�N�Q�D�edIv��6�9 ���1��~�:�E�a��x�U�B���|:�>C+\���_Z�����>;Kj�PxiMo�1p������A���2v���@�x\���Q����\"�zj��HL���N,t��(�c�D��4�����q�X��Q��"r�,�iQ�l5��q�X��Q��"r���P 1Au��4{��=�K���=*$&�x\�	zP�UD1L0��x�
P�H��"���L1{,"���0��2��5
T�b�f�P��Ye�@��������������j�(�?8R��Be��_�K���6�x}�!�'&�_��ks@���J�F�i�s"1A�9 �i�e{�Uf
dXO������X��3��iV�)�e=1 T�b�f�P�gYe�@����HLPm�u�=C�^�*3�YO������X��3�����w�B=%�D�Dmm�7�5�� ��������	���N�g(�3�2S �zb@$&�6�:���l���L���9����js@���J�F��;X
I=1 T�b�f�P�'1��H����	���N�g(��Xe�@����HLPm�u�=C��a��Y�s"1A�9 �i�e{�Uf
�XO������X��3�����w��zb@$&�6�:���lO��Gl]��� Q"Y�b�f�P��Ye�@-��9�� ��o����/��wm{�Ye[�����o��[��A,��qDhSI���-�#��@2���)�%��T5=��5h���<-U�	���.�'�58D�K�N�������1�`�S��E-�?�{]z�]tG��4��N�%������6���)@�YZ:�9���i��XN��3�9���X�������xG,tXq����E����,J �Zat�,�]�b%��e�d(�K�,,C�bd�h��9��S �,}7�,=�nD��t-�n�.���C���e�;l3��,�����vn��j����2��}W�e��;�]�-�]m�w�Y�����j��w�@�5b����k�2��)>����1����x��UKp������;����������������./����J��+����������v�a�����4�?ln5����������w���=��w����n5�������y�<l^�>_�o���-�����4o�5_5O��^��������="����[U�mh��d����pU������-����6�j>������`�c������;|���o^-���P��{���,�hz���."�a�}���1�C���~�5e��y���0�����W������E�Vp�_-����sH��tH�����b���}��r����k��W�����g?k�������+��y����
�s��9r&����p��n���b��w�E���|��a�Y?�O�s����n
��T?V�ycy~-{���mL�gE�<�������!?K�g\�W>i=n>k��?O�7�|�����O����\/����>p����K��D�������]L?��{'zs��e�Vu���33�/�h_����J�2����9�e��W����0��"���w�����h����T�p��<��0���p���/h��g��������u��g���4�����x�,�J�<=�~+�y��pn�C�����3�*������������{�C�,��U�@��}^��?
��G�Z<�����W4���c�5s����W��<�[�/��5oU������k���W��'�����{}&���0�G����h�.	���[���G������HW���0��<d_8 �r�p�
�/��M�`(@�W�H�+�����.a��rq]a��"����il���n��^����rW��`0��^H�+bB*��_����
���_(V���v�U�Zx�<�mBD[���������/?��#|t�C����N�����0N�����o>����[���{�t�����//���@�/������0�������WaMp�G���`�
���x���h��<}<Z>X�/�����2�!���.W�:;W��w���$�a�q�F�O���=�u8@��7fE�s������wW{��1Ko��1���������jVk|cC���������TX����Y���p�i#�����OkXU~��/����:�&�M�6���(,-������Yq��o���a�|?8�������Ml�����P\������]������`�|/8���[�^`��� �����l�s�.�����`�|/8,{/�Zv�'�z���[O�o6��9i1��X����{����#�C{^)�E���j�7�r���q�?����k��If�7�	g��b�����n;/xB�^�����Yi��wy58���6>p����|���>��V�_��^���E@�����k��)�������9��lP�����~D�

endstream
endobj
9
0
obj
4253
endobj
10
0
obj
[
]
endobj
11
0
obj
<<
/CA
0.14901961
/ca
0.14901961
>>
endobj
8
0
obj
<<
/Font
<<
/Font1
12
0
R
/Font2
13
0
R
>>
/Pattern
<<
>>
/XObject
<<
>>
/ExtGState
<<
/Alpha0
11
0
R
>>
/ProcSet
[
/PDF
/Text
/ImageB
/ImageC
/ImageI
]
>>
endobj
12
0
obj
<<
/Type
/Font
/Subtype
/Type0
/BaseFont
/MUFUZY+ArialMT
/Encoding
/Identity-H
/DescendantFonts
[
14
0
R
]
/ToUnicode
15
0
R
>>
endobj
13
0
obj
<<
/Type
/Font
/Subtype
/Type0
/BaseFont
/MUFUZY+Arial-BoldMT
/Encoding
/Identity-H
/DescendantFonts
[
18
0
R
]
/ToUnicode
19
0
R
>>
endobj
15
0
obj
<<
/Filter
/FlateDecode
/Length
22
0
R
>>
stream
x�}R�n�0��+|L`C�H�JU�C*�{I���9��5�!m)�x������h_>��y��{]����C�x
���Dp������;�X��4�����Y���=$��O|�`��X��
����s_\�����cV�@
=+��:����	�v��A����p�8�fto`pJ�W�,��*x�V�����TuC0�_�d���XG�:q,��=���*����v�'1�ClS�4��-D�(Mm������"vva(�5�vd��-6WRP�t:i�ZI��-~2�����iCI����-a�a��`�Q�o+.�2��<����G��������C�Z8������ym�+
endstream
endobj
17
0
obj
<<
/Filter
/FlateDecode
/Length
23
0
R
>>
stream
x���	��0\U}M�L�t�}������1�.���-��-�,���}�����" ���x�
F�,H1�� �xE�DP4�����|�����$����U�����W�~�
�!-E�&��0�L���C��#���:��E
�>����M�
�!�	����&O�t�{���,�k�O�w���[a�x������9?���P��Ys&N�|���O�=�����=�����?yn���{a�w�-�F!(a�%��(�P�K('�6;=w��[�5\��/mD����U���O�U��.��~��/<�b�s��h,�������?��\�D��A��k�h7��`�+����W��TT�.G��t���C��w�h���Kscr���=�^@��������D��}+�)��	�x�C�������^���O��h=������YA�c��`t�#��d�%��\��s���~8+��4���5xI�r�s�����mE;���~��`�p*�|�
�
t%<O�=��e��e�c`����9���Mt'�o��!t��������Q0����/����[����z#'��A�m��+�J<�&edy���l�cW�MB�����?���8�!�9��9� {4��I�����7X�'���N�!���!����o���M��	������>��o��=�p|-�����A����	r9If���i�<�W|o����w	+�{��1���?d����[��=,��?���'��������;��	<
��;�}�Y�o�-��a�7����#~"��)�_��'7���'�!�&���W�e���k����Vrk����+��9�s7��ia���u������!����k+o�4�����d�f[rE>��0`����'�o��#@q��{���r|��g�y���r�����K�������(sgRCz�����L&��Z�i!�����9����\#7�[�-����w�O��qg�����
_��i>����7�O�_�_
��w���"�W���?���e�0i��(= ����5u�mG;Q�?|�[������I"�'�z�&q�	P*��W��q)n/!��!��\ O�3�n0�G���y7����:���$����p�[D��|':�V�H-�����p��#�gX��A��'�K�0��_��	cP�{����oG�I?��s�5@�C�� F�n�.�82���9��$B'��W�G�$~*�U���K�"pE�p�X.��[d:��xp"�&x�Z\�9����Fn������
��{F���������nG+���2�H��OE�R�Q�n��n|�K@�����{7�������t1
$�z�=r�
�<~
H���q$iES'���N�j46�"Z���n�=�:�<X�[w�����F|w�64��s>�������?���&��������A�5�~	;�	����Gh����}�]
v�]���S~=\��CU�!dK�?7��34<�R�+hZn���$M�20������������Bnrv:��������=F�Q#/7�/����^�={�TWu����s��LyYiI:U�,J�c�H8�}^�[�\N�aWd�$
<G0�����oN75���Wt���	�0�CCSs��_|Ns�����L����3
�L��L���P]��x�d��`�d��>���&��'<��k��H��~�i}���)����M�V�k���bW�$�LV:U�-�@;@����-8pf	���� �
�j'��k%��4s�~&5>�_�H"���������%{7�2���u�,�i�X7���i���-�V�i���M����	��4shz�����X��.���g���G#��~��q��z��x���c:M������T������5���#����aL3����'�Oe>��d?��4#�,'{'����S^���^���rGQ�_|��1�Ds}$�0�ot���z���]|�S�M7�����#0�����xu;f1Q�J ����8�dL��'�&�D�'������U��`F�7�}�Vk�h;��YHi���!����o.n��oS��)������L���������x���TqS+I&�jq���0����^���D�N����v��c���������44�&zd�u�7�Yji��)	������k�����4����^����px�y|�����c����n��v������=����fO�1\��!��Q �q�'��1�f>�DF��Z%P%k����Z�f��$����N�����e�a6��\��E�
������8r����E������o����1�x�f4
83�Zs�z��i6e}�	@fS~��#y��(uv���n����x��M�'���^��k��������s�5Y����}o������4�����[�x��-^5b��]�
�F��J0����aK1�+���Z	m��t'Nw�@������]�},eGy���'�b��lVF[���Ym�x��`m����>#�t���
��	f���b�J�	=�{>��;o�����I7�����!�"�,�P�����4[8i%�
W0�
C���
w��������A�6�\8�p$L���Bh�L����G���(#�J�o+z�F��>�w�-�8<�����
f�3�'O���@��O������z(�Xw�����s�vm�.�>���qUY,S���]q�4@����U����
@@����[������K*'vb��fw"�����,�����U�@���4.}^U��5�iWa�?����#���\q�\��al��P������Q8�������c���{w�u�����,\���D������3=�&����5�@�|�4z�;`�z����h�n$Q�A��|C=�����C����O����������umu��vI����^�'|	���<�����������t�1{�s9n%3�l��
#4����`<��D$,��B���h��/P���]��y�����rR�[�osl?�W�?���$uH!u���[��o��y�M}#���]�j�|�<H�O��Erh�.��>���%��O����Q�in3G�����@�R�����xt�o��\�M����V
�3��zpc&����imvLH��,���Q�/y]��4T@\��r8�G�v{�Qbk����}!H�%���j��y��6���{TT���AkI��B��P�1^��T5 ��-.E#����A[�����A�P%�A�~(�"[����i��H��E��2�[#d����mA��Ak��~��l�!-
�����`f�����rG�!������r��d�$�<�|W��DFz��������f�'zf�f��"����M�[]+���G���G�����?�����������6~0�I���HVw�1�5���g0E���B�����tm� �F.�#*'��F�@��6�������3'��`�<�����F���a(

���T�hn��~�O#��%i�F9]���"I5��
7m]�{�{�����]�/�����W5��0�/}e��l�H6�������Of����g|;}�������)���W1G�j�=!b�b>�9C��g�K�d����2��v���P�P,"L�kk�h��!���6tF^QF^NF^0�F��E!�Z��Z��r�{	8.B�����L��g����N���:T_��z-�'j��h"���T��{�*r����F>�����m�-.������(��_%�B�w!	8�b����_��B���
Hc�+�d]S��8J�4�����5
��W�Q

�b1z4u����>m���f8��5��x!h����� ��$�����n��H{����
��������!�b^�F��nm>�����0��z�I�����������	{���7moE�+
�����I�[��z�q�q��
;��wzHD�jZL�;X<�l��a��1E������7
��a���p�ScZ+y~�P��8��>�C���C�U�U������ �/eV�Y��H�=
�����'s�0nv�b0�����*�����@
��o<��)�@���9��L�<��{�F�8?��)_"�(�;���"Q*������x�|H=�����n��	�����;s�K�?;.�����M�w���Sf�����C�����<�jBW���s_�~��n����o�S �u��P����"Ly#��\�T@[�b�R��E�XYT(S��#���(���4�'������`%�!wm}�

&�����V���F��RA����*�O�F�)�]�����N���.��PW{����*B�cDgw�N^��/�sJm��0������w��Q�L3d��T����)v��b����9qR�/��S%�T��TiA���4Fi-M�IO��W��v
���[C����'��}��]F��h���#�?K��4����c�/Nj�XLZ����k������7�@�h-��"���6�����K6?{{� ����u���k�-��y��3�L�sm���������V6����S���'��|y|��S�N�D���������Z����� �U�sr���P��"#&�EV��8g�����j����lL��Zb��f3�)�m�X-�Zf���c���o9�A� ��<��F����I�OT�m��r���8T^�^#�!x�<���V�V2e� (FAa�b)��*�-3/�V��P%�(Y--M�Hk]�2�]�V#pW��#�bz
�v�k�vg+^�������8M��N�BcjC;]w�N���y;�y�r�`��Q��T0�� m�7�U�\Q�Z�/(���hb�s����:��u�ZGQ��j��hh��;���B5�J��%uN��������8�����_�v�����3 �n�I����(���N7��Lh0#�N�B�P���C7���e�0&2O����nV��l��Il�/�B�l��8�Tb>_�MU��������H
��g�%�����J�U�Rm�A�P!S�fJ�����E�������C��#6�t��9�����
�F�(>������uz�N�
������
N�t��j����QQ��������m����k�/B%��J��$AK����{p
r����znun�o���b�r�xi�CL�0<4�P@[i����SAL��y�'4��l:�2��84����8�W�u��lyu�5kJ7�O>n�9t����m�}����j�������C����do�=��7�z�J��@_>�C��p���>�p������-��Xd�l'�����������$�T�%q\�i�.\��c��Kc��U���P��J��F�b��h��L��{���?��a�V�Im#��N3C��d�������G�gr��I��I����w�VD?�����8��Sf��a@�Q(�H�@I<O�:�0��8#�=j;�R�f�S����,�,�J�SVj��(K�Hxj'�}�� �z����1&bc���(���	,	���~zm�OGh%��2�����:��IS�1eh��8��(����R����D5��Z:�"�k=�^��d�����r���G]O.�3��������=��='^�����������n}����ep�������������x ^�7�f���?i|�����6o�N��^B*�k8��������<���B0/;�G("�2��#a�m��w4�i<��a3/(��3#�F��|�����_Nm�Z��4���h�@D�(%���=&p��dO�������{����y8���k����k��4�5�&\@I����E-W=�����N����W���e���������g_�8)��f�e�ub��P%;�f�y9%�"&����a�_fIvv9��+��t���oq�H�3U����Q�;�1Q(����(X���7��������
��� GRM�Ygq�<���t������B|����PN���� v����@Ds �X,�e)�|��
��Fm���+}L����^x>�3�W�`*Vz��q��J���/_u�.�vt;^�/����w������k��e����}�w�w����x�n��J��OS�*�;P,�0�
�qL[b$f��#L�������LE��I��L���,pq�5.�\���Z��F�[�	� 0A&`��9�������,f����>�����������Bc������zv�62$R�*/k�^k�?�k��FQ>��N�X�M�xF���v�9�1w�{�}=s����g>�8{���W��v�=S���u���6�z����H�c36�l��G�*����C�{�7x���w���r�����C_\z���x����
��X%I���5���N����hge��lp�_@!��V'M5�L�D;s�5+��r�������A���B0NR:�&g}MM��SF)%���(\g�=�Wd��1���9��9�^4c�H��.���>*�>8�����nLKtc��O�Q����7�q��3����3���^��O�����Q�+<�o$��_������OM��=�&|ol�SxO�k��3q��������^e�DRB��$�V0�������4��.�{�L��BQh�X��>�V��p7�E��a;E3=l�����/6�VP��	��!��(e3���G��}m�">M���<����F��pc����V�e����ji�"`����i�����}��x����u��_���<�<p��[���+G�;/,�e����?�Gh��0h���:��gb��>��������_f��r/W����O�U
\�\�|�exzq^@�$������+�L~Dh$������z��ffU�h��T�8(�<�5<x�������3|/^d�`�"�%�8�����y1����!d���2����13%=��m]���5O��=@�{��������m�S���!$4�O-!')�n�V�|K�������O%m���,���?����6��<�zl�0��t�r��
�~pe����WvV�NvK�N��<��[����	�oS�L�	����hSm��&m�V{K8 ��Niv���G�a�4{��O�?�:e������+����i%��MtH!��.��K/"G�|����/\%��9���5dds|eL�nl�k7��8�,qW�����Z���a�}�gn�;����Id��T"��\~dRO
����C���(X_>Y���,����d[3u���s�����B�l1�96|��������S���@��������K�*���'��KD�#U c>�E���|����Q�J�}�?���K��Gv�|�������R�Ix<���O$3
6E�H��'����n�D4-,X���E��_p/����M�0:V����.�
�r�T/�������F��	3ns��^��s��n�����N������<M^m-�e��_i��B�����Eb���]W�ts�0@X~�I�����t�����;�����b�1����T\�M
@���Y������8 ���bK���n|@JS�D|^7I|���f{�d���7�>��W\�����m�|��/V<�7B�~w�7��?���}������~��k��V��X}����Z�(�l6IB�S���$�����Z�]W�*Q�*/��X<�=�g�x>]q��3�Sg[�S@��[D3����E���k�xa�u��`S��s�X>��z��V����5��|����������W���d�WaD ����	e��q){�$�����O�I�NH�������B��a����gR.�?����CQ-�����}r�8inF����mS�l��<��C�p����|����\q1J�$�b����c1sr`��KR���*��5g��90Q��"����2��a���c�7����0�0�0���
V�+�rRB���^D����3y\h��n�R!�oF�k�g�g���OF��h(����������N��jA�]�����%�+R	���C�	T�A�c��	���|G�������:�2Q�����z�� 2����
�>��
���?����~���_�9�s%&�q�2R�
n;:�.|��>�Z���������/������N��u:�{�Zt��"#D9V��������P����J�Z��p�\��9����4���m=/e9�mU���Ss[Zfn�)s[3����3,W����V�,A��zm@���D�>C����C�Z�	f��rB0�!�X���!����c�,�aC�=�H#�[��Vkl�7���]k��2���_�^��}����#����9�i80����lq��KFB"&9F�C
�-��X�����"����1z��h4e�X����N��������\���>r���.����H �y�����)��y�����P���#����F��=c�����D�
�#Z(�q��]�Y�����G������X���,�J�V�fB2#����M��x$*���sK�������b�s����}fN�q6�l�Y���"�Rh�����?���b�h(��w���1]
n�WPlh"^�������%�c��������G}�������l������Yv��������;{W��6l�Y�8��)��6��)#6Y��%���k�k��������w[(�(������6�]��a�C[�Ac�F'���p<��_8�2��e*C���Us��6u�<���h�L���j�C�=�$j���q@	`�������H�C�g=��m���*|���u]��G��tO�1��l[�+^�d�]>�J�q���4M��.T����������`~z��aV�����D-�-���BJ���z"7�_�-��TI
W��])
*�W�����AWpM�=g�N�m��, m%�dh7O6���-���u
���bR�������}S�*��G'G�f�g�3�S���������n�n,^�Z������v���]|W�!��#�X~]C�D�I��tN#Tv�����d�P����=I��N��N	~�R��r�:����c,��h�C�idY����/btJ;U����"6I�9"�Tq����6(�=z��:1��M[4��p���b|�f���vI��_%[n�lq��:����Q!�t
=m�{���%� ����8��j���������GR.	u�[`Q^�����[�h�c�:M�v2uO0�
]� ���=�q������P�&7���0��i�7��,�>qz�Nu��n����a�.��>}�����W�]�nj~��'�x��[W�{���?������������&2=��<�7�����y����ZU5����7�xh���(gu������!��
��"������"�����:���G�U��,�7���b�J��x;��*:a��\���������%��[�(�T�w��X�Q�l��z��jO���"��"t��'[���F��W������	>�_�JQ����U�<�������Z���G�W����jc�uzyS����������T_�����uwz1�r���k��C�J��������i��&�Qn�'��F��R�0P�T�W���W�WT��5d���gnr�t���Q�1���vb^�,�tKx�������h������ig�)<������9��N���I����I���+��,��i����L�dO�3�Z����`������������(����l�6Y�3d�N���HT�)K%�)��E�7�YV��y-��<M���H��P�������Vr��,1�Z�x�KzsZ����D��p�i�t�Z��%�����%jq-]"h����@N ,�d���I�J&*����DR(��D�2���$'8).E����D������"�-��=�$%�y��$[0x�r�2Lf����X��d[���n���y����� f��D2���r�I��WS]b��/#L��}>�?�Ls��$f�N��&���y��W��<2W�[�dQAs�����zy�&��D���3������M�5��/��l�����S�
�.m��w�@c�U�o9u��K{�OJ�Z���+��z����\�T�DC�-�6,8\�B��O��IaaQ�*�;:�pm���S���
7��1�F�u��Y�4�
���
?v		���M����Gs���P���v�]�0�5L�")�Vsh>'/��V|Q�=hYAK{���b�]|��5�ao�/���l��q].A��0�h;5S�,����v�A�sM[�t���N��QF.zr3��?0��0�P���3_���A�m����q=�9L��Ly��R8f��������0#=L��6;�O��������p(6�GGg���|��em������Z)9�?��\>��k>��H�_

,9
%�J8�O6�^j�����������3�T�z��W^���W��m�z`�o/�~���I���Q�|���"{X�w�n�s
��Y����2�]��L��:�������]vL���C�;j��Q���>�F&1�I,gA�WC����L����-4#1@v��hO����@��)�8y�[�>�=v���2�L�f7:��K����v���X���p����9�%.����Lwa^ik-��G�;���eG���[���h�U��1�\a��%U�5�1Z*�g
1��h\�R6X��;S�������������������p�T/��|/�^&1�$�+���R�H��v%k��8?��[E����?M�����^[�5�� R���8`�?�fK���JS\����~y$���_���_
7���]����g����<���
&�6?�9���}��� s�-}2G���X�^M��j_U���D�!#���#�S�$a�<���W�������q�q�w����3��/,���@��I�L����^�FH����WF�QF�S��������S�>p�5���#:�EB���L�T���~'�����N��J�4���5�����:�%J��t��T$�LS9����u&�tz;�G�I�Q�N6KZi
M�����~��3F
�b��J��{�C�gRN�)}�8)����=)f��fHHaF3�X�������Rn.���� q��������f^#H���@���bwL����7�x���G*���_���6�v�3+�Zs���1�z���y�?q���oyw?�HA#�@���:�2�(�#��F�Qe�������65J��:f\M��([J��X8�=���{��F/w_��::�=;<!z�x��9����@`���?��������h�*�M^�\bI�}�*
�a����2��W�Y0�����Uk��J
;�y��J.)�nV�.���T��nwR3���n�2�U�0���k��b�(.�����zS�;�{���)+�l��"%:�k���'�6��3�:�N��Z>	Z�6�.�2������|K,����`�p�-^��vW|����w�����?�l�{���#d����{o�����B��\��4����{~xE�i/RJ���}
�C��
��n���w���W�B���"Yk������;Zc�f?�������(�,yY����*����e������F&F�M�&&&�5U,�8Rr"�m��=�}�dKKi�#1�������a)�����Jn74!u)������JUu\������(atS����F�)�4�Wv��
&L:��C�I����~mJz]X��je�K�X����Yc���.�BE��R
�2�(,��:����s���z�P�|��MLv�����f\El�P��l�u1Y�
e*&����@6�����Qb0����]gy,�E?V_������-13�Tjj�t�7�;�1��������W����?���������������x�����z��1���n���h��}��k[z~��n�W��}{�����R�e%B�Qy������f���#��k�~�n�gM�@�:`���0rE�kW�pX���3WN��H�FU������������+���K'V����k1�R��d2b-{�D�	[�(+�W���`��!~*5���W7�O��\��?�����������&����5 
Fu��I�=�x"�G�:���k��A�G4�RD�I�<�7`X��!1/�dt�b����3m�Z���8E��r��Vm�F4��e�[BU���������^��+[��w�/��8s�}u`�~�P��O��'���m������aLn�� 	�d��b�;$��|,������^��,vA4o�Zd��j���2����m���6sqa��j�����������M�������S�����fy���|J��\(����O����9Y)����x��"Gg����DA�QJ	����7�������?����������Ah�������
����������
�BI�b�)��c��a�3�/�RF��1zv�[l���������C�||����0��4�L�0s/��C���p�j��������Sp�hq����
gDNv�'M����`�p�5���Q��
q�qO��;��]R-S[����X-"���C�)��2F���Q9�}.J/�8)����V�)��C��A#5�����u������1�+����6�[Q���(J�l��fKI�W�D��S��E���m�R%�fR�V�2d�g��"��g��f�a��qagH�3a7�UH!�	k$�����E�
��i7�2������zcB}d��@��A!�����)]�k�fv��'�������z��.��x�6�^��4[���cu>���q���#rP��AT�k0�1���V���tYEA-l��g�-��[`����2�����5QK�f��n>�������9�f����|g�v����6�z�z�XW����%b���X���12s��=�$�����_eg���f�Y"�>�7goj�D
o�^�0@��l���E�+��� �.�N�����"�c.f��a��=��mu�������y]#j�%
O�	�P�N	\�0WX*���B8S��;1�����~�}�E��z��z����1��	d�R�C�8���y�����*hP.��e{?��SpWK��v��k2I��y�"E���3�
,�E- ba(���E- bapX9B�����e?j���<��Y��tP����@h��lW�S�1���������p&N�xRF�2�%cQ�G
?	��pHS�����Iagj��u���A����0sg�l�i��sj��e�a�JLvpmq��:��f�L���� ��A�u�a�vaVJ�E?"TX1s)��]E� t��P�HU��>��]�	�d
F��zH!�"�c"��?D�#�&:��'����G&I:M)X�j��lK��B6#w���k4_r���6����_�����t�`�F���x���z�^��n�g�N���-}��e�l)7��X�����L�g��h�o?���������e��A�z������~���;�J�����z���G��[n��������I~�����!�V�s�K�)��G���,�[��������\����N��
5���:N�h��9��@�����2���li;��������{;#��S���\�i���]�G��Lw���n���>$H�V�����dnpC�9�/�9R��3��3�3��3yw�E���>��9�����;��|^��3�?5���
��?��>�L��d�%�,is����uY�)���ZZ��R�y�����Q%�#�r�@+�����g�iJK��+�����o��n��- +n�}�C����y��	�f^E!�w��� �1�ha�}�0&S(��%%� ^a-6����m�j�����&�O���'�������������$m�{�R�f��EA��)�T�u��&��Y%�%������R��������#�t��OH,���.[i���/���0`��,NUw�0�4).q�����~���1��mv2rq:����b�p���	�FQF,0��LZ"�&2�;*�b!���,��d�5LC7��Xt�m^�������Z1Cct���G#����e��+�,{��_-��z�}��7���������'wm]�b���Wn%\r�M������8��w�y�o��6vev:��p�~�X��:i�j5�>�'��2G����[A�����q[�@��U��"
�k��"3l3������}����?	�;�=;���I>�e|5|/�?�6V;n�{AV��N���#�u��3dD�"�%�B��P�ak��4)K>��"n��j���S�P�������-��J#)��k�z���SE��aY3 kgS������:�����Bg~�b)g�,-T8�G_�jOeN���K	��BK�}^�ZB��u�����zh���3n����t�_���_��p���t�W��_�{����{�j;�=p�;���G���D��w}j��`��I��������yQ�m�MV=��"���l��"���a[Q��=�������w���vK�C� rE�T�i3�!v�V����oA�cZ���t%-EY��:��Z��}?E�|�hi����� /�~�����^wY���\����g�]�����M����1��Np[3]8���jn��	����[�&�����ik��	$-��@_6��hD����|���xt���������=��x�S�@8�2����!���a%8�6N����s�Sg�f�3���jK���E���u/�4�'�'�.L.,^Z�3�	�C��V<��ye�����K���H�K-K���Pl���G�����)���������
��}��sA�c�B,��

�m
��PahN��_z DB�
�=������k��D���w�f���y��,��9�j�;�+�U@
�>�7�6���V��C���v��q�8dx�����5Th��fM�:�����+CqzU���!w�Ga�w�k���~�`����Gk��r�'����0T��v�H��
���	z��0A�������n����n�ML��i�2z���'���t\�Z
����
��.&�\l��8��R�%�^'u���	f����>����<B����;h�����X�'2�y4����=Is����yl�����,�i_�0���S,)x+����<'���K�:A��n���������)\Z"+b���B��Z>�bmV1S�<�l���/�eh�s>h����>*R�.�Lj��gg~��~t�$�Y�ou�s��[jR?;�n��=�q����������+#��>:z���}�/���?����`�����XTZ��������]�#-�(�U�/7��k^���8�=)��.�_�Z��e��d��'��h
[�����}���0�U��kr������.�a�"5��j��s�����I�+-��J<�g��,��K"[�_|�+��K��}��>�h��UT��]��2�Fi7������)?��A���G����c���:����*�-�Cn�/03�z��J�����^O%ZxP���*�/��}�'S{�i������k�4+{����
�������;���](L�s�@5�{��.��,��:���6���=~;(0������������O��3/&�����%y�WW��
�{.o>����[���JQ��}�[B����0��n��<]�@sl*�|r�]��������Q��-E*�+�|^Ba��#��2�Zd����.
��#�����J�-K�������5��R�(�D�`�wD�j�#�:(����T�+�����*X���]��/�����j��~����_��D����, �m�����#XEj��
����B��B63��{��D�@e,��#�|�����
D���% ��b�� A�	�������'�OUR�>mdg��Q�^�P����2���6Z�tlq~����KT�R���)���*�;b�Q����r9�P��VjQ�r����I�m�<O!�m��[���f��v�|���$+�{�U�����1�A����+�S�����P���o���9tZ���Q�������C�E��Z�T[�X������=l�������Y�+����NW�}��@9�9�A����"FE��R���eq�������uh��EI�9��Jv��������vCX* C����#%���P[c[c8x�Xc��������+og/&�����������	\�����Ta����_K3��������O�3�&���Z�	;�����]Y�f�,IX�0#�4l��\��&b������74�iE1�z��/<k��n*b�u��~@�����o������_E>�N9!�����n��[���x��z���,����NX	��'0��y8��>�Rd�n��B��6����d�:�^����h���>]!w���8���>��B�������8]@2�C����c�+������.���#j���������T~����e
�J�V�_�������wix�_�1��D�-0SD����j^t�1"���x�.��6��<�W��"�g1JI�����H�l�8�rDClh���_���u�{�4�6��H�UZh�%�v�p�K<'���RT��8K]%�JoO��}�m��1�Q�Kx#�h���w;�(~,��O��t���Q�HG�`�&���Mk�Eg��Q�.��t�dKI�����N�S�#���>4zP����3_U�^�������G�W+��Y�b}���
K�����n�Y�t���^;F���"��P� +�
�Y�t��j�6��h����������-.�nwF��� 9a�S����N��re�.GB�8AKn���N�
�
z���J���E��Q�g47�t� ����%>T�s�%
QZ�(C��9���t��	���@8�@/m�g<g�0;84�tcc�X�G%Qc��v�����h�Y�rpG�t��r�S�/9�:Z(L����cZ��#N�����s9s�[PW��h�w>6W�C���-��4$Fl�b��l��[����������hxpo���J]����d��S���������mJ��#��T��m���;���
��yh���
^d��*�5Z��vV�_T$3��	P���J8<0���M�|��]O�\�cs���Me��~���6����w�)������Y��� �5��'���Zk�5f����u����"Od��*��9|���m��ud���]E!�M4��j�����s�w�����w\�����9��S�Z
�e_����*���
R�}��Q����}'iu�����]�������q�m������+��}��i���KDDE�BD��cJY31��"'�d��,���.0�T�r��,A��9���.�R���L����Q�XM98���)��qD���@�P7v_���(R\D�C-����K����8w)
��R_�?��O��A/k���'�����}�9O���/���\+m���6��luy�jqj����ZGQ���B��&j5�	\_-.J��F��"��f�Z�z�*@5|���J�/����s���me��~r�W�+R��?����\���{|UC��j�Dv8�-PR��:h.�1��2��.>��;mT��a��c��<��Z5
v���3�������s���-�E��v���#�'�Pe&�I8x0��������lsE��O����R�h�f�3Tf>^��Z�����~5�.��8J����j�s�n/u�z��7�<
�������E�M�"�V���������=�����=�k�n������m���\4f���c�FxW_�r�
�������,B����ls0��xRn�;.��]�������c�
PT�����(�����.���m%#
{��p����n�n��w�p�Q�!�-#������9r��3�U�����%_���F�o�J?o�N�o���BA��Z�k������JF� �� � _����N������tG�Z��G-c'��j�"_m�L��"��v0O3�s��.�������%�K*���i�����'�����-�Y�wY<�:;u�VZ��*�K����l�Md���m��0��r)H������7;p0oT����n%o��ws����2��[#��qe�T��jq�r%�O�����j��H2�6V����D��6��v�|/��v��#>M"![��2r���GX�\�S�U�2��g�]�I/Y!6EIa��`�52A��+Td~|�'�BZ��t� �F�EI4�2<E�'FN���\�<���[L9"��7#<�A9�� ���\��_4�k�h��(p,���s�FcXu������l5t��������)6��`�������M��(.a������g�5�FF6c.������H�l�G.����@��&���x���]rR��$}kK���R���1�������Y4��!�&>ts�u����o�#!��a�������e��������%�t���Kv���6UC6���0��]']���h�����j(����6��&�\�K3�]�/@>(WJ�fa4�W���e����+h>��2�_���Z8����A
%�oe�t��E��{���a�h���F����G�7�(O�,�9�(�����<\��G�=�yD|=�O�����l���3�����aY�����ep�{��[��u���
����
�
�cl�C�x`��J�&Z���=�a����W�v(}��+�>w��z����8�a����RJ^A@hl+���1���h}��g�������������$�����al?-w��\�U����	%e89�f��|��#��<��O�\�OBC`�8G-h=��2���6�	��;�z��[�G�9&��B9�*�7���BK������Ay
�y���$4���*�8��P�@_�Yx����e0�WC_�)G��#��yY
e�_IqN���������q�@{�xvJ��z=�+���g/l��p�}�����������,_���O��Jg(��<e&�^PB)�����;���l������@0@����,A@I'&a	�H"����8�qhPpCDeLph��&8������(�����(�� ����n�Ns	D�����&���U��V�ZN�Zb4�^�f�m�����ze���6k}�:Q�V��(�����$������,���~7�)n3��{�h�_�wr�
K�=�0��<�>��eK�w�3���j	-�\�v���,���\.��D��OH92�[�>�e�����vY��<z��i��N�@c�E4F��f�_R���������!�0M���A��	p?��kw�r�k����D��L�7���&���1?u���U�.��H'�.�K&����������3W�i�{��>�>�>[��AO����@�w�P�A�5X�h�+@C�]��$�y�����J��JZ�7��(A
�Mt�;�.WWC�!-�-e����D������-��n�N�:_�)/����O���[�
�Q1�dX?��:�n�W��p��C�C�e�OG;]�h��8��S��������r��Y?��c�z����)#���V��~��e��.�<~(�>�0�{�iE���3�f-��l���m�2��w�SK�f9����R������k]%��cB���8:M�/��JK\�Q���"�dDy"���(�����E���`����dxL�D9�X���j��^���(A��4y�#�0��d?�t�d���vUr]�wp~��=�Q�'	z���O!L�C�
���hwL*��{6��f/F~�F'@��<e!���6�e�wI4Y��i�����mti#LRB���w<�x%���*�����e�M��sH��r��V���zhA�Q
%��(���tK����G�&?��A�a�'�;�,*4�J��tAO"���w+��������z���r�s�\�e�F���PG#(�y`;�k��Fm-C;��<�r����I���Z�b�
�oI%]��_��:��D
��LCw���|}�h�w���'��c��G�^zX����;R/-���%�������	�*�G"�2�Z��*m��[�N���F<��h'����(Q�6
}�v�3�p8��3�tFC�D�D^myV��U�P��/���_�5�O;���O|'��8��0��� �a��I�J��w�B�"����l@�9��+7���`z������[-7l����
�~��&
��4�%���5�U�Y$�Nk�����
'���X�����<�
�/0��q���:���NZO��!�������,ejd���<�	�Q���o�����`����c�������\*��J��uP�!�)(^�m����vy���U��Qh+�e��w�����[���H�vn��(F�Ex�t{��(�x�^<��?���G[�yB�y���@=5y��q��@��:pX?�F3�w���@��`*d"�u����zn��]/��A��>��9r�-#����:�l]�ZG�p�w�}g/x��?��Bh� a����l�}r	��	������CS!�?����A,���3�G����k��da�z7� ��.��.�z���X���B���`��x5��_���������n�����D�����>�����B&A�A"��f�9e�����?T�f��|zy��f��K�>�����]�m��5���s�a��"�>g������^b��My��l���,�G)��M��H���-�vf��mg�_!7�5��O	��E����[��i���\�0����>��8��o07z����fa������z����N����l�z��mcL���g;F��15GR��t�6�K�2���lik���c�i���q��u���M�(�a���q����m���s����;����Kl��S�;��m�t��a��l����l��o������M�QF��@��c�&���f*�e�����)��4���,����9d%?�\����m�	���;^]�-�T�������sa������O�`H��Uv]�i��b��y�^n~���M9�~��;�8��NF�v����x�v����'����'��D�qbmy����Zo��/��bM������}��C��:�I�6���z�Y/��fG1N�x�c��&�����{���S�\C�d�%���WF������@}�\���*���ob��^w�.����V�]5��y��y*���D�7�����{�}7=bd���{\�1���?^��^�����	D�f�x^��L���)�XzT�CY��m�6����~��m����kr�s������u�4I[�y��&���L��2v��N�r�t��m��~�X���{x
�c�>\�(�OE}��:s���q��;tk._��U���������a0]}����^���6��{x�J�|B����73��\�k.�U���
�����^Bw
����I�d���V}U�1����.�
�*�4[���^b���>���/���.�(���a^���ks�������k�2��9*r�^�S���2���_vA������^�h��!����l-�*���������������_�/�=a{_�Z���������e�0j��.�	��}�u�a�]`��������q���O�j=���� -����������������N�e�����D�wu��N���J>N�t�8���	��?A>N��'��8C������,�q�r�t��3��b'�����'�c�_��t��r��r<$Z_�q���9W����~0�5�+���<���w@������B�������
����8n�N+m�L�����i�W���+=�6����V~�2�n��{�����)�7�x�L
LF|/�����0wC�����2_|�&����9~W�^�����3�0VwrW[R�%�:w�Ic�5B~D���3��FR�;�Q�g��u�k���c�>�&�������H]\�
�j*���.
}�4����z�mm9]�^�������v��%a:�G~�F����JIA|���{1�o�]���<WQ��%��Ds1^y�
��5�����U�:v���54������?���;`��AQfC���{�n��'������Y`��3�;L����}n�u)��R��b��������������+���$��[|�;5K����e?����?���;�o����Q�S��-y?�^���Q�'��D��%���~��i��p�5��)�Ax���H?��/e��a�)��}�DY��'�D�R�I���B[�������5�'h�q;Mq]�r�HS��)�=���>s��]w���c�E��us���7�K�e_�?�-V�����o���Z������3s�u���~��f+�	�C�������,�<�i���T��"[�����)��a>S���S���g�a�}�>z?���a��N�[�S[R��,�������sJ�����g9�k�3[�|����I���iCF��i��)�~���\s�j�V�Xkr-�8e�)E��&�X����}~>�s�g�~�6p2�>O�F�}��H;��� �x���`��[,��%�%�M�\��91�!h�|]��(��~�=��?(r�{�4x,<#�2��]6����n��].��O����y�����w�����������H�=[��=��|�~��gi����@��5`�d�����*is�������8������2�-��,;w�������V>�9V�s���I���l���;b���R�e�L������u�]���h��6�9��O��0N�>�����W���n�N��|���@Z�J�H6X���U��4�y�jz*�m��������f;�Z���[�-��u��/|�q�"����z�>s���E;���x�I���x������377������>�E,�e��9���>W�����0p��D|{~�K�/-�������3=x�ub�H���5�b�N2����#����F��[��6��7`�$���`!��!�@x\O��q���h:��A�0�w���d�?���T	�����5�8U*iUj�x���)i�(�$yo��m��h��y]���gv���0�����\*2:��f�+�lP>��z9%�Nc�`��>9`;j?@i�����:����R�����������h�h��[z��K���������vs�<�8K�d����m�RJ�y�F���o�R������D�G�,���[�e����V_v������1���\k6(��n�S��?N���s�f����a
tCx��%�i��%mAD5��o����{�D>�%�^b�KM^�~���#�O�����-��u�����f�uV��Y��8�n�u��M�c����2�U���0�4�f�����_ct2M�>j�k������0K�rM��I�����bM�v�}��)�Z�7���� �Sym��R-Y�DW�{
��qr�V��Dx��<*a]�:U�|��4��J�-��~o� �I@����d>��/��W�H��O1� |�*-��#tRKgi����>��k��T������,���06_��x����bN��!�c�w�����!q/~��?�q���i�^��e�C��e[v��S#��^��`,�(����7��
����������<g������E=����}�9/���[{No��5�!+,�8���w�e�0��i@����*�k�O��tA;�+<���r�\�h����~[h�I������q�d=.�2C��u�c�by����u����q���C���@��A��K�O]��^��t-��3�{���)�j�+��U�~#��93���������h�	�f��L���D��Q-[����:#\���"����v�H����0�H�"#9��z�O�����(�>o�=��0-/F7�(y�;��0�?D4�w��Dy�D����Dc� 7���O�=��^D��#*�w\���"�L��/J�(Q�D�%J�(Q�D�%J�(Q�D�%J�(Q�D�%J�(Q�D�%J�(Q�D�%J�(�GP�/Z�QI���T��l����[���\����Z�:������t�Z���T����Z;���2��r���i��lq���l�@�
-
���.A�4�7�A�+?���`=8�O�T-�������uA�.�c�v.&���k6�*�=`=0D8�Y��F��x�����~n�]B�]qe�p^n9g\*�u��,y�$K���
��
<����o��}-��#'��]l����Zg|dgd�\���(��
Z����'�%�e�s�7j:)��)TI^s����&���SM�%�W�B��z�~^�!!g}�8�C�
��~�����%�!.s\s�z���#�P������Oq�_(��
�4�#����x� �q��\��q�W��g��k��.��U�E���v����&+[�x{��s�����9�����z�E�Q�hQ;��4�i�k{��k��#�{����|Y�
y��(T��-����D0\���
�{�he�������G}�����k������>�e:%�������/	�����{ � ��/��y)�=���C�Cf��K}�.3�k�%��(;/�� L�`��j��Jo"^���z!k�S!��M
\�
�/D���?������������/����_����_�7��;����w|�W^�;���+p�������^]�\fO��	_^�zJ���
(�HWo�:�s����%�6����7���W����&%8G	.V��(��J�2%��S�`�(����(��x�$��@����V�UJ��{(�L%�S��������(�.�;���}��t�h:�|:tB#���)\�u�wIc���O���?<ga�u7"�F5����
��f�/�����*�.p��@����=��k6�`	8��#@��2�[E��e�'�K�����IW���)�Y�c�{R��4eB�������(1��P��n�g���K1y1���=����W�{j��z��5�����$�7����)�����<���{0�xX�G)j
dNm�4D�����6(8�v���������������?��u��������R�{�d�{����^�h���;R��>�W���z����U�h���`����*�q���r��� e�7P�wn���\�i��q�{ Y�md�w�H4#M��dh�2/����]�����q�u����Tw7w'O�'���s�����1<�G���S�y(�����!��#�J�B���W�*�����=*��PG�X-����v���Y���S2��v��C��|%�XL�S�C�g������Y�!��KJ�)��e�
����ZZ���u[�P���;HQn[��e��V��Qr��s�sG%+*h�2S^#�xj�I�����SJC��e��1S��C���f��P�*_�P�bQV�C�-���������ze�G>�+�C��J��``�p���Y��Z�z >�e�@���!�����t��m��,,���)����*��\_d��=�G�s���0{;9Lh���� i)"���RD���2�%H��<d�HISZ��Xab�ab!��B�����ge)u#�f�(��Q83�p����y���,�o��2~�i���f�cy��PY��������3Zy<���(�F3
��n��SP;"0�0�������zRZ��i�7���M����i������x4�5���i��i�h�K�y(�����S��C{��-�,�s�5�D�����[����>�,tNF~(��~y����?��8�(y���n
�f�(�	�������(�p~��_��k�u\��5��t���0���jQq����P����mn7|g�'���~�����,�������~#�/&F<����R�Q����N	�)���L�OU�
���[g��6������X�d)U�;d�������f�u�N��")���ReI�VV�������>�V
endstream
endobj
14
0
obj
<<
/Type
/Font
/Subtype
/CIDFontType2
/BaseFont
/MUFUZY+ArialMT
/CIDSystemInfo
<<
/Registry
(Adobe)
/Ordering
(UCS)
/Supplement
0
>>
/FontDescriptor
16
0
R
/CIDToGIDMap
/Identity
/DW
556
/W
[
0
[
750
0
0
277
]
4
7
0
8
[
889
]
9
13
0
14
[
583
0
333
277
277
]
19
28
556
29
[
277
0
0
583
]
33
35
0
36
[
666
0
722
0
666
610
777
0
277
0
0
556
0
0
777
666
0
0
666
610
]
56
67
0
68
69
556
70
[
500
556
556
0
556
556
222
0
500
222
833
]
81
83
556
84
[
0
333
500
277
556
500
722
]
91
93
500
]
>>
endobj
16
0
obj
<<
/Type
/FontDescriptor
/FontName
/MUFUZY+ArialMT
/Flags
4
/FontBBox
[
-664
-324
2000
1005
]
/Ascent
728
/Descent
-210
/ItalicAngle
0
/CapHeight
716
/StemV
80
/FontFile2
17
0
R
>>
endobj
19
0
obj
<<
/Filter
/FlateDecode
/Length
24
0
R
>>
stream
x�}R�j�0��+tl���(#()��n?@�����������MZ�����K�������f�a�-L����c�@�p��pA���Jw�+O�����}����5��bq��Lo����[���������G���7QF���8�I�g��R��1�n�y{~��*�hFF�4�@j���c\��3u�]�a$�^���?UHs�8�1�$��w���u^$/�#�����r(7HSrA�J��mU�4��uy��@�l����9�S��D��+~]��NN;�W��@�����?}�h���P��X���X)-��d��}!�$3�c��up������o2��{
endstream
endobj
21
0
obj
<<
/Filter
/FlateDecode
/Length
25
0
R
>>
stream
x���	xTE�7~���K:Ig�t6��u��!�
��D%�&h$  ���,.3�� ��+*
�"*M���q�ad�ywyu�A������!����}���=����=��ZN�:u�������B��/�7��7����6e���m�pO!��i;�W�������D���Jg��6����]D
����%���!�7��/��X*��
�����McK�:��N�g�z���RF���nF��w��y�<�=��%����L��(S
P&�y8������L��"�~Z�~�+d~jc�(��eil�J*}����.���i"��)�<4�Ne*�i
��\l~D'����|�]inG�u�4}��CeTAg��$�I)�Q�y�i���<4�^��W��
t#������&�����j��|�<N�i��N;�x���^����s���*4_3��5��t?�d��)�M�U���)O#t�Ca����h�1�t*M���ZE��y�������o�H�$*D���Gl;�������t6u�����T�V���W�w�OP
=��l{\+�����y�� ���A���hg:�������_j.�ShZ��b~��_�i|	_��L1�f�vm�fd��G!���!z�%�v����/����/*�+��WT�����|�h!�K��i?��4�_��l.��������������]Z |(��y��y)�N��i)d{7��n��J_���5s�al6����!�)w�>���7�{����z�qu�:J�P����]���M���o
�~ �W�����8��:H�w��{�1z��No�;BP�6���V���F���+��$���G�Z�:�_9]�o�7���{��������M�Q�*�������P�W�j@�R��ST3S���M��i;�'���*}�>O��v�m���]������p(���C�.�$��-������!������(f!�e������zv;���f�+�
v=��ng[����m�{���	|����|-���=�9�?�����J�T)�*S����0���e9$�^������|�|�������E�����}�n��������E{L�������\O�3��}���M�
�5����b��>�e�����z��4��~|;OV��#H�b*�c�A����/�Z	c^�D>�����$��j��^��DKu��*�������O���U���������y6��5Z����l��U|2��{�m��������B��v�#l8��U���
�(�r�2�p�9���sB�w�:�~��U���Q�N5V�-�S;�����f�cL3?�uS`�������_E��5c�-�zL����"�f:�x�>R��>��G�h�(X��s�;�w�
�+���a�����b���<��������-)��n�)4����[o����������x�������*z����l5���??���	��N��yY>+�z8�-��i������� H{9��~���������
�cn�h������F�oR��,��a�����F��\	�m�z~k�s��s��t�q��������r���[1��gmH����>����0����fX�N��Mz�6e��.�����:�f�����va�JX�Z���ws�(���_VheQ��.�4 |�9��Q�c"}3v�:��G/�1�.JaciHx<��2S�{I��V>�\�\��@���b[-�Q3��yR�����*��.TZ2�x@�QaA ?/7'���������M��$'%&���b]1N���k��
�[��ZBj ��S�E<w��Hh	��T��2!�,��~I%g�*iDJ�%��_EU��cr������v6e\#�kks���#2|����X�������]����P���������]1����g:��.g�1�Rs��b�#���1�wq���S����1���Z����?f��P���1���M�Bl�y��C�;*�Eh�l&���d3�9b4���k@��5�n��t���1����2�I��D�����{ODQy���=s3�Uc�s�"�j�
�s\c��l�ljB���u-�����~�����C�*4�#���of���r�?���;{�-���U!Yvkz��a��1�Us�C��M�j3w%������������N�vW\�p������!Y\���wK����
�����'���0��9�V�7��������r�nY�.�H�w��W}E���#�~?e������"z��j���C�`��"���S�q��)��������@|��Nk^�gg�	^�n�tDB��5F�~���JFI�)�[DNg4'e��Y��fo��&�&�������?�nO����C��3�3#��r��Mi��Y�b��~��b��a�yV(�4�Q��V�g(2JyNwait��|���R�)PJ���u!w�)�g�3;�'y�m�L����K�lV/C������^�{�s�R�_5��'NY�����:�U��r�u�ZVMk7�M���sWu���}���i�Nh��guF�nM1�
��r�+����`+'Li�p�$�rbc+g|t���]y�k���b�T��*b~�zEo�v���a-���L�����4{4��y�<���i�)�#&_�/����YX���j#�45�������u-��},@8�^��_WuU��>ZuFWU#�>��������|<��~�����w�Wq�c�)I	h�8AN6����\�j;+j��1�������1r9p�i���x����S�jHU�4�v�o-7W�!������6�TJ���	�m�����J ��m�����j��1f�sW����B�X�1�!������xx�H����9:kr���M����L����B�"�u�wt��t{�7/-/]����J�������gn��'R�;��5(kq���uY�e����N���R�����,7����[�B�jK��S;���3W|;�l��\%.�2�����9z<������/�i�^~B����G�t=������
�?���W%$V����f,��2;[*EZ�%1�����]��@*���i��GOl4bi<#�	�Os��R�\?��Q�����C��
kb����YB�����C��rst[����e��u���6�u�����?��lj�m���O����g}��i��nd����>k��3/�M�����ym�k�6��8/{^����F�2���0����p��_+��������f�|U_S���#�J���Z�s,-�����R<��O3?���^���5����$_��D�g�(��|�8�������"�"m��j�nK���&����J�f+�n�nq<��)F�fc���w;���9M��K��eS�To�j�3���������,�H��c����b��Y�d��dU���,3�`����|�R�����-c�����?���u�G��y?�)?T���31-����)�M��TO�����.�V3����O�o�W��Y9��6�,���{�����o�g������M��
�]���������,$wV�rm���F�]Su-�������mWK����n'E��!s��V����l����1�1<Fu��X_��4!���!����@D.�����htW����`U'd�dK����gtm��|������ok����)4��4����\���/�Q��ZN��5h��C���Z�y����L���Bv��K��t���<��J��6Yp�e������1�:���j{���w@F�j���d�7�D�*�����n�J����:z?,�E(R��5;�V�i~w�7b����1�����Q�@��*L��c82��;��G�;��Cm5���T<t�����S��:��$���>g.��%���lu���%�R��v�C�=�����M�:�&���������;?���9>v�^����{�F��c�s�5�����;f;��T[-�Wk����g9�6��$��W�#��q6��T��p��t5�a����r:4��V�����O�no������e\Ll���+(�$m4�"c�\e��$;�&$�Z����q�rD$d��#�b��W�G��&+��c��2�#�Q��R9w9�����cq�,�M�_��aR��n��S����Z���-�3��K1���c\��3�G
��BT�s1��&v�"��������tW�����w��J����A$��G�A��v�60����V�
��>�4��n��f�Y�H=Rp�P����Y�z�'I�>~+�n����^��cu���-�"�}�:���%F��u$wx��5v�����c��(�-�t<�=;m�&��#�\�&���*�j����,K�r�������������_'���y��u*�q`���M��TbO)�������/�>��3/x��-;�>��!��=���v�h�����7��p���5
�c�h�T�Cu�:�r���7f����Z�'���S2O��������������\�>����p�I6����)=�S��4�]���[����u�c���yV^����yFp`y��S�GZV����y<�N���q��'e1������fe
`��@j<���I�FfBu������^���>��\��B��������0���~��"Gal������O&T�����>�����6\[�\�=5������NM�����
�S�\�4�if6�����@�G�����
FVdkI��t$��<�������y3�xs��p�8Xga��7��,:.�'EI��fct=7'0�|(�������,�$c;���i_zq_{����8�mSN����G'�~��No�[?��;��������v��w�vc�5����\uzfE����u��������qcF�_J,�T��\���	�L�6TC��?�q��M�M���s�x��^�v�����i����y?�?���Q��z���a)�%����6���l�+<^���������mK�������'g)�\���������~���'���a*91��	1d�((G��a��0X,d�SmL��l*������;����������}_l���G�b�o>�����E4�����d�VhB���t������7v�K/l�����G���y�<���l�����x���?>�L����Ox`!�i�2d�:�8�Ior6%N�L�6en��������oY?>\)w
O)O;M�u��R�v����m�b��������1�������o��S�u�X?w�=-���{����:�HW���FD|9x4��G7�s�9�9��<��s2�����!�����%��aG4L���f��G����h���u%��^>m���g��xv+`v��n������~���<r�&���-��$S&������F]L����bovo��s�u��mO����)�d��9���������q>�z�y�����������$��K(�Oy,��%EjC�jI�RA�Z���������e�����u��G\���
G�7SR#&e�8�������s�������Q6+I�(QI�������O��m7b��!p�"��K���H����^�_<0C^a����K�(�	�H�A�D�\	�-
S#�]�@�H��nM$��p�����jlX(XX�f�|�)��F�D�p�S�IV��"�&W���t��9����C�����
�$��MO���w�G;��\5�%�|�%�]�r��QS
�K'�SU������zh�[��`����W�>������G/���}�<�n�kf�U�����.�jv�1/O�$��DOB\R<����y������ps�D8u��a��yD�N��sT�'%;���c��(�BwI�����T#6.)����fO��{�N8\����K;���y78��q�>���n�a�b�����,?�-N,�.�MZ���)�pr�+o]t�����'
y����@���'�=��W���G�S�����_z�6����NpV�_�9:�94������	���HS�tCz�
5sV�9��m�+Bq�y�j��:�����t��t���frq0z��!r�Sfj��w������O�p����"�?x�|��:��g'��	:��+F��P����Xm��k��K�wo�e(`#:���h��J�=�r��^�-���c�c���.�RR4��R��hS�=�}������\��E���������]������/���-[��g	uiu�����6wBBAFff��	q���	��!-	l.��������@V&��f����;?(����@G���P��E��
�+(/0��T^R�b��J|��`Y�B����@-H+|�*�@D����tpwU}�uU�z~s0z#]W����Z\"@��:�`Rv��
R����I����n�2��0eu���K����hKaV����q#f��zh����j`�&N�4q�9�����;V����0�u�OP����������9��&�kKJM�b�mW�U��r��k�?rk�qV�-.Vw��`��,�!��W���)�]��''�|�w����~���y��p�	�����A�f�^YZ��S��%)�YD��	RR������{>A
�OQ�����<ua���~����>��������}j`������F�����n�Hc���b��!���M�7)�3�C8�iZ��7�''M�4yo��
�[\��W���7��>�>�?�u�g��Y���K[d�F_nW���
%���J[zK����M�sK�-���f
'�y>vk��,��s�*kn�I���$SnN^ ?��^=~U�����s�^�f��|�E7�t�E7��5L_~����\nn�s����m�]��z���_r�1pX�)I<�\���L*��UN�=5�6�_����n�k��2�X?��1�	��������R������$����n�����eh)-�:2N�[�0�����J��1<����g��O`1�b�p�����W3}��t0>��x�XL���Y������Wbjf���
~�nR�GJG��;����	
���
9�mF�-s��	�,m���$6������:�.��_�2]��5��]����f�~+\w���(u�s�����������;$��n
0E���el3�,-���eF6��=�����3"�$��,��b>��R'��������Y6�I��F$����Yh��k[��:���K��-��j`���?1�R��c���0:�=�^�����!qC�-7�w����y�����g����6���(vR����bnI�/��e��5�j����H\�|u����1z]�i�c���G��r�
�!�Cr�����N-����-p������r�\�&_���hQ��)����rS��9�sc���R�xo�����zj����-���r�����~�=�!��|�ox������X���t+���.u3�`���e��:�#��#�R��v!������fYq~v%x��;�!:c:��@�������)u���5N��\M����I�.^�>Uej]aLC:K�K��W�q!E����1_h+��ci�����~y"~�������������lhN]���s��y%G��q��j��C�fi��k�R������xN~��F�>b��`
Lma���L!�F��Q2����g������\�c�j��T���4�RQ�*N��F~�7>�'�j��t�;>�5�����|q��?���y��G�8����xR����Q�3�31����x@�>[�JvU�`���xWL�tY�a��=��;[]�>��������S�*���Cr)KO���_W�'�����%o���+��o�6�-�g��M�G?{����O*�,��$'���|��}��4r����/%s�i�W_�R��g~��kw`O�o���r�E���N�k�����W��PjbR2KM����8lN��+�O��SC�JHg��
���Fq���fg:W���YBT���J����R'�T'oJ����$/K^�| ��d�������d��K7G���P����J6;�5E<���U����="�(��a�.b���63���R��Bh�4!w��!�	����������{���1�������C��W33��?x��A7��|O��g-��5�`��zV��	7k�CO��xUB=�O�����P�9S����s���0�q�%D�����n���>�3������Ad���4G��2;2��CEP9s��s.�~:K���>���,m����n��o{�1v�a�	7���4��aF�V�^Rn]<������@���O^~��t%�nw�bRX
OT���*�y&���������IZL2���S��r������b]��Gj����trR����
��2�H�!��t88g:��Jqcbx3�cb}���F�����vV;�:g;/5bT^�V�cUE��K��-3�]C��aB��z
��&�+�=�H3v���3���}_��*���J�.��l�H���YvR���J�f���DV���T=��<�Cz]�<4�S\��EdJ�%���'��?5��+{�]~u���*�5�
#>v�x���y(�X��,"����4�M����MVz�Ol�n%�J��]y���(��eQ��Ma�9���dQ�z?MB�E�/��W�](?�����Y&5�y��:��z$}�.�����7����t�n�+i�HG[kPG.��"�};�Gx��DYI�d:
��A�l���dC!��t��^�4����#�G��"�$��V�2����cc�F�!�%H_�VgC>��|>��"�~9@]@�J��2U�$
������I����/����$�����G�~�@������a�*����1�#�~�������o�y1������Av2�����n��xP%������*G1��r�f���_S>����|���Q�Y�L���������>�=JG]-�h�����l?��������\�s �
���h�D���
���B;�h�'��G���>�b���<D(�� �����E��zfA������4	H����-@�(���(���
��)�C������	���1����Z3���@P��O�X(DY!��Bg�z��-tK�L�J��P���b�B�z��N'� ��nE�Xw��2A�����W��7}�R!�kb=�5a��c`����'u��QYt��6�9Y_=���T��3�?���e��c|H�x�Wa��4��IE������� `{�]���Sw@��R����U�i;��4b�i;���
��T�g�����M�A��X{�41�����}�J�"�X�������6��:�Q`�j�p��
����2 �|�O�O�vw��}Bk1_W�R(W��m���?�~�3z���t��.EiT_{S�3���j�iXw{����x�x
p���}��l4�6����n�|�6�^��^z���~�z�eo*�a����u�~���_�Ga���vN�}���i��`;�&��~�b��"�(A�,;���Q�������js����W���j��|V�mn��������-�)��
9�}1��j�e���dY�/�����~��4��Y��b*�� O�w���~��C���xeg$]�@g
��.F���"?FY'���_�b��m��S�n������/�����4m
��+Q��{�]�(�J��1�s�5�n_Fw�:�����;1�g$�]���m3����FP��`|� xp��[��Y��S��&�����SE��D�Mt��I��`���tl�lk�e7��U�_�����$Z�%�����i*���>��`�K�4��ki��O���G��R��`|�?�	t�^�X�Ak�N����^��}��\H�^��0�C�1��D�H'��O��^l���heD���v����h%lI���[/��	��0(_
,�D ����Q�"���g�Nd2��?`��N5�}��g�����%�B9zw{�BW��:�
�#T�|+����*d9���Am'�P[i�b"�n�>�Ok�)�y���E=�P�8�A_�p�y�('������Q�����(D�����M��������}���������|����rz����8��v����;i	�������)=���hTu	�	Z�1�*����:��B�����s��#l(�����	����������g\+�J>6}���d�;�\�v���#�,&��GE6;�w�>|��Z!���E����R�~�)�!G������/���/(�W����'�����8_�3
�:�!|r��$�G��C�1�s] �t)�;)!:OH_)�{�te��y�t�������Kq�;�'�z����(��c?0t�c~�n��0��!�:u"������J�<�7 �}*��O�"QV������w([@�����H�rmrU:��������^R��=:�y"���=�l�u�;-jK~�L��Q�Su������g�����=g]���e�!��w����%�ZI���D���a>��&!�'�E�P�F�Bx�^������+����j���|���|74���
�v��@��{�F��P>�&P���-G��>�+�#������q�1�K�'�X�#?r���?q�����5K���}��/��|��}����/��Y���|��z�}~�����Y8
|�^cv���I?������hQ�o�*�If�)J*|g��
�Y����9�E�g�.���_�}��m�h&���G�Q�%��s��x��_��\'`]t�����x����>�+���ga/sD���m�������4������=u��9�M�e�w~����{���_����{�O��=���i<��G�Ie6�6~����~)�K~����w�����|���D������^��I�z�����w�u:J�k�]��>�^������K��l��k�sW.������f?Ne��������6�l��}����7���_��M�/�6Zh�%}����?��!d&��sq�J�@"��u�\��/6��*�y�9W9l~����)_��(�y�������g���������N�_��]|�����3��6Y�y���	;?g��������G����Q�������q7d�L��1���&�����Iz
���!"w�3P�<q7��C�{
��k�bq?%�+�H�1q=���M�P�TZ���V���-�w�|'���h�x��N7:����c2�a��;����p�`w���^�W�}���������q�)���'��
�Zin��n��>�y7d����o�z*�b�(����w���{�e�~������N���"w���5�q��K��K�-����|��ob�Q��lWZ����d+m��j�t��Xqg�� �������S�e�3�;��H�]%��F��e*#�����^�dy'��|�w��%������'�.l����&����?��n���;���|�g>e�vu���4K73�o�^�&u&�z'�����AG�ZX ����{�JY}����r��nn��Q����gG���i����N���h��|��(y�!�Wa�c�{%����2v��WFG�2�9l�w�����^mp#�#�m})����w���v�m�'���"a����/-l��3���7����_�������x�[P�,�P=��>F�x-�
���Vzzo ]�Q���Q?���*�S����@o =������7�7���3���
�����)9����~�g���������c8�>$�O�������$������k����Z�f���1}jq��~l~
l���h�L�����B��=9���
���-a��j���?�������;��d��GxO��1oC��GX���w8t��E�(��;����c�p��a����">S�����H�]8'�i@�����]�gqN<��)�j;'T�Zis�Pr������-�����ZEY:|8��~����<	�/�����gH�ay��@���q����P�!��,���[����B����)���8O�&}8�t��Q��/�F?W|_"���l����!���h��NZc;�|���_���G���U��
��(�MM����r�t��������������~q���.tgm�������/hhF��)��p&Wh�|������XW������0�tp��6U��G�����������
�~O)������k��E��H�>@��nS�E]w�_�����i�����]|+�����Q���uG���5A���c����7"w
��,�nL���~G/��x�'����s��5���]���������h����h{:�m�R���l����_w8~*�n'�qs4��9�K����'[k�o����I�ki]�Y���D�E��4��,R���m�|��U�w4�"�6r�~+�=�|���H���o�������;4���7U?���7��GD�X�/E |9�/Q?�7����>�x���E���B�������~���g�i?�ZgQ���^z����r~��=���1�_�����a�����Xwr����{�s�^?���W������A�7\_�_�_�����������C�~D��/l������~�����3���zRJ@��E`><��h:f~!��������{�zy>������w��;��$�+n{����4����
��}���b/�Y���[�_�v��1�sL�/�r��1*��9_�>G������#�\�s��y1������]{��+��c-�i�K��|��:���ke����Y�oi��_X�r}���Q���Y�P��@;�No=����|cv���m��o�u �������6��+t�-������$|/��Y���ol�Y�/����Zy'�{�=�&���i��}>s�e��w����D��&*a:����6�5�}����s�G|?�O���7�"�=��~G{h������{q����'����$<a�u	c�����������8�3Z#��G�����$��q����/��	A6�2Q�^~3:A�#�������wJ��<����D�����
|�O�sN:�m��C���/R��aS�-8����n�I�
�oqF�>�?���z	p)����������P����4�p�V�P�:W����(~��t�<�-�r��N���D�}��D�(Y���6N'��a�G#�
�9��{�/��h�Q'�hG���>Up��G�1�����:Q|?d����8=b�QX��X�Nq�������-�=K���T�{�J-��q����7R!����zR�Lg���{b�-��j�����a�
t�?G>Y�K�w��(��N�{����	�mG�#��Oc�E�\[���_�.:��E������#\)���hT�*4��X`��^��	��|AQ�~�#��2+��
�$����=8Xb��4�{g��O��f����[��O����_�6�����A��|�����_�����?x����w���-��-K��W�?)@�M��]�F�����f������;��'�~%��J�[��y��sw��z�=���]g	�T�c>%��������=�jk��iG�8ikaS������&m�SBvF� �99vF�K.D<;b�D�/�j�����S�)S�3i�"6K�La��:��R�\�?����#���w5��#{Nx�������z�=$���G{��n}�����d��Q����_�Q��������m��?��g��;/����6Z,�+��`.3z���[w��r��������+�6z������-����}Z��i+5�6`�,���_#�w���=�.�:�E�rK�
1������[��>����=���h����9���\���W�N�p���z�:���}��?|�����I�����.u"�&�{q��
���P,;��A���2����_��2��x���{`<��'`����7"py�bu��D"wO�>�?Q"�/��D�8��l��s-Q���e�)���>��}�C���>��}�C���>��}�C���>��}�C���>��}�C���>��}�C���>�����������*��t����7{mU�	������&V��v���l2���l�eF;hb����`Y������2����e��4�#yG�$�����-�t��-$i�=�mK.������o�������Ao&�(��-�u>�p/*��IV���<_L@A���X�����������-�2�����X�^4���&��� oqe�rW����q*w�R�+�Q<��_����-esk[|R�Q�Vn��SH9�:�j��m=q�o-$EX���+s��jtz5:�Mn���������<�����'H�����GmnoY�p)1e�r��OY��<�,������4���e��^5�W+)T���Ce��J:e�b�Z�"�,j-�_��V��H�K��v��Z���U)��m��������G��%��2�J��?�81�N9��m���u5.e"�9b���R�HVtQ+*�IP�(��A��J���)�$�O���@�hd�:�*7H��E�h~dD�F����u�8���
)�b����k+���RH����"�T*�*�Va�Va�Va�V�S��}�\��kP�D���)��:`�B�RZ!��+,�P�/��Q2���9�D����I����WV���z�u���To���J9�m��0������0z��<�dBB0YJ��_����Pd1�<? ��_�����/".��o��D���DI�C5��=T6��E��|/�J��o�����=������{Z������6����X�,�5Xb|�V 5�
$z�j���q�D�}�wR�c�^�N���}����-��'T�?��a�m�q��V� ;[uAl�H�����?�wP:�>�HG���@�/~/�c�^��5��X��w�Fv�6�AA)�oi���k���u�u|���0��bc�R�_Z\�U��������7�d������ ?����_��V�j�0&1.N���,C-x��!������U��h,�Q�`)���x^��-p�LY,.�5��y���y�c8��c8�I�y��E��hG8Z��"9Z���p�H��p�H�p4��
��
�hG��hG8$�8�a���Cr�0�aH�Rp��������(G��(G)8J%�~p����~p����_r����_r����n���np�%�[��"@p�!p�!�q��q�$�!p�!~�.�@���r,�r@�����r,�r��B)�Y,�������o�������!p��GHr��G!�G!������%�fpl�fpl����.����������F;�Z��I��>�t	��
�%�oi����+%��*$����>I���Z}�5����T`.�	�	<�d�E�m��C�5�6�������M�i;d���X}��SL�v��t����������u����l"xV�P5/G����C�[����#������������u�Y����Ti��T��q�h�#}��@�HX�k�4���kg�"���~
��W@P�>������}@�
�E��Qb�����lk��b�!�)(����R����� ��L��8��T �"�fn��V�ad?!�����lk���4�9��`��&�M"�*X'Zt�-��V�d��+	�D��h(�E����[\y��r[}#@rZ}����
��3��e�4@P�
���5����������@�P����*����l����+��k|�5NQ��.��}��5������?���7�wmq��k��kd��+��|���[�+�-,>�[�;�7�7�����V�9�}�������}
��T�"��wr~��b��2��+�U��	���H�����,����~���I�,��o����v�m�m�-��c�g��%��n{��ew��v����������7Yw����������}�U1;��(�����	�X}��<���}=!��9�M	i��X(���'�

�������`}��pv�.��mBj��lg4����"���P�hd�Uk3:�����65�����[�82����G-�3x���3���~Bch{VS�L������&��i���<vLm����C���������&;,�A��P�
A1�(��b�'�D1�Q�\�(�-�9c) ������D�]�cjw���L>�AY�`>�(�o��@@����FQ�5��e��dE>��d�NV�c��P��"�V�!�E���v��/R&�0Z&�e��������m��%O���;�%w�L�%�z�loh�t���E"�R-���-����E�3kCKrk��=�#�O��A�����1w=i��md�;��������{m]��Vc��TV%*kmU��Hv���m���jD[�F�lk���
���4�i�9��c�������Q���B�;Fd{�d�Q�m��`S��;*�������u&���oey�������YYn$'����hI�
W��0�Q�J����s�@��l/��S�?�/��o����G����E�������P�	������
M��6!m`4MQd�.�cL���� :���D(���������7��m\��g��};�R�8~Ik�<>�K�r���ea[���qU����2��VVA�#�H(F`]���u��7o�����V$������d�B���@pa��n���j���
o�`�)�@����[�A�?3������u��~atB"��J0��E�YL2s�d�T�u?N� F���77
endstream
endobj
18
0
obj
<<
/Type
/Font
/Subtype
/CIDFontType2
/BaseFont
/MUFUZY+Arial-BoldMT
/CIDSystemInfo
<<
/Registry
(Adobe)
/Ordering
(UCS)
/Supplement
0
>>
/FontDescriptor
20
0
R
/CIDToGIDMap
/Identity
/DW
556
/W
[
0
[
750
0
0
277
]
4
19
0
20
21
556
22
28
0
29
[
333
]
30
37
0
38
[
722
0
0
610
0
0
277
0
0
610
833
0
0
666
]
52
67
0
68
[
556
0
556
610
556
333
0
0
277
0
0
277
889
]
81
83
610
84
[
0
389
556
333
610
556
]
]
>>
endobj
20
0
obj
<<
/Type
/FontDescriptor
/FontName
/MUFUZY+Arial-BoldMT
/Flags
4
/FontBBox
[
-627
-376
2000
1017
]
/Ascent
728
/Descent
-210
/ItalicAngle
0
/CapHeight
715
/StemV
80
/FontFile2
21
0
R
>>
endobj
22
0
obj
349
endobj
23
0
obj
26198
endobj
24
0
obj
335
endobj
25
0
obj
16845
endobj
1
0
obj
<<
/Type
/Pages
/Kids
[
6
0
R
]
/Count
1
>>
endobj
xref
0 26
0000000002 65535 f 
0000050720 00000 n 
0000000003 00000 f 
0000000000 00000 f 
0000000016 00000 n 
0000000160 00000 n 
0000000231 00000 n 
0000000397 00000 n 
0000004816 00000 n 
0000004724 00000 n 
0000004744 00000 n 
0000004764 00000 n 
0000004987 00000 n 
0000005131 00000 n 
0000031979 00000 n 
0000005280 00000 n 
0000032482 00000 n 
0000005705 00000 n 
0000050011 00000 n 
0000032679 00000 n 
0000050434 00000 n 
0000033090 00000 n 
0000050636 00000 n 
0000050656 00000 n 
0000050678 00000 n 
0000050698 00000 n 
trailer
<<
/Size
26
/Root
4
0
R
/Info
5
0
R
>>
startxref
50779
%%EOF
pios_v2.sqltext/x-sql; name=pios_v2.sqlDownload
pios_v2.outtext/plain; charset=UTF-8; name=pios_v2.outDownload
#14Michael Paquier
michael.paquier@gmail.com
In reply to: Rafia Sabih (#12)
Re: Parallel Index-only scan

On Thu, Jan 19, 2017 at 9:07 PM, Rafia Sabih
<rafia.sabih@enterprisedb.com> wrote:

Please find the attached file rebased patch of parallel index-only
scan on the latest Parallel index-scan patch [1].

Moved to CF 2017-03.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Robert Haas
robertmhaas@gmail.com
In reply to: Rafia Sabih (#12)
Re: Parallel Index-only scan

On Thu, Jan 19, 2017 at 7:07 AM, Rafia Sabih
<rafia.sabih@enterprisedb.com> wrote:

Please find the attached file rebased patch of parallel index-only
scan on the latest Parallel index-scan patch [1].

This again needs minor rebasing but basically looks fine. It's a
pretty straightforward extension of the parallel index scan work.

Please make sure that this is pgindent-clean - i.e. that when you
pgindent the files that it touches, pgindent doesn't change anything
of the same parts of the file that you've changed in the patch. Also,
I believe Amit may have made some adjustments to the logic in
nodeIndexScan.c; if so, it would be good to make sure that the
nodeIndexOnlyScan.c changes match what was done there. In particular,
he's got this:

if (reset_parallel_scan && node->iss_ScanDesc->parallel_scan)
index_parallelrescan(node->iss_ScanDesc);

And you've got this:

+               if (reset_parallel_scan)
+                       index_parallelrescan(node->ioss_ScanDesc);

There might be some other inconsistencies as well that I didn't notice
on a quick look.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Rahila Syed
rahilasyed90@gmail.com
In reply to: Robert Haas (#15)
Re: Parallel Index-only scan

I reviewed the patch. Overall it looks fine to me.

One comment,

-       if (index->amcanparallel &&
-           !index_only_scan &&
+       if ((index->amcanparallel ||
+           index_only_scan) &&

Why do we need to check for index_only_scan in the above condition. IIUC,
index->amcanparallel is necessary for
parallel index scan to be chosen. We cannot chose parallel index only scan
if index_only_scan is happening
without worrying about index->amcanparallel value. So OR-ing
index->amcanparallel with index_only_scan is probably not
correct.

Thank you,
Rahila Syed

On Thu, Feb 16, 2017 at 1:06 AM, Robert Haas <robertmhaas@gmail.com> wrote:

Show quoted text

On Thu, Jan 19, 2017 at 7:07 AM, Rafia Sabih
<rafia.sabih@enterprisedb.com> wrote:

Please find the attached file rebased patch of parallel index-only
scan on the latest Parallel index-scan patch [1].

This again needs minor rebasing but basically looks fine. It's a
pretty straightforward extension of the parallel index scan work.

Please make sure that this is pgindent-clean - i.e. that when you
pgindent the files that it touches, pgindent doesn't change anything
of the same parts of the file that you've changed in the patch. Also,
I believe Amit may have made some adjustments to the logic in
nodeIndexScan.c; if so, it would be good to make sure that the
nodeIndexOnlyScan.c changes match what was done there. In particular,
he's got this:

if (reset_parallel_scan && node->iss_ScanDesc->parallel_
scan)
index_parallelrescan(node->iss_ScanDesc);

And you've got this:

+               if (reset_parallel_scan)
+                       index_parallelrescan(node->ioss_ScanDesc);

There might be some other inconsistencies as well that I didn't notice
on a quick look.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#17Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Rahila Syed (#16)
1 attachment(s)
Re: Parallel Index-only scan

On Thu, Feb 16, 2017 at 1:26 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:

I reviewed the patch. Overall it looks fine to me.

One comment,

-       if (index->amcanparallel &&
-           !index_only_scan &&
+       if ((index->amcanparallel ||
+           index_only_scan) &&

Why do we need to check for index_only_scan in the above condition. IIUC,
index->amcanparallel is necessary for
parallel index scan to be chosen. We cannot chose parallel index only scan
if index_only_scan is happening
without worrying about index->amcanparallel value. So OR-ing
index->amcanparallel with index_only_scan is probably not
correct.

True, we do not need this, only removing !index_only_scan should work.

Fixed

On Thu, Feb 16, 2017 at 1:06 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

This again needs minor rebasing but basically looks fine. It's a
pretty straightforward extension of the parallel index scan work.

Please make sure that this is pgindent-clean - i.e. that when you
pgindent the files that it touches, pgindent doesn't change anything
of the same parts of the file that you've changed in the patch. Also,
I believe Amit may have made some adjustments to the logic in
nodeIndexScan.c; if so, it would be good to make sure that the
nodeIndexOnlyScan.c changes match what was done there. In particular,
he's got this:

if (reset_parallel_scan && node->iss_ScanDesc->parallel_s
can)
index_parallelrescan(node->iss_ScanDesc);

And you've got this:

+               if (reset_parallel_scan)
+                       index_parallelrescan(node->ioss_ScanDesc);

Fixed.
Please find the attached patch for rebased and cleaner version.

--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v6.patchapplication/octet-stream; name=parallel_index_only_v6.patchDownload
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 98d4f1e..646df08 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -29,6 +29,7 @@
 #include "executor/nodeForeignscan.h"
 #include "executor/nodeSeqscan.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeIndexonlyscan.h"
 #include "executor/tqueue.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
@@ -202,6 +203,10 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+										  e->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -258,6 +263,10 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+											   d->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -737,6 +746,9 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index d5b19b7..c0c03dc 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -21,6 +21,11 @@
  *		ExecEndIndexOnlyScan		releases all storage.
  *		ExecIndexOnlyMarkPos		marks scan position.
  *		ExecIndexOnlyRestrPos		restores scan position.
+ *		ExecIndexOnlyScanEstimate	estimates DSM space needed for
+ *						parallel index-only scan
+ *		ExecIndexOnlyScanInitializeDSM	initialize DSM for parallel
+ *						index-only scan
+ *		ExecIndexOnlyScanInitializeWorker attach to DSM info in parallel worker
  */
 #include "postgres.h"
 
@@ -277,6 +282,15 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * if we are here to just update the scan keys, then don't reset parallel
+	 * scan
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +310,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
+
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
 
+		if (reset_parallel_scan && node->ioss_ScanDesc->parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -536,29 +556,123 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	/*
 	 * Initialize scan descriptor.
 	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
-												indexstate->ioss_RelationDesc,
-												estate->es_snapshot,
+	if (!node->scan.plan.parallel_aware)
+	{
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+											   indexstate->ioss_RelationDesc,
+													estate->es_snapshot,
 												indexstate->ioss_NumScanKeys,
 											indexstate->ioss_NumOrderByKeys);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
-					 indexstate->ioss_ScanKeys,
-					 indexstate->ioss_NumScanKeys,
-					 indexstate->ioss_OrderByKeys,
-					 indexstate->ioss_NumOrderByKeys);
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
+
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to
+		 * the index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
+						 indexstate->ioss_ScanKeys,
+						 indexstate->ioss_NumScanKeys,
+						 indexstate->ioss_OrderByKeys,
+						 indexstate->ioss_NumOrderByKeys);
+	}
 
 	/*
 	 * all done.
 	 */
 	return indexstate;
 }
+
+/* ----------------------------------------------------------------
+ *		Parallel Index-only Scan Support
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanEstimate
+ *
+ *	estimates the space required to serialize index-only scan node.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+						  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+													  estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeDSM
+ *
+ *		Set up a parallel index-only scan descriptor.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+							   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to
+	 * the index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeWorker
+ *
+ *		Copy relevant information from TOC into planstate.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 56eccaf..0e2902e 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1050,7 +1050,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 		 * If appropriate, consider parallel index scan.  We don't allow
 		 * parallel index scan for bitmap or index only scans.
 		 */
-		if (index->amcanparallel && !index_only_scan &&
+		if (index->amcanparallel &&
 			rel->consider_parallel && outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
 		{
@@ -1104,7 +1104,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 			result = lappend(result, ipath);
 
 			/* If appropriate, consider parallel index scan */
-			if (index->amcanparallel && !index_only_scan &&
+			if (index->amcanparallel &&
 				rel->consider_parallel && outer_relids == NULL &&
 				scantype != ST_BITMAPSCAN)
 			{
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index 4018af2..5bb44c2 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -15,6 +15,7 @@
 #define NODEINDEXONLYSCAN_H
 
 #include "nodes/execnodes.h"
+#include "access/parallel.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
@@ -23,4 +24,9 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+/* Support functions for parallel index-only scans */
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 9f41bab..c41100b 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1409,6 +1409,7 @@ typedef struct IndexScanState
  *		ScanDesc		   index scan descriptor
  *		VMBuffer		   buffer in use for visibility map testing, if any
  *		HeapFetches		   number of tuples we were forced to fetch from heap
+ *		ioss_PscanLen	   This is needed for parallel index scan
  * ----------------
  */
 typedef struct IndexOnlyScanState
@@ -1427,6 +1428,7 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	Size		ioss_PscanLen;	/* This is needed for parallel index scan */
 } IndexOnlyScanState;
 
 /* ----------------
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 48fb80e..888dacf 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -92,12 +92,14 @@ explain (costs off)
 explain (costs off)
 	select  sum(parallel_restricted(unique1)) from tenk1
 	group by(parallel_restricted(unique1));
-                     QUERY PLAN                     
-----------------------------------------------------
+                            QUERY PLAN                             
+-------------------------------------------------------------------
  HashAggregate
    Group Key: parallel_restricted(unique1)
-   ->  Index Only Scan using tenk1_unique1 on tenk1
-(3 rows)
+   ->  Gather
+         Workers Planned: 4
+         ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
+(5 rows)
 
 -- test parallel plans for queries containing un-correlated subplans.
 alter table tenk2 set (parallel_workers = 0);
#18Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Rafia Sabih (#17)
1 attachment(s)
Re: Parallel Index-only scan

On Thu, Feb 16, 2017 at 3:40 PM, Rafia Sabih <rafia.sabih@enterprisedb.com>
wrote:

On Thu, Feb 16, 2017 at 1:26 PM, Rahila Syed <rahilasyed90@gmail.com>
wrote:

I reviewed the patch. Overall it looks fine to me.

One comment,

-       if (index->amcanparallel &&
-           !index_only_scan &&
+       if ((index->amcanparallel ||
+           index_only_scan) &&

Why do we need to check for index_only_scan in the above condition. IIUC,
index->amcanparallel is necessary for
parallel index scan to be chosen. We cannot chose parallel index only
scan if index_only_scan is happening
without worrying about index->amcanparallel value. So OR-ing
index->amcanparallel with index_only_scan is probably not
correct.

True, we do not need this, only removing !index_only_scan should work.

Fixed

On Thu, Feb 16, 2017 at 1:06 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

This again needs minor rebasing but basically looks fine. It's a
pretty straightforward extension of the parallel index scan work.

Please make sure that this is pgindent-clean - i.e. that when you
pgindent the files that it touches, pgindent doesn't change anything
of the same parts of the file that you've changed in the patch. Also,
I believe Amit may have made some adjustments to the logic in
nodeIndexScan.c; if so, it would be good to make sure that the
nodeIndexOnlyScan.c changes match what was done there. In particular,
he's got this:

if (reset_parallel_scan && node->iss_ScanDesc->parallel_s
can)
index_parallelrescan(node->iss_ScanDesc);

And you've got this:

+               if (reset_parallel_scan)
+                       index_parallelrescan(node->ioss_ScanDesc);

Fixed.
Please find the attached patch for rebased and cleaner version.

Please find the attached patch with a minor comment update.

--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v7.patchapplication/octet-stream; name=parallel_index_only_v7.patchDownload
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 98d4f1e..646df08 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -29,6 +29,7 @@
 #include "executor/nodeForeignscan.h"
 #include "executor/nodeSeqscan.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeIndexonlyscan.h"
 #include "executor/tqueue.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
@@ -202,6 +203,10 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+										  e->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -258,6 +263,10 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+											   d->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -737,6 +746,9 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index d5b19b7..c0c03dc 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -21,6 +21,11 @@
  *		ExecEndIndexOnlyScan		releases all storage.
  *		ExecIndexOnlyMarkPos		marks scan position.
  *		ExecIndexOnlyRestrPos		restores scan position.
+ *		ExecIndexOnlyScanEstimate	estimates DSM space needed for
+ *						parallel index-only scan
+ *		ExecIndexOnlyScanInitializeDSM	initialize DSM for parallel
+ *						index-only scan
+ *		ExecIndexOnlyScanInitializeWorker attach to DSM info in parallel worker
  */
 #include "postgres.h"
 
@@ -277,6 +282,15 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * if we are here to just update the scan keys, then don't reset parallel
+	 * scan
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +310,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
+
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
 
+		if (reset_parallel_scan && node->ioss_ScanDesc->parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -536,29 +556,123 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	/*
 	 * Initialize scan descriptor.
 	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
-												indexstate->ioss_RelationDesc,
-												estate->es_snapshot,
+	if (!node->scan.plan.parallel_aware)
+	{
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+											   indexstate->ioss_RelationDesc,
+													estate->es_snapshot,
 												indexstate->ioss_NumScanKeys,
 											indexstate->ioss_NumOrderByKeys);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
-					 indexstate->ioss_ScanKeys,
-					 indexstate->ioss_NumScanKeys,
-					 indexstate->ioss_OrderByKeys,
-					 indexstate->ioss_NumOrderByKeys);
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
+
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to
+		 * the index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
+						 indexstate->ioss_ScanKeys,
+						 indexstate->ioss_NumScanKeys,
+						 indexstate->ioss_OrderByKeys,
+						 indexstate->ioss_NumOrderByKeys);
+	}
 
 	/*
 	 * all done.
 	 */
 	return indexstate;
 }
+
+/* ----------------------------------------------------------------
+ *		Parallel Index-only Scan Support
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanEstimate
+ *
+ *	estimates the space required to serialize index-only scan node.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+						  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+													  estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeDSM
+ *
+ *		Set up a parallel index-only scan descriptor.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+							   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to
+	 * the index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeWorker
+ *
+ *		Copy relevant information from TOC into planstate.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 56eccaf..d92826b 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1048,9 +1048,9 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 
 		/*
 		 * If appropriate, consider parallel index scan.  We don't allow
-		 * parallel index scan for bitmap or index only scans.
+		 * parallel index scan for bitmap index scans.
 		 */
-		if (index->amcanparallel && !index_only_scan &&
+		if (index->amcanparallel &&
 			rel->consider_parallel && outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
 		{
@@ -1104,7 +1104,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 			result = lappend(result, ipath);
 
 			/* If appropriate, consider parallel index scan */
-			if (index->amcanparallel && !index_only_scan &&
+			if (index->amcanparallel &&
 				rel->consider_parallel && outer_relids == NULL &&
 				scantype != ST_BITMAPSCAN)
 			{
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index 4018af2..5bb44c2 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -15,6 +15,7 @@
 #define NODEINDEXONLYSCAN_H
 
 #include "nodes/execnodes.h"
+#include "access/parallel.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
@@ -23,4 +24,9 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+/* Support functions for parallel index-only scans */
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 9f41bab..c41100b 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1409,6 +1409,7 @@ typedef struct IndexScanState
  *		ScanDesc		   index scan descriptor
  *		VMBuffer		   buffer in use for visibility map testing, if any
  *		HeapFetches		   number of tuples we were forced to fetch from heap
+ *		ioss_PscanLen	   This is needed for parallel index scan
  * ----------------
  */
 typedef struct IndexOnlyScanState
@@ -1427,6 +1428,7 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	Size		ioss_PscanLen;	/* This is needed for parallel index scan */
 } IndexOnlyScanState;
 
 /* ----------------
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 48fb80e..888dacf 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -92,12 +92,14 @@ explain (costs off)
 explain (costs off)
 	select  sum(parallel_restricted(unique1)) from tenk1
 	group by(parallel_restricted(unique1));
-                     QUERY PLAN                     
-----------------------------------------------------
+                            QUERY PLAN                             
+-------------------------------------------------------------------
  HashAggregate
    Group Key: parallel_restricted(unique1)
-   ->  Index Only Scan using tenk1_unique1 on tenk1
-(3 rows)
+   ->  Gather
+         Workers Planned: 4
+         ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
+(5 rows)
 
 -- test parallel plans for queries containing un-correlated subplans.
 alter table tenk2 set (parallel_workers = 0);
#19Amit Kapila
amit.kapila16@gmail.com
In reply to: Rafia Sabih (#18)
Re: Parallel Index-only scan

On Thu, Feb 16, 2017 at 3:57 PM, Rafia Sabih
<rafia.sabih@enterprisedb.com> wrote:

On Thu, Feb 16, 2017 at 3:40 PM, Rafia Sabih <rafia.sabih@enterprisedb.com>
wrote:

Please find the attached patch for rebased and cleaner version.

Please find the attached patch with a minor comment update.

Few comments:

1.
+ * ioss_PscanLen   This is needed for parallel index scan
  * ----------------
  */
 typedef struct IndexOnlyScanState
@@ -1427,6 +1428,7 @@ typedef struct IndexOnlyScanState
  IndexScanDesc ioss_ScanDesc;
  Buffer ioss_VMBuffer;
  long ioss_HeapFetches;
+ Size ioss_PscanLen; /* This is needed for parallel index scan */

No need to mention same comment at multiple places. I think you keep
it on top of structure. The explanation could be some thing like
"size of parallel index only scan descriptor"

2.
+ node->ioss_ScanDesc->xs_want_itup = true;

I think wherever you are initializing xs_want_itup, you should
initialize ioss_VMBuffer as well. Is there a reason for not doing so?

3.
explain (costs off)
  select  sum(parallel_restricted(unique1)) from tenk1
  group by(parallel_restricted(unique1));
-                     QUERY PLAN
-----------------------------------------------------
+                            QUERY PLAN
+-------------------------------------------------------------------
  HashAggregate
    Group Key: parallel_restricted(unique1)
-   ->  Index Only Scan using tenk1_unique1 on tenk1
-(3 rows)
+   ->  Gather
+         Workers Planned: 4
+         ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
+(5 rows)

It doesn't look good that you want to test parallel index only scan
for a test case that wants to test restricted function. The comments
atop test looks odd. I suggest add a separate test (both explain and
actual execution of query) for parallel index only scan as we have for
parallel plans for other queries and see if we can keep the output of
existing test same.

4.
ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
{
..
+ /*
+ * if we are here to just update the scan keys, then don't reset parallel
+ * scan
+ */
+ if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+ reset_parallel_scan = false;
..
}

I think here you can update the comment to indicate that for detailed
reason refer ExecReScanIndexScan.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Amit Kapila (#19)
1 attachment(s)
Re: Parallel Index-only scan

On Thu, Feb 16, 2017 at 9:25 PM, Amit Kapila <amit.kapila16@gmail.com>
wrote:

Few comments:

1.
+ * ioss_PscanLen   This is needed for parallel index scan
* ----------------
*/
typedef struct IndexOnlyScanState
@@ -1427,6 +1428,7 @@ typedef struct IndexOnlyScanState
IndexScanDesc ioss_ScanDesc;
Buffer ioss_VMBuffer;
long ioss_HeapFetches;
+ Size ioss_PscanLen; /* This is needed for parallel index scan */

No need to mention same comment at multiple places. I think you keep
it on top of structure. The explanation could be some thing like
"size of parallel index only scan descriptor"

Fixed.

2.
+ node->ioss_ScanDesc->xs_want_itup = true;

I think wherever you are initializing xs_want_itup, you should
initialize ioss_VMBuffer as well. Is there a reason for not doing so?

Done.

3.
explain (costs off)
select  sum(parallel_restricted(unique1)) from tenk1
group by(parallel_restricted(unique1));
-                     QUERY PLAN
-----------------------------------------------------
+                            QUERY PLAN
+-------------------------------------------------------------------
HashAggregate
Group Key: parallel_restricted(unique1)
-   ->  Index Only Scan using tenk1_unique1 on tenk1
-(3 rows)
+   ->  Gather
+         Workers Planned: 4
+         ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
+(5 rows)

It doesn't look good that you want to test parallel index only scan
for a test case that wants to test restricted function. The comments
atop test looks odd. I suggest add a separate test (both explain and
actual execution of query) for parallel index only scan as we have for
parallel plans for other queries and see if we can keep the output of
existing test same.

Agree, but actually the objective of this test-case is met even with this
plan. To restrict parallel index-only scan here, modification in query or
other parameters would be required. However, for the proper code-coverage
and otherwise I have added test-case for parallel index-only scan.

4.
ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
{
..
+ /*
+ * if we are here to just update the scan keys, then don't reset parallel
+ * scan
+ */
+ if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+ reset_parallel_scan = false;
..
}

I think here you can update the comment to indicate that for detailed
reason refer ExecReScanIndexScan.

Done.
Please find the attached patch for the revised version.
Just an FYI, in my recent tests on TPC-H 300 scale factor, Q16 showed
improved execution time from 830 seconds to 730 seconds with this patch
when used with parallel merge-join patch [1]/messages/by-id/CAFiTN-tX3EzDw7zYvi97eNADG9PH-nmhLa24Y3uWdzy_Y4SkfQ@mail.gmail.com Regards, Rafia Sabih EnterpriseDB: http://www.enterprisedb.com/.

[1]: /messages/by-id/CAFiTN-tX3EzDw7zYvi97eNADG9PH-nmhLa24Y3uWdzy_Y4SkfQ@mail.gmail.com Regards, Rafia Sabih EnterpriseDB: http://www.enterprisedb.com/
/messages/by-id/CAFiTN-tX3EzDw7zYvi97eNADG9PH-nmhLa24Y3uWdzy_Y4SkfQ@mail.gmail.com
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

Attachments:

parallel_index_only_v8.patchapplication/octet-stream; name=parallel_index_only_v8.patchDownload
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index 98d4f1e..646df08 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -29,6 +29,7 @@
 #include "executor/nodeForeignscan.h"
 #include "executor/nodeSeqscan.h"
 #include "executor/nodeIndexscan.h"
+#include "executor/nodeIndexonlyscan.h"
 #include "executor/tqueue.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
@@ -202,6 +203,10 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
 				ExecIndexScanEstimate((IndexScanState *) planstate,
 									  e->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
+										  e->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanEstimate((ForeignScanState *) planstate,
 										e->pcxt);
@@ -258,6 +263,10 @@ ExecParallelInitializeDSM(PlanState *planstate,
 				ExecIndexScanInitializeDSM((IndexScanState *) planstate,
 										   d->pcxt);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
+											   d->pcxt);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
 											 d->pcxt);
@@ -737,6 +746,9 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
 			case T_IndexScanState:
 				ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
 				break;
+			case T_IndexOnlyScanState:
+				ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
+				break;
 			case T_ForeignScanState:
 				ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
 												toc);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index d5b19b7..66c2ad6 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -21,6 +21,11 @@
  *		ExecEndIndexOnlyScan		releases all storage.
  *		ExecIndexOnlyMarkPos		marks scan position.
  *		ExecIndexOnlyRestrPos		restores scan position.
+ *		ExecIndexOnlyScanEstimate	estimates DSM space needed for
+ *						parallel index-only scan
+ *		ExecIndexOnlyScanInitializeDSM	initialize DSM for parallel
+ *						index-only scan
+ *		ExecIndexOnlyScanInitializeWorker attach to DSM info in parallel worker
  */
 #include "postgres.h"
 
@@ -277,6 +282,16 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
 void
 ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 {
+	bool		reset_parallel_scan = true;
+
+	/*
+	 * If we are here to just update the scan keys, then don't reset parallel
+	 * scan. For detailed reason behind this look in the comments for
+	 * ExecReScanIndexScan.
+	 */
+	if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+		reset_parallel_scan = false;
+
 	/*
 	 * If we are doing runtime key calculations (ie, any of the index key
 	 * values weren't simple Consts), compute the new key values.  But first,
@@ -296,10 +311,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
 	node->ioss_RuntimeKeysReady = true;
 
 	/* reset index scan */
-	index_rescan(node->ioss_ScanDesc,
-				 node->ioss_ScanKeys, node->ioss_NumScanKeys,
-				 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+	if (node->ioss_ScanDesc)
+	{
+
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
 
+		if (reset_parallel_scan && node->ioss_ScanDesc->parallel_scan)
+			index_parallelrescan(node->ioss_ScanDesc);
+	}
 	ExecScanReScan(&node->ss);
 }
 
@@ -536,29 +557,124 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
 	/*
 	 * Initialize scan descriptor.
 	 */
-	indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
-												indexstate->ioss_RelationDesc,
-												estate->es_snapshot,
+	if (!node->scan.plan.parallel_aware)
+	{
+		indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
+											   indexstate->ioss_RelationDesc,
+													estate->es_snapshot,
 												indexstate->ioss_NumScanKeys,
 											indexstate->ioss_NumOrderByKeys);
 
-	/* Set it up for index-only scan */
-	indexstate->ioss_ScanDesc->xs_want_itup = true;
-	indexstate->ioss_VMBuffer = InvalidBuffer;
 
-	/*
-	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
-	 * index AM.
-	 */
-	if (indexstate->ioss_NumRuntimeKeys == 0)
-		index_rescan(indexstate->ioss_ScanDesc,
-					 indexstate->ioss_ScanKeys,
-					 indexstate->ioss_NumScanKeys,
-					 indexstate->ioss_OrderByKeys,
-					 indexstate->ioss_NumOrderByKeys);
+		/* Set it up for index-only scan */
+		indexstate->ioss_ScanDesc->xs_want_itup = true;
+		indexstate->ioss_VMBuffer = InvalidBuffer;
+
+		/*
+		 * If no run-time keys to calculate, go ahead and pass the scankeys to
+		 * the index AM.
+		 */
+		if (indexstate->ioss_NumRuntimeKeys == 0)
+			index_rescan(indexstate->ioss_ScanDesc,
+						 indexstate->ioss_ScanKeys,
+						 indexstate->ioss_NumScanKeys,
+						 indexstate->ioss_OrderByKeys,
+						 indexstate->ioss_NumOrderByKeys);
+	}
 
 	/*
 	 * all done.
 	 */
 	return indexstate;
 }
+
+/* ----------------------------------------------------------------
+ *		Parallel Index-only Scan Support
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanEstimate
+ *
+ *	estimates the space required to serialize index-only scan node.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
+						  ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+
+	node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
+													  estate->es_snapshot);
+	shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeDSM
+ *
+ *		Set up a parallel index-only scan descriptor.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
+							   ParallelContext *pcxt)
+{
+	EState	   *estate = node->ss.ps.state;
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
+	index_parallelscan_initialize(node->ss.ss_currentRelation,
+								  node->ioss_RelationDesc,
+								  estate->es_snapshot,
+								  piscan);
+	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+	node->ioss_VMBuffer = InvalidBuffer;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to
+	 * the index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
+
+/* ----------------------------------------------------------------
+ *		ExecIndexOnlyScanInitializeWorker
+ *
+ *		Copy relevant information from TOC into planstate.
+ * ----------------------------------------------------------------
+ */
+void
+ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
+{
+	ParallelIndexScanDesc piscan;
+
+	piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
+	node->ioss_ScanDesc =
+		index_beginscan_parallel(node->ss.ss_currentRelation,
+								 node->ioss_RelationDesc,
+								 node->ioss_NumScanKeys,
+								 node->ioss_NumOrderByKeys,
+								 piscan);
+	node->ioss_ScanDesc->xs_want_itup = true;
+
+	/*
+	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
+	 * index AM.
+	 */
+	if (node->ioss_NumRuntimeKeys == 0)
+		index_rescan(node->ioss_ScanDesc,
+					 node->ioss_ScanKeys, node->ioss_NumScanKeys,
+					 node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 56eccaf..d92826b 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1048,9 +1048,9 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 
 		/*
 		 * If appropriate, consider parallel index scan.  We don't allow
-		 * parallel index scan for bitmap or index only scans.
+		 * parallel index scan for bitmap index scans.
 		 */
-		if (index->amcanparallel && !index_only_scan &&
+		if (index->amcanparallel &&
 			rel->consider_parallel && outer_relids == NULL &&
 			scantype != ST_BITMAPSCAN)
 		{
@@ -1104,7 +1104,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
 			result = lappend(result, ipath);
 
 			/* If appropriate, consider parallel index scan */
-			if (index->amcanparallel && !index_only_scan &&
+			if (index->amcanparallel &&
 				rel->consider_parallel && outer_relids == NULL &&
 				scantype != ST_BITMAPSCAN)
 			{
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index 4018af2..5bb44c2 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -15,6 +15,7 @@
 #define NODEINDEXONLYSCAN_H
 
 #include "nodes/execnodes.h"
+#include "access/parallel.h"
 
 extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
@@ -23,4 +24,9 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
 extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
 extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
 
+/* Support functions for parallel index-only scans */
+extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt);
+extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc);
+
 #endif   /* NODEINDEXONLYSCAN_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 9f41bab..1c1cb80 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1409,6 +1409,7 @@ typedef struct IndexScanState
  *		ScanDesc		   index scan descriptor
  *		VMBuffer		   buffer in use for visibility map testing, if any
  *		HeapFetches		   number of tuples we were forced to fetch from heap
+ *		ioss_PscanLen	   Size of parallel index-only scan descriptor
  * ----------------
  */
 typedef struct IndexOnlyScanState
@@ -1427,6 +1428,7 @@ typedef struct IndexOnlyScanState
 	IndexScanDesc ioss_ScanDesc;
 	Buffer		ioss_VMBuffer;
 	long		ioss_HeapFetches;
+	Size		ioss_PscanLen;
 } IndexOnlyScanState;
 
 /* ----------------
diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out
index 48fb80e..a5a2232 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -92,12 +92,14 @@ explain (costs off)
 explain (costs off)
 	select  sum(parallel_restricted(unique1)) from tenk1
 	group by(parallel_restricted(unique1));
-                     QUERY PLAN                     
-----------------------------------------------------
+                            QUERY PLAN                             
+-------------------------------------------------------------------
  HashAggregate
    Group Key: parallel_restricted(unique1)
-   ->  Index Only Scan using tenk1_unique1 on tenk1
-(3 rows)
+   ->  Gather
+         Workers Planned: 4
+         ->  Parallel Index Only Scan using tenk1_unique1 on tenk1
+(5 rows)
 
 -- test parallel plans for queries containing un-correlated subplans.
 alter table tenk2 set (parallel_workers = 0);
@@ -146,6 +148,25 @@ select  count((unique1)) from tenk1 where hundred > 1;
   9800
 (1 row)
 
+-- test parallel index-only scans.
+explain (costs off)
+	select  count(*) from tenk1 where thousand > 95;
+                                   QUERY PLAN                                   
+--------------------------------------------------------------------------------
+ Finalize Aggregate
+   ->  Gather
+         Workers Planned: 4
+         ->  Partial Aggregate
+               ->  Parallel Index Only Scan using tenk1_thous_tenthous on tenk1
+                     Index Cond: (thousand > 95)
+(6 rows)
+
+select  count(*) from tenk1 where thousand > 95;
+ count 
+-------
+  9040
+(1 row)
+
 reset enable_seqscan;
 reset enable_bitmapscan;
 set force_parallel_mode=1;
diff --git a/src/test/regress/sql/select_parallel.sql b/src/test/regress/sql/select_parallel.sql
index f5bc4d1..d72addf 100644
--- a/src/test/regress/sql/select_parallel.sql
+++ b/src/test/regress/sql/select_parallel.sql
@@ -56,6 +56,11 @@ explain (costs off)
 	select  count((unique1)) from tenk1 where hundred > 1;
 select  count((unique1)) from tenk1 where hundred > 1;
 
+-- test parallel index-only scans.
+explain (costs off)
+	select  count(*) from tenk1 where thousand > 95;
+select  count(*) from tenk1 where thousand > 95;
+
 reset enable_seqscan;
 reset enable_bitmapscan;
 
#21Amit Kapila
amit.kapila16@gmail.com
In reply to: Rafia Sabih (#20)
Re: Parallel Index-only scan

On Fri, Feb 17, 2017 at 10:35 AM, Rafia Sabih
<rafia.sabih@enterprisedb.com> wrote:

On Thu, Feb 16, 2017 at 9:25 PM, Amit Kapila <amit.kapila16@gmail.com>
wrote:

4.
ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
{
..
+ /*
+ * if we are here to just update the scan keys, then don't reset parallel
+ * scan
+ */
+ if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
+ reset_parallel_scan = false;
..
}

I think here you can update the comment to indicate that for detailed
reason refer ExecReScanIndexScan.

Done.

+       /*
+        * If we are here to just update the scan keys, then don't
reset parallel
+        * scan. For detailed reason behind this look in the comments for
+        * ExecReScanIndexScan.
+        */

You can phrase the second line as "See ExecReScanIndexScan for
details.". Apart from that this patch looks good to me. I have
marked this patch as "Ready For Committer".

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#22Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#21)
Re: Parallel Index-only scan

On Sat, Feb 18, 2017 at 12:02 PM, Amit Kapila <amit.kapila16@gmail.com> wrote:

+       /*
+        * If we are here to just update the scan keys, then don't
reset parallel
+        * scan. For detailed reason behind this look in the comments for
+        * ExecReScanIndexScan.
+        */

You can phrase the second line as "See ExecReScanIndexScan for
details.". Apart from that this patch looks good to me. I have
marked this patch as "Ready For Committer".

Committed, although I neglected to incorporate this change. Not sure
if I should go back and do that; it doesn't read too badly as-is.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Rafia Sabih
rafia.sabih@enterprisedb.com
In reply to: Robert Haas (#22)
Re: Parallel Index-only scan

On Sun, Feb 19, 2017 at 4:02 PM, Robert Haas <robertmhaas@gmail.com> wrote:

Committed, although I neglected to incorporate this change. Not sure
if I should go back and do that; it doesn't read too badly as-is.

Thanks Robert for committing, and thanks Rahila, Amit, and Tushar for
reviewing and testing the patch.

--
Regards,
Rafia Sabih
EnterpriseDB: http://www.enterprisedb.com/

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers