1818 */
1919package org .elasticsearch .index ;
2020
21+ import org .apache .lucene .analysis .Analyzer ;
2122import org .apache .lucene .index .AssertingDirectoryReader ;
2223import org .apache .lucene .index .DirectoryReader ;
2324import org .apache .lucene .index .FieldInvertState ;
4041import org .elasticsearch .common .settings .Settings ;
4142import org .elasticsearch .common .util .BigArrays ;
4243import org .elasticsearch .common .util .PageCacheRecycler ;
44+ import org .elasticsearch .common .util .concurrent .EsRejectedExecutionException ;
4345import org .elasticsearch .core .internal .io .IOUtils ;
4446import org .elasticsearch .env .Environment ;
4547import org .elasticsearch .env .NodeEnvironment ;
4648import org .elasticsearch .env .ShardLock ;
4749import org .elasticsearch .env .TestEnvironment ;
4850import org .elasticsearch .index .analysis .AnalysisRegistry ;
51+ import org .elasticsearch .index .analysis .AnalyzerProvider ;
52+ import org .elasticsearch .index .analysis .AnalyzerScope ;
4953import org .elasticsearch .index .cache .query .DisabledQueryCache ;
5054import org .elasticsearch .index .cache .query .IndexQueryCache ;
5155import org .elasticsearch .index .cache .query .QueryCache ;
6569import org .elasticsearch .index .store .FsDirectoryFactory ;
6670import org .elasticsearch .indices .IndicesModule ;
6771import org .elasticsearch .indices .IndicesQueryCache ;
72+ import org .elasticsearch .indices .analysis .AnalysisModule ;
6873import org .elasticsearch .indices .breaker .CircuitBreakerService ;
6974import org .elasticsearch .indices .breaker .NoneCircuitBreakerService ;
7075import org .elasticsearch .indices .cluster .IndicesClusterStateService .AllocatedIndices .IndexRemovalReason ;
8489
8590import java .io .IOException ;
8691import java .util .Collections ;
92+ import java .util .HashSet ;
8793import java .util .Map ;
94+ import java .util .Set ;
8895import java .util .concurrent .TimeUnit ;
8996import java .util .concurrent .atomic .AtomicBoolean ;
9097
9198import static java .util .Collections .emptyMap ;
99+ import static java .util .Collections .singletonMap ;
92100import static org .elasticsearch .index .IndexService .IndexCreationContext .CREATE_INDEX ;
93101import static org .hamcrest .Matchers .containsString ;
102+ import static org .hamcrest .Matchers .empty ;
94103import static org .hamcrest .Matchers .hasToString ;
95104import static org .hamcrest .Matchers .instanceOf ;
96105
@@ -174,7 +183,7 @@ public void testRegisterIndexStore() throws IOException {
174183 .put (IndexModule .INDEX_STORE_TYPE_SETTING .getKey (), "foo_store" )
175184 .build ();
176185 final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings (index , settings );
177- final Map <String , IndexStorePlugin .DirectoryFactory > indexStoreFactories = Collections . singletonMap (
186+ final Map <String , IndexStorePlugin .DirectoryFactory > indexStoreFactories = singletonMap (
178187 "foo_store" , new FooFunction ());
179188 final IndexModule module = new IndexModule (indexSettings , emptyAnalysisRegistry , new InternalEngineFactory (), indexStoreFactories );
180189
@@ -354,11 +363,19 @@ public void testForceCustomQueryCache() throws IOException {
354363 .put (IndexMetaData .SETTING_VERSION_CREATED , Version .CURRENT ).build ();
355364 final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings ("foo" , settings );
356365 IndexModule module = new IndexModule (indexSettings , emptyAnalysisRegistry , new InternalEngineFactory (), Collections .emptyMap ());
357- module .forceQueryCacheProvider ((a , b ) -> new CustomQueryCache ());
358- expectThrows (AlreadySetException .class , () -> module .forceQueryCacheProvider ((a , b ) -> new CustomQueryCache ()));
366+ final Set <CustomQueryCache > liveQueryCaches = new HashSet <>();
367+ module .forceQueryCacheProvider ((a , b ) -> {
368+ final CustomQueryCache customQueryCache = new CustomQueryCache (liveQueryCaches );
369+ liveQueryCaches .add (customQueryCache );
370+ return customQueryCache ;
371+ });
372+ expectThrows (AlreadySetException .class , () -> module .forceQueryCacheProvider ((a , b ) -> {
373+ throw new AssertionError ("never called" );
374+ }));
359375 IndexService indexService = newIndexService (module );
360376 assertTrue (indexService .cache ().query () instanceof CustomQueryCache );
361377 indexService .close ("simon says" , false );
378+ assertThat (liveQueryCaches , empty ());
362379 }
363380
364381 public void testDefaultQueryCacheImplIsSelected () throws IOException {
@@ -379,12 +396,73 @@ public void testDisableQueryCacheHasPrecedenceOverForceQueryCache() throws IOExc
379396 .put (IndexMetaData .SETTING_VERSION_CREATED , Version .CURRENT ).build ();
380397 final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings ("foo" , settings );
381398 IndexModule module = new IndexModule (indexSettings , emptyAnalysisRegistry , new InternalEngineFactory (), Collections .emptyMap ());
382- module .forceQueryCacheProvider ((a , b ) -> new CustomQueryCache ());
399+ module .forceQueryCacheProvider ((a , b ) -> new CustomQueryCache (null ));
383400 IndexService indexService = newIndexService (module );
384401 assertTrue (indexService .cache ().query () instanceof DisabledQueryCache );
385402 indexService .close ("simon says" , false );
386403 }
387404
405+ public void testCustomQueryCacheCleanedUpIfIndexServiceCreationFails () {
406+ Settings settings = Settings .builder ()
407+ .put (Environment .PATH_HOME_SETTING .getKey (), createTempDir ().toString ())
408+ .put (IndexMetaData .SETTING_VERSION_CREATED , Version .CURRENT ).build ();
409+ final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings ("foo" , settings );
410+ IndexModule module = new IndexModule (indexSettings , emptyAnalysisRegistry , new InternalEngineFactory (), Collections .emptyMap ());
411+ final Set <CustomQueryCache > liveQueryCaches = new HashSet <>();
412+ module .forceQueryCacheProvider ((a , b ) -> {
413+ final CustomQueryCache customQueryCache = new CustomQueryCache (liveQueryCaches );
414+ liveQueryCaches .add (customQueryCache );
415+ return customQueryCache ;
416+ });
417+ threadPool .shutdown (); // causes index service creation to fail
418+ expectThrows (EsRejectedExecutionException .class , () -> newIndexService (module ));
419+ assertThat (liveQueryCaches , empty ());
420+ }
421+
422+ public void testIndexAnalyzersCleanedUpIfIndexServiceCreationFails () {
423+ Settings settings = Settings .builder ()
424+ .put (Environment .PATH_HOME_SETTING .getKey (), createTempDir ().toString ())
425+ .put (IndexMetaData .SETTING_VERSION_CREATED , Version .CURRENT ).build ();
426+ final IndexSettings indexSettings = IndexSettingsModule .newIndexSettings ("foo" , settings );
427+
428+ final HashSet <Analyzer > openAnalyzers = new HashSet <>();
429+ final AnalysisModule .AnalysisProvider <AnalyzerProvider <?>> analysisProvider = (i ,e ,n ,s ) -> new AnalyzerProvider <>() {
430+ @ Override
431+ public String name () {
432+ return "test" ;
433+ }
434+
435+ @ Override
436+ public AnalyzerScope scope () {
437+ return AnalyzerScope .INDEX ;
438+ }
439+
440+ @ Override
441+ public Analyzer get () {
442+ final Analyzer analyzer = new Analyzer () {
443+ @ Override
444+ protected TokenStreamComponents createComponents (String fieldName ) {
445+ throw new AssertionError ("should not be here" );
446+ }
447+
448+ @ Override
449+ public void close () {
450+ super .close ();
451+ openAnalyzers .remove (this );
452+ }
453+ };
454+ openAnalyzers .add (analyzer );
455+ return analyzer ;
456+ }
457+ };
458+ final AnalysisRegistry analysisRegistry = new AnalysisRegistry (environment , emptyMap (), emptyMap (), emptyMap (),
459+ singletonMap ("test" , analysisProvider ), emptyMap (), emptyMap (), emptyMap (), emptyMap (), emptyMap ());
460+ IndexModule module = new IndexModule (indexSettings , analysisRegistry , new InternalEngineFactory (), Collections .emptyMap ());
461+ threadPool .shutdown (); // causes index service creation to fail
462+ expectThrows (EsRejectedExecutionException .class , () -> newIndexService (module ));
463+ assertThat (openAnalyzers , empty ());
464+ }
465+
388466 public void testMmapNotAllowed () {
389467 String storeType = randomFrom (IndexModule .Type .HYBRIDFS .getSettingsKey (), IndexModule .Type .MMAPFS .getSettingsKey ());
390468 final Settings settings = Settings .builder ()
@@ -403,12 +481,19 @@ public void testMmapNotAllowed() {
403481
404482 class CustomQueryCache implements QueryCache {
405483
484+ private final Set <CustomQueryCache > liveQueryCaches ;
485+
486+ CustomQueryCache (Set <CustomQueryCache > liveQueryCaches ) {
487+ this .liveQueryCaches = liveQueryCaches ;
488+ }
489+
406490 @ Override
407491 public void clear (String reason ) {
408492 }
409493
410494 @ Override
411- public void close () throws IOException {
495+ public void close () {
496+ assertTrue (liveQueryCaches == null || liveQueryCaches .remove (this ));
412497 }
413498
414499 @ Override
0 commit comments