diff --git a/CHANGELOG.carto.md b/CHANGELOG.carto.md index ad8079e94a526..13f3c0e42d64f 100644 --- a/CHANGELOG.carto.md +++ b/CHANGELOG.carto.md @@ -1,5 +1,12 @@ # Changelog +## 10.1.2+carto-1 + +**Release data**: 2018-XX-XX + +Changes + - Revert [#10](https://github.com/CartoDB/postgres/pull/10) as the patch was incomplete and causing crashes + ## 10.1.1+carto-1 **Release date**: 2017-12-05 diff --git a/doc/src/sgml/parallel.sgml b/doc/src/sgml/parallel.sgml index 1f5efd9e6d9fc..2a25f21eb4b8d 100644 --- a/doc/src/sgml/parallel.sgml +++ b/doc/src/sgml/parallel.sgml @@ -151,10 +151,9 @@ EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; The query writes any data or locks any database rows. If a query contains a data-modifying operation either at the top level or within - a CTE, no parallel plans for that query will be generated. As an - exception, the commands CREATE TABLE, SELECT - INTO, and CREATE MATERIALIZED VIEW which create a new - table and populate it can use a parallel plan. + a CTE, no parallel plans for that query will be generated. This is a + limitation of the current implementation which could be lifted in a + future release. @@ -242,6 +241,15 @@ EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; + + + A prepared statement is executed using a CREATE TABLE .. AS + EXECUTE .. statement. This construct converts what otherwise + would have been a read-only operation into a read-write operation, + making it ineligible for parallel query. + + + The transaction isolation level is serializable. This situation diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index f73894676ed27..2d321171fad54 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2581,17 +2581,15 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, int options) { /* - * Parallel operations are required to be strictly read-only in a parallel - * worker. Parallel inserts are not safe even in the leader in the - * general case, because group locking means that heavyweight locks for - * relation extension or GIN page locks will not conflict between members - * of a lock group, but we don't prohibit that case here because there are - * useful special cases that we can safely allow, such as CREATE TABLE AS. - */ - if (IsParallelWorker()) + * For now, parallel operations are required to be strictly read-only. + * Unlike heap_update() and heap_delete(), an insert should never create a + * combo CID, so it might be possible to relax this restriction, but not + * without more thought and testing. + */ + if (IsInParallelMode()) ereport(ERROR, (errcode(ERRCODE_INVALID_TRANSACTION_STATE), - errmsg("cannot insert tuples in a parallel worker"))); + errmsg("cannot insert tuples during a parallel operation"))); if (relation->rd_rel->relhasoids) { diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index 17cbce0bdbdd2..97f9c55d6e764 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -326,8 +326,8 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, query = linitial_node(Query, rewritten); Assert(query->commandType == CMD_SELECT); - /* plan the query */ - plan = pg_plan_query(query, CURSOR_OPT_PARALLEL_OK, params); + /* plan the query --- note we disallow parallelism */ + plan = pg_plan_query(query, 0, params); /* * Use a snapshot with an updated command ID to ensure this query sees diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index fa1b716530791..953e74d73cae3 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -400,6 +400,8 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, * We have to rewrite the contained SELECT and then pass it back to * ExplainOneQuery. It's probably not really necessary to copy the * contained parsetree another time, but let's be safe. + * + * Like ExecCreateTableAs, disallow parallelism in the plan. */ CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt; List *rewritten; @@ -407,7 +409,7 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query))); Assert(list_length(rewritten) == 1); ExplainOneQuery(linitial_node(Query, rewritten), - CURSOR_OPT_PARALLEL_OK, ctas->into, es, + 0, ctas->into, es, queryString, params, queryEnv); } else if (IsA(utilityStmt, DeclareCursorStmt)) diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 76147d9d65b82..53dd2f0fc0cb0 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1697,9 +1697,11 @@ ExecutePlan(EState *estate, /* * If the plan might potentially be executed multiple times, we must force - * it to run without parallelism, because we might exit early. + * it to run without parallelism, because we might exit early. Also + * disable parallelism when writing into a relation, because no database + * changes are allowed in parallel mode. */ - if (!execute_once) + if (!execute_once || dest->mydest == DestIntoRel) use_parallel_mode = false; estate->es_use_parallel_mode = use_parallel_mode; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 34f6267c78505..cc3d7af42f62f 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -257,16 +257,6 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) * to values that don't permit parallelism, or if parallel-unsafe * functions are present in the query tree. * - * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE - * MATERIALIZED VIEW to use parallel plans, but this is safe only because - * the command is writing into a completely new table which workers won't - * be able to see. If the workers could see the table, the fact that - * group locking would cause them to ignore the leader's heavyweight - * relation extension lock and GIN page locks would make this unsafe. - * We'll have to fix that somehow if we want to allow parallel inserts in - * general; updates and deletes have additional problems especially around - * combo CIDs.) - * * For now, we don't try to use parallel mode if we're running inside a * parallel worker. We might eventually be able to relax this * restriction, but for now it seems best not to have parallel workers diff --git a/src/test/regress/expected/write_parallel.out b/src/test/regress/expected/write_parallel.out deleted file mode 100644 index 0c4da2591a0fc..0000000000000 --- a/src/test/regress/expected/write_parallel.out +++ /dev/null @@ -1,79 +0,0 @@ --- --- PARALLEL --- --- Serializable isolation would disable parallel query, so explicitly use an --- arbitrary other level. -begin isolation level repeatable read; --- encourage use of parallel plans -set parallel_setup_cost=0; -set parallel_tuple_cost=0; -set min_parallel_table_scan_size=0; -set max_parallel_workers_per_gather=4; --- --- Test write operations that has an underlying query that is eligble --- for parallel plans --- -explain (costs off) create table parallel_write as - select length(stringu1) from tenk1 group by length(stringu1); - QUERY PLAN ---------------------------------------------------- - Finalize HashAggregate - Group Key: (length((stringu1)::text)) - -> Gather - Workers Planned: 4 - -> Partial HashAggregate - Group Key: length((stringu1)::text) - -> Parallel Seq Scan on tenk1 -(7 rows) - -create table parallel_write as - select length(stringu1) from tenk1 group by length(stringu1); -drop table parallel_write; -explain (costs off) select length(stringu1) into parallel_write - from tenk1 group by length(stringu1); - QUERY PLAN ---------------------------------------------------- - Finalize HashAggregate - Group Key: (length((stringu1)::text)) - -> Gather - Workers Planned: 4 - -> Partial HashAggregate - Group Key: length((stringu1)::text) - -> Parallel Seq Scan on tenk1 -(7 rows) - -select length(stringu1) into parallel_write - from tenk1 group by length(stringu1); -drop table parallel_write; -explain (costs off) create materialized view parallel_mat_view as - select length(stringu1) from tenk1 group by length(stringu1); - QUERY PLAN ---------------------------------------------------- - Finalize HashAggregate - Group Key: (length((stringu1)::text)) - -> Gather - Workers Planned: 4 - -> Partial HashAggregate - Group Key: length((stringu1)::text) - -> Parallel Seq Scan on tenk1 -(7 rows) - -create materialized view parallel_mat_view as - select length(stringu1) from tenk1 group by length(stringu1); -drop materialized view parallel_mat_view; -prepare prep_stmt as select length(stringu1) from tenk1 group by length(stringu1); -explain (costs off) create table parallel_write as execute prep_stmt; - QUERY PLAN ---------------------------------------------------- - Finalize HashAggregate - Group Key: (length((stringu1)::text)) - -> Gather - Workers Planned: 4 - -> Partial HashAggregate - Group Key: length((stringu1)::text) - -> Parallel Seq Scan on tenk1 -(7 rows) - -create table parallel_write as execute prep_stmt; -drop table parallel_write; -rollback; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index a114ac92c17ad..eefdeeacaef6f 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -96,7 +96,6 @@ test: rules psql_crosstab amutils # run by itself so it can run parallel workers test: select_parallel -test: write_parallel # no relation related tests can be put in this group test: publication subscription diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index ef275d0d9a2b5..76b0de30a7a51 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -134,7 +134,6 @@ test: stats_ext test: rules test: psql_crosstab test: select_parallel -test: write_parallel test: publication test: subscription test: amutils diff --git a/src/test/regress/sql/write_parallel.sql b/src/test/regress/sql/write_parallel.sql deleted file mode 100644 index 78b479cedf4b6..0000000000000 --- a/src/test/regress/sql/write_parallel.sql +++ /dev/null @@ -1,42 +0,0 @@ --- --- PARALLEL --- - --- Serializable isolation would disable parallel query, so explicitly use an --- arbitrary other level. -begin isolation level repeatable read; - --- encourage use of parallel plans -set parallel_setup_cost=0; -set parallel_tuple_cost=0; -set min_parallel_table_scan_size=0; -set max_parallel_workers_per_gather=4; - --- --- Test write operations that has an underlying query that is eligble --- for parallel plans --- -explain (costs off) create table parallel_write as - select length(stringu1) from tenk1 group by length(stringu1); -create table parallel_write as - select length(stringu1) from tenk1 group by length(stringu1); -drop table parallel_write; - -explain (costs off) select length(stringu1) into parallel_write - from tenk1 group by length(stringu1); -select length(stringu1) into parallel_write - from tenk1 group by length(stringu1); -drop table parallel_write; - -explain (costs off) create materialized view parallel_mat_view as - select length(stringu1) from tenk1 group by length(stringu1); -create materialized view parallel_mat_view as - select length(stringu1) from tenk1 group by length(stringu1); -drop materialized view parallel_mat_view; - -prepare prep_stmt as select length(stringu1) from tenk1 group by length(stringu1); -explain (costs off) create table parallel_write as execute prep_stmt; -create table parallel_write as execute prep_stmt; -drop table parallel_write; - -rollback;