Selaa lähdekoodia

Inc store reference before refresh (#28656)

If a tragic even happens while we are refreshing a searcher/reader the engine can open new files on a store that is already closed
For instance the following CI job failed because a merge was concurrently called on a failing shard:
https://elasticsearch-ci.elastic.co/job/elastic+elasticsearch+master+oracle-java10-periodic/84
This change increments the ref count of the store during a refresh in order to postpone the closing after a tragic event.
Jim Ferenczi 7 vuotta sitten
vanhempi
commit
3b9f530839

+ 19 - 12
server/src/main/java/org/elasticsearch/index/engine/InternalEngine.java

@@ -1359,18 +1359,25 @@ public class InternalEngine extends Engine {
         writingBytes.addAndGet(bytes);
         try (ReleasableLock lock = readLock.acquire()) {
             ensureOpen();
-            switch (scope) {
-                case EXTERNAL:
-                    // even though we maintain 2 managers we really do the heavy-lifting only once.
-                    // the second refresh will only do the extra work we have to do for warming caches etc.
-                    externalSearcherManager.maybeRefreshBlocking();
-                    // the break here is intentional we never refresh both internal / external together
-                    break;
-                case INTERNAL:
-                    internalSearcherManager.maybeRefreshBlocking();
-                    break;
-                default:
-                    throw new IllegalArgumentException("unknown scope: " + scope);
+            if (store.tryIncRef()) {
+                // increment the ref just to ensure nobody closes the store during a refresh
+                try {
+                    switch (scope) {
+                        case EXTERNAL:
+                            // even though we maintain 2 managers we really do the heavy-lifting only once.
+                            // the second refresh will only do the extra work we have to do for warming caches etc.
+                            externalSearcherManager.maybeRefreshBlocking();
+                            // the break here is intentional we never refresh both internal / external together
+                            break;
+                        case INTERNAL:
+                            internalSearcherManager.maybeRefreshBlocking();
+                            break;
+                        default:
+                            throw new IllegalArgumentException("unknown scope: " + scope);
+                    }
+                } finally {
+                    store.decRef();
+                }
             }
         } catch (AlreadyClosedException e) {
             failOnTragicEvent(e);