-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Fix inserting into transactional table when task_writer_count > 1 #10261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -103,4 +103,18 @@ public void testHiveViewTranslationError() | |
| // TODO: combine this with tests for successful translation (currently in TestHiveViews product test) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testInsertBucketedTransactionalTableLayout() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not in
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yet |
||
| throws Exception | ||
| { | ||
| insertBucketedTableLayout(true); | ||
| } | ||
|
|
||
| @Test | ||
| public void testInsertPartitionedBucketedTransactionalTableLayout() | ||
| throws Exception | ||
| { | ||
| insertPartitionedBucketedTableLayout(true); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,6 +80,13 @@ public boolean isUsePartitionedBucketing() | |
| return usePartitionedBucketing; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isSingleNode() | ||
| { | ||
| // empty hiveTypes means there is no bucketing | ||
| return hiveTypes.isEmpty() && !usePartitionedBucketing; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why no bucketing means no insert distribution? Because you want single file? |
||
| } | ||
|
|
||
| @Override | ||
| public String toString() | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,6 +73,8 @@ | |
| import static java.util.concurrent.TimeUnit.MINUTES; | ||
| import static java.util.stream.Collectors.joining; | ||
| import static java.util.stream.Collectors.toUnmodifiableList; | ||
| import static org.testng.Assert.assertEquals; | ||
| import static org.testng.Assert.assertTrue; | ||
|
|
||
| public class TestHiveTransactionalTable | ||
| extends HiveProductTest | ||
|
|
@@ -546,7 +548,7 @@ public void testSimpleUnpartitionedTransactionalInsert() | |
|
|
||
| // ensure that we treat ACID tables as implicitly bucketed on INSERT | ||
| String explainOutput = (String) onTrino().executeQuery("EXPLAIN " + insertQuery).row(0).get(0); | ||
| Assertions.assertThat(explainOutput).contains("Output partitioning: hive:HivePartitioningHandle{buckets=1"); | ||
| Assertions.assertThat(explainOutput).containsPattern("(.*)Fragment 2 \\[SINGLE\\]\n(.*)Output layout: \\[field, column2\\]\n(.*)Output partitioning: SINGLE \\[\\].*"); | ||
|
|
||
| onTrino().executeQuery(insertQuery); | ||
|
|
||
|
|
@@ -1903,6 +1905,58 @@ public void testDeleteAfterMajorCompaction() | |
| }); | ||
| } | ||
|
|
||
| @Test | ||
| public void testUnbucketedPartitionedTransactionalTableWithTaskWriterCountGreaterThanOne() | ||
| { | ||
| unbucketedTransactionalTableWithTaskWriterCountGreaterThanOne(true); | ||
| } | ||
|
|
||
| @Test | ||
| public void testUnbucketedTransactionalTableWithTaskWriterCountGreaterThanOne() | ||
| { | ||
| unbucketedTransactionalTableWithTaskWriterCountGreaterThanOne(false); | ||
| } | ||
|
|
||
| private void unbucketedTransactionalTableWithTaskWriterCountGreaterThanOne(boolean isPartitioned) | ||
| { | ||
| withTemporaryTable(format("test_unbucketed%s_transactional_table_with_task_writer_count_greater_than_one", isPartitioned ? "_partitioned" : ""), true, isPartitioned, NONE, tableName -> { | ||
| onTrino().executeQuery(format( | ||
| "CREATE TABLE %s " + | ||
| "WITH (" + | ||
| "format='ORC', " + | ||
| "transactional=true " + | ||
| "%s" + | ||
| ") AS SELECT orderkey, orderstatus, totalprice, orderdate, clerk, shippriority, \"comment\", custkey, orderpriority " + | ||
| "FROM tpch.sf1000.orders LIMIT 0", tableName, isPartitioned ? ", partitioned_by = ARRAY['orderpriority']" : "")); | ||
| onTrino().executeQuery("SET SESSION scale_writers = true"); | ||
| onTrino().executeQuery("SET SESSION writer_min_size = '4kB'"); | ||
| onTrino().executeQuery("SET SESSION task_writer_count = 4"); | ||
|
||
| onTrino().executeQuery("SET SESSION hive.target_max_file_size = '1MB'"); | ||
|
|
||
| onTrino().executeQuery( | ||
| format( | ||
| "INSERT INTO %s SELECT orderkey, orderstatus, totalprice, orderdate, clerk, shippriority, \"comment\", custkey, orderpriority " + | ||
| "FROM tpch.sf1000.orders LIMIT 100000", tableName)); | ||
| assertThat(onTrino().executeQuery(format("SELECT count(*) FROM %s", tableName))).containsOnly(row(100000)); | ||
| int numberOfCreatedFiles = onTrino().executeQuery(format("SELECT DISTINCT \"$path\" FROM %s", tableName)).getRowsCount(); | ||
| int expectedNumberOfPartitions = isPartitioned ? 5 : 1; | ||
| assertEquals(numberOfCreatedFiles, expectedNumberOfPartitions, format("There should be only %s files created", expectedNumberOfPartitions)); | ||
|
|
||
| int sizeBeforeDeletion = onTrino().executeQuery(format("SELECT orderkey FROM %s", tableName)).rows().size(); | ||
|
|
||
| onTrino().executeQuery(format("DELETE FROM %s WHERE (orderkey %% 2) = 0", tableName)); | ||
| assertThat(onTrino().executeQuery(format("SELECT COUNT (orderkey) FROM %s WHERE orderkey %% 2 = 0", tableName))).containsOnly(row(0)); | ||
|
|
||
| int sizeOnTrinoWithWhere = onTrino().executeQuery(format("SELECT orderkey FROM %s WHERE orderkey %% 2 = 1", tableName)).rows().size(); | ||
| int sizeOnHiveWithWhere = onHive().executeQuery(format("SELECT orderkey FROM %s WHERE orderkey %% 2 = 1", tableName)).rows().size(); | ||
| int sizeOnTrinoWithoutWhere = onTrino().executeQuery(format("SELECT orderkey FROM %s", tableName)).rows().size(); | ||
|
|
||
| assertEquals(sizeOnHiveWithWhere, sizeOnTrinoWithWhere); | ||
| assertEquals(sizeOnTrinoWithWhere, sizeOnTrinoWithoutWhere); | ||
| assertTrue(sizeBeforeDeletion > sizeOnTrinoWithoutWhere); | ||
| }); | ||
| } | ||
|
|
||
| private void hdfsDeleteAll(String directory) | ||
| { | ||
| if (!hdfsClient.exist(directory)) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Single node doesn't mean single writer (there can be multiple writers per node).
Currently, single node partitioning is used only by system partitioning handle and it's not for insert path.
This code here only deals with local distribution, but there is also
io.trino.sql.planner.optimizations.AddLocalExchanges.Rewriter#visitTableWriterand possibly more, see changes in b8e4e3fI would rather not change this code.
Could we just handle your case using dedicated constant partitioning function which would direct all rows to single writer?