SRC-09: suchindex-neuaufbau-reindexierung

Werkzeug für vollständigen Suchindex-Neuaufbau: neue Tabelle anlegen,
Dokumente aus der lebenden Tabelle kopieren, Trefferzahlen verifizieren,
erst dann per Manticore RENAME atomar umschalten.

- reindex.go: Reindexer.Rebuild mit Fortschritts-Callback, Cursor-
  Paginierung über id, strukturierte JSON-API (kein dynamischer
  SQL-Klauselbau). Bei Fehler vor dem Umschalten bleibt die lebende
  Tabelle unverändert, Zwischentabelle wird entfernt.
- Manticore-Verhalten entdeckt: frisch eingefügte Dokumente einer neuen
  RT-Tabelle sind für match_all-Zählungen erst nach FLUSH RAMCHUNK
  zuverlässig sichtbar — vor der Konsistenzprüfung eingebaut.
- Plattformgrenze entdeckt: kein atomares Mehrfach-RENAME in Manticore,
  Sub-Millisekunden-Fenster zwischen den zwei nötigen Einzel-RENAMEs.
  Client.Search bekam einen begrenzten Retry auf "unknown local table".
- Nebenbei echten latenten Bug in Search behoben: ohne explizites limit
  begrenzte Manticore Ergebnisse standardmäßig auf 20 Treffer, unbemerkt
  seit SRC-01 (bisherige Tests prüften nur Vorhandensein, nie Gesamtzahl).

Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-09-PRUEFPROTOKOLL.md):
1. TestRebuild_SearchKeepsWorkingDuringReindex: 0 fehlgeschlagene Suchen
   während parallelem Reindex.
2. TestRebuild_AbortedReindexLeavesNoInconsistentState: abgebrochener
   Kontext hinterlässt real weder Datenverlust noch verwaiste Tabellen.
3. TestRebuild_SampleComparisonMatchesOldAndNewIndex: Stichproben vor/
   nach Reindex real identisch.

Kein Umbau: Index/Delete/Facets-Verhalten sonst unverändert,
dedup/indexworker/storage/crypto/encstorage unverändert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
This commit is contained in:
sysops
2026-08-31 11:01:45 +02:00
co-authored by Claude Sonnet 5
parent db73aab0de
commit 86c4223855
4 changed files with 631 additions and 16 deletions
+72
View File
@@ -0,0 +1,72 @@
# SRC-09 Prüfprotokoll: Suchindex-Neuaufbau/Reindexierung
Voraussetzung SRC-01 (Fertig).
## Umsetzung
- `mail/internal/search/reindex.go``Reindexer.Rebuild(ctx, onProgress)`:
1. legt eine neue physische Manticore-Tabelle an (Name aus striktem
Muster `mail_documents_reindex_<Ziffern>`, per Regex validiert —
Verteidigung in der Tiefe, obwohl der Wert ausschließlich
paketintern erzeugt wird),
2. kopiert alle Dokumente aus der lebenden Tabelle seitenweise
(Cursor-Paginierung über `id`, strukturierte JSON-API, kein
dynamischer SQL-Klauselbau) — die lebende Tabelle wird dabei nur
gelesen, nie verändert (Akzeptanzkriterium 1),
3. meldet Fortschritt über einen `onProgress`-Callback
(Akzeptanzkriterium 2),
4. vergleicht Trefferzahlen alt/neu — bei Abweichung kein Umschalten,
5. schaltet erst danach per Manticore `ALTER TABLE ... RENAME`
(reine Metadaten-Operation) atomar um. Schlägt ein Schritt vor dem
Umschalten fehl, wird die Zwischentabelle entfernt, die lebende
Tabelle bleibt unverändert (Akzeptanzkriterium 3 / Pflichtprüfung 2).
- Echtes Manticore-Verhalten entdeckt und behandelt: frisch eingefügte
Dokumente einer neu angelegten RT-Tabelle sind für `match_all`-Zählungen
erst nach explizitem `FLUSH RAMCHUNK` zuverlässig sichtbar (SQL-`SELECT`
sah sie sofort, `/search`-Zählung zeigte 0) — vor der
Konsistenzprüfung eingebaut.
- Echte Plattformgrenze gefunden und abgefangen: Manticore unterstützt kein
atomares Mehrfach-`RENAME` in einer Anweisung — zwischen den zwei
nötigen Einzel-`RENAME`s existiert ein Sub-Millisekunden-Fenster ohne
`mail_documents`-Tabelle. `Client.Search` bekam dafür einen begrenzten
Retry (bis zu 2 Wiederholungen, 20ms Pause) speziell auf den
Manticore-Fehler `"unknown local table"` — real durch eine parallele
Suchlast während des Umschaltens nachgewiesen (Pflichtprüfung 1).
- Nebenbei einen echten, latenten Fehler in `Search` gefunden und behoben:
ohne explizites `limit` begrenzte Manticore Ergebnisse standardmäßig auf
20 Treffer — unbemerkt, weil bisherige Tests (SRC-01/03/05) nur auf das
Vorhandensein einzelner Treffer prüften, nie auf die Gesamtzahl. Jetzt
`searchResultLimit = 1000`.
- Kein Umbau: `Index`/`Delete`/`Facets`-Verhalten sonst unverändert,
`mail/internal/dedup`/`indexworker`/`storage`/`crypto`/`encstorage`
unverändert.
## Prüfungen
| # | Prüfung | Ergebnis |
|---|---|---|
| 1 | Test: Reindex während laufender Suchanfragen unterbricht die Suche nicht | **bestanden** `TestRebuild_SearchKeepsWorkingDuringReindex`: 30 reale Dokumente indexiert, parallele Sucher-Goroutine (alle 2ms) läuft während `Rebuild` mit — 0 fehlgeschlagene Suchen über den gesamten Umschaltvorgang, danach weiterhin real alle 30 Treffer auffindbar |
| 2 | Test: abgebrochener Reindex hinterlässt keinen inkonsistenten Zustand | **bestanden** `TestRebuild_AbortedReindexLeavesNoInconsistentState`: Kontext vor `Rebuild` abgebrochen, Fehler kommt real zurück, lebende Tabelle bleibt danach unverändert (weiterhin 1 Treffer real auffindbar), keine verwaisten Zwischentabellen über `SHOW TABLES` real bestätigt |
| 3 | Stichprobenvergleich Alt-/Neuindex bestätigt gleiche Trefferzahlen | **bestanden** `TestRebuild_SampleComparisonMatchesOldAndNewIndex`: 3 unterschiedliche Suchbegriffe vor und nach Reindex real verglichen, identische Trefferzahlen je Stichprobe |
Zusätzlich (Akzeptanzkriterium 2): `TestRebuild_ReportsProgress` bestätigt
reale Fortschrittsmeldungen bis zum vollständigen Abschluss.
## Build/Test-Ergebnis (192.168.1.131)
```
go build ./... -> clean
go vet ./... -> clean
golangci-lint run ./... -> 0 issues
TEST_TENANT_DSN=postgresql://nexarch_test:***@localhost:5432/tenant_acme?sslmode=disable \
TEST_MANTICORE_URL=http://127.0.0.1:9308 \
go test ./... -v -p 1 -> alle Pakete bestanden, inkl. internal/search (14 Tests,
keine Regression in dedup/indexworker/storage/encstorage/example/mimeparse/pflichttestgate)
```
## Gesamtergebnis
**Bestanden.** Alle drei Akzeptanzkriterien und alle drei Pflichtprüfungen
real erfüllt. Trägt (gemeinsam mit ARC-08, SRC-02, SRC-04, SRC-05,
SRC-08, SRC-10) zu QA-03 bei — QA-03 bleibt weiterhin blockiert, bis auch
ARC-08, SRC-08 und SRC-10 fertig sind.