Skip to content

Make search much faster - #62658

Merged
SomeoneToIgnore merged 3 commits into
zed-industries:mainfrom
39ali:search-share-worktree-snapshot
Aug 15, 2026
Merged

Make search much faster#62658
SomeoneToIgnore merged 3 commits into
zed-industries:mainfrom
39ali:search-share-worktree-snapshot

Conversation

@39ali

@39ali 39ali commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Objective

Project search sends one candidate per file to its worker pool, and each one
carried an owned Snapshot. Every field of Snapshot is cheap to clone except
always_included_entries, a Vec<Arc<RelPath>> holding one entry per
always-included file.

With a broad file_scan_inclusions such as **/*, that vector holds an entry per file in the project, so cloning it once per file made search O(files²).

Partially addresses #38799 (still needs to fix the huge memory usage and the occasional stutters) .

Solution

Share the snapshot behind an Arc instead, the consumer only reads id(), abs_path()
and root_name(), so nothing needs an owned copy.

Testing

Using the linux kernel repo, i searched for vmx_l1d_should_flush and netif_rx and its at least 60x faster on 5950x.
with file_scan_inclusions: ["**/*"]

Release Notes:

  • Fixed project search being very slow on projects that set a broad file_scan_inclusions

@cla-bot

cla-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @39ali on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@zed-community-bot zed-community-bot Bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label Aug 14, 2026
@39ali

39ali commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@cla-bot check

@cla-bot

cla-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @39ali on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@cla-bot

cla-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

The cla-bot has been summoned, and re-checked this pull request!

@maxdeviant maxdeviant changed the title make search much faster Make search much faster Aug 14, 2026
@cla-bot

cla-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @39ali on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@39ali

39ali commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Aug 15, 2026
@cla-bot

cla-bot Bot commented Aug 15, 2026

Copy link
Copy Markdown

The cla-bot has been summoned, and re-checked this pull request!

@SomeoneToIgnore
SomeoneToIgnore added this pull request to the merge queue Aug 15, 2026
Merged via the queue into zed-industries:main with commit 1e3d8b5 Aug 15, 2026
38 checks passed
@MrSubidubi

Copy link
Copy Markdown
Member

Very nice finding, thank you so much!

ysalitrynskyi pushed a commit to ysalitrynskyi/zed that referenced this pull request Aug 15, 2026
…2685)

Follow-up to zed-industries#62658

The problematic field is not needed at all in the snapshot, as can be
constructed before starting the scanner — moreover, the field had
accumulated more and more paths between rescans, leaking memory.

Now, we spend more time traversing the entire tree between rescans, but
that happens for rescans only which should be relatively rare?

Release Notes:

