Reindex Zoekt projects moved within the same top-level group
What does this MR do and why?
This MR fixes two bugs that happen when a project or subgroup moves within the same top-level group, a case where the Zoekt index doesn't change. A group transfer queued no Zoekt work for a same-root move, so shards kept stale traversal_ids and the projects fell out of group-level search at the new location. A project transfer queued a delete and an index for the same Zoekt repository; the delete destroyed the repository record first, the index task was then skipped, and the project dropped out of code search entirely. Both paths now do the right thing for a same-root move.
Details
- Group transfer (
EE::Groups::TransferService#post_update_hooks): Zoekt handling used to run only when the top-level group changed, so a same-root subgroup move queued nothing. Group-level search filters ontraversal_ids, so the moved projects vanished from search at the new location.process_zoekt_projectnow runs for every transferred project. Whether to delete from the old index is decided once per transfer, before the project loop: only when the old root had Zoekt and the group's new root differs from the old one. Whether the new root uses Zoekt is also checked once per transfer, and when it does,index_asyncruns for every project. - Project transfer (
Search::Zoekt::ProjectTransferWorker): it always calleddelete_asyncfor the old root and thenindex_async. Within one root, both target the same Zoekt repository, so the delete callback destroys the repository row and the index task is either skipped (repository no longer indexable) or removed along with the row. After the indexer's deferred delete runs, the project is missing from all code search.delete_asyncnow only runs when the root changed. - Why
index_repoand notforce_index_repo: the indexer already forces a full rebuild when the commit is unchanged but metadata changed, so a plain index is enough. - History: the same-root skip came from !130178 (merged) (2023), when group search matched on repository ids only, so a same-root move changed nothing Zoekt stored. Traversal-id-based search made that assumption stale.
- Load: same-root group moves now enqueue one
index_asyncper project, the same load cross-root moves already produce. - No feature flag: this is a small bug fix restoring expected behaviour on an existing code path.
- Not included: projects already affected by this bug need a one-off reindex (
force_index_repo) or a push to recover. This MR only fixes new moves going forward.
References
- Resolves #631246 (closed)
- Related: #630027
- Origin of the same-root skip: !130178 (merged)
Screenshots or screen recordings
Backend-only change, no UI. See the GDK before/after table under How to set up and validate locally for verification evidence.
How to set up and validate locally
Prerequisites:
- Zoekt running.
- Exact code search indexing and search enabled.
- A top-level group enrolled for exact code search, for example
toolbox.
Steps:
- In the enrolled top-level group, create subgroups
zoekt-a,zoekt-b,zoekt-c,zoekt-d. - In
zoekt-a, create projectmove-checkwith a README containing a unique word such aszoektmovecheck. Inzoekt-c, create projectmove-check-2with a README containingzoektprojectmove. Wait a minute, then confirm Code search in each subgroup finds its word. - Transfer group
zoekt-aunderzoekt-b(Group > Settings > General > Advanced > Transfer group). - Transfer project
move-check-2tozoekt-d(Project > Settings > General > Advanced > Transfer project). - Wait a minute, then search the Code tab:
zoektmovecheckinzoekt-b/zoekt-aand inzoekt-b;zoektprojectmoveinzoekt-dand inzoekt-c. Search group-level before project-level, because a project-level search can re-queue indexing and hide the bug.
Expected with this MR: zoekt-b/zoekt-a, zoekt-b, and zoekt-d find the words, and zoekt-c no longer returns move-check-2. On master: those new-location searches return nothing, and after about 7 minutes move-check-2 is missing from all code search.
GDK before/after (scripted)
| Case | Move | Before this MR | With this MR |
|---|---|---|---|
| p1a/p1b/p1c | project, subgroup → subgroup, same root | delete + index skipped; repository deleted; after 7 min missing from all search | index_repo done; shard has new traversal_ids; found at new group, not old |
| p2 | project, subgroup → top-level group | same as above | same as above (found at top level) |
| g1 | subgroup → other subgroup, same root | no Zoekt task; stale traversal_ids; 0 results at new subgroup and parent |
index_repo done; new traversal_ids; found at new subgroup and parent |
| p3, g2 | move to another enrolled top-level group | delete + index, correct | unchanged |
| p4, g3 | move to a non-enrolled top-level group | delete, correct | unchanged |
| p5 | from non-enrolled group into enrolled group | index, correct | unchanged |
Specs: the updated group transfer example and the new worker example both fail on master and pass with this change.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.