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 on traversal_ids, so the moved projects vanished from search at the new location. process_zoekt_project now 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_async runs for every project.
  • Project transfer (Search::Zoekt::ProjectTransferWorker): it always called delete_async for the old root and then index_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_async now only runs when the root changed.
  • Why index_repo and not force_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_async per 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

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:

  1. In the enrolled top-level group, create subgroups zoekt-a, zoekt-b, zoekt-c, zoekt-d.
  2. In zoekt-a, create project move-check with a README containing a unique word such as zoektmovecheck. In zoekt-c, create project move-check-2 with a README containing zoektprojectmove. Wait a minute, then confirm Code search in each subgroup finds its word.
  3. Transfer group zoekt-a under zoekt-b (Group > Settings > General > Advanced > Transfer group).
  4. Transfer project move-check-2 to zoekt-d (Project > Settings > General > Advanced > Transfer project).
  5. Wait a minute, then search the Code tab: zoektmovecheck in zoekt-b/zoekt-a and in zoekt-b; zoektprojectmove in zoekt-d and in zoekt-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.

Edited by Ravi Kumar

Merge request reports

Loading
Loading