Skip to content

feat: add process name to 2pc transaction ID + cleanup abandoned#1248

Open
levkk wants to merge 14 commits into
mainfrom
levkk-pod-transaction-name
Open

feat: add process name to 2pc transaction ID + cleanup abandoned#1248
levkk wants to merge 14 commits into
mainfrom
levkk-pod-transaction-name

Conversation

@levkk

@levkk levkk commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Globally unique transaction ID

Without hopefully going over the 200 bytes limit.

Example:

__pgdog_2pc_pgdog-node-1_1231424234

The last part (the number) can be up to 20 chars long (usize::MAX), so I'm optimistic people don't name their nodes something 150 characters long, but I may be proven wrong.

Cleanup abandoned

Without durability, 2pc transactions can be left unfinished on PgDog crash/dirty shutdown. Leaving those around is bad: they can block vacuum.

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

@levkk levkk changed the title feat: add process name to 2pc transaction ID feat: add process name to 2pc transaction ID + cleanup abandoned Jul 22, 2026
@levkk
levkk requested review from meskill and sgrif July 22, 2026 00:09
/// WARNING: This only happens if durability for 2pc is off. Running this
/// will cause data loss.
///
pub async fn cleanup_abandoned(&self) -> Result<(), Error> {

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.

Suggested change
pub async fn cleanup_abandoned(&self) -> Result<(), Error> {
pub(crate) async fn cleanup_abandoned(&self) -> Result<(), Error> {

@levkk levkk Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This one I'm calling from main.rs actually so needs to be pub

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.

Ah. We should fix that so main doesn't have different visibility rules than lib but that's a separate change

Comment thread pgdog/src/frontend/client/query_engine/two_pc/statement.rs Outdated
/// Build `PREPARE TRANSACTION`, `COMMIT PREPARED`, or `ROLLBACK PREPARED`
/// for a shard participant.
pub fn phase_control(transaction: &str, shard: usize, phase: TwoPcPhase) -> String {
pub fn phase_control(transaction: TwoPcTransaction, shard: usize, phase: TwoPcPhase) -> String {

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.

Suggested change
pub fn phase_control(transaction: TwoPcTransaction, shard: usize, phase: TwoPcPhase) -> String {
pub(crate) fn phase_control(transaction: TwoPcTransaction, shard: usize, phase: TwoPcPhase) -> String {

Comment thread pgdog/src/util.rs Outdated

/// Execute two-phase commit transaction control statements.
pub async fn two_pc(&mut self, name: &str, phase: TwoPcPhase) -> Result<(), Error> {
pub async fn two_pc(

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.

Suggested change
pub async fn two_pc(
pub(crate) async fn two_pc(

Comment thread pgdog/src/frontend/client/query_engine/two_pc/transaction.rs Outdated
}

/// This transaction was created by this process.
pub(crate) fn is_mine(&self) -> bool {

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 function name confused me, I think we can make it clearer.

Suggested change
pub(crate) fn is_mine(&self) -> bool {
pub(crate) fn created_by_this_deployment(&self) -> bool {

fn test_instance_id() {
for id in [1024, 11111111, usize::MAX, usize::MIN] {
let transaction = TwoPcTransaction(id);
let instance_id = instance_id(); // Generate it, it's a singleton.

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.

It feels really gross having TwoPcTransaction rely on global state for its Display impl. Can we separate that out into something that allows the state to be injected?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It does, yeah. We could call it more explicitly for sure, but we also want to avoid ever rendering a "non-unique" ID by accident.

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.

Right, I'm thinking we remove the Display impl and have fn display_name(&self, deployment_id: Option<&str>, instance_id: &str), pushing the state up to the caller and making this easier to test

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That'll be a lot of places, which I guess...doesn't really help, since we can fat-finger the calling site. And those are very much invariants/identifiers which we never ever want to confuse.

Comment thread pgdog/src/util.rs
instance_id().split("-").last().unwrap().parse()
}

static DEPLOYMENT_ID: Lazy<Option<String>> = Lazy::new(|| env::var("DEPLOYMENT_ID").ok());

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.

DEPLOYMENT_ID is a really generic name. Should we prefix this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Like PGDOG_DEPLOYMENT_ID or something?

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.

Yes

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Maybe. We already use other similar-named env variables there, e.g. NODE_ID. I don't expect ppl to run pgdog in an env shared by another app, and if they do, they certainly wouldn't be sharding, and if they did, I would be like...damn. But yeah, gotta be careful with breaking changes, like I'd want to change all env variables to match the new PGDOG_ format, but I cant :(

levkk and others added 4 commits July 22, 2026 06:49
Co-authored-by: Sage Griffin <sage@sagetheprogrammer.com>
Co-authored-by: Sage Griffin <sage@sagetheprogrammer.com>
Co-authored-by: Sage Griffin <sage@sagetheprogrammer.com>
Comment on lines +629 to +635
#[serde(default = "General::two_phase_commit_rollback_abandoned")]
pub two_phase_commit_rollback_abandoned: bool,

/// Maximum amount of time to block startup in order to rollback abandoned
/// transactions.
#[serde(default = "General::two_phase_commit_rollback_abandoned_timeout")]
pub two_phase_commit_rollback_abandoned_timeout: u64,

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.

raising hands to the sky: when would we split the configuration into the subsections and not put everything in general

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

LOL. Yeah....might be time, huh?

Comment thread pgdog-config/src/general.rs
Comment thread pgdog/src/frontend/client/query_engine/two_pc/statement.rs Outdated
Comment thread pgdog/src/frontend/client/query_engine/two_pc/manager.rs Outdated
Comment thread pgdog/src/frontend/client/query_engine/two_pc/manager.rs Outdated
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.

3 participants