Skip to content

[segment replication] Simplify the ckp verification for the primary shard relocation#20609

Open
guojialiang92 wants to merge 4 commits intoopensearch-project:mainfrom
guojialiang92:dev/simplify-ckp-verification
Open

[segment replication] Simplify the ckp verification for the primary shard relocation#20609
guojialiang92 wants to merge 4 commits intoopensearch-project:mainfrom
guojialiang92:dev/simplify-ckp-verification

Conversation

@guojialiang92
Copy link
Contributor

@guojialiang92 guojialiang92 commented Feb 12, 2026

Description

This PR is to address the issues in #[20610].

If we can specifically identify the scenario of primary shard relocation, we can avoid continuously patching the ckp verification logic.

Fortunately, we set state handoffInProgress during the hand-off phase of peer recovery. We can leverage this state to require that when the primary shard receives request GET_CHECKPOINT_INFO, it must be a started primary shard that is not in the hand-off process.

Related Issues

Resolves #[20610]

Check List

  • Functionality includes testing.
  • API changes companion pull request created, if applicable.
  • Public documentation issue/PR created, if applicable.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Signed-off-by: guojialiang <guojialiang.2012@bytedance.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds handoff state tracking to detect relocation in progress and removes the isRetry parameter from segment replication target classes. New accessor methods expose handoff state, validation is added before replication setup, and the isRetry field and related gating logic are eliminated from replication target constructors and method signatures.

Changes

Cohort / File(s) Summary
Handoff state accessors
server/src/main/java/org/opensearch/index/seqno/ReplicationTracker.java, server/src/main/java/org/opensearch/index/shard/IndexShard.java
Added public accessor methods isHandoffInProgress() to expose relocation handoff state.
Handoff validation
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationSourceService.java
Added validation in CheckpointInfoRequestHandler.messageReceived to ensure target shard is a started primary and not undergoing handoff; throws IllegalStateException if check fails.
isRetry parameter removal from replication targets
server/src/main/java/org/opensearch/indices/replication/AbstractSegmentReplicationTarget.java, server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTarget.java, server/src/main/java/org/opensearch/indices/replication/MergedSegmentReplicationTarget.java
Removed isRetry field and constructor parameter from abstract and concrete replication target classes; eliminated gating logic that rejected stale metadata checkpoints.
isRetry removal from replication services
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java, server/src/main/java/org/opensearch/indices/replication/SegmentReplicator.java
Removed overloaded methods and simplified signatures by eliminating isRetry parameter; consolidated checkpoint processing flow to single pathway without retry distinction.
Test updates
server/src/test/java/org/opensearch/indices/replication/SegmentReplicationTargetServiceTests.java
Updated test stubs, verifications, and argument indices to reflect new 3-argument startReplication signature; removed anyBoolean matcher usage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

Indexing:Replication, bug

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly refers to simplifying checkpoint verification for primary shard relocation, which aligns with the substantive changes removing isRetry logic and adding handoff validation.
Description check ✅ Passed The PR description is mostly complete with clear context, issue reference, and code rationale, though specific implementation details are minimal.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

❗ AI-powered Code-Diff-Analyzer found issues on commit dccf9cc.

PathLineSeverityDescription
server/src/main/java/org/opensearch/indices/replication/AbstractSegmentReplicationTarget.java165mediumRemoves checkpoint validation logic that rejected stale metadata checkpoints. This eliminates a security check that prevented replicas from accepting checkpoints ahead of received metadata. While referenced as fixing issue #18490, removing validation without replacement could allow acceptance of invalid/stale replication state. Partially mitigated by new handoff check added in SegmentReplicationSourceService.java

The table above displays the top 10 most important findings.

Total: 1 | Critical: 0 | High: 0 | Medium: 1 | Low: 0


Pull Requests Author(s): Please update your Pull Request according to the report above.

Repository Maintainer(s): You can bypass diff analyzer by adding label skip-diff-analyzer after reviewing the changes carefully, then re-run failed actions. To re-enable the analyzer, remove the label, then re-run all actions.


⚠️ Note: The Code-Diff-Analyzer helps protect against potentially harmful code patterns. Please ensure you have thoroughly reviewed the changes beforehand.

Thanks.

@guojialiang92 guojialiang92 marked this pull request as draft February 12, 2026 06:59
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@server/src/main/java/org/opensearch/index/seqno/ReplicationTracker.java`:
- Around line 849-851: The public accessor isHandoffInProgress() reads the
non-volatile field handoffInProgress without synchronization, risking stale
reads across threads; fix by making handoffInProgress volatile or by
synchronizing accessors in ReplicationTracker (e.g., mark handoffInProgress as
volatile or add synchronized to isHandoffInProgress() and any writers) so
readers see up-to-date handoff state during relocation handoff checks.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ea8359 and dccf9cc.

📒 Files selected for processing (9)
  • server/src/main/java/org/opensearch/index/seqno/ReplicationTracker.java
  • server/src/main/java/org/opensearch/index/shard/IndexShard.java
  • server/src/main/java/org/opensearch/indices/replication/AbstractSegmentReplicationTarget.java
  • server/src/main/java/org/opensearch/indices/replication/MergedSegmentReplicationTarget.java
  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicationSourceService.java
  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTarget.java
  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java
  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicator.java
  • server/src/test/java/org/opensearch/indices/replication/SegmentReplicationTargetServiceTests.java
💤 Files with no reviewable changes (1)
  • server/src/main/java/org/opensearch/indices/replication/AbstractSegmentReplicationTarget.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-13T17:40:27.167Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20411
File: server/src/main/java/org/opensearch/index/codec/CodecService.java:112-133
Timestamp: 2026-01-13T17:40:27.167Z
Learning: Avoid capturing or evaluating a supplier (e.g., this::defaultCodec) upfront when passing it to a registry during object construction. If registries may replace defaults during iteration (as in EnginePlugin.getAdditionalCodecs), pass the supplier itself and only resolve it at use time. This ensures dynamic behavior is preserved during initialization and prevents premature binding of defaults in codecs/registry setup. This pattern should apply to similar initialization paths in Java server code where registries may mutate defaults during construction.

Applied to files:

  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicationSourceService.java
  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicator.java
  • server/src/main/java/org/opensearch/index/shard/IndexShard.java
  • server/src/main/java/org/opensearch/index/seqno/ReplicationTracker.java
  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTarget.java
  • server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java
  • server/src/main/java/org/opensearch/indices/replication/MergedSegmentReplicationTarget.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: gradle-check
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: Analyze (java)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: detect-breaking-change
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, ubuntu-latest)
🔇 Additional comments (13)
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTarget.java (2)

39-46: Constructor update looks good.
The new super call aligns with the simplified constructor signature.


130-131: Retry copy update looks good.
The retry path now uses the simplified constructor consistently.

server/src/main/java/org/opensearch/indices/replication/MergedSegmentReplicationTarget.java (1)

30-37: Constructor update looks good.
The superclass delegation matches the new signature across the target hierarchy.

server/src/main/java/org/opensearch/index/shard/IndexShard.java (1)

4383-4385: Clean delegation for handoff state.
Simple accessor keeps the API consistent and reduces direct tracker access elsewhere.

server/src/main/java/org/opensearch/indices/replication/SegmentReplicationSourceService.java (1)

132-146: Good pre-check before replication setup.
Blocking replication while a handoff is in progress is the right safety net.

server/src/main/java/org/opensearch/indices/replication/SegmentReplicator.java (1)

112-121: LGTM!

The startReplication method correctly constructs SegmentReplicationTarget with the simplified 4-argument signature (removing isRetry), consistent with the broader refactor to eliminate retry-gating at the call site.

server/src/test/java/org/opensearch/indices/replication/SegmentReplicationTargetServiceTests.java (3)

479-479: LGTM!

The verification correctly reflects the updated 3-argument startReplication signature after removing the isRetry parameter.


630-634: LGTM!

The listener argument index correctly updated from position 3 to position 2 to match the new 3-argument startReplication(IndexShard, ReplicationCheckpoint, SegmentReplicationListener) signature.


678-678: LGTM!

Verification updated to use the 3-argument form, consistent with the API change.

server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java (4)

298-298: LGTM!

The onNewCheckpoint method now has a cleaner signature without the isRetry parameter, simplifying the checkpoint processing flow.


335-372: LGTM!

The replication listener implementation is well-structured:

  • On success: updates visible checkpoint and processes any newer checkpoints received during replication
  • On failure: logs the failure, handles shard failure if needed, otherwise processes latest checkpoint for retry

The removal of isRetry from processLatestReceivedCheckpoint (line 369) simplifies the retry path while maintaining the same behavior of attempting to process any newer checkpoints after a non-fatal failure.


483-509: LGTM!

The processLatestReceivedCheckpoint method correctly delegates to onNewCheckpoint (line 497) without the isRetry flag. The thread-forking logic is preserved to avoid stack overflow on recursive checkpoint processing.


523-529: LGTM!

The public startReplication method signature is now simplified to 3 parameters (IndexShard, ReplicationCheckpoint, SegmentReplicationListener), with the source obtained internally from the factory. This provides a cleaner API surface for callers.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@github-actions
Copy link
Contributor

❌ Gradle check result for dccf9cc: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Signed-off-by: guojialiang <guojialiang.2012@bytedance.com>
@github-actions
Copy link
Contributor

❗ AI-powered Code-Diff-Analyzer found issues on commit 413289e.

PathLineSeverityDescription
server/src/main/java/org/opensearch/indices/replication/AbstractSegmentReplicationTarget.java165highComplete removal of checkpoint validation logic that was preventing stale metadata checkpoints from being accepted. This validation was explicitly added to fix issue #18490 and rejected checkpoints when 'checkpoint.isAheadOf(getMetadataCheckpoint)'. Removing this could allow replay of old checkpoints, potentially enabling data inconsistency or rollback attacks in the replication system. The removed code included critical checks for recovery state and retry scenarios.

The table above displays the top 10 most important findings.

Total: 1 | Critical: 0 | High: 1 | Medium: 0 | Low: 0


Pull Requests Author(s): Please update your Pull Request according to the report above.

Repository Maintainer(s): You can bypass diff analyzer by adding label skip-diff-analyzer after reviewing the changes carefully, then re-run failed actions. To re-enable the analyzer, remove the label, then re-run all actions.


⚠️ Note: The Code-Diff-Analyzer helps protect against potentially harmful code patterns. Please ensure you have thoroughly reviewed the changes beforehand.

Thanks.

Signed-off-by: guojialiang <guojialiang.2012@bytedance.com>
Signed-off-by: guojialiang <guojialiang.2012@bytedance.com>
@guojialiang92 guojialiang92 marked this pull request as ready for review February 12, 2026 09:43
@github-actions
Copy link
Contributor

✅ Gradle check result for 6104bb8: SUCCESS

@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.37%. Comparing base (e59c30c) to head (6104bb8).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
...org/opensearch/index/seqno/ReplicationTracker.java 0.00% 1 Missing ⚠️
...in/java/org/opensearch/index/shard/IndexShard.java 0.00% 1 Missing ⚠️
...s/replication/SegmentReplicationSourceService.java 88.88% 0 Missing and 1 partial ⚠️
.../indices/replication/SegmentReplicationTarget.java 50.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #20609      +/-   ##
============================================
- Coverage     73.37%   73.37%   -0.01%     
- Complexity    72197    72248      +51     
============================================
  Files          5798     5798              
  Lines        329816   329814       -2     
  Branches      47538    47536       -2     
============================================
- Hits         242001   241985      -16     
- Misses        68458    68488      +30     
+ Partials      19357    19341      -16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

// See: https://github.com/opensearch-project/OpenSearch/issues/19234
boolean isRecovering = indexShard.routingEntry().initializing() || indexShard.routingEntry().relocating();
if (indexShard.indexSettings().isSegRepLocalEnabled()
&& checkpoint.isAheadOf(getMetadataCheckpoint)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot remove checkpoint.isAheadOf(getMetadataCheckpoint). isHandoffInProgress handles the relocation race but fails against split-brain or Zombie Primaries returning outdated metadata. Without this check, the replica will accept older metadata causing state rollback (deletion of committed segments). The safety check must stay.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants