Skip to content

Drop transactions from a foreign origin take 2 - #42

Merged
airhorns merged 1 commit into
integration-testsfrom
drop-foreign-origin-2
Dec 3, 2025
Merged

Drop transactions from a foreign origin take 2#42
airhorns merged 1 commit into
integration-testsfrom
drop-foreign-origin-2

Conversation

@airhorns

@airhorns airhorns commented Dec 3, 2025

Copy link
Copy Markdown

The databases we listen to at Gadget see really huge transactions when we do shard moves. Shard moves use logical replication to move data from one database to another, and logical replication does a bigass COPY statement for each table at the start of replication to move the initial state of the table from the source database to the destination.

These create huge transactions in the WAL which the wal-listener needs to process. We don't really care about this data downstream -- we in fact don't want it at all, as it is just a replay of data on a new shard that we've already seen on the old shard. Luckily, postgres has a property in the replication protocol that allows us to tell postgres that we don't actually want these transactions streamed to us in the wal-listener: the ORIGIN option of a subscription!

When you create a subscription, you can specify that you only want messages with no origin, which means only messages that originate from the instance the subscription is on, instead of any upstream instances:

primary1=# CREATE SUBSCRIPTION sub_pri1_pri3
primary1-#   CONNECTION 'dbname=foo host=primary3 user=repuser'
primary1-#   PUBLICATION pub_pri3 WITH (origin = NONE);

This matches what we want when using the wal-listener at Gadget: we want transactions from a data plane database for envs that currently live on that database. But, when an env is moving to that database, the transactions will have an origin of the upstream shard move source, and we don't want that data, as we're still actually serving the data from that source, and listening to it too.

Sadly, this ORIGIN option is only supported on PG 16 and newer, and we were on PG 15 at the time, so we couldn't use it. This PR switches that around, as now we're on PG 17! Horray

At the time though, we were persistent, and tried to make due with a different, lower level feature of the postgres logical replication protocol, where each incoming message includes an origin property that describes where it came from. We hoped we could inspect this property and quickly drop messages that had origins we didn't care about as well. We added the dropForeignOrigin configuration flag to the wal-listener to set this flag in #31. Even more sadly, we learned the hard way that while the origin property of was present in the older postgres versions, and valid in the protocol, it was just never set at all. Sad.

So, this PR drops support for the old, busted, message-inspection based way of origin filtering, in favour of the better peforming, server-side filtering using the ORIGIN property of the subscription.

The databases we listen to at Gadget see really huge transactions when we do shard moves. Shard moves use logical replication to move data from one database to another, and logical replication does a bigass COPY statement for each table at the start of replication to move the initial state of the table from the source database to the destination.

These create huge transactions in the WAL which the wal-listener needs to process. We don't really care about this data downstream -- we in fact don't want it at all, as it is just a replay of data on a new shard that we've already seen on the old shard. Luckily, postgres has a property in the replication protocol that allows us to tell postgres that we don't actually want these transactions streamed to us in the wal-listener: the `ORIGIN` option of a subscription!

When you create a subscription, you can specify that you only want messages with no origin, which means only messages that originate from the instance the subscription is on, instead of any upstream instances:

```
primary1=# CREATE SUBSCRIPTION sub_pri1_pri3
primary1-#   CONNECTION 'dbname=foo host=primary3 user=repuser'
primary1-#   PUBLICATION pub_pri3 WITH (origin = NONE);
```

This matches what we want when using the wal-listener at Gadget: we want transactions from a data plane database for envs that currently live on that database. But, when an env is moving to that database, the transactions will have an origin of the upstream shard move source, and we don't want that data, as we're still actually serving the data from that source, and listening to it too.

Sadly, this `ORIGIN` option is only supported on PG 16 and newer, and we were on PG 15 at the time, so we couldn't use it. This PR switches that around, as now we're on PG 17! Horray

At the time though, we were persistent, and tried to make due with a different, lower level feature of the postgres logical replication protocol, where each incoming message includes an `origin` property that describes where it came from. We hoped we could inspect this property and quickly drop messages that had origins we didn't care about as well. We added the `dropForeignOrigin` configuration flag to the wal-listener to set this flag in #31. Even more sadly, we learned the hard way that while the `origin` property of was present in the older postgres versions, and valid in the protocol, it was just never set at all. Sad.

So, this PR drops support for the old, busted, message-inspection based way of origin filtering, in favour of the better peforming, server-side filtering using the ORIGIN property of the subscription.
@airhorns
airhorns changed the base branch from main to integration-tests December 3, 2025 01:57
@airhorns airhorns changed the title drop foreign origin 2 Drop transactions from a foreign origin take 2 Dec 3, 2025
Comment thread listener/parser.go
// Origin message format:
// Int64 - LSN of the commit on the origin server
// String - Name of the origin
_ = p.readInt64() // Skip the LSN, we only need the name

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.

this doesn't really matter, but claude noticed it was wrong so we fixed it

func (w *WalTransaction) ShouldDropMessage() bool {
return w.dropForeignOrigin && w.origin != ""
}

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.

dont need any of this anymore, postgres does it for us

Comment thread listener/listener.go
// Requires PostgreSQL 16+.
if l.cfg.Listener.DropForeignOrigin {
pluginArgs = append(pluginArgs, "origin 'none'")
}

@airhorns airhorns Dec 3, 2025

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.

this is the entire implementation now :)

@kirinrastogi kirinrastogi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

love the new integration tests

@airhorns
airhorns merged commit 88f931d into integration-tests Dec 3, 2025
2 checks passed
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