-
Notifications
You must be signed in to change notification settings - Fork 25.1k
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
CCR: Optimize indexing ops using seq_no on followers #34099
Changes from 6 commits
be60aa6
7d25e69
a81d1df
34f6f81
6cd688e
adb9933
be86b4f
319dbb8
91f419b
5a0f464
f34b447
516c99e
6f807cf
d79d26e
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 |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
*/ | ||
package org.elasticsearch.xpack.ccr.index.engine; | ||
|
||
import org.elasticsearch.common.metrics.CounterMetric; | ||
import org.elasticsearch.index.VersionType; | ||
import org.elasticsearch.index.engine.EngineConfig; | ||
import org.elasticsearch.index.engine.InternalEngine; | ||
|
@@ -18,6 +19,8 @@ | |
*/ | ||
public final class FollowingEngine extends InternalEngine { | ||
|
||
private final CounterMetric numOfOptimizedIndexing = new CounterMetric(); | ||
|
||
/** | ||
* Construct a new following engine with the specified engine configuration. | ||
* | ||
|
@@ -51,7 +54,48 @@ private void preFlight(final Operation operation) { | |
@Override | ||
protected InternalEngine.IndexingStrategy indexingStrategyForOperation(final Index index) throws IOException { | ||
preFlight(index); | ||
return planIndexingAsNonPrimary(index); | ||
/* | ||
* A note about optimization using sequence numbers: | ||
* | ||
* 1. Indexing operations are processed concurrently in an engine. However, operations of the same docID are processed | ||
* one by one under the docID lock. | ||
* | ||
* 2. An engine itself can resolve correctly if an operation is delivered multiple times. However, if an operation is | ||
* optimized and delivered multiple times, it will be appended into Lucene more than once. We void this issue by | ||
* not executing operations which have been processed before (using LocalCheckpointTracker). | ||
* | ||
* 3. When replicating operations to replicas or followers, we also carry the max seq_no_of_updates_or_deletes on the | ||
* leader to followers. This transfer guarantees the MUS on a follower when operation O is processed at least the | ||
* MUS on the leader when it was executed [every operation O => MSU_r(O) >= MSU_p(O)]. | ||
* | ||
* 4. The following proves that docID(O) does not exist on a follower when operation O is applied if MSU_r(O) <= LCP < seqno(O): | ||
* | ||
* 4.1) Given two operations O and O' with docID(O’) = docID(O) and seqno(O) < seqno(O’) then MSU_p(O') on the 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. I think you mean |
||
* must be at least seqno(O). Moreover, the MSU_r on a follower >= min(seqno(O), seqno(O')) after these operations | ||
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.
I still don't follow this. 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. I break it into two cases. I hope this is clear now. |
||
* arrive in any order. | ||
* | ||
* 4.2) If such operation O' with docID(O’) = docID(O) and LCP < seqno(O’) then MSU_r(O) >= min(seqno(O), seqno(O')) > LCP | ||
* because both arrived on the follower[4.1]. This contradicts the assumption [MSU_r(O) <= LCP]. | ||
* | ||
* 4.3) MSU(O) < seqno(O) then docID(O) does not exist when O is applied on a leader. This means docID(O) does not exist | ||
* after we apply every operation with docID = docID(O) and seqno < seqno(O). On the follower, we have applied every | ||
* operation with seqno <= LCP, and there is no such O' with docID(O’) = docID(O) and LCP < seqno(O’)[4.2]. | ||
* These mean the follower has applied every operation with docID = docID(O) and seqno < seqno(O). | ||
* Thus docID(O) does not exist on the follower. | ||
*/ | ||
final long maxSeqNoOfUpdatesOrDeletes = getMaxSeqNoOfUpdatesOrDeletes(); | ||
assert maxSeqNoOfUpdatesOrDeletes != SequenceNumbers.UNASSIGNED_SEQ_NO : "max_seq_no_of_updates is not initialized"; | ||
if (hasBeenProcessedBefore(index)) { | ||
return IndexingStrategy.processButSkipLucene(false, index.seqNo(), index.version()); | ||
dnhatn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
} else if (maxSeqNoOfUpdatesOrDeletes <= getLocalCheckpoint()) { | ||
assert maxSeqNoOfUpdatesOrDeletes < index.seqNo() : "seq_no[" + index.seqNo() + "] <= msu[" + maxSeqNoOfUpdatesOrDeletes + "]"; | ||
numOfOptimizedIndexing.inc(); | ||
return InternalEngine.IndexingStrategy.optimizedAppendOnly(index.seqNo(), index.version()); | ||
|
||
} else { | ||
return planIndexingAsNonPrimary(index); | ||
} | ||
} | ||
|
||
@Override | ||
|
@@ -85,4 +129,11 @@ protected boolean assertPrimaryCanOptimizeAddDocument(final Index index) { | |
return true; | ||
} | ||
|
||
/** | ||
* Returns the number of indexing operations that have been optimized (bypass version lookup) using sequence numbers in this engine. | ||
* This metric is not persisted, and started from 0 when the engine is opened. | ||
*/ | ||
public long getNumberOfOptimizedIndexing() { | ||
return numOfOptimizedIndexing.count(); | ||
} | ||
} |
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.
I'm not sure this note is correct? we don't execute if we see we did before?
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.
I've updated this.
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.
Did you forget to push something? this statement is not correct. There is no notion of an "optimized op" (for replicas) just an op with a seq# about the MSU. Also "However, if an operation is optimized and delivered multiple times, it will be appended into Lucene more than once." reads weird. Maybe as simple as "Operations that are optimized using the MSU optimization may not be processed twice as this will create duplicates in lucene. To avoid it we check the local checkpoint tracker to see if an operation was already processed".
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.
I've applied your suggestion.