-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Segment Replication - Implement segment replication event cancellation. #4225
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
import org.apache.lucene.store.ByteBuffersDataInput; | ||
import org.apache.lucene.store.ByteBuffersIndexInput; | ||
import org.apache.lucene.store.ChecksumIndexInput; | ||
import org.opensearch.ExceptionsHelper; | ||
import org.opensearch.OpenSearchException; | ||
import org.opensearch.action.ActionListener; | ||
import org.opensearch.action.StepListener; | ||
|
@@ -103,7 +104,15 @@ public String description() { | |
|
||
@Override | ||
public void notifyListener(OpenSearchException e, boolean sendShardFailure) { | ||
listener.onFailure(state(), e, sendShardFailure); | ||
// Cancellations still are passed to our SegmentReplicationListner as failures, if we have failed because of cancellation | ||
// update the stage. | ||
final Throwable cancelledException = ExceptionsHelper.unwrap(e, CancellableThreads.ExecutionCancelledException.class); | ||
if (cancelledException != null) { | ||
state.setStage(SegmentReplicationState.Stage.CANCELLED); | ||
listener.onFailure(state(), (CancellableThreads.ExecutionCancelledException) cancelledException, sendShardFailure); | ||
} else { | ||
listener.onFailure(state(), e, sendShardFailure); | ||
} | ||
} | ||
|
||
@Override | ||
|
@@ -134,13 +143,22 @@ public void writeFileChunk( | |
* @param listener {@link ActionListener} listener. | ||
*/ | ||
public void startReplication(ActionListener<Void> listener) { | ||
cancellableThreads.setOnCancel((reason, beforeCancelEx) -> { | ||
// This method only executes when cancellation is triggered by this node and caught by a call to checkForCancel, | ||
// SegmentReplicationSource does not share CancellableThreads. | ||
final CancellableThreads.ExecutionCancelledException executionCancelledException = | ||
new CancellableThreads.ExecutionCancelledException("replication was canceled reason [" + reason + "]"); | ||
notifyListener(executionCancelledException, false); | ||
throw executionCancelledException; | ||
}); | ||
state.setStage(SegmentReplicationState.Stage.REPLICATING); | ||
final StepListener<CheckpointInfoResponse> checkpointInfoListener = new StepListener<>(); | ||
final StepListener<GetSegmentFilesResponse> getFilesListener = new StepListener<>(); | ||
final StepListener<Void> finalizeListener = new StepListener<>(); | ||
|
||
logger.trace("[shardId {}] Replica starting replication [id {}]", shardId().getId(), getId()); | ||
// Get list of files to copy from this checkpoint. | ||
cancellableThreads.checkForCancel(); | ||
state.setStage(SegmentReplicationState.Stage.GET_CHECKPOINT_INFO); | ||
source.getCheckpointMetadata(getId(), checkpoint, checkpointInfoListener); | ||
|
||
|
@@ -154,6 +172,7 @@ public void startReplication(ActionListener<Void> listener) { | |
|
||
private void getFiles(CheckpointInfoResponse checkpointInfo, StepListener<GetSegmentFilesResponse> getFilesListener) | ||
throws IOException { | ||
cancellableThreads.checkForCancel(); | ||
state.setStage(SegmentReplicationState.Stage.FILE_DIFF); | ||
final Store.MetadataSnapshot snapshot = checkpointInfo.getSnapshot(); | ||
Store.MetadataSnapshot localMetadata = getMetadataSnapshot(); | ||
|
@@ -188,12 +207,14 @@ private void getFiles(CheckpointInfoResponse checkpointInfo, StepListener<GetSeg | |
} | ||
// always send a req even if not fetching files so the primary can clear the copyState for this shard. | ||
state.setStage(SegmentReplicationState.Stage.GET_FILES); | ||
cancellableThreads.checkForCancel(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this check added again on this method, shouldn't checkForCancel handle this as well ? Is this added just as a safeguard for state changes just before b/w start of this method and when actual files are requested from primary ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct, I wanted to add the check in both the GET_FILES step and FILE_DIFF |
||
source.getSegmentFiles(getId(), checkpointInfo.getCheckpoint(), filesToFetch, store, getFilesListener); | ||
} | ||
|
||
private void finalizeReplication(CheckpointInfoResponse checkpointInfoResponse, ActionListener<Void> listener) { | ||
state.setStage(SegmentReplicationState.Stage.FINALIZE_REPLICATION); | ||
ActionListener.completeWith(listener, () -> { | ||
cancellableThreads.checkForCancel(); | ||
state.setStage(SegmentReplicationState.Stage.FINALIZE_REPLICATION); | ||
multiFileWriter.renameAllTempFiles(); | ||
final Store store = store(); | ||
store.incRef(); | ||
|
@@ -261,4 +282,10 @@ Store.MetadataSnapshot getMetadataSnapshot() throws IOException { | |
} | ||
return store.getMetadata(indexShard.getSegmentInfosSnapshot().get()); | ||
} | ||
|
||
@Override | ||
protected void onCancel(String reason) { | ||
cancellableThreads.cancel(reason); | ||
source.cancel(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is the case for partial files copy is handled i.e. replica copied few but not all files ?
Can this be problematic when this replica is promoted as new primary with few files from previous primary ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there are partial files copied they will remain tmp with a prefix like
replication_0.cfe
. The rename occurs once all files have been copied in finalize. So in this case the replication would be cancelled and the partial files discarded in the commit made before the shard's engine is re-opened swapped.