Skip to content

perf(workspace): don't let one database block the others - #921

Open
psteinroe wants to merge 5 commits into
fix/configuration-resolutionfrom
perf/per-connection-snapshot-loading
Open

psteinroe wants to merge 5 commits into
fix/configuration-resolutionfrom
perf/per-connection-snapshot-loading

Conversation

@psteinroe

@psteinroe psteinroe commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #915 → #992 → #991.

With nested configurations (#881), one project can point at several databases, and one bad one stalled everything (C8):

  • SnapshotManager::load took the write lock of the whole snapshot map and kept it while Snapshot::load ran against the database. Until an unreachable database timed out (10 s by default), every snapshot lookup for every database waited, including cache hits, so hover, completions and diagnostics stalled in all projects of the language server.
  • check verified the databases one after the other and stopped at the first failure. Three unreachable databases with connTimeoutSecs: 2 took 6.15 s and reported one error, Database error: pool timed out while waiting for an open connection, without saying which database or which configuration.

What changed

  • Per-connection lock. The map holds a slot per connection; the map lock is only taken to find or create the slot. The slot's mutex is held while that connection loads, so callers for the same database wait for one load instead of starting their own, and other databases aren't affected. A failed load leaves the slot empty for the next attempt, as before.

  • Concurrent check. check_database_connection collects the distinct connections of the root and nested settings (by host, port, user, database, connection string, password and timeout), checks them on scoped threads, and returns errors: Vec<String> instead of error: Option<String>, one per database it can't reach:

    database/connection ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
      × Could not connect to postgres@10.255.255.1:5001/postgres, the database of /repo/db1: Database error: pool timed out while waiting for an open connection
    

    The CLI turns each into its own database/connection diagnostic. The same three databases now take 2.07 s (one timeout) and all three are reported.

Tests

  • CLI check_reports_every_unreachable_database_at_once (Linux): three blackholed databases, each reported with its address and folder, in under 5 s.
  • The check_fails_when_database_login_fails snapshot now has the address prefix; the test output normalizes the address (it names the database sqlx::test creates) and the working directory.

Not covered

  • The per-connection lock in the language server has no dedicated test; it needs a database that answers slowly. The CLI test covers the concurrent check.
  • The workspace protocol change (errors instead of error) has no TS counterpart; the type isn't exported to the JS bindings.

Update: brought up to date with main and the reworked #915 (merge commits). Main had since added a check for an invalid db.connectionString to check_database_connection, which returned that one error; it now goes into errors like the connection failures, once per distinct message. The LSP's refresh of inlay hints and semantic tokens, also new on main, checks errors.is_empty(). No other changes.

Load each connection's snapshot under its own lock instead of holding
the write lock of the whole snapshot map during network I/O. check
verifies the distinct databases of all configuration files concurrently
and reports every one it can't reach, with its address and the folders
that use it.
…snapshot-loading

# Conflicts:
#	crates/pgls_cli/tests/assert_check.rs

This branch has not been deployed

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant