Commit b4216cb
## Proposed Changes
Fixes #36077.
During OpenSearch migration **Phase 3** (OS primary, ES decommissioned),
a full reindex left stale ES-side rows in the `indicies` table — the old
`live`/`working` pair plus the transient
`reindex_live`/`reindex_working` pair (all NULL version) — alongside the
correctly-promoted `.os` (v3.X) pair. The table accumulated **6 rows
instead of 2** on every Phase-3 reindex.
### Root cause
An asymmetry in `ContentletIndexAPIImpl`:
- `initAndPointReindex` wrote the legacy ES store **unconditionally**
(`pointES` had no phase gate), so a Phase-3 reindex still inserted ES
`reindex_*` rows and re-persisted the old ES `live`/`working` rows.
- The Phase-3 switchover (`fullReindexSwitchoverOS`) only touches the OS
store (`versionedIndicesAPI`) — it never promotes or clears those ES
rows. So they orphaned.
### The fix (DB-only — never contacts the ES cluster, which may be down
in Phase 3)
1. **Gate `pointES(...)`** in `initAndPointReindex` on
`!isMigrationComplete()` so a Phase-3 reindex no longer writes ES
pointers (mirrors the existing `isMigrationStarted()` gate on the OS
write).
2. **Add `VersionedIndicesAPI.removeLegacyContentIndices()`**
(delegating to `IndicesFactory`): deletes the NULL-version
`live`/`working`/`reindex_live`/`reindex_working` rows, **preserves**
the unmigrated `site_search` pointer and all OS (non-NULL version) rows,
and flushes the index caches. Invoked best-effort by
`fullReindexSwitchoverOS` after promoting OS (a housekeeping failure
must not undo a successful switchover).
**Physical index deletion is intentionally out of scope** — in Phase 3
ES may not be running, so touching the cluster is fragile. Orphaned
physical indices are cleaned by the existing scheduled
`DeleteInactiveLiveWorkingIndicesJob`.
### Why an explicit cleanup — and why earlier phases never needed one
The legacy ES `reindex_*` rows were never purged by a dedicated call. In
the classic ES path (phases 0–2) the cleanup is an **emergent property
of `IndiciesFactory.point()`**: `fullReindexSwitchover()` rebuilds the
entire `indicies` table from a *fresh* `IndiciesInfo.Builder` that sets
only `working`/`live`/`site_search` and leaves `reindex_*` null, so
`point()`'s delete-then-conditional-insert drops the reindex rows for
free — and overwrites the old `working`/`live` rows in the same pass.
The Phase-3 switchover (`fullReindexSwitchoverOS`) does **not** go
through that full-table rebuild — it writes only the OS/versioned rows
via `versionedIndicesAPI`, so the implicit cleanup that every earlier
phase gets for free simply never runs and the legacy ES rows orphan.
`removeLegacyContentIndices()` is the explicit equivalent of that
implicit `point()` sweep, scoped to the OS-only path. It is therefore
*restoring symmetry of outcome* (a clean 2-row table) across two
structurally different switchover paths — not introducing a new, riskier
deletion.
**Scope guard:** the delete is intentionally narrow (`index_version IS
NULL` + content-index types only), so it can never touch OS (non-NULL
version) rows nor the still-unmigrated `site_search` pointer. The phase
protection currently lives at the *call site*
(`removeLegacyContentIndices()` is only invoked from
`fullReindexSwitchoverOS`, which runs only in Phase 3); the method
itself has no internal phase guard.
## Acceptance criteria
- [x] After a Phase-3 reindex, no leftover ES `live`/`working` (NULL
version) rows.
- [x] Transient `reindex_live`/`reindex_working` rows removed.
- [ ] Physical indices deleted — deferred to
`DeleteInactiveLiveWorkingIndicesJob` (see scope note above).
- [x] Re-running reindex in Phase 3 does not accumulate orphan rows.
- [x] Integration coverage asserts the final `indicies` table state.
## Testing
-
`ContentletIndexAPIImplMigrationIntegrationTest#test_phase3_removeLegacyContentIndices_purgesEsRowsPreservesSiteSearchAndOs`
— seeds the issue's exact 6-row orphan state and asserts the legacy ES
content rows are purged while `site_search` and OS rows survive.
- `ContentletIndexAPIImplPhaseTest` — fake updated for the new API
method.
- `./mvnw test-compile -pl :dotcms-core,:dotcms-integration` passes on
JDK 25.
> Note: the new IT still needs a run against a live OpenSearch Phase-3
environment (`opensearch-upgrade` profile) — a full-reindex E2E was
deliberately avoided due to the known `inferIndexToHit` gap (#36054);
the test validates the cleanup guarantee deterministically at the DB
level.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c5ca97d commit b4216cb
8 files changed
Lines changed: 304 additions & 28 deletions
File tree
- dotCMS/src
- main/java/com/dotcms/content
- elasticsearch/business
- index
- test/java/com/dotcms/content/elasticsearch/business
- dotcms-integration/src/test/java/com/dotcms/content/elasticsearch/business
Lines changed: 82 additions & 27 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1092 | 1092 | | |
1093 | 1093 | | |
1094 | 1094 | | |
1095 | | - | |
1096 | | - | |
1097 | | - | |
1098 | | - | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
1099 | 1103 | | |
1100 | 1104 | | |
1101 | 1105 | | |
| |||
1221 | 1225 | | |
1222 | 1226 | | |
1223 | 1227 | | |
| 1228 | + | |
1224 | 1229 | | |
1225 | 1230 | | |
1226 | 1231 | | |
1227 | 1232 | | |
| 1233 | + | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + | |
1228 | 1237 | | |
1229 | 1238 | | |
1230 | 1239 | | |
1231 | | - | |
1232 | | - | |
| 1240 | + | |
| 1241 | + | |
1233 | 1242 | | |
| 1243 | + | |
| 1244 | + | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
1234 | 1248 | | |
1235 | 1249 | | |
1236 | 1250 | | |
1237 | 1251 | | |
1238 | 1252 | | |
1239 | | - | |
1240 | | - | |
1241 | | - | |
1242 | | - | |
1243 | | - | |
1244 | | - | |
1245 | | - | |
1246 | | - | |
1247 | | - | |
1248 | | - | |
1249 | | - | |
1250 | | - | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + | |
1251 | 1260 | | |
1252 | 1261 | | |
1253 | 1262 | | |
| |||
1314 | 1323 | | |
1315 | 1324 | | |
1316 | 1325 | | |
| 1326 | + | |
| 1327 | + | |
| 1328 | + | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
| 1335 | + | |
| 1336 | + | |
| 1337 | + | |
| 1338 | + | |
1317 | 1339 | | |
1318 | 1340 | | |
| 1341 | + | |
1319 | 1342 | | |
1320 | 1343 | | |
1321 | | - | |
1322 | | - | |
1323 | | - | |
1324 | | - | |
1325 | | - | |
1326 | | - | |
1327 | | - | |
1328 | | - | |
1329 | | - | |
| 1344 | + | |
1330 | 1345 | | |
1331 | 1346 | | |
1332 | 1347 | | |
1333 | 1348 | | |
1334 | 1349 | | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
| 1361 | + | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
1335 | 1390 | | |
1336 | 1391 | | |
1337 | 1392 | | |
| |||
Lines changed: 23 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
131 | 131 | | |
132 | 132 | | |
133 | 133 | | |
134 | | - | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
135 | 157 | | |
136 | 158 | | |
137 | 159 | | |
| |||
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
135 | 150 | | |
136 | 151 | | |
137 | 152 | | |
| |||
Lines changed: 19 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
46 | 51 | | |
47 | 52 | | |
48 | 53 | | |
| |||
168 | 173 | | |
169 | 174 | | |
170 | 175 | | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
171 | 190 | | |
172 | 191 | | |
173 | 192 | | |
| |||
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
107 | 122 | | |
108 | 123 | | |
109 | 124 | | |
| |||
Lines changed: 27 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
228 | 228 | | |
229 | 229 | | |
230 | 230 | | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
231 | 258 | | |
232 | 259 | | |
233 | 260 | | |
| |||
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
576 | 576 | | |
577 | 577 | | |
578 | 578 | | |
| 579 | + | |
579 | 580 | | |
580 | 581 | | |
581 | 582 | | |
582 | 583 | | |
583 | 584 | | |
584 | 585 | | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
585 | 592 | | |
586 | 593 | | |
587 | 594 | | |
| |||
0 commit comments