Repository navigation
Pin the output settings on every ACE connection - #171
Conversation
ACE compares rows by the text that the server prints for them. The row hash of table-diff and mtree is computed over the text of each column, and the CDC walsender sends pgoutput values as text. This text depends on session settings, and their defaults can differ between nodes (postgresql.conf, ALTER DATABASE ... SET, ALTER ROLE ... SET). Then equal rows give different hashes, and ACE reports false differences, for example for a timestamptz column on nodes with different TimeZone. Every connection, including the replication connection, now sends fixed values in its startup packet: client_encoding = UTF8, DateStyle = 'ISO, MDY', IntervalStyle = postgres, TimeZone = UTC, extra_float_digits = 3, bytea_output = hex, lc_monetary = C and standard_conforming_strings = on. A startup-packet value has priority over role and database defaults and over PGOPTIONS. Logical replication pins a similar set on the publisher; ACE needs more settings, because it compares the text byte by byte. A connection pooler can drop a startup parameter without an error. A ValidateConnect hook compares the values that the server reports in ParameterStatus with the values sent, and fails the connection if they differ. It costs no extra round trip. schema-diff now builds its SET LOCAL statements from the same list. The mtree hash version is now 3, so the next mtree update recomputes the stored hashes once.
TestCatastrophicSingleNodeFailure stops n1 and starts it again in its cleanup. startService returns as soon as the container runs, while PostgreSQL in it still starts. The DROP TABLE of the cleanup and every test that ran next connected in this window and failed with "connection reset by peer"; in a full run this failed about 40 tests. The cleanup also dropped the table while n2 still had to replay the changes it missed while its subscription was disabled. Add two helpers: startServiceAndWait starts a node and waits until it runs a query, and waitForSpockSettled waits until every Spock subscription is replicating and every Spock slot has confirmed the current WAL position. The cleanups of TestCatastrophicSingleNodeFailure now restart n1, re-enable the subscription of n2 and wait for replication, and only then drop the table. TestTableDiffAgainstOriginWithUntil stops n3 and gets the same wait. Cleanup errors are now reported, not ignored.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (10)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughACE pool and replication connections now pin and validate output settings. Schema deparsing uses those settings, and mtree hash version 3 accounts for them. Integration recovery tests add service-readiness and replication-settling checks. ChangesSession output consistency
Integration recovery test readiness
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to The identified lint changes are not required by this repository, and the checked connection and recovery-wait paths show no actionable failure. The PR is mergeable after normal checks. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Pinning connection settings improves comparison consistency. The remaining risk is rollback: an older release can reuse newly generated comparison data without checking compatibility. Retained concerns
Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 64.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 28 functions across 9 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
A rabbit checks the clock set to UTC, Comment |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 13 |
| Duplication | 0 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Problem
ACE compares rows by the text that each server prints for them. table-diff and mtree hash the text of each column, and the CDC walsender sends pgoutput values as text. This text depends on session settings:
TimeZone,DateStyle,IntervalStyle,extra_float_digits,bytea_output,lc_monetary. ACE used the defaults of each server. These defaults come frompostgresql.conf,ALTER DATABASE ... SETandALTER ROLE ... SET, so they can differ between nodes. Then equal rows give different hashes, and ACE reports differences that do not exist. The most common case is atimestamptzcolumn on nodes with differentTimeZone.ACE also did not set
client_encoding. The server then sends text in the database encoding, but Go strings and pgx expect UTF-8.Logical replication solves a part of this problem: the subscriber connects with its own
client_encodingand withdatestyle=ISO,intervalstyle=postgresandextra_float_digits=3(seelibpqwalreceiver.c). This is enough for logical replication, because the subscriber only reads each value back. ACE compares the text byte by byte, so it needs more settings, with fixed values.Changes
Every ACE connection, the pool and the replication connection, sends these values in its startup packet:
client_encodingUTF8DateStyleISO, MDYIntervalStylepostgresTimeZoneUTCextra_float_digits3bytea_outputhexlc_monetaryCstandard_conforming_stringsonA value in the startup packet has priority over role and database defaults and over
PGOPTIONS. It costs no extra round trip, and it also covers the replication connection, which has noAfterConnecthook. Keys that differ only in case (for exampleTimeZonefrom a connection string, ortimezonefromPGTZ) are removed, so each setting is sent once.ValidateConnecthook compares the values that the server reports inParameterStatus(client_encoding,DateStyle,IntervalStyle,TimeZone,standard_conforming_strings) with the values that ACE sent. If one of them differs, the connection fails with an error that names the setting. An existing hook, for example fromtarget_session_attrs, still runs first.SET LOCALstatements from the same list (auth.OutputSettings()), and addssearch_path = pg_catalog. So the two places cannot get different values.CurrentHashVersionis now 3. The nextmtree updaterecomputes all stored hashes of a tree once.