18
18
*/
19
19
package org .elasticsearch .gateway ;
20
20
21
+ import org .apache .logging .log4j .Level ;
22
+ import org .apache .logging .log4j .LogManager ;
23
+ import org .apache .logging .log4j .Logger ;
21
24
import org .apache .lucene .store .Directory ;
22
25
import org .apache .lucene .store .MockDirectoryWrapper ;
23
26
import org .elasticsearch .Version ;
27
+ import org .elasticsearch .cluster .ClusterName ;
24
28
import org .elasticsearch .cluster .ClusterState ;
25
29
import org .elasticsearch .cluster .ESAllocationTestCase ;
26
30
import org .elasticsearch .cluster .metadata .IndexMetaData ;
27
31
import org .elasticsearch .cluster .metadata .Manifest ;
28
32
import org .elasticsearch .cluster .metadata .MetaData ;
33
+ import org .elasticsearch .cluster .node .DiscoveryNode ;
29
34
import org .elasticsearch .cluster .node .DiscoveryNodeRole ;
30
35
import org .elasticsearch .cluster .node .DiscoveryNodes ;
31
36
import org .elasticsearch .cluster .routing .RoutingTable ;
32
37
import org .elasticsearch .cluster .routing .allocation .AllocationService ;
33
38
import org .elasticsearch .cluster .routing .allocation .decider .ClusterRebalanceAllocationDecider ;
34
39
import org .elasticsearch .common .collect .Tuple ;
40
+ import org .elasticsearch .common .logging .Loggers ;
41
+ import org .elasticsearch .common .settings .ClusterSettings ;
35
42
import org .elasticsearch .common .settings .Settings ;
36
43
import org .elasticsearch .common .xcontent .NamedXContentRegistry ;
37
44
import org .elasticsearch .common .xcontent .XContentBuilder ;
38
45
import org .elasticsearch .common .xcontent .XContentParser ;
39
46
import org .elasticsearch .env .NodeEnvironment ;
40
47
import org .elasticsearch .index .Index ;
48
+ import org .elasticsearch .test .MockLogAppender ;
49
+ import org .elasticsearch .test .junit .annotations .TestLogging ;
41
50
import org .mockito .ArgumentCaptor ;
42
51
43
52
import java .io .IOException ;
48
57
import java .util .List ;
49
58
import java .util .Map ;
50
59
import java .util .Set ;
60
+ import java .util .concurrent .atomic .AtomicLong ;
51
61
52
62
import static org .hamcrest .Matchers .containsString ;
53
63
import static org .hamcrest .Matchers .equalTo ;
54
64
import static org .hamcrest .Matchers .hasSize ;
65
+ import static org .hamcrest .Matchers .lessThan ;
55
66
import static org .mockito .Matchers .anyString ;
56
67
import static org .mockito .Matchers .eq ;
57
68
import static org .mockito .Mockito .mock ;
69
+ import static org .mockito .Mockito .times ;
58
70
import static org .mockito .Mockito .verify ;
59
- import static org .mockito .Mockito .verifyZeroInteractions ;
71
+ import static org .mockito .Mockito .verifyNoMoreInteractions ;
60
72
import static org .mockito .Mockito .when ;
61
73
62
74
public class IncrementalClusterStateWriterTests extends ESAllocationTestCase {
@@ -250,20 +262,28 @@ public void testResolveStatesToBeWritten() throws WriteStateException {
250
262
251
263
assertThat (actions , hasSize (3 ));
252
264
265
+ boolean keptPreviousGeneration = false ;
266
+ boolean wroteNewIndex = false ;
267
+ boolean wroteChangedIndex = false ;
268
+
253
269
for (IncrementalClusterStateWriter .IndexMetaDataAction action : actions ) {
254
270
if (action instanceof IncrementalClusterStateWriter .KeepPreviousGeneration ) {
255
271
assertThat (action .getIndex (), equalTo (notChangedIndex .getIndex ()));
256
272
IncrementalClusterStateWriter .AtomicClusterStateWriter writer
257
273
= mock (IncrementalClusterStateWriter .AtomicClusterStateWriter .class );
258
274
assertThat (action .execute (writer ), equalTo (3L ));
259
- verifyZeroInteractions (writer );
275
+ verify (writer , times (1 )).incrementIndicesSkipped ();
276
+ verifyNoMoreInteractions (writer );
277
+ keptPreviousGeneration = true ;
260
278
}
261
279
if (action instanceof IncrementalClusterStateWriter .WriteNewIndexMetaData ) {
262
280
assertThat (action .getIndex (), equalTo (newIndex .getIndex ()));
263
281
IncrementalClusterStateWriter .AtomicClusterStateWriter writer
264
282
= mock (IncrementalClusterStateWriter .AtomicClusterStateWriter .class );
265
283
when (writer .writeIndex ("freshly created" , newIndex )).thenReturn (0L );
266
284
assertThat (action .execute (writer ), equalTo (0L ));
285
+ verify (writer , times (1 )).incrementIndicesWritten ();
286
+ wroteNewIndex = true ;
267
287
}
268
288
if (action instanceof IncrementalClusterStateWriter .WriteChangedIndexMetaData ) {
269
289
assertThat (action .getIndex (), equalTo (newVersionChangedIndex .getIndex ()));
@@ -273,10 +293,16 @@ public void testResolveStatesToBeWritten() throws WriteStateException {
273
293
assertThat (action .execute (writer ), equalTo (3L ));
274
294
ArgumentCaptor <String > reason = ArgumentCaptor .forClass (String .class );
275
295
verify (writer ).writeIndex (reason .capture (), eq (newVersionChangedIndex ));
296
+ verify (writer , times (1 )).incrementIndicesWritten ();
276
297
assertThat (reason .getValue (), containsString (Long .toString (versionChangedIndex .getVersion ())));
277
298
assertThat (reason .getValue (), containsString (Long .toString (newVersionChangedIndex .getVersion ())));
299
+ wroteChangedIndex = true ;
278
300
}
279
301
}
302
+
303
+ assertTrue (keptPreviousGeneration );
304
+ assertTrue (wroteNewIndex );
305
+ assertTrue (wroteChangedIndex );
280
306
}
281
307
282
308
private static class MetaStateServiceWithFailures extends MetaStateService {
@@ -426,4 +452,84 @@ public void testAtomicityWithFailures() throws IOException {
426
452
assertTrue (possibleMetaData .stream ().anyMatch (md -> metaDataEquals (md , loadedMetaData )));
427
453
}
428
454
}
455
+
456
+ @ TestLogging (value = "org.elasticsearch.gateway:WARN" , reason = "to ensure that we log gateway events on WARN level" )
457
+ public void testSlowLogging () throws WriteStateException , IllegalAccessException {
458
+ final long slowWriteLoggingThresholdMillis ;
459
+ final Settings settings ;
460
+ if (randomBoolean ()) {
461
+ slowWriteLoggingThresholdMillis = IncrementalClusterStateWriter .SLOW_WRITE_LOGGING_THRESHOLD .get (Settings .EMPTY ).millis ();
462
+ settings = Settings .EMPTY ;
463
+ } else {
464
+ slowWriteLoggingThresholdMillis = randomLongBetween (2 , 100000 );
465
+ settings = Settings .builder ()
466
+ .put (IncrementalClusterStateWriter .SLOW_WRITE_LOGGING_THRESHOLD .getKey (), slowWriteLoggingThresholdMillis + "ms" )
467
+ .build ();
468
+ }
469
+
470
+ final DiscoveryNode localNode = newNode ("node" );
471
+ final ClusterState clusterState = ClusterState .builder (ClusterName .DEFAULT )
472
+ .nodes (DiscoveryNodes .builder ().add (localNode ).localNodeId (localNode .getId ())).build ();
473
+
474
+ final long startTimeMillis = randomLongBetween (0L , Long .MAX_VALUE - slowWriteLoggingThresholdMillis * 10 );
475
+ final AtomicLong currentTime = new AtomicLong (startTimeMillis );
476
+ final AtomicLong writeDurationMillis = new AtomicLong (slowWriteLoggingThresholdMillis );
477
+
478
+ final ClusterSettings clusterSettings = new ClusterSettings (settings , ClusterSettings .BUILT_IN_CLUSTER_SETTINGS );
479
+ final IncrementalClusterStateWriter incrementalClusterStateWriter
480
+ = new IncrementalClusterStateWriter (settings , clusterSettings , mock (MetaStateService .class ),
481
+ new Manifest (randomNonNegativeLong (), randomNonNegativeLong (), randomNonNegativeLong (), Collections .emptyMap ()),
482
+ clusterState , () -> currentTime .getAndAdd (writeDurationMillis .get ()));
483
+
484
+ assertExpectedLogs (clusterState , incrementalClusterStateWriter , new MockLogAppender .SeenEventExpectation (
485
+ "should see warning at threshold" ,
486
+ IncrementalClusterStateWriter .class .getCanonicalName (),
487
+ Level .WARN ,
488
+ "writing cluster state took [*] which is above the warn threshold of [*]; " +
489
+ "wrote metadata for [0] indices and skipped [0] unchanged indices" ));
490
+
491
+ writeDurationMillis .set (randomLongBetween (slowWriteLoggingThresholdMillis , slowWriteLoggingThresholdMillis * 2 ));
492
+ assertExpectedLogs (clusterState , incrementalClusterStateWriter , new MockLogAppender .SeenEventExpectation (
493
+ "should see warning above threshold" ,
494
+ IncrementalClusterStateWriter .class .getCanonicalName (),
495
+ Level .WARN ,
496
+ "writing cluster state took [*] which is above the warn threshold of [*]; " +
497
+ "wrote metadata for [0] indices and skipped [0] unchanged indices" ));
498
+
499
+ writeDurationMillis .set (randomLongBetween (1 , slowWriteLoggingThresholdMillis - 1 ));
500
+ assertExpectedLogs (clusterState , incrementalClusterStateWriter , new MockLogAppender .UnseenEventExpectation (
501
+ "should not see warning below threshold" ,
502
+ IncrementalClusterStateWriter .class .getCanonicalName (),
503
+ Level .WARN ,
504
+ "*" ));
505
+
506
+ clusterSettings .applySettings (Settings .builder ()
507
+ .put (IncrementalClusterStateWriter .SLOW_WRITE_LOGGING_THRESHOLD .getKey (), writeDurationMillis .get () + "ms" )
508
+ .build ());
509
+ assertExpectedLogs (clusterState , incrementalClusterStateWriter , new MockLogAppender .SeenEventExpectation (
510
+ "should see warning at reduced threshold" ,
511
+ IncrementalClusterStateWriter .class .getCanonicalName (),
512
+ Level .WARN ,
513
+ "writing cluster state took [*] which is above the warn threshold of [*]; " +
514
+ "wrote metadata for [0] indices and skipped [0] unchanged indices" ));
515
+
516
+ assertThat (currentTime .get (), lessThan (startTimeMillis + 10 * slowWriteLoggingThresholdMillis )); // ensure no overflow
517
+ }
518
+
519
+ private void assertExpectedLogs (ClusterState clusterState , IncrementalClusterStateWriter incrementalClusterStateWriter ,
520
+ MockLogAppender .LoggingExpectation expectation ) throws IllegalAccessException , WriteStateException {
521
+ MockLogAppender mockAppender = new MockLogAppender ();
522
+ mockAppender .start ();
523
+ mockAppender .addExpectation (expectation );
524
+ Logger classLogger = LogManager .getLogger (IncrementalClusterStateWriter .class );
525
+ Loggers .addAppender (classLogger , mockAppender );
526
+
527
+ try {
528
+ incrementalClusterStateWriter .updateClusterState (clusterState , clusterState );
529
+ } finally {
530
+ Loggers .removeAppender (classLogger , mockAppender );
531
+ mockAppender .stop ();
532
+ }
533
+ mockAppender .assertAllExpectationsMatched ();
534
+ }
429
535
}
0 commit comments