Skip to content

TRT-2741: Add partitioned prefix sum tables for matview refresh optimization#3762

Open
mstaeble wants to merge 1 commit into
openshift:mainfrom
mstaeble:trt-2741-prefix-sum-tables
Open

TRT-2741: Add partitioned prefix sum tables for matview refresh optimization#3762
mstaeble wants to merge 1 commit into
openshift:mainfrom
mstaeble:trt-2741-prefix-sum-tables

Conversation

@mstaeble

@mstaeble mstaeble commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds two new LIST(release)->RANGE(date) partitioned tables: test_daily_totals and test_cumulative_summaries
  • test_daily_totals is a partitioned replacement for test_daily_summaries, populated in parallel
  • test_cumulative_summaries stores running prefix sums from test_daily_totals, enabling sub-second queries for any arbitrary date range via prefix sum subtraction (cum(end) - cum(start-1))
  • Variant grouping happens at query time via JOIN to prow_jobs, so variant changes are immediately reflected without any rebuild step
  • Phase 1 is additive only: new tables are populated alongside existing test_daily_summaries. Nothing reads from them yet. Later phases will switch query paths and remove the old matview dependency.
  • Includes sippy backfill CLI command and backfill-summaries.sh script for populating the tables
  • RefreshData now returns errors and short-circuits on failure
  • All refresh and backfill operations process data day-by-day, then release-by-release, for full partition pruning and restartability

Staging validation

Correctness

  • Full 91-day backfill completed on staging (prod-scale data)
  • test_daily_totals values verified identical to test_daily_summaries across 200 sampled rows (two releases, two dates)
  • Prefix sum subtraction verified correct: range queries match direct SUM from daily summaries (98/98 entities, 50/50 variant range queries)
  • Carry-forward behavior verified: gap-day cumulative values correctly equal previous day (5/5 entities)
  • Base case verified: first-day cumulative values equal raw daily values (100/100 entities)

Performance (warm queries, prod-scale staging data)

Query Matview Prefix Sum Speedup
Install page (filtered, release 5.0) 9.5s 200ms 47x
TestReportsByVariant (all tests, 4.22) 58s 3.4s 17x
CR ad-hoc query (28-day window) 47s 3.4s 14x
PlatformInfraSuccess 1.1s 0.6s 1.8x
Single test lookup 15ms 22ms ~tie

Refresh pipeline

Operation Non-partitioned Partitioned Speedup
Cumulative summary, single release+date 0.6s 0.11s 5.5x

Test plan

  • make lint passes
  • make test passes
  • make e2e passes (108 tests, 1 skipped)
  • sippy migrate creates partitioned tables on staging
  • sippy backfill creates partitions via gopar and populates data correctly
  • Partition names verified under 62-char PostgreSQL identifier limit

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a new CLI backfill command to backfill daily, totals, and cumulative summary data over a chosen date range.
    • Added an optional deployment script to run backfills in batches, with dry-run and progress reporting.
  • Improvements
    • Refresh now rebuilds daily summaries, totals, and cumulative summaries in one flow.
    • Refresh operations include a bounded auto-fill behavior; older ranges can be restored via backfill.
  • Bug Fixes
    • Refresh failures are now surfaced and propagated more reliably.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@openshift-ci-robot

openshift-ci-robot commented Jul 12, 2026

Copy link
Copy Markdown

@mstaeble: This pull request references TRT-2741 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Adds three new LIST(release)->RANGE(date) partitioned tables: test_daily_totals, test_cumulative_summaries, variant_cumulative_summaries
  • Tables store pre-aggregated daily totals and running prefix sums, enabling sub-second queries for any arbitrary date range via prefix sum subtraction
  • Phase 1 is additive only: new tables are populated alongside existing test_daily_summaries. Nothing reads from them yet.
  • Includes sippy backfill CLI command and backfill-summaries.sh script for populating the tables
  • RefreshData now returns errors and short-circuits on failure

Test plan

  • make lint passes
  • make test passes
  • make e2e passes (108 tests, 1 skipped)
  • Deployed to staging, ran sippy migrate, verified partitioned tables created
  • Full 91-day backfill completed on staging, data verified correct against existing test_daily_summaries
  • Benchmarked: install page query goes from 9.5s (matview) to 200ms (prefix sum), CR ad-hoc queries from 47s to 3.4s

