bug(index): product fixes & findings from phased (ES→OS) integration runs
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Purpose
Single tracking issue for genuine product fixes and findings surfaced while running the integration battery under a non-zero ES→OS migration phase (see #36320 for the phase-testing tooling and PR #36500). Test-only decoupling of ContentletIndexAPIImplTest stays in #36320; product-code fixes land here.
Finding #1 — deactivateIndex fails / leaves a stale OS store row when the last index is deactivated
Where: dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ContentletIndexAPIImpl.java — deactivateIndex(String)
When the index being deactivated holds the last populated slot of the OS VersionedIndices, osBuilder.build() produces an empty record and VersionedIndicesAPI.saveIndices(...) rejects it by contract (IndicesFactoryImpl:120 — "At least one index must be specified when saving versioned indices for version: 3.X"). Two affected sites, two severities:
| Site | Phase | Current behavior | Severity |
|---|---|---|---|
:3148 |
3 (OS-only) | saveIndices(build()) with no try/catch → exception propagates → deactivateIndex fails hard |
🔴 High |
:3186 |
1 & 2 (best-effort OS mirror) | caught → WARN "Could not mirror index deactivation to OS store" + stale OS store row left dangling |
🟠 Medium |
The stale-row case is the exact failure mode clearOsStorePointer (:1966-1978) was written to prevent for issue #35640: on the next restart, initOSCatchup would treat the stale row as authoritative and recreate the deleted index empty.
Root cause: deactivateIndex never got the empty-record guard that clearOsStorePointer already has.
Fix (parity with clearOsStorePointer): at both save sites, if build().hasAnyIndex() → saveIndices(...), else → versionedIndicesAPI.removeVersion(VersionedIndices.OPENSEARCH_3X). This gives the OS versioned store the same "empty = OK" semantics the legacy ES path already has (legacyIndiciesAPI.point(...) accepts an all-null IndiciesInfo).
Reproduction:
just test-integration-phase 1 ContentletIndexAPIImplTest
# WARN "Could not mirror index deactivation to OS store for index: live_..." during activateDeactivateIndex
# (under phase 3 the same path throws instead of warning)
Acceptance:
- Deactivating the last index under phase 3 does not throw; the OS version row is removed.
- Under phase 1/2 no stale OS store row is left (no dangling
VersionedIndicesafter deactivating the last slot). - Regression IT covering deactivate-last-index for phase 3 and phase 1.
Further product findings from phased runs will be appended as additional sections.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ContentletIndexAPIImpl.java at deactivateIndex(String), then compare its save sites with clearOsStorePointer around lines 1966-1978. Run just test-integration-phase 1 ContentletIndexAPIImplTest and reproduce activateDeactivateIndex. Done means last-index deactivation passes in phases 3 and 1 without an exception or dangling VersionedIndices row, with regression integration coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- elasticsearch, java
- Domain
- backend, search, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 64/100