Skip to content

Optimize ReparseWindowsHostCertificates migration to fix DB overload during upgrade - #50262

Draft
sharon-fdm wants to merge 2 commits into
mainfrom
sharon-fdm/fix-reparse-certs-migration
Draft

Optimize ReparseWindowsHostCertificates migration to fix DB overload during upgrade#50262
sharon-fdm wants to merge 2 commits into
mainfrom
sharon-fdm/fix-reparse-certs-migration

Conversation

@sharon-fdm

Copy link
Copy Markdown
Collaborator

Related issue: Closes #50228

Checklist for submitter

  • Changes file added for user-visible changes in changes/.
  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

For unreleased bug fixes in a release candidate, one of:

  • Confirmed that the fix is not expected to adversely impact load test results
  • Alerted the release DRI if additional load testing is needed

Summary

The ReparseWindowsHostCertificates migration (from #49787) causes ~14 minutes of sustained full DB load at 100K hosts during the 4.89 to 4.90 upgrade:

  • RDS Writer CPU avg = 89.75%
  • Threads Running = 31.78 (2x the 16 vCPU limit)
  • Fleet Server CPU avg = 96.62%

Root cause: The original migration re-joins the hosts table on every batch of 1,000 cert IDs to filter by platform = 'windows'. At 100K hosts with many certs per host, this repeated JOIN is expensive.

Fix: Collect all Windows host IDs in a single query upfront (bounded by host count, not cert count), then soft-delete certs in batches of 500 host IDs using WHERE host_id IN (?) AND origin = 'osquery' AND deleted_at IS NULL without re-joining hosts.

This should reduce the migration from ~14 minutes to under a minute.

Needs cherry-pick to 4.90 RC.

Test plan

  • Existing migration test TestUp_20260723181402 passes (verifies correct soft-delete behavior)
  • @andrey-fleet load test the 4.89 to 4.90 migration with this fix and confirm DB load is acceptable

The original migration re-joined the hosts table on every batch of
1000 cert IDs, causing ~14 minutes of sustained full DB load at 100K
hosts. Instead, collect all Windows host IDs once upfront and then
soft-delete certs in batches by host_id without the repeated join.
Copilot AI review requested due to automatic review settings July 30, 2026 20:00

Copilot AI 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.

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.

Pull request overview

Optimizes the ReparseWindowsHostCertificates MySQL migration to avoid repeatedly joining hosts during batched soft-deletes, reducing DB load during large upgrades (e.g., 100K hosts).

Changes:

  • Collect Windows host IDs once, then soft-delete host_certificates in host_id batches (instead of paging by certificate ID with repeated hosts joins).
  • Keep the existing migration test validating the intended soft-delete behavior.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 2 comments.

File Description
server/datastore/mysql/migrations/tables/20260723181402_ReparseWindowsHostCertificates.go Refactors migration batching to reduce DB load by eliminating repeated hosts joins.
changes/50228-fix-reparse-certs-migration User-visible changes entry (content excluded from review).
Files excluded by content exclusion policy (1)
  • changes/50228-fix-reparse-certs-migration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +35 to +38
// softDeleteWindowsHostCertsForReparse collects Windows host IDs once upfront,
// then soft-deletes their certificate rows in batches using only the
// host_certificates primary key. This avoids re-joining the hosts table on
// every batch, which was causing ~14 minutes of sustained full DB load at
Comment on lines +73 to 76
affected, _ := result.RowsAffected()
for range affected {
increment()
}
Inserts 1,000 Windows hosts x 20 certs (20K rows) and verifies the
migration completes in under 30s. Measured at 445ms with the fix,
vs the original which took ~14 minutes at 100K hosts.

Copilot AI 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.

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.

Pull request overview

Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.

Files excluded by content exclusion policy (1)
  • changes/50228-fix-reparse-certs-migration
Comments suppressed due to low confidence (2)

server/datastore/mysql/migrations/tables/20260723181402_ReparseWindowsHostCertificates.go:76

  • The progress loop is currently for range affected, but affected is an int64 (rows affected) and you can’t range over an integer. This won’t compile and also drops the error from RowsAffected.

Consider handling the RowsAffected error and looping with an index so increment() is called once per affected row.

		affected, _ := result.RowsAffected()
		for range affected {
			increment()
		}

server/datastore/mysql/migrations/tables/20260723181402_ReparseWindowsHostCertificates.go:38

  • The function comment says the batched delete uses only the host_certificates primary key, but the implementation updates by host_id IN (...) (which is the key optimization). Updating the comment will avoid confusion during future perf investigations.
// softDeleteWindowsHostCertsForReparse collects Windows host IDs once upfront,
// then soft-deletes their certificate rows in batches using only the
// host_certificates primary key. This avoids re-joining the hosts table on
// every batch, which was causing ~14 minutes of sustained full DB load at

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.18182% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.12%. Comparing base (4c32e72) to head (632edf0).
⚠️ Report is 48 commits behind head on main.

Files with missing lines Patch % Lines
...s/20260723181402_ReparseWindowsHostCertificates.go 68.18% 4 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #50262      +/-   ##
==========================================
+ Coverage   68.08%   68.12%   +0.03%     
==========================================
  Files        3936     3937       +1     
  Lines      250690   250978     +288     
  Branches    13239    13239              
==========================================
+ Hits       170687   170977     +290     
+ Misses      64692    64673      -19     
- Partials    15311    15328      +17     
Flag Coverage Δ
backend 69.46% <68.18%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

Migration loadtest from 4.89.0 > 4.90.0 is causing extremely high Server & DB CPU load

2 participants