Skip to content

CONFIG_PG_MEMORY_OVERCOMMIT tells a PostgreSQL operator whether the backends that actually showed up could overrun the box, with what the settings permit stated beside it (#3691 lane 47) - #3907

Merged
erikdarlingdata merged 4 commits into
devfrom
fix/3691-overcommit-observed-backends
Sep 22, 2026
Merged

erikdarlingdata merged 4 commits into
devfrom
fix/3691-overcommit-observed-backends

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

PARTIAL for #3691 — do not close. This implements Erik's ruling on the D2 read (ruling comment; D2 measurement): "CONFIG_PG_MEMORY_OVERCOMMIT is graded on the connections that actually show up, not on max_connections."

What an operator now learns

Until now the overcommit card said "your settings permit more memory than the box has." That is true of about half the measured population: 24 of 50 Aurora clusters scored overcommit_ratio ≥ 1.0 in D2, and 87% of that worst case was the backend term max_connections × work_mem × (1 + max_parallel_workers_per_gather). The same clusters never peaked above about 10% of max_connections, and numbackends tracks the capture peak within 10%. A card that fires on half a fleet for connections that never arrive describes a permission. It says nothing about the server.

The card now grades the worst case at the window's peak backend count:

  • basis 1. At least one instant in the window sampled pg_database_stats.numbackends. The backend term becomes min(peak, max_connections) × work_mem × (1 + parallel), and the fact's value and overcommit_ratio hold that worst case over the window's minimum memory_total_bytes. The headline reads "The worst-case memory at the window's peak of N backends is X — R× the host's T". The investigation then states the configured permission as its own sentence: "The settings permit Y× if all max_connections sorted at once — a ceiling the window's concurrency never approached / approached (≥ 50 %) / reached (clamped, and why): peak N of M; stated, not graded."
  • basis 0. No instant sampled the level: a pre-V133 store, an empty pg_database_stats window, or a failed level read. There is no evidence of concurrency, so the permission is the only statement the store supports. It is graded exactly as before, and the card says so: "No backend count was sampled in the window … this is the configured permission … and that is what was graded."

The denominator is unchanged, as ruled. On the D2 tail cluster the expected effect is 1.41 → about 0.25. A server whose real concurrency approaches its limit still fires.

Where it reads from

The peak is the existing PgTargetNumbackendsPeakSql, the same statement PG_SESSION_SATURATION divides by (lane 25, #3782). It is reused, not copied, so the two facts cannot disagree about the peak. It runs as a third statement on the memory family's connection, with the same timeout, and only when there is a composition to form (terms present and at least one host sample). It sits in its own try/catch: a pre-V133 store raises 42703 on numbackends, and that must not cost the pressure fact the host read already earned. The composition falls back to basis 0. No new SQL, no migration, no rung.

Stamps (doubles-only, as always)

Always: overcommit_basis (0/1), configured_overcommit_ratio (the old number, stated, not graded), peak_backends_samples. Only when sampled: peak_backends (raw, before the clamp, so a peak above the ceiling stays visible), observed_backend_term_bytes, observed_worst_case_bytes. peak_backends_at is omitted because the family has no time-as-double precedent. Every configured term (worst_case_bytes, backend_term_bytes, …) still rides as read.

Lineage of every bar — unchanged

OvercommitRatioLine = 1.0 (engine-defined, threshold_lineage = 1) and OvercommitCriticalRatio = 2.0 (the chosen band, lineage 0 when it participates) keep their values and scoring branches. Only the line's doc changed: it now says the line applies to the observed ratio at basis 1 and to the configured ratio at basis 0. The collector changes which ratio sits under the key the scorer already grades.

Co-fire gating — unchanged

Alone the card is still exactly the advisory base (0.4). PG_HOST_MEMORY_PRESSURE or PG_TEMP_SPILL lifts it (0.5 each, 0.6 both, 0.7 with the band beside a co-fire). The band alone lifts nothing (D5).

What it does NOT do

It does not change the denominator, either bar's value, PG_HOST_MEMORY_PRESSURE, any rung or SQL, or the counter-objective sentences (pooler, per-role work_mem). It adds no DDL.

Pins

Harness first: net10.0 in-worktree obj/mactest, AssemblyName=Darling.Tests, xunit.v3, against a throwaway timescale/timescaledb:2.28.1-pg18, DARLING_TEST_PG set. Baseline before any pin: 162/162 green on Part A's product commits, live tests included. That is the proof that every existing number holds.

Pins that moved: none. Every existing PgTargetMemoryTests fixture lands on basis 0. The unit facts pass ReadTerms(Snapshot()) with no peak. The Sum(ratio) helper carries no basis key. The live quiet, short and stock e2e planters leave numbackends NULL. Those planters were deliberately not given numbackends: at a realistic peak the quiet card stops firing and the exit-criterion pin loses its subject.

New (3 facts + 1 extended):

  • TheGradedRatio_IsTheWindowsPeakBackends_…_AndAPeakAboveTheCeilingClamps:
    • (i) max_connections 5000, work_mem 4MB, host 16 GiB, peak 50 → overcommit_ratio 0.30 < 1, configured_overcommit_ratio 3.92 > 1, base 0, no card.
    • (ii) peak 4,000 → fires at exactly 0.4, one card.
    • (iii) basis 0 (no peak; or a peak with 0 samples, meaning "not observed", never "zero backends") → the permission is the value, stamp 0, base 0.4, observed keys absent.
    • (iv) peak 6,000 > 5,000 → peak_backends raw 6000, the observed term equals the configured term, and the graded ratio equals the permission.
  • TheAdvice_StatesWhichWorstCaseWasGraded_…: (v) the three shapes, composed from the stamps the real emit writes. Basis 1 is covered as never approached (exact headline), approached (4,000, and the 2,500/2,499 boundary on the 50% word) and reached (clamped, with the reason). Basis 0 says no count was sampled. The static text names the rule. Counter-objectives and no-DDL are checked on every block.
  • Live AnAuroraTarget_WithSampledBackends_IsGradedAtThePeak_AndThePermissionIsStatedNotGraded: a NEW planter (PlantDatabaseStatsWithBackendsAsync) writes numbackends across two databases, with a single instant peaking at 30 + 20. Through the REAL PgTargetFactCollector: basis 1 at 50, 0.85×, configured_overcommit_ratio 6.12. The peak and sample count equal what PgTargetNumbackendsPeakSql returns on its own. Through the real analyze_server nothing stories through the sum (all-clear); get_analysis_facts shows base 0 and the stamps.
  • Extended AMeasuredWindow_EmitsThePressureAndTheSum…, the natural basis-0 twin: overcommit_basis = 0, configured_overcommit_ratio == value, peak_backends_samples = 0, observed keys absent.

Final local run: 196/196 green: PgTargetMemoryTests 17 (4 live), PgTargetFactCollectorTests 8, PgTargetV3PlumbingTests 3, PgTargetBetweenWavesV3Tests 8, PgTargetSharedSwitchRoutingTests 28, TsqlConventionGuardTests 14, DocCommentHygieneTests 77, RepoFileAdoptionTests 2, PgTargetThresholdLineageTests 4, PgTargetMeasuredLineageTests 4, LiveCleanupConversionRatchetTests 15, LivePostgresCollectionHygieneTests 11, FleetIdentifierScrubTests 2, StoreSqlClockDisciplineTests 3. Required checks are now build, Darling PostgreSQL tests and Lite tests (result). Windows build is the first execution of the Lite/Viewer censuses.

Self-review

Files:

  • PgTargetFactCollector.Memory.cs: MemoryTerms gains the optional peak, the derived observed term and the observed worst case; the level read and its own degrade; the fact stamps.
  • PgTargetScorer.Memory.cs: six key constants, plus the line's doc sentence.
  • PgTargetAdvice.Memory.cs: headline subject, ObservedSentence, ConfiguredOnlySentence, and the static text naming the rule.
  • PgTargetMemoryTests.cs: the pins above.

Riskiest hunks and their pins:

  1. ObservedBackendTermBytes. The clamp and the PeakBackendsSamples > 0 guard; a peak with 0 samples must be null, not 0 backends. Pinned by (iii) and (iv).
  2. The level read's placement inside the memory family's outer try. Its own catch means a 42703 degrades to basis 0 without losing the pressure fact. The live fact pins the happy path end to end; the unchanged stock and Aurora e2e pins prove the NULL-numbackends path is basis 0 and byte-identical.
  3. The advice's observed gate (basis > 0 && peak_backends present). A fact from before the stamp reads as basis 0. Pinned by the unchanged Sum(ratio) advice fact plus the three new shapes.

Reviewer checklist: the scorer's grading branch is untouched (git diff 2f30c9faf -- PerformanceMonitor.Analysis/PgTargetScorer.Memory.cs is constants and doc only). The collector adds no SQL (it reuses PgTargetNumbackendsPeakSql). The denominator is unchanged. CRLF on every .cs.

 Darling/Darling.Tests/PgTargetMemoryTests.cs       | 277 ++++++++++++++++++++-
 .../PgTargetFactCollector.Memory.cs                | 105 +++++++-
 .../PgTargetAdvice.Memory.cs                       |  56 ++++-
 .../PgTargetScorer.Memory.cs                       |  30 ++-
 4 files changed, 448 insertions(+), 20 deletions(-)

…s engine line says it now grades the observed worst case (#3691 lane 47)

New metadata keys beside overcommit_ratio: overcommit_basis (1 observed, 0 configured),
configured_overcommit_ratio, peak_backends, peak_backends_samples, observed_backend_term_bytes,
observed_worst_case_bytes. OvercommitRatioLine's doc gains the sentence Erik's ruling on the D2
read requires: the line is applied to the observed ratio, and to the configured ratio only when no
concurrency was observed. No constant, no scoring branch and no threshold_lineage stamp changes.
…howed up, with the configured worst case stated beside it (#3691 lane 47)

Erik's ruling on the D2 read (24 of 50 measured clusters at or past 1.0 on the configured ratio, 87 %
of it the max_connections backend term, peak sessions never past ~10 % of max_connections): after the
host read the collector runs the existing PgTargetNumbackendsPeakSql (the statement PG_SESSION_SATURATION
divides by, so the two facts cannot disagree about the peak) and forms the backend term at
min(peak numbackends, max_connections). overcommit_ratio carries that observed ratio (basis 1);
configured_overcommit_ratio always carries the old number. No sampled instant (pre-V133, empty
pg_database_stats, a failed level read under its own degrade) keeps today's configured ratio at basis 0.
Denominator unchanged.
…k backends with the configured permission as its own sentence, or the permission alone when no backend count was sampled (#3691 lane 47)

Three shapes. Basis 1: the headline states the worst case at the window's peak of N backends against
the host, and the investigation states the configured permission separately (the settings permit Yx if
all max_connections sorted at once, a ceiling the window's concurrency never approached / approached /
reached, peak N of M; a peak at or past max_connections is said to be clamped). Basis 0: the sum as
today, plus the plain statement that no backend count was sampled, so the permission is what was graded.
The fact-less static names the rule. Counter-objective sentences (pooler, per-role work_mem) unchanged;
no DDL.
…nds: 50 of 5000 reads 0.3x with the 3.92x permission stated, 4000 fires at 0.4, no sample grades the permission, a peak over the ceiling clamps, the advice's three shapes, and a live collector read (#3691 lane 47)
@erikdarlingdata
erikdarlingdata merged commit 77252d5 into dev Sep 22, 2026
15 of 16 checks passed
@erikdarlingdata
erikdarlingdata deleted the fix/3691-overcommit-observed-backends branch September 22, 2026 19:43
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.

1 participant