feat: add process name to 2pc transaction ID + cleanup abandoned#1248
feat: add process name to 2pc transaction ID + cleanup abandoned#1248levkk wants to merge 14 commits into
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
| /// WARNING: This only happens if durability for 2pc is off. Running this | ||
| /// will cause data loss. | ||
| /// | ||
| pub async fn cleanup_abandoned(&self) -> Result<(), Error> { |
There was a problem hiding this comment.
| pub async fn cleanup_abandoned(&self) -> Result<(), Error> { | |
| pub(crate) async fn cleanup_abandoned(&self) -> Result<(), Error> { |
There was a problem hiding this comment.
This one I'm calling from main.rs actually so needs to be pub
There was a problem hiding this comment.
Ah. We should fix that so main doesn't have different visibility rules than lib but that's a separate change
| /// 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 { |
There was a problem hiding this comment.
| pub fn phase_control(transaction: TwoPcTransaction, shard: usize, phase: TwoPcPhase) -> String { | |
| pub(crate) fn phase_control(transaction: TwoPcTransaction, shard: usize, phase: TwoPcPhase) -> String { |
|
|
||
| /// 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( |
There was a problem hiding this comment.
| pub async fn two_pc( | |
| pub(crate) async fn two_pc( |
| } | ||
|
|
||
| /// This transaction was created by this process. | ||
| pub(crate) fn is_mine(&self) -> bool { |
There was a problem hiding this comment.
This function name confused me, I think we can make it clearer.
| 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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
| instance_id().split("-").last().unwrap().parse() | ||
| } | ||
|
|
||
| static DEPLOYMENT_ID: Lazy<Option<String>> = Lazy::new(|| env::var("DEPLOYMENT_ID").ok()); |
There was a problem hiding this comment.
DEPLOYMENT_ID is a really generic name. Should we prefix this?
There was a problem hiding this comment.
Like PGDOG_DEPLOYMENT_ID or something?
There was a problem hiding this comment.
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 :(
Co-authored-by: Sage Griffin <sage@sagetheprogrammer.com>
Co-authored-by: Sage Griffin <sage@sagetheprogrammer.com>
Co-authored-by: Sage Griffin <sage@sagetheprogrammer.com>
| #[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, |
There was a problem hiding this comment.
raising hands to the sky: when would we split the configuration into the subsections and not put everything in general
There was a problem hiding this comment.
LOL. Yeah....might be time, huh?
Globally unique transaction ID
Without hopefully going over the 200 bytes limit.
Example:
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.