- N/A
miguelraz added a commit that referenced this pull request Aug 27, 2026
Found by a new deep_clone_in_loop dylint modeled on the accidentally
quadratic search fix (#62658). None of these were quadratic in practice,
but each paid an avoidable copy:

- collab: take() the S3 pagination marker instead of cloning it; it is
  overwritten or the loop breaks before the next read.
- project: build Arc<RelPath> directly from the borrowed path in
  path_trie, avoiding a clone-then-copy double allocation.
- context_server: move the notification payload into the last handler
  instead of cloning it for every handler.
- editor: mem::replace the rewrap accumulators instead of cloning them
  on every range boundary.
Prohect pushed a commit to Prohect/zed that referenced this pull request Aug 27, 2026
# Objective

Remove avoidable clones of loop-invariant values that pay a copy on
every loop iteration. These were found by running a prototype
`deep_clone_in_loop` dylint (modeled on the accidentally quadratic
project-search fix in zed-industries#62658) across the workspace. None of these sites
are quadratic in practice — the loops are bounded — but each one does
strictly wasted work that a one-line change removes.

## Solution

- `collab/src/api/extensions.rs`: use `next_marker.take()` instead of
`next_marker.clone()` for the S3 pagination marker. The marker is either
overwritten via `clone_from` at the end of the iteration or the loop
breaks, so it is never read after the `take`.
- `project/src/manifest_tree/path_trie.rs`: build the trie key with
`Arc::from(path_so_far.as_rel_path())` instead of
`path_so_far.clone().into()`. The `From<RelPathBuf> for Arc<RelPath>`
impl copies the bytes into the `Arc` anyway, so the intermediate
`RelPathBuf` clone was a second, redundant copy.
- `context_server/src/client.rs`: in `notify`, split off the last
handler and move the `serde_json::Value` payload into it, cloning only
for the preceding handlers. Previously every handler received a clone
and the final one was always wasted.
- `editor/src/rewrap.rs`: use `std::mem::replace` to move the
comment-delimiter and rewrap-prefix accumulators into the pushed range
instead of cloning them and immediately reassigning.

## Testing

- `cargo check -p collab -p project -p context_server -p editor` —
clean.
- `cargo test -p editor rewrap` — 7/7 pass, including the
boundary-sensitive `test_rewrap*` editor tests.
- `cargo test -p context_server` — 97/97 pass.
- `cargo test -p project path_trie` — 2/2 pass.
- Re-ran the `deep_clone_in_loop` lint on the four crates: the
`extensions.rs`, `path_trie.rs`, and `rewrap.rs` hits are gone;
`client.rs` still (correctly) reports the remaining required per-handler
clone.
- Not tested platform-specifically; the changes are
platform-independent.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- N/A
playdohface pushed a commit to playdohface/zed that referenced this pull request Aug 29, 2026
# Objective

Project search sends one candidate per file to its worker pool, and each
one
carried an owned `Snapshot`. Every field of `Snapshot` is cheap to clone
except
`always_included_entries`, a `Vec<Arc<RelPath>>` holding one entry per
always-included file.

With a broad file_scan_inclusions such as **/*, that vector holds an
entry per file in the project, so cloning it once per file made search
O(files²).

Partially addresses zed-industries#38799 (still needs to fix the huge memory usage and
the occasional stutters) .

## Solution

Share the snapshot behind an `Arc` instead, the consumer only reads
`id()`, `abs_path()`
and `root_name()`, so nothing needs an owned copy.

## Testing
Using the [linux kernel repo](https://github.com/torvalds/linux), i
searched for `vmx_l1d_should_flush
` and `netif_rx` and its at least 60x faster on 5950x. 
with `file_scan_inclusions: ["**/*"]`


Release Notes:

- Fixed project search being very slow on projects that set a broad
`file_scan_inclusions`
playdohface pushed a commit to playdohface/zed that referenced this pull request Aug 29, 2026
…2685)

Follow-up to zed-industries#62658

The problematic field is not needed at all in the snapshot, as can be
constructed before starting the scanner — moreover, the field had
accumulated more and more paths between rescans, leaking memory.

Now, we spend more time traversing the entire tree between rescans, but
that happens for rescans only which should be relatively rare?

Release Notes:

- N/A
playdohface pushed a commit to playdohface/zed that referenced this pull request Aug 29, 2026
# Objective

Remove avoidable clones of loop-invariant values that pay a copy on
every loop iteration. These were found by running a prototype
`deep_clone_in_loop` dylint (modeled on the accidentally quadratic
project-search fix in zed-industries#62658) across the workspace. None of these sites
are quadratic in practice — the loops are bounded — but each one does
strictly wasted work that a one-line change removes.

## Solution

- `collab/src/api/extensions.rs`: use `next_marker.take()` instead of
`next_marker.clone()` for the S3 pagination marker. The marker is either
overwritten via `clone_from` at the end of the iteration or the loop
breaks, so it is never read after the `take`.
- `project/src/manifest_tree/path_trie.rs`: build the trie key with
`Arc::from(path_so_far.as_rel_path())` instead of
`path_so_far.clone().into()`. The `From<RelPathBuf> for Arc<RelPath>`
impl copies the bytes into the `Arc` anyway, so the intermediate
`RelPathBuf` clone was a second, redundant copy.
- `context_server/src/client.rs`: in `notify`, split off the last
handler and move the `serde_json::Value` payload into it, cloning only
for the preceding handlers. Previously every handler received a clone
and the final one was always wasted.
- `editor/src/rewrap.rs`: use `std::mem::replace` to move the
comment-delimiter and rewrap-prefix accumulators into the pushed range
instead of cloning them and immediately reassigning.

## Testing

- `cargo check -p collab -p project -p context_server -p editor` —
clean.
- `cargo test -p editor rewrap` — 7/7 pass, including the
boundary-sensitive `test_rewrap*` editor tests.
- `cargo test -p context_server` — 97/97 pass.
- `cargo test -p project path_trie` — 2/2 pass.
- Re-ran the `deep_clone_in_loop` lint on the four crates: the
`extensions.rs`, `path_trie.rs`, and `rewrap.rs` hits are gone;
`client.rs` still (correctly) reports the remaining required per-handler
clone.
- Not tested platform-specifically; the changes are
platform-independent.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- N/A
m-altaifi pushed a commit to m-altaifi/zed that referenced this pull request Sep 2, 2026
# Objective

Remove avoidable clones of loop-invariant values that pay a copy on
every loop iteration. These were found by running a prototype
`deep_clone_in_loop` dylint (modeled on the accidentally quadratic
project-search fix in zed-industries#62658) across the workspace. None of these sites
are quadratic in practice — the loops are bounded — but each one does
strictly wasted work that a one-line change removes.

## Solution

- `collab/src/api/extensions.rs`: use `next_marker.take()` instead of
`next_marker.clone()` for the S3 pagination marker. The marker is either
overwritten via `clone_from` at the end of the iteration or the loop
breaks, so it is never read after the `take`.
- `project/src/manifest_tree/path_trie.rs`: build the trie key with
`Arc::from(path_so_far.as_rel_path())` instead of
`path_so_far.clone().into()`. The `From<RelPathBuf> for Arc<RelPath>`
impl copies the bytes into the `Arc` anyway, so the intermediate
`RelPathBuf` clone was a second, redundant copy.
- `context_server/src/client.rs`: in `notify`, split off the last
handler and move the `serde_json::Value` payload into it, cloning only
for the preceding handlers. Previously every handler received a clone
and the final one was always wasted.
- `editor/src/rewrap.rs`: use `std::mem::replace` to move the
comment-delimiter and rewrap-prefix accumulators into the pushed range
instead of cloning them and immediately reassigning.

## Testing

- `cargo check -p collab -p project -p context_server -p editor` —
clean.
- `cargo test -p editor rewrap` — 7/7 pass, including the
boundary-sensitive `test_rewrap*` editor tests.
- `cargo test -p context_server` — 97/97 pass.
- `cargo test -p project path_trie` — 2/2 pass.
- Re-ran the `deep_clone_in_loop` lint on the four crates: the
`extensions.rs`, `path_trie.rs`, and `rewrap.rs` hits are gone;
`client.rs` still (correctly) reports the remaining required per-handler
clone.
- Not tested platform-specifically; the changes are
platform-independent.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

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

Labels

cla-signed The user has signed the Contributor License Agreement first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants