Skip to content

feat: 2pc logic for resharding#1088

Open
yogesh1801 wants to merge 4 commits into
pgdogdev:mainfrom
yogesh1801:feat-2pc-resharding
Open

feat: 2pc logic for resharding#1088
yogesh1801 wants to merge 4 commits into
pgdogdev:mainfrom
yogesh1801:feat-2pc-resharding

Conversation

@yogesh1801

@yogesh1801 yogesh1801 commented Jun 18, 2026

Copy link
Copy Markdown

Use two-phase commit for COPY commands when resharding. This allows for a clean rollback on error.

@CLAassistant

CLAassistant commented Jun 18, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@levkk levkk requested a review from meskill June 18, 2026 14:29
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

@meskill

meskill commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Could you please uncomment the tests in the integration/copy_data/run.sh and make sure you have 2pc enabled for them? We had issues with these tests and I'd like to check if 2pc fixes them

@yogesh1801

Copy link
Copy Markdown
Author

@meskill these tests pass for me even if two_pc flag is disabled

@meskill

meskill commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

@meskill these tests pass for me even if two_pc flag is disabled

yeah, they are just flaky sometimes on ci. don't worry about it, I'll be just checking ci status

@levkk

levkk commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

@meskill are we ok to merge or do we need anything else?

Comment on lines +288 to +289
TwoPcPhase::Phase1 => format!("PREPARE TRANSACTION '{txn}_{shard}'"),
TwoPcPhase::Phase2 => format!("COMMIT PREPARED '{txn}_{shard}'"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this should work rn since the same logic is used for tx name as in the binding

let shard_name = format!("{}_{}", name, shard);

but it could diverge if something changed on one side. It's especially important since the rollback is used exactly from the binding.

Can we share some of the logic of the query or tx name creation between here and binding.rs? that'll prevent possible issues

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@meskill have added statement.rs for this

Comment thread pgdog/src/backend/replication/logical/subscriber/copy.rs Outdated
let query = match phase {
TwoPcPhase::Phase1 => format!("PREPARE TRANSACTION '{txn}_{shard}'"),
TwoPcPhase::Phase2 => format!("COMMIT PREPARED '{txn}_{shard}'"),
_ => unreachable!(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There could be some issues due to the nature of cli calls i.e. when we run pgdog data-sync instead admin command on the running instance:

  • the Manager::monitor should be running anyway, but we don't wait for it's shutdown in the cli path. That means if we fail the prepared transactions could be left on some shards and they won't be cleaned up.
  • wal is also is not enabled in cli path, but on running instance it'll be enabled. We can get different behavior depending how exactly the copy command was run.

We probably should unify this and make sure we wait for shutdown and enable wal for the cli path. But that also means we should think how the old transactions should be recovered..

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

should i take up this as another PR, after thinking about crash recovery

@levkk levkk Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

}

for result in join_all(futures).await {
result?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure if it's really a problem, but the commit/rollback for prepared transactions happens inside Manager::monitor handler and it's async to this code meaning we may actually start new attempt before the manager logic is fired and the cleanup could happen in the middle of new copy attempt.

@levkk wdyt? should we care about it?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe we can add a waiter to make sure the transaction is rolled back / committed?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

That makes sense. Should we add some code to wait for the transaction to be rolled back?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yeah, something like this, but this should be probably done not just after the error, but when starting the new attempt, so we won't wait twice until the transaction is rolled back and then the sleep timeout between retries. We could wait for manager's queue exhausting, before starting to push data.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@meskill @levkk have added a v1 for this problem, could you review this

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Taking a look!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants