Skip to content

Commit f0340d6

Browse files
authored
[Zen2] Storage layer WriteStateException propagation (#36052)
Currently, we only log that WriteStateException has occurred, in GatewayMetaState. This PR goal is to re-throw WriteStateException to upper layers. If dirty flag is set to false, we wrap WriteStateException in UncheckedIOException, we prefer unchecked exception not to add explicit throws in the multitude of layers. If dirty flag is set to true - the world is broken. And we need to halt the JVM. Instead of explicit halting in GatewayMetaState, we prefer to throw IOError, which will be subsequently handled by ElasticsearchUncaughtExceptionHandler and JVM will be halted. This PR also adds tests for WriteStateException.
1 parent b08cffa commit f0340d6

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

server/src/main/java/org/elasticsearch/gateway/GatewayMetaState.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
2323
import org.apache.logging.log4j.LogManager;
2424
import org.apache.logging.log4j.Logger;
25+
import org.apache.logging.log4j.message.ParameterizedMessage;
2526
import org.elasticsearch.Version;
2627
import org.elasticsearch.cluster.ClusterChangedEvent;
2728
import org.elasticsearch.cluster.ClusterName;
@@ -235,8 +236,8 @@ public void setCurrentTerm(long currentTerm) {
235236
try {
236237
innerSetCurrentTerm(currentTerm);
237238
} catch (WriteStateException e) {
238-
logger.warn("Exception occurred when setting current term", e);
239-
//TODO re-throw exception
239+
logger.error(new ParameterizedMessage("Failed to set current term to {}", currentTerm), e);
240+
e.rethrowAsErrorOrUncheckedException();
240241
}
241242
}
242243

@@ -253,8 +254,8 @@ public void setLastAcceptedState(ClusterState clusterState) {
253254
incrementalWrite = previousClusterState.term() == clusterState.term();
254255
updateClusterState(clusterState, previousClusterState);
255256
} catch (WriteStateException e) {
256-
logger.warn("Exception occurred when setting last accepted state", e);
257-
//TODO re-throw exception
257+
logger.error(new ParameterizedMessage("Failed to set last accepted state with version {}", clusterState.version()), e);
258+
e.rethrowAsErrorOrUncheckedException();
258259
}
259260
}
260261

server/src/main/java/org/elasticsearch/gateway/WriteStateException.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
*/
1919
package org.elasticsearch.gateway;
2020

21+
import java.io.IOError;
2122
import java.io.IOException;
23+
import java.io.UncheckedIOException;
2224

2325
/**
2426
* This exception is thrown when there is a problem of writing state to disk.
@@ -38,4 +40,16 @@ public class WriteStateException extends IOException {
3840
public boolean isDirty() {
3941
return dirty;
4042
}
43+
44+
/**
45+
* Rethrows this {@link WriteStateException} as {@link IOError} if dirty flag is set, which will lead to JVM shutdown.
46+
* If dirty flag is not set, this exception is wrapped into {@link UncheckedIOException}.
47+
*/
48+
public void rethrowAsErrorOrUncheckedException() {
49+
if (isDirty()) {
50+
throw new IOError(this);
51+
} else {
52+
throw new UncheckedIOException(this);
53+
}
54+
}
4155
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.gateway;
21+
22+
import org.elasticsearch.test.ESTestCase;
23+
24+
import java.io.IOError;
25+
import java.io.UncheckedIOException;
26+
27+
import static org.hamcrest.Matchers.equalTo;
28+
import static org.hamcrest.Matchers.instanceOf;
29+
30+
public class WriteStateExceptionTests extends ESTestCase {
31+
32+
public void testDirtyFlag() {
33+
boolean dirty = randomBoolean();
34+
WriteStateException ex = new WriteStateException(dirty, "test", null);
35+
assertThat(ex.isDirty(), equalTo(dirty));
36+
}
37+
38+
public void testNonDirtyRethrow() {
39+
WriteStateException ex = new WriteStateException(false, "test", null);
40+
UncheckedIOException ex2 = expectThrows(UncheckedIOException.class, () -> ex.rethrowAsErrorOrUncheckedException());
41+
assertThat(ex2.getCause(), instanceOf(WriteStateException.class));
42+
}
43+
44+
public void testDirtyRethrow() {
45+
WriteStateException ex = new WriteStateException(true, "test", null);
46+
IOError err = expectThrows(IOError.class, () -> ex.rethrowAsErrorOrUncheckedException());
47+
assertThat(err.getCause(), instanceOf(WriteStateException.class));
48+
}
49+
}

0 commit comments

Comments
 (0)