Skip to content
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

Fault Tolerant Execution for PostgreSQL and MySQL connectors #14445

Merged
merged 4 commits into from
Oct 22, 2022

Conversation

mwd410
Copy link
Contributor

@mwd410 mwd410 commented Oct 3, 2022

Description

This PR primarily introduces fault tolerant writes for Postgres and MySQL. To do this, the write process is changed thusly:

  1. Add a ConstructorPageSinkId to trino-spi. The implementation of this is PageSinkId.
    1. The JdbcPageSink takes a ConstructorPageSinkId to use as a long identifier. We chose long instead of a string for the fast joins.
    2. The identifier (see fromTaskId in PageSinkId), is calculated thusly:
      1. The 4 bytes from the StageId's id
      2. The bottom 3 bytes of the partitionId - this affords us ~16 million partitions
      3. The bottom byte of the attemptId - this affords us 256 attempts
  2. When creating the temporary staging table the JdbcPageSinks write to, we subsequently add a trino_page_sink_id column to that temporary table.
  3. The PageSink will include its identifier for that column in the insert.
  4. The PageSink, in finish, will return its identifier in the fragment slice passed back to the coordinator.
  5. The coordinator will then insert all the successful page sink ID fragments from the successful PageSinks into an additional temporary helper table.
  6. In the final insert into ... select from, we do a semi-join to that helper table created in step 7, thereby including only the rows inserted by successful tasks.

Non-technical explanation

This guarantees the ability to only include data from successful tasks. There is no additional necessary cleanup of data from failed tasks. This PR avoids changing any behavior of existing JDBC clients, including in 3rd party plugins, unless you opt-in by extending FaultTolerantJdbcClient. I have opted in for the PostgreSqlClient, and the MySqlClient.

Release notes

( ) This is not user-visible or docs only and no release notes are required.
( ) Release notes are required, please propose a release note for me.
(X) Release notes are required, with the following suggested text:
PostgreSQL and MySQL connectors now fault tolerant and only include data from successful tasks, automatically discarding any data from retried tasks.

# Section
* Allow writes to PostgreSQL and MySQL connectors when fault tolerant execution is enabled (`retry-policy` is set to `TASK` or `QUERY`). (https://github.com/starburstdata/stargate/issues/3877)

@cla-bot
Copy link

cla-bot bot commented Oct 3, 2022

Thank you for your pull request and welcome to the Trino community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. Continue to work with us on the review and improvements in this PR, and submit the signed CLA to [email protected]. Photos, scans, or digitally-signed PDF files are all suitable. Processing may take a few days. The CLA needs to be on file before we merge your changes. For more information, see https://github.com/trinodb/cla

@findepi
Copy link
Member

findepi commented Oct 4, 2022

Atomic writes for PostgreSQL and MySQL connectors

Writes appear atomic in these connectors, because they are publish in ConnectorMetadata.finish* methods.

Did you mean "Support fault tolerant execution when writing to PostgreSQL or MySQL connector" ?

@findepi
Copy link
Member

findepi commented Oct 4, 2022

cc @losipiuk @hashhar

@mwd410 mwd410 changed the title Atomic writes for PostgreSQL and MySQL connectors Fault Tolerant Execution for PostgreSQL and MySQL connectors Oct 4, 2022
@mwd410
Copy link
Contributor Author

mwd410 commented Oct 4, 2022

@findepi yes - sorry for the confusion. my brain was pinned to the language of the original issue assigned to me, and even though it felt like the writes already were atomic, i was just going along with the language. i've adjusted the verbiage in the PR, though i now want to change the name of the AtomicJdbcClient to FaultTolerantJdbcClient and fix any other mention of atomic in my code.

@mwd410 mwd410 force-pushed the mdeady-atomic-writes-3877 branch from 1961526 to 19486e8 Compare October 4, 2022 18:47
@cla-bot cla-bot bot added the cla-signed label Oct 4, 2022
@mwd410 mwd410 force-pushed the mdeady-atomic-writes-3877 branch from 19486e8 to 88b4988 Compare October 4, 2022 18:57
@arhimondr arhimondr self-requested a review October 4, 2022 19:11
@findepi findepi requested review from hashhar and findepi October 4, 2022 19:42
@losipiuk losipiuk self-requested a review October 4, 2022 20:25
@losipiuk
Copy link
Member

losipiuk commented Oct 4, 2022

@mwd410 tests are failing. Please make sure there are no change-relevant tests, fixing those may make shape of PR significantly.

@mwd410 mwd410 force-pushed the mdeady-atomic-writes-3877 branch 5 times, most recently from c8639e8 to e6d855e Compare October 6, 2022 19:09
@mwd410 mwd410 marked this pull request as draft October 6, 2022 20:22
@mwd410 mwd410 force-pushed the mdeady-atomic-writes-3877 branch from e6d855e to 90bb1dc Compare October 12, 2022 15:16
@mwd410 mwd410 marked this pull request as ready for review October 12, 2022 16:43
@mwd410 mwd410 force-pushed the mdeady-atomic-writes-3877 branch 2 times, most recently from 8e03bf9 to f58c304 Compare October 13, 2022 14:09
@@ -928,17 +928,9 @@ protected String createTableSql(RemoteTableName remoteTableName, List<String> co
}

@Override
protected String buildInsertSql(ConnectorSession session, RemoteTableName targetTable, RemoteTableName sourceTable, List<String> columnNames)
protected String postProcessInsertTableClause(ConnectorSession session)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass source sql statement as arguemnt and return postporcessed one (with suffix appended)

@@ -735,7 +743,7 @@ public void rollback()
public ConnectorInsertTableHandle beginInsert(ConnectorSession session, ConnectorTableHandle tableHandle, List<ColumnHandle> columns, RetryMode retryMode)
{
verify(!((JdbcTableHandle) tableHandle).isSynthetic(), "Not a table reference: %s", tableHandle);
if (retryMode != NO_RETRIES) {
if (retryMode != NO_RETRIES && !jdbcClient.supportsFaultTolerantExecution(session)) {
Copy link
Member

@losipiuk losipiuk Oct 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move this checks inside client itself. Now you are checking here, and there doing same check again inside to decide which code flow to follow - it is confusing.
Also please emit different error message if connector does not support retries at all and when connetor supports retries but NON_TRANSACTIONAL_INSERT is set. Currently we would get This connector does not support query retries for latter case and it is not a good error message.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also then maybe we do not need to expose supportsFaultTolerantExecution() from JdbcClient

@@ -698,7 +699,7 @@ public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle
@Override
public ConnectorOutputTableHandle beginCreateTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, Optional<ConnectorTableLayout> layout, RetryMode retryMode)
{
if (retryMode != NO_RETRIES) {
if (retryMode != NO_RETRIES && !jdbcClient.supportsFaultTolerantExecution(session)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as for beginInsert

@@ -844,16 +1013,25 @@ public void rollbackCreateTable(ConnectorSession session, JdbcOutputTableHandle
}
}

@Override
public boolean supportsFaultTolerantExecution(ConnectorSession session)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given internal uses of this method it should rather be "shouldUseFaultTolerantExecution"

Copy link
Member

@losipiuk losipiuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. One comment really.

@mwd410 mwd410 force-pushed the mdeady-atomic-writes-3877 branch 4 times, most recently from 1dfee0f to 173e7c7 Compare October 21, 2022 15:09
@mwd410 mwd410 force-pushed the mdeady-atomic-writes-3877 branch 6 times, most recently from 438a844 to 689a121 Compare October 21, 2022 18:51
public BaseJdbcClient(
BaseJdbcConfig config,
String identifierQuote,
ConnectionFactory connectionFactory,
QueryBuilder queryBuilder,
IdentifierMapping identifierMapping)
{
this(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecate the old constructor and remove all usages of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

4 participants