Skip to content
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

Closed shard should never open new engine #47186

Merged
merged 7 commits into from
Nov 7, 2019
Merged

Conversation

dnhatn
Copy link
Member

@dnhatn dnhatn commented Sep 26, 2019

We should not open new engines if a shard is closed. We break this assumption in #45263 where we stop verifying the shard state before creating an engine but only before swapping the engine reference. We can fail to snapshot the store metadata or checkIndex a closed shard if there's some IndexWriter holding the index lock.

Closes #47060

@dnhatn dnhatn added >bug :Distributed/Distributed A catch all label for anything in the Distributed Area. If you aren't sure, use this one. v8.0.0 v7.5.0 v7.4.1 labels Sep 26, 2019
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-distributed

@dnhatn dnhatn changed the title Use only engineMutex to protect engine reference Closed shard should never open new engine Sep 26, 2019
Copy link
Contributor

@henningandersen henningandersen left a comment

Choose a reason for hiding this comment

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

Thanks for looking into this @dnhatn, I believe I know what you want to achieve, but I also think this might revert back blocking the cluster state applier thread (more details in comments)?

@dnhatn
Copy link
Member Author

dnhatn commented Oct 2, 2019

@henningandersen Thank you for your thoughtful review.

I think this means that we now risk waiting for an engine warmer during close.

Great catch. I spent some time on this, but I did not come up with a solution unless we introduce the "start" method to Engine. Do you have any suggestions for this?

@henningandersen
Copy link
Contributor

@dnhatn I also lean towards the "start" method that runs outside the mutex. The other options I can think of are:

  • Move the locking to IndexService to prevent snapshot'ing from hitting this (and fix checkIndex to also avoid it).
  • Make close async, i.e., it reports back through a listener when done.
  • Keep close, but fix the caller to run in another thread and async-notify.

Unfortunately, using the generic thread pool for the last approach might lead to issues if it can be called during shutdown?

I think I prefer to add a method to do the warmup, seems simpler overall. The benefit of doing close async though is that it avoids waiting for the rest of the IO happening during InternalEngine constructor. Not sure if this has any benefits?

@dnhatn
Copy link
Member Author

dnhatn commented Oct 9, 2019

I think I prefer to add a method to do the warmup, seems simpler overall.

+1. Thank you for your suggestion. I will work on this solution.

@dnhatn
Copy link
Member Author

dnhatn commented Oct 10, 2019

@henningandersen I worked on a change that moves the engine warming out of the constructor. It is pretty straightforward. However, it does not eliminate the blocking issue. Closing an engine acquires the writeLock, which can be blocked by an engine warming as it holds the readLock (via refresh). We can fix the refresh, but indexing and flushing can cause the same problem. I will reach out to discuss this with you.

@tomcallahan tomcallahan added v7.4.2 and removed v7.4.1 labels Oct 22, 2019
dnhatn added a commit that referenced this pull request Oct 25, 2019
Today, we hold the engine readLock while refreshing. Although this 
choice simplifies the correctness reasoning, it can block IndexShard 
from closing if warming an external reader takes time. The current
implementation of refresh does not need to hold readLock as
ReferenceManager can handle errors correctly if the engine is closed in
midway.

This PR is a prerequisite that we need to solve #47186.
dnhatn added a commit that referenced this pull request Oct 25, 2019
Today, we hold the engine readLock while refreshing. Although this 
choice simplifies the correctness reasoning, it can block IndexShard 
from closing if warming an external reader takes time. The current
implementation of refresh does not need to hold readLock as
ReferenceManager can handle errors correctly if the engine is closed in
midway.

This PR is a prerequisite that we need to solve #47186.
dnhatn added a commit that referenced this pull request Oct 30, 2019
With this change, we won't warm up searchers until we externally refresh 
an engine. We explicitly refresh before allowing reading from a shard
(i.e., move to post_recovery state) and during resetting. These
guarantees that we have warmed up the engine before exposing the
external searcher.

Another prerequisite for #47186.
dnhatn added a commit that referenced this pull request Oct 30, 2019
With this change, we won't warm up searchers until we externally refresh
an engine. We explicitly refresh before allowing reading from a shard
(i.e., move to post_recovery state) and during resetting. These
guarantees that we have warmed up the engine before exposing the
external searcher.

Another prerequisite for #47186.
@polyfractal polyfractal added v7.4.3 and removed v7.4.2 labels Oct 31, 2019
@dnhatn dnhatn added the v7.6.0 label Nov 1, 2019
@dnhatn
Copy link
Member Author

dnhatn commented Nov 1, 2019

I have two tests in a56d9ff that can reliably reproduce the test failure reported in #47060. However, neither of them works with the latest change as we now hold engineMutex while closing a shard. I am not sure if I can come up with a useful test for this change. Any suggestions would be great.

@henningandersen This is ready again. Can you please take another look? Thank you.

dnhatn added a commit that referenced this pull request Nov 3, 2019
Today, we hold the engine readLock while refreshing. Although this 
choice simplifies the correctness reasoning, it can block IndexShard 
from closing if warming an external reader takes time. The current
implementation of refresh does not need to hold readLock as
ReferenceManager can handle errors correctly if the engine is closed in
midway.

This PR is a prerequisite that we need to solve #47186.
dnhatn added a commit that referenced this pull request Nov 3, 2019
With this change, we won't warm up searchers until we externally refresh
an engine. We explicitly refresh before allowing reading from a shard
(i.e., move to post_recovery state) and during resetting. These
guarantees that we have warmed up the engine before exposing the
external searcher.

Another prerequisite for #47186.
Copy link
Contributor

@henningandersen henningandersen left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for the large effort on this, @dnhatn .

@dnhatn
Copy link
Member Author

dnhatn commented Nov 7, 2019

@henningandersen Thank you so much for your review and discussion on this.

@dnhatn dnhatn merged commit d029e18 into elastic:master Nov 7, 2019
@dnhatn dnhatn deleted the engine-mutex branch November 7, 2019 20:39
dnhatn added a commit that referenced this pull request Nov 9, 2019
We should not open new engines if a shard is closed. We break this
assumption in #45263 where we stop verifying the shard state before
creating an engine but only before swapping the engine reference.
We can fail to snapshot the store metadata or checkIndex a closed shard
if there's some IndexWriter holding the index lock.

Closes #47060
dnhatn added a commit that referenced this pull request Nov 9, 2019
We should not open new engines if a shard is closed. We break this
assumption in #45263 where we stop verifying the shard state before
creating an engine but only before swapping the engine reference.
We can fail to snapshot the store metadata or checkIndex a closed shard
if there's some IndexWriter holding the index lock.

Closes #47060
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>bug :Distributed/Distributed A catch all label for anything in the Distributed Area. If you aren't sure, use this one. v7.5.0 v7.6.0 v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CI] FlushIT.testSyncedFlushWithConcurrentIndexing failure
6 participants