From 0eb1a816c8ad5ba8c630d8af783210fb79b7901b Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Thu, 7 Apr 2016 15:46:32 +0200 Subject: [PATCH] Allow the query cache to be disabled. #16268 This replaces the internal `index.queries.cache.type` setting with a new `index.queries.cache.enabled` setting, which is documented. Closes #15802 --- .../common/settings/IndexScopedSettings.java | 2 +- .../org/elasticsearch/index/IndexModule.java | 61 ++++++++----------- ...ueryCache.java => DisabledQueryCache.java} | 7 +-- .../query/{index => }/IndexQueryCache.java | 2 +- .../elasticsearch/index/IndexModuleTests.java | 57 ++++------------- .../indices/stats/IndexStatsIT.java | 2 +- .../search/child/ChildQuerySearchIT.java | 2 +- .../modules/indices/query_cache.asciidoc | 7 +++ .../messy/tests/ScriptQuerySearchTests.java | 2 +- .../elasticsearch/test/ESIntegTestCase.java | 2 +- 10 files changed, 52 insertions(+), 92 deletions(-) rename core/src/main/java/org/elasticsearch/index/cache/query/{none/NoneQueryCache.java => DisabledQueryCache.java} (85%) rename core/src/main/java/org/elasticsearch/index/cache/query/{index => }/IndexQueryCache.java (97%) diff --git a/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java b/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java index a7edab721ef..5f83a1ae954 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/IndexScopedSettings.java @@ -132,7 +132,7 @@ public final class IndexScopedSettings extends AbstractScopedSettings { MapperService.INDEX_MAPPING_DEPTH_LIMIT_SETTING, BitsetFilterCache.INDEX_LOAD_RANDOM_ACCESS_FILTERS_EAGERLY_SETTING, IndexModule.INDEX_STORE_TYPE_SETTING, - IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING, + IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING, IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING, PrimaryShardAllocator.INDEX_RECOVERY_INITIAL_SHARDS_SETTING, FsDirectoryService.INDEX_LOCK_FACTOR_SETTING, diff --git a/core/src/main/java/org/elasticsearch/index/IndexModule.java b/core/src/main/java/org/elasticsearch/index/IndexModule.java index 24f075e98f5..6ceabd1146d 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexModule.java +++ b/core/src/main/java/org/elasticsearch/index/IndexModule.java @@ -27,8 +27,8 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.index.analysis.AnalysisRegistry; import org.elasticsearch.index.cache.query.QueryCache; -import org.elasticsearch.index.cache.query.index.IndexQueryCache; -import org.elasticsearch.index.cache.query.none.NoneQueryCache; +import org.elasticsearch.index.cache.query.IndexQueryCache; +import org.elasticsearch.index.cache.query.DisabledQueryCache; import org.elasticsearch.index.engine.EngineFactory; import org.elasticsearch.index.shard.IndexEventListener; import org.elasticsearch.index.shard.IndexSearcherWrapper; @@ -75,14 +75,15 @@ public final class IndexModule { public static final Setting INDEX_STORE_TYPE_SETTING = new Setting<>("index.store.type", "", Function.identity(), Property.IndexScope, Property.NodeScope); public static final String SIMILARITY_SETTINGS_PREFIX = "index.similarity"; - public static final String INDEX_QUERY_CACHE = "index"; - public static final String NONE_QUERY_CACHE = "none"; - public static final Setting INDEX_QUERY_CACHE_TYPE_SETTING = - new Setting<>("index.queries.cache.type", INDEX_QUERY_CACHE, Function.identity(), Property.IndexScope); + + // whether to use the query cache + public static final Setting INDEX_QUERY_CACHE_ENABLED_SETTING = + Setting.boolSetting("index.queries.cache.enabled", true, Property.IndexScope); // for test purposes only public static final Setting INDEX_QUERY_CACHE_EVERYTHING_SETTING = Setting.boolSetting("index.queries.cache.everything", false, Property.IndexScope); + private final IndexSettings indexSettings; private final IndexStoreConfig indexStoreConfig; private final AnalysisRegistry analysisRegistry; @@ -92,8 +93,7 @@ public final class IndexModule { private final Set indexEventListeners = new HashSet<>(); private final Map> similarities = new HashMap<>(); private final Map> storeTypes = new HashMap<>(); - private final Map> queryCaches = new HashMap<>(); - private final SetOnce forceQueryCacheType = new SetOnce<>(); + private final SetOnce> forceQueryCacheProvider = new SetOnce<>(); private final List searchOperationListeners = new ArrayList<>(); private final List indexOperationListeners = new ArrayList<>(); private final AtomicBoolean frozen = new AtomicBoolean(false); @@ -102,8 +102,6 @@ public final class IndexModule { this.indexStoreConfig = indexStoreConfig; this.indexSettings = indexSettings; this.analysisRegistry = analysisRegistry; - registerQueryCache(INDEX_QUERY_CACHE, IndexQueryCache::new); - registerQueryCache(NONE_QUERY_CACHE, (a, b) -> new NoneQueryCache(a)); this.searchOperationListeners.add(new SearchSlowLog(indexSettings)); this.indexOperationListeners.add(new IndexingSlowLog(indexSettings)); } @@ -235,22 +233,6 @@ public final class IndexModule { similarities.put(name, similarity); } - /** - * Registers a {@link QueryCache} provider for a given name - * @param name the providers / caches name - * @param provider the provider instance - */ - public void registerQueryCache(String name, BiFunction provider) { - ensureNotFrozen(); - if (provider == null) { - throw new IllegalArgumentException("provider must not be null"); - } - if (queryCaches.containsKey(name)) { - throw new IllegalArgumentException("Can't register the same [query_cache] more than once for [" + name + "]"); - } - queryCaches.put(name, provider); - } - /** * Sets a {@link org.elasticsearch.index.IndexModule.IndexSearcherWrapperFactory} that is called once the IndexService * is fully constructed. @@ -331,26 +313,33 @@ public final class IndexModule { indexSettings.getScopedSettings().addSettingsUpdateConsumer(IndexStore.INDEX_STORE_THROTTLE_TYPE_SETTING, store::setType); indexSettings.getScopedSettings().addSettingsUpdateConsumer(IndexStore.INDEX_STORE_THROTTLE_MAX_BYTES_PER_SEC_SETTING, store::setMaxRate); - final String queryCacheType = forceQueryCacheType.get() != null - ? forceQueryCacheType.get() : indexSettings.getValue(INDEX_QUERY_CACHE_TYPE_SETTING); - final BiFunction queryCacheProvider = queryCaches.get(queryCacheType); - final QueryCache queryCache = queryCacheProvider.apply(indexSettings, indicesQueryCache); + final QueryCache queryCache; + if (indexSettings.getValue(INDEX_QUERY_CACHE_ENABLED_SETTING)) { + BiFunction queryCacheProvider = forceQueryCacheProvider.get(); + if (queryCacheProvider == null) { + queryCache = new IndexQueryCache(indexSettings, indicesQueryCache); + } else { + queryCache = queryCacheProvider.apply(indexSettings, indicesQueryCache); + } + } else { + queryCache = new DisabledQueryCache(indexSettings); + } return new IndexService(indexSettings, environment, new SimilarityService(indexSettings, similarities), shardStoreDeleter, analysisRegistry, engineFactory.get(), servicesProvider, queryCache, store, eventListener, searcherWrapperFactory, mapperRegistry, indicesFieldDataCache, searchOperationListeners, indexOperationListeners); } /** - * Forces a certain query cache type. If this is set - * the given cache type is overriding the default as well as the type - * set on the index level. + * Forces a certain query cache to use instead of the default one. If this is set + * and query caching is not disabled with {@code index.queries.cache.enabled}, then + * the given provider will be used. * NOTE: this can only be set once * - * @see #INDEX_QUERY_CACHE_TYPE_SETTING + * @see #INDEX_QUERY_CACHE_ENABLED_SETTING */ - public void forceQueryCacheType(String type) { + public void forceQueryCacheProvider(BiFunction queryCacheProvider) { ensureNotFrozen(); - this.forceQueryCacheType.set(type); + this.forceQueryCacheProvider.set(queryCacheProvider); } private void ensureNotFrozen() { diff --git a/core/src/main/java/org/elasticsearch/index/cache/query/none/NoneQueryCache.java b/core/src/main/java/org/elasticsearch/index/cache/query/DisabledQueryCache.java similarity index 85% rename from core/src/main/java/org/elasticsearch/index/cache/query/none/NoneQueryCache.java rename to core/src/main/java/org/elasticsearch/index/cache/query/DisabledQueryCache.java index 70cbfeb3830..730dc63b939 100644 --- a/core/src/main/java/org/elasticsearch/index/cache/query/none/NoneQueryCache.java +++ b/core/src/main/java/org/elasticsearch/index/cache/query/DisabledQueryCache.java @@ -17,11 +17,10 @@ * under the License. */ -package org.elasticsearch.index.cache.query.none; +package org.elasticsearch.index.cache.query; import org.apache.lucene.search.QueryCachingPolicy; import org.apache.lucene.search.Weight; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.index.AbstractIndexComponent; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.cache.query.QueryCache; @@ -29,9 +28,9 @@ import org.elasticsearch.index.cache.query.QueryCache; /** * */ -public class NoneQueryCache extends AbstractIndexComponent implements QueryCache { +public class DisabledQueryCache extends AbstractIndexComponent implements QueryCache { - public NoneQueryCache(IndexSettings indexSettings) { + public DisabledQueryCache(IndexSettings indexSettings) { super(indexSettings); logger.debug("Using no query cache"); } diff --git a/core/src/main/java/org/elasticsearch/index/cache/query/index/IndexQueryCache.java b/core/src/main/java/org/elasticsearch/index/cache/query/IndexQueryCache.java similarity index 97% rename from core/src/main/java/org/elasticsearch/index/cache/query/index/IndexQueryCache.java rename to core/src/main/java/org/elasticsearch/index/cache/query/IndexQueryCache.java index 96b2ede2a99..77a32a6789a 100644 --- a/core/src/main/java/org/elasticsearch/index/cache/query/index/IndexQueryCache.java +++ b/core/src/main/java/org/elasticsearch/index/cache/query/IndexQueryCache.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.index.cache.query.index; +package org.elasticsearch.index.cache.query; import org.apache.lucene.search.QueryCachingPolicy; import org.apache.lucene.search.Weight; diff --git a/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java b/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java index 303d36cf084..c0225a9aaae 100644 --- a/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java +++ b/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.TermStatistics; import org.apache.lucene.search.Weight; import org.apache.lucene.search.similarities.BM25Similarity; import org.apache.lucene.search.similarities.Similarity; +import org.apache.lucene.util.SetOnce.AlreadySetException; import org.elasticsearch.Version; import org.elasticsearch.cache.recycler.PageCacheRecycler; import org.elasticsearch.client.Client; @@ -43,8 +44,8 @@ import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.env.ShardLock; import org.elasticsearch.index.analysis.AnalysisRegistry; import org.elasticsearch.index.cache.query.QueryCache; -import org.elasticsearch.index.cache.query.index.IndexQueryCache; -import org.elasticsearch.index.cache.query.none.NoneQueryCache; +import org.elasticsearch.index.cache.query.IndexQueryCache; +import org.elasticsearch.index.cache.query.DisabledQueryCache; import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.EngineException; import org.elasticsearch.index.fielddata.IndexFieldDataCache; @@ -320,9 +321,8 @@ public class IndexModuleTests extends ESTestCase { assertEquals(msg, expectThrows(IllegalStateException.class, () -> module.addIndexOperationListener(null)).getMessage()); assertEquals(msg, expectThrows(IllegalStateException.class, () -> module.addSimilarity(null, null)).getMessage()); assertEquals(msg, expectThrows(IllegalStateException.class, () -> module.setSearcherWrapper(null)).getMessage()); - assertEquals(msg, expectThrows(IllegalStateException.class, () -> module.forceQueryCacheType("foo")).getMessage()); + assertEquals(msg, expectThrows(IllegalStateException.class, () -> module.forceQueryCacheProvider(null)).getMessage()); assertEquals(msg, expectThrows(IllegalStateException.class, () -> module.addIndexStore("foo", null)).getMessage()); - assertEquals(msg, expectThrows(IllegalStateException.class, () -> module.registerQueryCache("foo", null)).getMessage()); } public void testSetupUnknownSimilarity() throws IOException { @@ -355,47 +355,13 @@ public class IndexModuleTests extends ESTestCase { } } - public void testCannotRegisterProvidedImplementations() { + public void testForceCustomQueryCache() throws IOException { Settings indexSettings = Settings.builder() .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString()) .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); IndexModule module = new IndexModule(IndexSettingsModule.newIndexSettings("foo", indexSettings), null, new AnalysisRegistry(null, environment)); - try { - module.registerQueryCache("index", IndexQueryCache::new); - fail("only once"); - } catch (IllegalArgumentException e) { - assertEquals(e.getMessage(), "Can't register the same [query_cache] more than once for [index]"); - } - - try { - module.registerQueryCache("none", (settings, x) -> new NoneQueryCache(settings)); - fail("only once"); - } catch (IllegalArgumentException e) { - assertEquals(e.getMessage(), "Can't register the same [query_cache] more than once for [none]"); - } - - try { - module.registerQueryCache("index", null); - fail("must not be null"); - } catch (IllegalArgumentException e) { - assertEquals(e.getMessage(), "provider must not be null"); - } - } - - public void testRegisterCustomQueryCache() throws IOException { - Settings indexSettings = Settings.builder() - .put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), "custom") - .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString()) - .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); - IndexModule module = new IndexModule(IndexSettingsModule.newIndexSettings("foo", indexSettings), null, new AnalysisRegistry(null, environment)); - module.registerQueryCache("custom", (a, b) -> new CustomQueryCache()); - try { - module.registerQueryCache("custom", (a, b) -> new CustomQueryCache()); - fail("only once"); - } catch (IllegalArgumentException e) { - assertEquals(e.getMessage(), "Can't register the same [query_cache] more than once for [custom]"); - } - + module.forceQueryCacheProvider((a, b) -> new CustomQueryCache()); + expectThrows(AlreadySetException.class, () -> module.forceQueryCacheProvider((a, b) -> new CustomQueryCache())); IndexService indexService = module.newIndexService(nodeEnvironment, deleter, nodeServicesProvider, indicesQueryCache, mapperRegistry, new IndicesFieldDataCache(settings, listener)); assertTrue(indexService.cache().query() instanceof CustomQueryCache); @@ -413,17 +379,16 @@ public class IndexModuleTests extends ESTestCase { indexService.close("simon says", false); } - public void testForceCacheType() throws IOException { + public void testDisableQueryCacheHasPrecedenceOverForceQueryCache() throws IOException { Settings indexSettings = Settings.builder() - .put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), "none") + .put(IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING.getKey(), false) .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString()) .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); IndexModule module = new IndexModule(IndexSettingsModule.newIndexSettings("foo", indexSettings), null, new AnalysisRegistry(null, environment)); - module.forceQueryCacheType("custom"); - module.registerQueryCache("custom", (a, b) -> new CustomQueryCache()); + module.forceQueryCacheProvider((a, b) -> new CustomQueryCache()); IndexService indexService = module.newIndexService(nodeEnvironment, deleter, nodeServicesProvider, indicesQueryCache, mapperRegistry, new IndicesFieldDataCache(settings, listener)); - assertTrue(indexService.cache().query() instanceof CustomQueryCache); + assertTrue(indexService.cache().query() instanceof DisabledQueryCache); indexService.close("simon says", false); } diff --git a/core/src/test/java/org/elasticsearch/indices/stats/IndexStatsIT.java b/core/src/test/java/org/elasticsearch/indices/stats/IndexStatsIT.java index e29bfd33a47..b1513908874 100644 --- a/core/src/test/java/org/elasticsearch/indices/stats/IndexStatsIT.java +++ b/core/src/test/java/org/elasticsearch/indices/stats/IndexStatsIT.java @@ -85,7 +85,7 @@ public class IndexStatsIT extends ESIntegTestCase { public Settings indexSettings() { return Settings.builder().put(super.indexSettings()) .put(IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING.getKey(), true) - .put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), IndexModule.INDEX_QUERY_CACHE) + .put(IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING.getKey(), true) .build(); } diff --git a/core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java b/core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java index 503a346aa0e..d308c17ce54 100644 --- a/core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java @@ -97,7 +97,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase { public Settings indexSettings() { return Settings.builder().put(super.indexSettings()) // aggressive filter caching so that we can assert on the filter cache size - .put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), IndexModule.INDEX_QUERY_CACHE) + .put(IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING.getKey(), true) .put(IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING.getKey(), true) .build(); } diff --git a/docs/reference/modules/indices/query_cache.asciidoc b/docs/reference/modules/indices/query_cache.asciidoc index 47506650b21..f6cdf71925a 100644 --- a/docs/reference/modules/indices/query_cache.asciidoc +++ b/docs/reference/modules/indices/query_cache.asciidoc @@ -16,3 +16,10 @@ the cluster: Controls the memory size for the filter cache , defaults to `10%`. Accepts either a percentage value, like `5%`, or an exact value, like `512mb`. +The following setting is an _index_ setting that can be configured on a +per-index basis: + +`index.queries.cache.enabled`:: + + Controls whether to enable query caching. Accepts `true` (default) or + `false`. diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/ScriptQuerySearchTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/ScriptQuerySearchTests.java index bd9f8c3e7ff..e1620c8f619 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/ScriptQuerySearchTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/ScriptQuerySearchTests.java @@ -53,7 +53,7 @@ public class ScriptQuerySearchTests extends ESIntegTestCase { public Settings indexSettings() { return Settings.builder().put(super.indexSettings()) // aggressive filter caching so that we can assert on the number of iterations of the script filters - .put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), IndexModule.INDEX_QUERY_CACHE) + .put(IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING.getKey(), true) .put(IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING.getKey(), true) .build(); } diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java index 06288d6cdc8..5a7fcbec290 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java @@ -399,7 +399,7 @@ public abstract class ESIntegTestCase extends ESTestCase { // always default delayed allocation to 0 to make sure we have tests are not delayed randomSettingsBuilder.put(UnassignedInfo.INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING.getKey(), 0); if (randomBoolean()) { - randomSettingsBuilder.put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), randomBoolean() ? IndexModule.INDEX_QUERY_CACHE : IndexModule.NONE_QUERY_CACHE); + randomSettingsBuilder.put(IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING.getKey(), randomBoolean()); } if (randomBoolean()) {