🤖 Generated with Claude Code

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 12, 2026
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@mstaeble, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 19f1be6c-bfa4-46cf-b557-9605be382f9c

📥 Commits

Reviewing files that changed from the base of the PR and between d5e4e2f and 4039a46.

📒 Files selected for processing (20)
  • cmd/sippy/backfill.go
  • cmd/sippy/load.go
  • cmd/sippy/main.go
  • cmd/sippy/refresh.go
  • cmd/sippy/seed_data.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/db/cumulativesummary/cumulative_summary_test.go
  • pkg/db/cumulativesummary/date_range.go
  • pkg/db/cumulativesummary/date_range_test.go
  • pkg/db/dailysummary/dailysummary.go
  • pkg/db/dailysummary/dailysummary_test.go
  • pkg/db/db.go
  • pkg/db/migrations/000006_partition_cumulative_tables.down.sql
  • pkg/db/migrations/000006_partition_cumulative_tables.up.sql
  • pkg/db/migrations/MANIFEST
  • pkg/db/models/prow.go
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/sippyserver/server.go
  • scripts/backfill-summaries.sh
  • scripts/updatesuites.go

Walkthrough

Adds civil-date daily and cumulative summary aggregation, partitioned storage, refresh orchestration, and CLI/OpenShift backfill workflows.

Changes

Summary pipeline

