Browse Source

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
Adrien Grand 9 years ago
parent
commit
0eb1a816c8

+ 1 - 1
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,

+ 25 - 36
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<String> 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<String> 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<Boolean> INDEX_QUERY_CACHE_ENABLED_SETTING =
+            Setting.boolSetting("index.queries.cache.enabled", true, Property.IndexScope);
 
     // for test purposes only
     public static final Setting<Boolean> 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<IndexEventListener> indexEventListeners = new HashSet<>();
     private final Map<String, BiFunction<String, Settings, SimilarityProvider>> similarities = new HashMap<>();
     private final Map<String, BiFunction<IndexSettings, IndexStoreConfig, IndexStore>> storeTypes = new HashMap<>();
-    private final Map<String, BiFunction<IndexSettings, IndicesQueryCache, QueryCache>> queryCaches = new HashMap<>();
-    private final SetOnce<String> forceQueryCacheType = new SetOnce<>();
+    private final SetOnce<BiFunction<IndexSettings, IndicesQueryCache, QueryCache>> forceQueryCacheProvider = new SetOnce<>();
     private final List<SearchOperationListener> searchOperationListeners = new ArrayList<>();
     private final List<IndexingOperationListener> 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<IndexSettings, IndicesQueryCache, QueryCache> 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<IndexSettings, IndicesQueryCache, QueryCache> queryCacheProvider = queryCaches.get(queryCacheType);
-        final QueryCache queryCache = queryCacheProvider.apply(indexSettings, indicesQueryCache);
+        final QueryCache queryCache;
+        if (indexSettings.getValue(INDEX_QUERY_CACHE_ENABLED_SETTING)) {
+            BiFunction<IndexSettings, IndicesQueryCache, QueryCache> 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<IndexSettings, IndicesQueryCache, QueryCache> queryCacheProvider) {
         ensureNotFrozen();
-        this.forceQueryCacheType.set(type);
+        this.forceQueryCacheProvider.set(queryCacheProvider);
     }
 
     private void ensureNotFrozen() {

+ 3 - 4
core/src/main/java/org/elasticsearch/index/cache/query/none/NoneQueryCache.java → 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");
     }

+ 1 - 1
core/src/main/java/org/elasticsearch/index/cache/query/index/IndexQueryCache.java → 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;

+ 11 - 46
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);
     }
 

+ 1 - 1
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();
     }
 

+ 1 - 1
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();
     }

+ 7 - 0
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`.

+ 1 - 1
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();
     }

+ 1 - 1
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()) {