Repository navigation
Conversation
…nce for hover The parse and tree-sitter caches of a document held 1,000 statements, so on bigger files every walk over the document parsed every statement again. They now keep the statements of the document and drop the ones that are gone when the content changes. Hover walked the statements before the cursor twice: once to resolve the references, and once more in snapshot_before, which also deep-cloned every AST. It now builds the snapshot from the catalog of its own walk, skips it when the hovered references are all to objects the file didn't change, and caches it by the text before the statement.
This was referenced Oct 24, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #892.
On files with more than a few hundred statements, hover, inlay hints and code actions got much slower than the file size explains. Two causes:
references_atwalks them to resolve the hovered statement. Thensnapshot_beforeiterated them again withExecuteStatementMapperto hash their text for its cache key, which deep-cloned every AST even on a cache hit. On a miss it re-applied all the DDL to a fresh catalog. The cache had one entry, so moving the cursor to another statement always missed.What changed
PgQueryStore,TreeSitterStoreandAnnotationStoreuse plain maps.Document::update_contentdrops the entries of statements that are no longer in the document. SQL function bodies are kept as long as theirCREATE FUNCTIONis. The cache can't hold more than the document's own statements, so it doesn't need a size limit.lruis no longer a dependency ofpgls_workspace.walk_statementsreturns its catalog, and hover builds the snapshot from the catalog that the hovered statement sees during that walk. A statement that doesn't parse isn't visited, so it gets the catalog at the end of the walk, which is the same catalog.Origin::Database, or columns of CTEs and subqueries), hover uses the database snapshot and doesn't build one.CREATE FUNCTIONfor a function body, together with the database snapshot it was built from. Hashing the text is cheap and needs no walk, and edits inside or after the statement keep the cached snapshot. The cache is cleared when the settings change, because the search path and migration sections change what a statement sees. Completions use the same cache and only walk on a miss.A side effect: hover and completions now follow migration sections the way the analyser and inlay hints do. The old
snapshot_beforeignored sections.Timings
Release build, best of 3, on a shared and loaded machine, so the numbers are noisy. Measured with the probe from the release analysis. The file has groups of a table, an index, a SQL function and a query; "@EnD" is the last query of the file. "Hover, moving" hovers a different statement on each run, so the snapshot cache misses every time.
Hover and inlay hints at the top of a file were already fast (under 10 ms) and stay that way. Code actions are dominated by the lint run on every request, which is a separate PR.
Tests
keeps_the_parsed_statements_that_are_still_in_the_document: after an edit, the parse result and tree of an unchanged statement are the sameArc, and a removed statement is parsed again.hover_follows_the_ddl_before_the_statement: hover on a table created in the file, on a database table that the file alters (the snapshot is built), on a database table the file doesn't touch (the database snapshot is used), and again after theCREATE TABLEabove the hovered statement changes (the cache key changes).Risks and not covered
Follow-ups: The cached walk shared between requests is #930 (on the #888 stack). The memory of these caches is bounded in #951.