Layer / File(s) Summary
Partitioned summary storage contracts
pkg/db/migrations/*, pkg/db/models/prow.go, pkg/db/db.go
Adds partitioned daily-total and cumulative-summary tables, models, indexes, migration registration, and partition management.
Civil-date daily aggregation
pkg/db/dailysummary/*
Refactors aggregation to civil dates and adds refresh/backfill flows for daily summaries and totals.
Cumulative summary rollups
pkg/db/cumulativesummary/*
Adds bounded incremental refresh, explicit backfill, cumulative prefix-sum upserts, and date-range/error tests.
Refresh orchestration and integrations
pkg/sippyserver/server.go, cmd/sippy/*, scripts/updatesuites.go, pkg/flags/postgres_benchmarking_test.go
Sequences daily, totals, cumulative, and materialized-view refreshes through RefreshOptions, updating callers and error handling.
Backfill command and batch workflow
cmd/sippy/backfill.go, cmd/sippy/main.go, scripts/backfill-summaries.sh
Adds validated date-range backfill execution and batched OpenShift pod orchestration.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant BackfillScript
  participant BackfillCommand
  participant PostgreSQL
  Operator->>BackfillScript: provide table and batching options
  BackfillScript->>BackfillCommand: launch sippy backfill with date range
  BackfillCommand->>PostgreSQL: ensure partitions
  BackfillCommand->>PostgreSQL: write selected summary table
Loading

Suggested labels: ready-for-human-review

Suggested reviewers: smg247, xueqzhan


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error scripts/backfill-summaries.sh logs the auto-detected image verbatim (Using image: $IMAGE), which can expose internal registry hostnames. Do not print the full image reference; redact or omit hostnames when auto-detecting the image from oc get dc.
Docstring Coverage ⚠️ Warning Docstring coverage is 20.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Coverage For New Features ⚠️ Warning Lower-level date logic is tested, but NewBackfillCommand and RefreshData/BackfillData lack unit tests; only a benchmark touches RefreshData. Add focused unit tests for the new backfill command validation/routing and for RefreshData/BackfillData orchestration/error paths, or refactor to isolate testable pure logic.
✅ Passed checks (18 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately highlights the main change: adding partitioned prefix-sum tables for refresh optimization.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Go Error Handling ✅ Passed New Go paths wrap errors with fmt.Errorf/%w and check nils; no PR-introduced ignored errors or panics were found.
Sql Injection Prevention ✅ Passed User-controlled values are whitelisted before table dispatch, and SQL values use placeholders; only internal table/column identifiers are interpolated.
Excessive Css In React Should Use Styles ✅ Passed The PR only changes Go, SQL, and shell files; no React components or inline CSS are touched, so the check is not applicable.
Single Responsibility And Clear Naming ✅ Passed New packages, commands, and model types are narrowly scoped to summary refresh/backfill, with descriptive names and thin orchestration methods.
Feature Documentation ✅ Passed docs/features only has job-analysis-symptoms.md, which is unrelated to the new summary/backfill pipeline, so no feature doc update was required.
Stable And Deterministic Test Names ✅ Passed No Ginkgo titles or dynamic test names were added; the touched tests use static Go TestX names only.
Test Structure And Quality ✅ Passed PASS: The new tests are plain unit tests with mocks, no cluster resources or waits/timeouts, and they follow the repo’s testify-style patterns.
Microshift Test Compatibility ✅ Passed No changed files under test/e2e and no Ginkgo DSL/imports in the diff; PR adds CLI, DB, and unit tests only.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The PR adds only Go unit tests/helpers; no new Ginkgo e2e specs or multi-node assumptions/SNO guards are present.
Topology-Aware Scheduling Compatibility ✅ Passed The PR only changes CLI/DB/backfill code and scripts; no deployment manifests, controllers, or scheduling constraints (nodeSelector/affinity/PDB/replicas) were added.
Ote Binary Stdout Contract ✅ Passed PASS: The touched code only logs or returns errors; no new main/init/TestMain/BeforeSuite stdout writes were added in process-level setup.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the diff only adds unit tests and CLI/DB code, and no IPv4-only or public-internet assumptions were found.
No-Weak-Crypto ✅ Passed Changed files contain no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, no custom crypto, and no secret/token comparisons; only SHA256 is used.
Container-Privileges ✅ Passed No changed manifest sets privileged/host* or allowPrivilegeEscalation; backfill pod override only defines image, command, args, env.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 12, 2026
@openshift-ci

openshift-ci Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@mstaeble mstaeble force-pushed the trt-2741-prefix-sum-tables branch from 8d46f4f to 844e9a6 Compare July 12, 2026 16:01
@mstaeble mstaeble changed the title TRT-2741: Add partitioned prefix sum tables for matview refresh optimization [WIP] TRT-2741: Add partitioned prefix sum tables for matview refresh optimization Jul 12, 2026
@openshift-ci

openshift-ci Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mstaeble
Once this PR has been reviewed and has the lgtm label, please assign xueqzhan for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

1 similar comment
@openshift-ci

openshift-ci Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mstaeble
Once this PR has been reviewed and has the lgtm label, please assign xueqzhan for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@mstaeble mstaeble force-pushed the trt-2741-prefix-sum-tables branch 2 times, most recently from 30b569d to ab4daf2 Compare July 12, 2026 18:30

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 7

🧹 Nitpick comments (7)
pkg/db/dailysummary/dailysummary.go (3)

200-209: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a brief godoc for startDateFromMax.

The function always caps the returned start at yesterday even when maxSummary is more recent (or invalid/in the future) — this "always re-process at least yesterday+today" behavior isn't obvious from the name alone.

📝 Suggested doc comment
+// startDateFromMax returns the earliest date to re-aggregate. It always
+// includes at least yesterday and today (since "today" data is still
+// arriving), and falls back to defaultLookbackDays when the table is empty.
 func startDateFromMax(maxSummary *civil.Date, today civil.Date) civil.Date {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/dailysummary/dailysummary.go` around lines 200 - 209, Add a brief Go
doc comment immediately above startDateFromMax describing that it derives the
processing start date and caps maxSummary at yesterday, ensuring yesterday and
today are reprocessed; mention the default lookback behavior when maxSummary is
nil.

Source: Path instructions


23-60: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Identifier interpolation via fmt.Sprintf — safe here, but worth a defensive allow-list.

buildInsertSQL/buildOnConflictClause (and MaxSummaryDate at line 220) interpolate tableName/dateColumn into SQL text via fmt.Sprintf. Since these are compile-time literals from the two pgStore{...} construction sites in this file, there's no injection path today. As per path instructions, database/sql calls should use placeholders and avoid fmt.Sprintf in queries; since identifiers can't be parameterized, consider at least validating tableName/dateColumn against a small allow-list inside these helpers as defense-in-depth against a future caller passing a non-literal value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/dailysummary/dailysummary.go` around lines 23 - 60, Add
defense-in-depth validation in buildInsertSQL and buildOnConflictClause, and
apply the same validation to MaxSummaryDate, restricting tableName and
dateColumn to the known allowed identifiers before interpolating them into SQL.
Preserve the existing SQL generation for valid compile-time values and reject or
fail safely for unsupported identifiers.

Source: Path instructions


110-167: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

backfillSummaries and doAggregate are near-duplicate day-loop implementations.

Both query releases, log identical fields, loop day-by-day calling aggregateReleases, and log elapsed time — differing only in log level (Info vs Debug) and the error-message prefix ("backfilling" vs "aggregating"). Consider extracting the shared day-loop into one helper parameterized by a log level/verb, reducing duplicated control flow.

♻️ Suggested consolidation
func processDateRange(store summaryStore, releases []string, startDate, endDate civil.Date, skipConflictDetection bool, verb string, logFn func(args ...interface{})) error {
	for date := startDate; !date.After(endDate); date = date.AddDays(1) {
		dayStart := time.Now()
		if err := aggregateReleases(store, releases, date, date, skipConflictDetection); err != nil {
			return fmt.Errorf("%s %s: %w", verb, date, err)
		}
		log.WithFields(log.Fields{"date": date, "elapsed": time.Since(dayStart)}).Info("processed date")
	}
	return nil
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/dailysummary/dailysummary.go` around lines 110 - 167, Extract the
duplicated date-processing loop from backfillSummaries and doAggregate into a
shared helper, such as processDateRange, parameterized by releases,
skipConflictDetection, and the operation verb. Preserve each caller’s error
prefix and per-day log level (Info for backfill, Debug for aggregation), then
have both functions invoke the helper while retaining their existing range-level
logging.
pkg/db/dailysummary/dailysummary_test.go (1)

187-207: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use sets.New[string]() instead of map[string]bool.

seen := make(map[string]bool) is a hand-rolled set for tracking processed releases. As per coding guidelines, k8s.io/apimachinery/pkg/util/sets (e.g. sets.New[string]()) should be used instead of map[string]bool for this pattern.

♻️ Suggested fix
-	seen := make(map[string]bool)
+	seen := sets.New[string]()
 	for _, call := range calls {
-		seen[call.release] = true
+		seen.Insert(call.release)
 		assert.Equal(t, call.start, call.end, "each call should be a single day")
 	}
 	for _, rel := range releases {
-		assert.True(t, seen[rel], "release %s not processed", rel)
+		assert.True(t, seen.Has(rel), "release %s not processed", rel)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/dailysummary/dailysummary_test.go` around lines 187 - 207, In
TestRefresh_ProcessesAllReleasesPerDay, replace the hand-rolled seen map with a
k8s.io/apimachinery/pkg/util/sets Set initialized via sets.New[string](). Add
each call.release using the set API and update the release-presence assertion to
use the set’s membership method.

Source: Coding guidelines

pkg/db/db.go (1)

32-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Table-name constants duplicated as raw literals elsewhere.

partitionedTableTestDailyTotals/partitionedTableTestCumulativeSummaries are unexported here, so pkg/db/dailysummary/dailysummary.go ("test_daily_totals") and pkg/db/cumulativesummary/cumulative_summary.go ("test_daily_totals", "test_cumulative_summaries") must re-declare the same strings as bare literals. A future rename here would silently desync from those packages (compiles fine, breaks at runtime).

Consider exporting these as shared constants (e.g. in pkg/db or a small shared package) so all three files reference one source of truth.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/db.go` around lines 32 - 33, Export the partitioned table-name
constants currently defined in db.go, then update dailysummary.go and
cumulative_summary.go to reference those shared db constants instead of
repeating raw table-name literals. Preserve the existing names and table
mappings while establishing one source of truth for both daily and cumulative
summary tables.
pkg/db/cumulativesummary/cumulative_summary.go (1)

100-120: 🚀 Performance & Scalability | 🔵 Trivial

Ensure MAX(date) on the new partitioned tables uses an index-friendly plan.

MaxCumulativeSummaryDate/MaxDailySummaryDate run an unfiltered MAX(date) over partitioned tables on every refresh. Worth confirming this reliably uses a per-partition index scan (e.g. via enable_partitionwise_aggregate or a backward index scan on the newest partition) rather than scanning every partition, especially as partition count grows over time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/cumulativesummary/cumulative_summary.go` around lines 100 - 120,
Update MaxCumulativeSummaryDate and MaxDailySummaryDate so MAX(date) on the
partitioned tables uses an index-friendly per-partition plan, such as enabling
partitionwise aggregation or issuing a backward index scan against the newest
partition. Verify the resulting queries avoid scanning every partition as
partition count increases while preserving the existing return and error
behavior.
pkg/db/cumulativesummary/date_range_test.go (1)

1-61: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

LGTM! The tests cover all main branches of resolveStartDate with descriptive names and a fixed testToday for determinism.

Optionally, these could be consolidated into a table-driven test for conciseness and easier extension, per the project's preference for table-driven tests.

♻️ Optional table-driven refactor
 func TestResolveStartDate(t *testing.T) {
-	earliestChanged := testToday.AddDays(-3)
-	result := resolveStartDate(earliestChanged, nil, testToday)
-	assert.Equal(t, earliestChanged, result)
-}
-
-func TestResolveStartDate_UsesMaxPlusOneWhenEarlier(t *testing.T) {
-	earliestChanged := testToday.AddDays(-1)
-	maxExisting := testToday.AddDays(-5)
-	result := resolveStartDate(earliestChanged, &maxExisting, testToday)
-	assert.Equal(t, maxExisting.AddDays(1), result)
-}
-
-func TestResolveStartDate_UsesEarliestChangedWhenEarlierThanMax(t *testing.T) {
-	earliestChanged := testToday.AddDays(-5)
-	maxExisting := testToday.AddDays(-2)
-	result := resolveStartDate(earliestChanged, &maxExisting, testToday)
-	assert.Equal(t, earliestChanged, result)
-}
-
-func TestResolveStartDate_ClampsToFloor(t *testing.T) {
-	earliestChanged := testToday.AddDays(-30)
-	result := resolveStartDate(earliestChanged, nil, testToday)
-	assert.Equal(t, testToday.AddDays(-maxAutoFillDays), result)
-}
-
-func TestResolveStartDate_ClampsMaxPlusOneToFloor(t *testing.T) {
-	earliestChanged := testToday.AddDays(-1)
-	maxExisting := testToday.AddDays(-30)
-	result := resolveStartDate(earliestChanged, &maxExisting, testToday)
-	assert.Equal(t, testToday.AddDays(-maxAutoFillDays), result)
-}
-
-func TestResolveStartDate_DoesNotClampWhenWithinFloor(t *testing.T) {
-	earliestChanged := testToday.AddDays(-7)
-	result := resolveStartDate(earliestChanged, nil, testToday)
-	assert.Equal(t, earliestChanged, result)
+	tests := []struct {
+		name            string
+		earliestChanged civil.Date
+		maxExisting     *civil.Date
+		want            civil.Date
+	}{
+		{"UsesEarliestChanged", testToday.AddDays(-3), nil, testToday.AddDays(-3)},
+		{"UsesMaxPlusOneWhenEarlier", testToday.AddDays(-1), ptrDate(testToday.AddDays(-5)), testToday.AddDays(-4)},
+		{"UsesEarliestChangedWhenEarlierThanMax", testToday.AddDays(-5), ptrDate(testToday.AddDays(-2)), testToday.AddDays(-5)},
+		{"ClampsToFloor", testToday.AddDays(-30), nil, testToday.AddDays(-maxAutoFillDays)},
+		{"ClampsMaxPlusOneToFloor", testToday.AddDays(-1), ptrDate(testToday.AddDays(-30)), testToday.AddDays(-maxAutoFillDays)},
+		{"DoesNotClampWhenWithinFloor", testToday.AddDays(-7), nil, testToday.AddDays(-7)},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equal(t, tt.want, resolveStartDate(tt.earliestChanged, tt.maxExisting, testToday))
+		})
+	}
 }
+
+func ptrDate(d civil.Date) *civil.Date { return &d }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/cumulativesummary/date_range_test.go` around lines 1 - 61, Optionally
consolidate the six resolveStartDate tests into a single table-driven test,
preserving each existing scenario, expected result, descriptive case names, and
the fixed testToday value. Keep the test focused on resolveStartDate without
changing production behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/sippy/backfill.go`:
- Around line 67-70: Wrap the error returned by GetDBClient in the backfill flow
with call-site context using fmt.Errorf and the %w verb, while preserving the
existing early return behavior and error chain.
- Around line 43-90: Validate f.Table against the known supported table names
immediately after the existing required-field checks and before parsing dates or
obtaining the DB client. Use k8s.io/apimachinery/pkg/util/sets to define/check
the supported table set, return a clear error for unsupported values, and leave
valid-table backfill behavior unchanged.

In `@pkg/db/cumulativesummary/cumulative_summary.go`:
- Around line 29-34: Update Backfill to require a continuous cumulative boundary
before calling refreshDateRange: verify that startDate-1 exists for every
release, fail fast when any prior-day boundary is missing, and avoid mutating
cumulative data in that case. Preserve normal backfill behavior when all release
boundaries are present.

In `@pkg/sippyserver/server.go`:
- Around line 405-430: Update refreshMaterializedViews and its refreshMatview
path to return and propagate materialized-view refresh errors instead of only
logging them. In RefreshData, handle the returned error from
refreshMaterializedViews and return it with context, preserving the existing
successful refresh flow.
- Around line 432-451: Define shared constants for the supported table names and
replace the duplicated literals in BackfillData and the corresponding seed-data
dispatch code. Add unit tests covering RefreshData and BackfillData dispatch for
each supported table and asserting unknown table names return an error.

In `@scripts/backfill-summaries.sh`:
- Around line 86-89: Update the batch_end_offset lower-bound clamp in the
backfill calculation to use 1 instead of 0, preventing the final batch from
including today when DAYS is not divisible by BATCH. Preserve the existing
offset calculation and all other batching behavior.
- Around line 107-125: Update the oc run invocation in the backfill execution
loop to explicitly redirect standard input from /dev/null while preserving --rm
-i and the existing output filtering. Ensure interactive shell usage cannot
leave the command waiting for input and stall the loop.

---

Nitpick comments:
In `@pkg/db/cumulativesummary/cumulative_summary.go`:
- Around line 100-120: Update MaxCumulativeSummaryDate and MaxDailySummaryDate
so MAX(date) on the partitioned tables uses an index-friendly per-partition
plan, such as enabling partitionwise aggregation or issuing a backward index
scan against the newest partition. Verify the resulting queries avoid scanning
every partition as partition count increases while preserving the existing
return and error behavior.

In `@pkg/db/cumulativesummary/date_range_test.go`:
- Around line 1-61: Optionally consolidate the six resolveStartDate tests into a
single table-driven test, preserving each existing scenario, expected result,
descriptive case names, and the fixed testToday value. Keep the test focused on
resolveStartDate without changing production behavior.

In `@pkg/db/dailysummary/dailysummary_test.go`:
- Around line 187-207: In TestRefresh_ProcessesAllReleasesPerDay, replace the
hand-rolled seen map with a k8s.io/apimachinery/pkg/util/sets Set initialized
via sets.New[string](). Add each call.release using the set API and update the
release-presence assertion to use the set’s membership method.

In `@pkg/db/dailysummary/dailysummary.go`:
- Around line 200-209: Add a brief Go doc comment immediately above
startDateFromMax describing that it derives the processing start date and caps
maxSummary at yesterday, ensuring yesterday and today are reprocessed; mention
the default lookback behavior when maxSummary is nil.
- Around line 23-60: Add defense-in-depth validation in buildInsertSQL and
buildOnConflictClause, and apply the same validation to MaxSummaryDate,
restricting tableName and dateColumn to the known allowed identifiers before
interpolating them into SQL. Preserve the existing SQL generation for valid
compile-time values and reject or fail safely for unsupported identifiers.
- Around line 110-167: Extract the duplicated date-processing loop from
backfillSummaries and doAggregate into a shared helper, such as
processDateRange, parameterized by releases, skipConflictDetection, and the
operation verb. Preserve each caller’s error prefix and per-day log level (Info
for backfill, Debug for aggregation), then have both functions invoke the helper
while retaining their existing range-level logging.

In `@pkg/db/db.go`:
- Around line 32-33: Export the partitioned table-name constants currently
defined in db.go, then update dailysummary.go and cumulative_summary.go to
reference those shared db constants instead of repeating raw table-name
literals. Preserve the existing names and table mappings while establishing one
source of truth for both daily and cumulative summary tables.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: ac6762e2-c6a7-4607-963e-0cfc2f15918b

📥 Commits

Reviewing files that changed from the base of the PR and between 9370b21 and ab4daf2.

📒 Files selected for processing (20)
  • cmd/sippy/backfill.go
  • cmd/sippy/load.go
  • cmd/sippy/main.go
  • cmd/sippy/refresh.go
  • cmd/sippy/seed_data.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/db/cumulativesummary/cumulative_summary_test.go
  • pkg/db/cumulativesummary/date_range.go
  • pkg/db/cumulativesummary/date_range_test.go
  • pkg/db/dailysummary/dailysummary.go
  • pkg/db/dailysummary/dailysummary_test.go
  • pkg/db/db.go
  • pkg/db/migrations/000006_partition_cumulative_tables.down.sql
  • pkg/db/migrations/000006_partition_cumulative_tables.up.sql
  • pkg/db/migrations/MANIFEST
  • pkg/db/models/prow.go
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/sippyserver/server.go
  • scripts/backfill-summaries.sh
  • scripts/updatesuites.go

Comment thread cmd/sippy/backfill.go
Comment thread cmd/sippy/backfill.go
Comment thread pkg/db/cumulativesummary/cumulative_summary.go
Comment thread pkg/sippyserver/server.go
Comment thread pkg/sippyserver/server.go
Comment thread scripts/backfill-summaries.sh
Comment thread scripts/backfill-summaries.sh Outdated
@mstaeble mstaeble force-pushed the trt-2741-prefix-sum-tables branch from ab4daf2 to cfc1cec Compare July 12, 2026 19:38
@mstaeble mstaeble changed the title [WIP] TRT-2741: Add partitioned prefix sum tables for matview refresh optimization TRT-2741: Add partitioned prefix sum tables for matview refresh optimization Jul 12, 2026
@mstaeble mstaeble marked this pull request as ready for review July 12, 2026 19:43
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 12, 2026
@openshift-ci openshift-ci Bot requested review from smg247 and xueqzhan July 12, 2026 19:43
@mstaeble mstaeble force-pushed the trt-2741-prefix-sum-tables branch from cfc1cec to d5e4e2f Compare July 12, 2026 20:58

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/db/dailysummary/dailysummary_test.go (1)

93-103: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Strengthen the assertion in TestRefresh_IncrementalCapsAtYesterday.

The test name implies verifying that the refresh caps at yesterday, but the assertion calls[0].start.Before(future) is trivially true for any reasonable date. Add an assertion that the end date is at most yesterday:

 	require.NotEmpty(t, calls)
-	assert.True(t, calls[0].start.Before(future))
+	assert.True(t, calls[0].start.Before(future))
+	today := civil.DateOf(time.Now().UTC())
+	assert.True(t, calls[len(calls)-1].end.Before(today),
+		"end date should be capped at yesterday, not extend to today or beyond")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/dailysummary/dailysummary_test.go` around lines 93 - 103, Strengthen
TestRefresh_IncrementalCapsAtYesterday by asserting that the first refresh
call’s end date does not exceed yesterday, using the existing date
representation and current-date helper. Keep the existing non-empty and
start-before-future assertions unchanged.
🧹 Nitpick comments (1)
pkg/db/models/prow.go (1)

187-220: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using civil.Date consistently for date-only columns.

TestDailyTotal.Date uses time.Time while TestCumulativeSummary.Date uses civil.Date. Both map to PostgreSQL date correctly, but civil.Date is semantically more precise for date-only columns and matches the downstream code pattern (e.g., cumulativesummary.go uses civil.Date throughout). Using civil.Date in both models would improve consistency across the new partitioned summary tables.

This is optional since TestDailyTotal mirrors the existing TestDailySummary which also uses time.Time, and the downstream write paths use raw SQL rather than GORM model methods.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/models/prow.go` around lines 187 - 220, Update TestDailyTotal.Date
from time.Time to civil.Date while preserving its date column mapping and
constraints, matching TestCumulativeSummary.Date and downstream date-only usage.
Leave the other model fields and schema tags unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/db/dailysummary/dailysummary_test.go`:
- Around line 93-103: Strengthen TestRefresh_IncrementalCapsAtYesterday by
asserting that the first refresh call’s end date does not exceed yesterday,
using the existing date representation and current-date helper. Keep the
existing non-empty and start-before-future assertions unchanged.

---

Nitpick comments:
In `@pkg/db/models/prow.go`:
- Around line 187-220: Update TestDailyTotal.Date from time.Time to civil.Date
while preserving its date column mapping and constraints, matching
TestCumulativeSummary.Date and downstream date-only usage. Leave the other model
fields and schema tags unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: f733f060-15cf-46cb-867c-d7eaa31e7e02

📥 Commits

Reviewing files that changed from the base of the PR and between cfc1cec and d5e4e2f.

📒 Files selected for processing (20)
  • cmd/sippy/backfill.go
  • cmd/sippy/load.go
  • cmd/sippy/main.go
  • cmd/sippy/refresh.go
  • cmd/sippy/seed_data.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/db/cumulativesummary/cumulative_summary_test.go
  • pkg/db/cumulativesummary/date_range.go
  • pkg/db/cumulativesummary/date_range_test.go
  • pkg/db/dailysummary/dailysummary.go
  • pkg/db/dailysummary/dailysummary_test.go
  • pkg/db/db.go
  • pkg/db/migrations/000006_partition_cumulative_tables.down.sql
  • pkg/db/migrations/000006_partition_cumulative_tables.up.sql
  • pkg/db/migrations/MANIFEST
  • pkg/db/models/prow.go
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/sippyserver/server.go
  • scripts/backfill-summaries.sh
  • scripts/updatesuites.go
🚧 Files skipped from review as they are similar to previous changes (14)
  • pkg/db/cumulativesummary/date_range_test.go
  • cmd/sippy/backfill.go
  • pkg/db/migrations/000006_partition_cumulative_tables.up.sql
  • pkg/db/cumulativesummary/date_range.go
  • pkg/db/migrations/MANIFEST
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/db/db.go
  • cmd/sippy/refresh.go
  • scripts/backfill-summaries.sh
  • pkg/db/dailysummary/dailysummary.go
  • scripts/updatesuites.go
  • pkg/db/cumulativesummary/cumulative_summary_test.go
  • pkg/sippyserver/server.go

@mstaeble mstaeble force-pushed the trt-2741-prefix-sum-tables branch 2 times, most recently from f95c6c8 to baac3a7 Compare July 12, 2026 21:48
…ization

Introduces two new LIST(release)->RANGE(date) partitioned tables that store
pre-aggregated daily totals and running prefix sums. These tables enable
sub-second queries for any arbitrary date range via prefix sum subtraction,
eliminating the need for matview refreshes that currently take 7+ minutes.

New tables:
- test_daily_totals: partitioned replacement for test_daily_summaries
- test_cumulative_summaries: running totals from test_daily_totals

Variant grouping happens at query time via JOIN to prow_jobs, which keeps
variant changes immediately reflected without any rebuild step.

Phase 1 is additive only: the new tables are populated alongside the existing
test_daily_summaries table. Nothing reads from them yet. Later phases will
switch query paths to use these tables and remove the old matview dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mstaeble mstaeble force-pushed the trt-2741-prefix-sum-tables branch from baac3a7 to 4039a46 Compare July 12, 2026 21:49
@mstaeble

Copy link
Copy Markdown
Contributor Author

@coderabbitai resolve

@openshift-ci openshift-ci Bot added the ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review label Jul 12, 2026
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Comments resolved and changes approved.

@mstaeble

Copy link
Copy Markdown
Contributor Author

/test agentic-images

@mstaeble

Copy link
Copy Markdown
Contributor Author

/test images

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@openshift-ci

openshift-ci Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

@mstaeble: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/verify 4039a46 link true /test verify

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants