Skip to content

Commit 85a7424

Browse files
committed
Require freshest state to have the freshest current term
1 parent 79fc46b commit 85a7424

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

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

+10-4
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,9 @@ private OnDiskState loadBestOnDiskState() throws IOException {
202202
long maxAcceptedTerm = bestOnDiskState.metaData.coordinationMetaData().term();
203203
if (acceptedTerm > maxAcceptedTerm
204204
|| (acceptedTerm == maxAcceptedTerm
205-
&& onDiskState.lastAcceptedVersion > bestOnDiskState.lastAcceptedVersion)) {
206-
205+
&& (onDiskState.lastAcceptedVersion > bestOnDiskState.lastAcceptedVersion
206+
|| (onDiskState.lastAcceptedVersion == bestOnDiskState.lastAcceptedVersion)
207+
&& onDiskState.currentTerm > bestOnDiskState.currentTerm))) {
207208
bestOnDiskState = onDiskState;
208209
}
209210
} catch (IndexNotFoundException e) {
@@ -213,7 +214,12 @@ private OnDiskState loadBestOnDiskState() throws IOException {
213214
}
214215
}
215216

216-
return new OnDiskState(bestOnDiskState.nodeId, maxCurrentTerm, bestOnDiskState.lastAcceptedVersion, bestOnDiskState.metaData);
217+
if (bestOnDiskState.currentTerm != maxCurrentTerm) {
218+
throw new IllegalStateException("inconsistent terms found: best state is in term [" + bestOnDiskState.currentTerm +
219+
"] but there is a stale state with greater term [" + maxCurrentTerm + "]");
220+
}
221+
222+
return bestOnDiskState;
217223
}
218224

219225
private static Path getMetaDataIndexPath(Path path, int majorVersion) {
@@ -234,7 +240,7 @@ private OnDiskState loadOnDiskState(DirectoryReader reader) throws IOException {
234240
{
235241
final MetaData metaData = MetaData.fromXContent(XContentFactory.xContent(XContentType.SMILE)
236242
.createParser(namedXContentRegistry, LoggingDeprecationHandler.INSTANCE, bytes));
237-
logger.trace("found global metadata");
243+
logger.trace("found global metadata with last-accepted term [{}]", metaData.coordinationMetaData().term());
238244
builderReference.set(MetaData.builder(metaData));
239245
});
240246

server/src/test/java/org/elasticsearch/gateway/LucenePersistedStateFactoryTests.java

+54
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,60 @@ public void testFailsOnMismatchedCommittedClusterUUIDs() throws IOException {
252252
}
253253
}
254254

255+
public void testFailsIfFreshestStateIsInStaleTerm() throws IOException {
256+
final Path[] dataPaths1 = createDataPaths();
257+
final Path[] dataPaths2 = createDataPaths();
258+
final Path[] combinedPaths = Stream.concat(Arrays.stream(dataPaths1), Arrays.stream(dataPaths2)).toArray(Path[]::new);
259+
260+
final long staleCurrentTerm = randomLongBetween(1L, Long.MAX_VALUE - 1);
261+
final long freshCurrentTerm = randomLongBetween(staleCurrentTerm + 1, Long.MAX_VALUE);
262+
263+
final long freshTerm = randomLongBetween(1L, Long.MAX_VALUE);
264+
final long staleTerm = randomBoolean() ? freshTerm : randomLongBetween(1L, freshTerm);
265+
final long freshVersion = randomLongBetween(2L, Long.MAX_VALUE);
266+
final long staleVersion = staleTerm == freshTerm ? randomLongBetween(1L, freshVersion - 1) : randomLongBetween(1L, Long.MAX_VALUE);
267+
268+
try (NodeEnvironment nodeEnvironment = newNodeEnvironment(combinedPaths)) {
269+
try (CoordinationState.PersistedState persistedState
270+
= loadPersistedState(new LucenePersistedStateFactory(nodeEnvironment, xContentRegistry()))) {
271+
final ClusterState clusterState = persistedState.getLastAcceptedState();
272+
persistedState.setCurrentTerm(staleCurrentTerm);
273+
persistedState.setLastAcceptedState(ClusterState.builder(clusterState)
274+
.metaData(MetaData.builder(clusterState.metaData()).version(1)
275+
.coordinationMetaData(CoordinationMetaData.builder(clusterState.coordinationMetaData()).term(staleTerm).build()))
276+
.version(staleVersion)
277+
.build());
278+
}
279+
}
280+
281+
try (NodeEnvironment nodeEnvironment = newNodeEnvironment(dataPaths1)) {
282+
try (CoordinationState.PersistedState persistedState
283+
= loadPersistedState(new LucenePersistedStateFactory(nodeEnvironment, xContentRegistry()))) {
284+
persistedState.setCurrentTerm(freshCurrentTerm);
285+
}
286+
}
287+
288+
try (NodeEnvironment nodeEnvironment = newNodeEnvironment(dataPaths2)) {
289+
try (CoordinationState.PersistedState persistedState
290+
= loadPersistedState(new LucenePersistedStateFactory(nodeEnvironment, xContentRegistry()))) {
291+
final ClusterState clusterState = persistedState.getLastAcceptedState();
292+
persistedState.setLastAcceptedState(ClusterState.builder(clusterState)
293+
.metaData(MetaData.builder(clusterState.metaData()).version(2)
294+
.coordinationMetaData(CoordinationMetaData.builder(clusterState.coordinationMetaData()).term(freshTerm).build()))
295+
.version(freshVersion)
296+
.build());
297+
}
298+
}
299+
300+
try (NodeEnvironment nodeEnvironment = newNodeEnvironment(combinedPaths)) {
301+
assertThat(expectThrows(IllegalStateException.class,
302+
() -> loadPersistedState(new LucenePersistedStateFactory(nodeEnvironment, xContentRegistry()))).getMessage(), allOf(
303+
containsString("inconsistent terms found"),
304+
containsString(Long.toString(staleCurrentTerm)),
305+
containsString(Long.toString(freshCurrentTerm))));
306+
}
307+
}
308+
255309
public void testFailsGracefullyOnExceptionDuringFlush() throws IOException {
256310
final AtomicBoolean throwException = new AtomicBoolean();
257311

0 commit comments

Comments
 (0)