1313import org .apache .lucene .index .IndexWriter ;
1414import org .apache .lucene .index .IndexWriterConfig ;
1515import org .apache .lucene .index .Term ;
16+ import org .apache .lucene .mockfile .ExtrasFS ;
1617import org .apache .lucene .store .Directory ;
1718import org .apache .lucene .store .FilterDirectory ;
1819import org .apache .lucene .store .IOContext ;
4041import org .elasticsearch .gateway .PersistedClusterStateService .Writer ;
4142import org .elasticsearch .index .Index ;
4243import org .elasticsearch .indices .breaker .NoneCircuitBreakerService ;
44+ import org .elasticsearch .test .CorruptionUtils ;
4345import org .elasticsearch .test .ESTestCase ;
4446import org .elasticsearch .test .MockLogAppender ;
4547import org .elasticsearch .test .junit .annotations .TestLogging ;
4648
4749import java .io .IOError ;
4850import java .io .IOException ;
51+ import java .nio .file .DirectoryStream ;
52+ import java .nio .file .Files ;
4953import java .nio .file .Path ;
5054import java .util .ArrayList ;
5155import java .util .Arrays ;
5660import java .util .concurrent .atomic .AtomicLong ;
5761import java .util .stream .Collectors ;
5862import java .util .stream .Stream ;
63+ import java .util .stream .StreamSupport ;
5964
65+ import static org .apache .lucene .index .IndexWriter .WRITE_LOCK_NAME ;
6066import static org .hamcrest .Matchers .allOf ;
6167import static org .hamcrest .Matchers .containsString ;
68+ import static org .hamcrest .Matchers .endsWith ;
6269import static org .hamcrest .Matchers .equalTo ;
6370import static org .hamcrest .Matchers .lessThan ;
6471import static org .hamcrest .Matchers .nullValue ;
72+ import static org .hamcrest .Matchers .startsWith ;
6573
6674public class PersistedClusterStateServiceTests extends ESTestCase {
6775
@@ -79,7 +87,7 @@ public void testPersistsAndReloadsTerm() throws IOException {
7987 assertThat (persistedClusterStateService .loadBestOnDiskState ().currentTerm , equalTo (0L ));
8088 try (Writer writer = persistedClusterStateService .createWriter ()) {
8189 writer .writeFullStateAndCommit (newTerm , ClusterState .EMPTY_STATE );
82- assertThat (persistedClusterStateService .loadBestOnDiskState ().currentTerm , equalTo (newTerm ));
90+ assertThat (persistedClusterStateService .loadBestOnDiskState (false ).currentTerm , equalTo (newTerm ));
8391 }
8492
8593 assertThat (persistedClusterStateService .loadBestOnDiskState ().currentTerm , equalTo (newTerm ));
@@ -218,8 +226,12 @@ public void testFailsOnMismatchedNodeIds() throws IOException {
218226 .toArray (Path []::new ), nodeIds [0 ], xContentRegistry (), BigArrays .NON_RECYCLING_INSTANCE ,
219227 new ClusterSettings (Settings .EMPTY , ClusterSettings .BUILT_IN_CLUSTER_SETTINGS ), () -> 0L
220228 ).loadBestOnDiskState ()).getMessage ();
221- assertThat (message ,
222- allOf (containsString ("unexpected node ID in metadata" ), containsString (nodeIds [0 ]), containsString (nodeIds [1 ])));
229+ assertThat (message , allOf (
230+ containsString ("the index containing the cluster metadata under the data path" ),
231+ containsString ("belongs to a node with ID" ),
232+ containsString ("but this node's ID is" ),
233+ containsString (nodeIds [0 ]),
234+ containsString (nodeIds [1 ])));
223235 assertTrue ("[" + message + "] should match " + Arrays .toString (dataPaths2 ),
224236 Arrays .stream (dataPaths2 ).anyMatch (p -> message .contains (p .toString ())));
225237 }
@@ -315,7 +327,7 @@ public void testFailsIfFreshestStateIsInStaleTerm() throws IOException {
315327 try (NodeEnvironment nodeEnvironment = newNodeEnvironment (dataPaths2 )) {
316328 try (Writer writer = newPersistedClusterStateService (nodeEnvironment ).createWriter ()) {
317329 final PersistedClusterStateService .OnDiskState onDiskState = newPersistedClusterStateService (nodeEnvironment )
318- .loadBestOnDiskState ();
330+ .loadBestOnDiskState (false );
319331 final ClusterState clusterState = clusterStateFromMetadata (onDiskState .lastAcceptedVersion , onDiskState .metadata );
320332 writeState (writer , onDiskState .currentTerm , ClusterState .builder (clusterState )
321333 .metadata (Metadata .builder (clusterState .metadata ()).version (2 )
@@ -851,6 +863,30 @@ public void testSlowLogging() throws IOException, IllegalAccessException {
851863 }
852864 }
853865
866+ public void testFailsIfCorrupt () throws IOException {
867+ try (NodeEnvironment nodeEnvironment = newNodeEnvironment (createDataPaths ())) {
868+ final PersistedClusterStateService persistedClusterStateService = newPersistedClusterStateService (nodeEnvironment );
869+
870+ try (Writer writer = persistedClusterStateService .createWriter ()) {
871+ writer .writeFullStateAndCommit (1 , ClusterState .EMPTY_STATE );
872+ }
873+
874+ try (DirectoryStream <Path > directoryStream = Files .newDirectoryStream (nodeEnvironment .nodeDataPaths ()[0 ].resolve ("_state" ))) {
875+ CorruptionUtils .corruptFile (random (), randomFrom (StreamSupport
876+ .stream (directoryStream .spliterator (), false )
877+ .filter (p -> {
878+ final String filename = p .getFileName ().toString ();
879+ return ExtrasFS .isExtra (filename ) == false && filename .equals (WRITE_LOCK_NAME ) == false ;
880+ })
881+ .collect (Collectors .toList ())));
882+ }
883+
884+ assertThat (expectThrows (IllegalStateException .class , persistedClusterStateService ::loadBestOnDiskState ).getMessage (), allOf (
885+ startsWith ("the index containing the cluster metadata under the data path [" ),
886+ endsWith ("] has been changed by an external force after it was last written by Elasticsearch and is now unreadable" )));
887+ }
888+ }
889+
854890 private void assertExpectedLogs (long currentTerm , ClusterState previousState , ClusterState clusterState ,
855891 PersistedClusterStateService .Writer writer , MockLogAppender .LoggingExpectation expectation )
856892 throws IllegalAccessException , IOException {
@@ -896,7 +932,7 @@ private NodeEnvironment newNodeEnvironment(Path[] dataPaths) throws IOException
896932 }
897933
898934 private static ClusterState loadPersistedClusterState (PersistedClusterStateService persistedClusterStateService ) throws IOException {
899- final PersistedClusterStateService .OnDiskState onDiskState = persistedClusterStateService .loadBestOnDiskState ();
935+ final PersistedClusterStateService .OnDiskState onDiskState = persistedClusterStateService .loadBestOnDiskState (false );
900936 return clusterStateFromMetadata (onDiskState .lastAcceptedVersion , onDiskState .metadata );
901937 }
902938
0 commit comments