From c13df3b6c5020c185c232c590132151896d48d03 Mon Sep 17 00:00:00 2001 From: Daniel Mitterdorfer Date: Wed, 18 May 2016 09:18:10 +0200 Subject: [PATCH 01/12] Clear all caches after testing parent breaker With this commit we clear all caches after testing the parent circuit breaker. This is necessary as caches hold on to circuit breakers internally. Additionally, due to usage of CircuitBreaker#addWithoutBreaking() in caches, it's even possible to go above the limit. As a consequence, all subsequent requests fall victim to the limit. Hence, right after the parent circuit breaker tripped, we clear all caches to reduce these circuit breakers to 0 again. We also exclude the clear caches transport request from limit check in order to ensure it will succeed. As this is typically a very small and low-volume request, it is deemed ok to exclude it. Closes #18325 --- .../TransportClearIndicesCacheAction.java | 2 +- .../node/TransportBroadcastByNodeAction.java | 20 +++++++++++++++++-- .../breaker/CircuitBreakerServiceIT.java | 7 +++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/cache/clear/TransportClearIndicesCacheAction.java b/core/src/main/java/org/elasticsearch/action/admin/indices/cache/clear/TransportClearIndicesCacheAction.java index 59cd95044cc..fe97302060d 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/cache/clear/TransportClearIndicesCacheAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/cache/clear/TransportClearIndicesCacheAction.java @@ -54,7 +54,7 @@ public class TransportClearIndicesCacheAction extends TransportBroadcastByNodeAc TransportService transportService, IndicesService indicesService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) { super(settings, ClearIndicesCacheAction.NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver, - ClearIndicesCacheRequest::new, ThreadPool.Names.MANAGEMENT); + ClearIndicesCacheRequest::new, ThreadPool.Names.MANAGEMENT, false); this.indicesService = indicesService; } diff --git a/core/src/main/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeAction.java b/core/src/main/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeAction.java index 29863419a4e..3356d189143 100644 --- a/core/src/main/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeAction.java +++ b/core/src/main/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeAction.java @@ -84,6 +84,20 @@ public abstract class TransportBroadcastByNodeAction request, + String executor) { + this(settings, actionName, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver, request, + executor, true); + } + public TransportBroadcastByNodeAction( Settings settings, String actionName, @@ -93,7 +107,8 @@ public abstract class TransportBroadcastByNodeAction request, - String executor) { + String executor, + boolean canTripCircuitBreaker) { super(settings, actionName, threadPool, transportService, actionFilters, indexNameExpressionResolver, request); this.clusterService = clusterService; @@ -101,7 +116,8 @@ public abstract class TransportBroadcastByNodeAction resetting breaker settings"); + // clear all caches, we could be very close (or even above) the limit and then we will not be able to reset the breaker settings + client().admin().indices().prepareClearCache().setFieldDataCache(true).setQueryCache(true).setRequestCache(true).get(); + Settings resetSettings = Settings.builder() .put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING.getKey(), HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING.getDefaultRaw(null)) @@ -214,7 +217,6 @@ public class CircuitBreakerServiceIT extends ESIntegTestCase { * Test that a breaker correctly redistributes to a different breaker, in * this case, the fielddata breaker borrows space from the request breaker */ - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/18325") public void testParentChecking() throws Exception { if (noopBreakerUsed()) { logger.info("--> noop breakers used, skipping test"); @@ -274,9 +276,6 @@ public class CircuitBreakerServiceIT extends ESIntegTestCase { cause.toString(), startsWith("CircuitBreakingException[[parent] Data too large")); assertThat("Exception: [" + cause.toString() + "] should contain a CircuitBreakingException", cause.toString(), endsWith(errMsg)); - } finally { - // reset before teardown as it requires properly set up breakers - reset(); } } From 947daf68d1efe1406f2a5e7b23834032cd1991fc Mon Sep 17 00:00:00 2001 From: Isabel Drost-Fromm Date: Wed, 18 May 2016 11:54:41 +0200 Subject: [PATCH 02/12] Add CONSOLE to from/size docs Relates to #18160 --- docs/reference/search/request/from-size.asciidoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/reference/search/request/from-size.asciidoc b/docs/reference/search/request/from-size.asciidoc index 2e170dc2604..1c44a7ca8d2 100644 --- a/docs/reference/search/request/from-size.asciidoc +++ b/docs/reference/search/request/from-size.asciidoc @@ -12,6 +12,7 @@ defaults to `10`. [source,js] -------------------------------------------------- +GET /_search { "from" : 0, "size" : 10, "query" : { @@ -19,6 +20,8 @@ defaults to `10`. } } -------------------------------------------------- +// CONSOLE + Note that `from` + `size` can not be more than the `index.max_result_window` index setting which defaults to 10,000. See the <> or <> From 808ef6cec798fb186c8638dcddec3dc25f4e9067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Wed, 18 May 2016 14:25:20 +0200 Subject: [PATCH 03/12] Fix parsing single `rescore` element in SearchSourceBuilder We are currently only parsing the array-syntax for the rescore part in SearchSourceBuilder ("rescore" : [ {...}, {...} ]) . We also need to support "rescore" : {...} Closes #18439 --- .../search/builder/SearchSourceBuilder.java | 3 ++ .../builder/SearchSourceBuilderTests.java | 52 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java b/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java index 61f4acb81aa..429aa36e56f 100644 --- a/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java @@ -1033,6 +1033,9 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ suggestBuilder = SuggestBuilder.fromXContent(context, suggesters); } else if (context.getParseFieldMatcher().match(currentFieldName, SORT_FIELD)) { sorts = new ArrayList<>(SortBuilder.fromXContent(context)); + } else if (context.getParseFieldMatcher().match(currentFieldName, RESCORE_FIELD)) { + rescoreBuilders = new ArrayList<>(); + rescoreBuilders.add(RescoreBuilder.parseFromXContent(context)); } else if (context.getParseFieldMatcher().match(currentFieldName, EXT_FIELD)) { XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().copyCurrentStructure(parser); ext = xContentBuilder.bytes(); diff --git a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java index 9f0113829ce..077d978a4ce 100644 --- a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java @@ -72,6 +72,7 @@ import org.elasticsearch.search.aggregations.AggregatorParsers; import org.elasticsearch.search.fetch.source.FetchSourceContext; import org.elasticsearch.search.highlight.HighlightBuilderTests; import org.elasticsearch.search.rescore.QueryRescoreBuilderTests; +import org.elasticsearch.search.rescore.QueryRescorerBuilder; import org.elasticsearch.search.searchafter.SearchAfterBuilder; import org.elasticsearch.search.sort.FieldSortBuilder; import org.elasticsearch.search.sort.ScoreSortBuilder; @@ -561,6 +562,57 @@ public class SearchSourceBuilderTests extends ESTestCase { } } + /** + * test that we can parse the `rescore` element either as single object or as array + */ + public void testParseRescore() throws IOException { + { + String restContent = "{\n" + + " \"query\" : {\n" + + " \"match\": { \"content\": { \"query\": \"foo bar\" }}\n" + + " },\n" + + " \"rescore\": {" + + " \"window_size\": 50,\n" + + " \"query\": {\n" + + " \"rescore_query\" : {\n" + + " \"match\": { \"content\": { \"query\": \"baz\" } }\n" + + " }\n" + + " }\n" + + " }\n" + + "}\n"; + try (XContentParser parser = XContentFactory.xContent(restContent).createParser(restContent)) { + SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(createParseContext(parser), + aggParsers, suggesters); + assertEquals(1, searchSourceBuilder.rescores().size()); + assertEquals(new QueryRescorerBuilder(QueryBuilders.matchQuery("content", "baz")).windowSize(50), + searchSourceBuilder.rescores().get(0)); + } + } + + { + String restContent = "{\n" + + " \"query\" : {\n" + + " \"match\": { \"content\": { \"query\": \"foo bar\" }}\n" + + " },\n" + + " \"rescore\": [ {" + + " \"window_size\": 50,\n" + + " \"query\": {\n" + + " \"rescore_query\" : {\n" + + " \"match\": { \"content\": { \"query\": \"baz\" } }\n" + + " }\n" + + " }\n" + + " } ]\n" + + "}\n"; + try (XContentParser parser = XContentFactory.xContent(restContent).createParser(restContent)) { + SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(createParseContext(parser), + aggParsers, suggesters); + assertEquals(1, searchSourceBuilder.rescores().size()); + assertEquals(new QueryRescorerBuilder(QueryBuilders.matchQuery("content", "baz")).windowSize(50), + searchSourceBuilder.rescores().get(0)); + } + } + } + public void testEmptyPostFilter() throws IOException { SearchSourceBuilder builder = new SearchSourceBuilder(); builder.postFilter(new EmptyQueryBuilder()); From d7a31c8cf7f411aadc7202a4a2326679ed820e88 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Wed, 18 May 2016 15:19:30 +0200 Subject: [PATCH 04/12] Add missing builder.endObject() in FsInfo closes #18433 --- core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java | 2 ++ .../rest-api-spec/test/nodes.stats/30_discovery.yaml | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java b/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java index caa97ea7387..641dc3a5bb3 100644 --- a/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java +++ b/core/src/main/java/org/elasticsearch/monitor/fs/FsInfo.java @@ -396,12 +396,14 @@ public class FsInfo implements Iterable, Writeable, ToXContent { builder.endObject(); } builder.endArray(); + builder.startObject("total"); builder.field(OPERATIONS, totalOperations); builder.field(READ_OPERATIONS, totalReadOperations); builder.field(WRITE_OPERATIONS, totalWriteOperations); builder.field(READ_KILOBYTES, totalReadKilobytes); builder.field(WRITE_KILOBYTES, totalWriteKilobytes); + builder.endObject(); } return builder; } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/30_discovery.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/30_discovery.yaml index 4769465eb1d..2617f76941c 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/30_discovery.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/nodes.stats/30_discovery.yaml @@ -1,9 +1,5 @@ --- "Discovery stats": - - skip: - version: "5.0.0 - " - reason: Tracked in issue 18433 - - do: cluster.state: {} From cad0608cdb28e2b8485e5c01c26579a35cb84356 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Wed, 18 May 2016 09:31:28 -0400 Subject: [PATCH 05/12] Add GC overhead logging This commit adds simple GC overhead logging. This logging captures intervals where the JVM is spending a lot of time performing GC but it is not necessarily the case that each GC is large. For a start, this logging is simple and does not attempt to incorporate whether or not the collections were efficient (that is, we are only capturing that a lot of GC is happening, not that a lot of useless GC is happening). Relates #18419 --- .../common/settings/ClusterSettings.java | 3 + .../common/settings/Setting.java | 30 ++-- .../monitor/jvm/JvmGcMonitorService.java | 154 +++++++++++++++-- .../common/settings/SettingTests.java | 2 +- .../jvm/JvmGcMonitorServiceSettingsTests.java | 40 +++++ .../monitor/jvm/JvmGcMonitorServiceTests.java | 39 +++++ .../monitor/jvm/JvmMonitorTests.java | 156 ++++++++++++++++-- 7 files changed, 384 insertions(+), 40 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java b/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java index dad5f48ce27..e66534a4feb 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java @@ -397,6 +397,9 @@ public final class ClusterSettings extends AbstractScopedSettings { JvmGcMonitorService.ENABLED_SETTING, JvmGcMonitorService.REFRESH_INTERVAL_SETTING, JvmGcMonitorService.GC_SETTING, + JvmGcMonitorService.GC_OVERHEAD_WARN_SETTING, + JvmGcMonitorService.GC_OVERHEAD_INFO_SETTING, + JvmGcMonitorService.GC_OVERHEAD_DEBUG_SETTING, PageCacheRecycler.LIMIT_HEAP_SETTING, PageCacheRecycler.WEIGHT_BYTES_SETTING, PageCacheRecycler.WEIGHT_INT_SETTING, diff --git a/core/src/main/java/org/elasticsearch/common/settings/Setting.java b/core/src/main/java/org/elasticsearch/common/settings/Setting.java index edd5d511f86..1efb65c18b1 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/Setting.java +++ b/core/src/main/java/org/elasticsearch/common/settings/Setting.java @@ -18,19 +18,6 @@ */ package org.elasticsearch.common.settings; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.action.support.ToXContentToBytes; @@ -50,6 +37,19 @@ import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + /** * A setting. Encapsulates typical stuff like default value, parsing, and scope. * Some (SettingsProperty.Dynamic) can by modified at run time using the API. @@ -504,7 +504,7 @@ public class Setting extends ToXContentToBytes { throw new IllegalArgumentException("Failed to parse value [" + s + "] for setting [" + key + "] must be >= " + minValue); } if (value > maxValue) { - throw new IllegalArgumentException("Failed to parse value [" + s + "] for setting [" + key + "] must be =< " + maxValue); + throw new IllegalArgumentException("Failed to parse value [" + s + "] for setting [" + key + "] must be <= " + maxValue); } return value; } @@ -572,7 +572,7 @@ public class Setting extends ToXContentToBytes { throw new IllegalArgumentException("Failed to parse value [" + s + "] for setting [" + key + "] must be >= " + minValue); } if (value.bytes() > maxValue.bytes()) { - throw new IllegalArgumentException("Failed to parse value [" + s + "] for setting [" + key + "] must be =< " + maxValue); + throw new IllegalArgumentException("Failed to parse value [" + s + "] for setting [" + key + "] must be <= " + maxValue); } return value; } diff --git a/core/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java b/core/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java index 01b4c68537e..ac75eb93aaa 100644 --- a/core/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java +++ b/core/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java @@ -31,6 +31,7 @@ import org.elasticsearch.monitor.jvm.JvmStats.GarbageCollector; import org.elasticsearch.threadpool.ThreadPool; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.ScheduledFuture; @@ -45,6 +46,7 @@ public class JvmGcMonitorService extends AbstractLifecycleComponent gcThresholds; + private final GcOverheadThreshold gcOverheadThreshold; private volatile ScheduledFuture scheduledFuture; @@ -57,6 +59,27 @@ public class JvmGcMonitorService extends AbstractLifecycleComponent GC_SETTING = Setting.groupSetting(GC_COLLECTOR_PREFIX, Property.NodeScope); + public final static Setting GC_OVERHEAD_WARN_SETTING = + Setting.intSetting("monitor.jvm.gc.overhead.warn", 50, 0, 100, Property.NodeScope); + public final static Setting GC_OVERHEAD_INFO_SETTING = + Setting.intSetting("monitor.jvm.gc.overhead.info", 25, 0, 100, Property.NodeScope); + public final static Setting GC_OVERHEAD_DEBUG_SETTING = + Setting.intSetting("monitor.jvm.gc.overhead.debug", 10, 0, 100, Property.NodeScope); + + static class GcOverheadThreshold { + final int warnThreshold; + final int infoThreshold; + final int debugThreshold; + + public GcOverheadThreshold(final int warnThreshold, final int infoThreshold, final int debugThreshold) { + this.warnThreshold = warnThreshold; + this.infoThreshold = infoThreshold; + this.debugThreshold = debugThreshold; + } + } + + + static class GcThreshold { public final String name; public final long warnThreshold; @@ -102,7 +125,42 @@ public class JvmGcMonitorService extends AbstractLifecycleComponent[{}]/[{}], all_pools {}"; - @Override protected void doStart() { if (!enabled) { return; } - scheduledFuture = threadPool.scheduleWithFixedDelay(new JvmMonitor(gcThresholds) { + scheduledFuture = threadPool.scheduleWithFixedDelay(new JvmMonitor(gcThresholds, gcOverheadThreshold) { @Override void onMonitorFailure(Throwable t) { logger.debug("failed to monitor", t); @@ -138,9 +193,17 @@ public class JvmGcMonitorService extends AbstractLifecycleComponent[{}]/[{}], all_pools {}"; + static void logSlowGc( final ESLogger logger, final JvmMonitor.Threshold threshold, @@ -162,7 +225,7 @@ public class JvmGcMonitorService extends AbstractLifecycleComponent gcThresholds; + private final Map gcThresholds; + final GcOverheadThreshold gcOverheadThreshold; - public JvmMonitor(Map gcThresholds) { + public JvmMonitor(final Map gcThresholds, final GcOverheadThreshold gcOverheadThreshold) { this.gcThresholds = Objects.requireNonNull(gcThresholds); + this.gcOverheadThreshold = Objects.requireNonNull(gcOverheadThreshold); } @Override public void run() { try { - monitorLongGc(); + monitorGc(); } catch (Throwable t) { onMonitorFailure(t); } @@ -304,12 +396,21 @@ public class JvmGcMonitorService extends AbstractLifecycleComponent= gcOverheadThreshold.warnThreshold) { + overheadThreshold = Threshold.WARN; + } else if (fraction >= gcOverheadThreshold.infoThreshold) { + overheadThreshold = Threshold.INFO; + } else if (fraction >= gcOverheadThreshold.debugThreshold) { + overheadThreshold = Threshold.DEBUG; + } + if (overheadThreshold != null) { + onGcOverhead(overheadThreshold, current, elapsed, seq); + } } JvmStats jvmStats() { @@ -364,6 +488,8 @@ public class JvmGcMonitorService extends AbstractLifecycleComponent null, t -> { + assertThat(t, instanceOf(IllegalArgumentException.class)); + assertThat(t.getMessage(), containsString("setting [monitor.jvm.gc.overhead." + threshold + "] must be >= 0")); + }, true, null); + } + + for (final String threshold : new String[] { "warn", "info", "debug" }) { + final Settings.Builder builder = Settings.builder(); + builder.put("monitor.jvm.gc.overhead." + threshold, randomIntBetween(100 + 1, Integer.MAX_VALUE)); + execute(builder.build(), (command, interval) -> null, t -> { + assertThat(t, instanceOf(IllegalArgumentException.class)); + assertThat(t.getMessage(), containsString("setting [monitor.jvm.gc.overhead." + threshold + "] must be <= 100")); + }, true, null); + } + + final Settings.Builder infoWarnOutOfOrderBuilder = Settings.builder(); + final int info = randomIntBetween(2, 98); + infoWarnOutOfOrderBuilder.put("monitor.jvm.gc.overhead.info", info); + final int warn = randomIntBetween(1, info - 1); + infoWarnOutOfOrderBuilder.put("monitor.jvm.gc.overhead.warn", warn); + execute(infoWarnOutOfOrderBuilder.build(), (command, interval) -> null, t -> { + assertThat(t, instanceOf(IllegalArgumentException.class)); + assertThat(t.getMessage(), containsString("[monitor.jvm.gc.overhead.warn] must be greater than [monitor.jvm.gc.overhead.info] [" + info + "] but was [" + warn + "]")); + }, true, null); + + final Settings.Builder debugInfoOutOfOrderBuilder = Settings.builder(); + debugInfoOutOfOrderBuilder.put("monitor.jvm.gc.overhead.info", info); + final int debug = randomIntBetween(info + 1, 99); + debugInfoOutOfOrderBuilder.put("monitor.jvm.gc.overhead.debug", debug); + debugInfoOutOfOrderBuilder.put("monitor.jvm.gc.overhead.warn", randomIntBetween(debug + 1, 100)); // or the test will fail for the wrong reason + execute(debugInfoOutOfOrderBuilder.build(), (command, interval) -> null, t -> { + assertThat(t, instanceOf(IllegalArgumentException.class)); + assertThat(t.getMessage(), containsString("[monitor.jvm.gc.overhead.info] must be greater than [monitor.jvm.gc.overhead.debug] [" + debug + "] but was [" + info + "]")); + }, true, null); + } + private static void execute(Settings settings, BiFunction> scheduler, Runnable asserts) throws InterruptedException { execute(settings, scheduler, null, false, asserts); } diff --git a/core/src/test/java/org/elasticsearch/monitor/jvm/JvmGcMonitorServiceTests.java b/core/src/test/java/org/elasticsearch/monitor/jvm/JvmGcMonitorServiceTests.java index 2c17fca7c8c..ab5b1ac4750 100644 --- a/core/src/test/java/org/elasticsearch/monitor/jvm/JvmGcMonitorServiceTests.java +++ b/core/src/test/java/org/elasticsearch/monitor/jvm/JvmGcMonitorServiceTests.java @@ -133,4 +133,43 @@ public class JvmGcMonitorServiceTests extends ESTestCase { verifyNoMoreInteractions(logger); } + public void testGcOverheadLogging() { + final JvmGcMonitorService.JvmMonitor.Threshold threshold = randomFrom(JvmGcMonitorService.JvmMonitor.Threshold.values()); + final int current = randomIntBetween(1, Integer.MAX_VALUE); + final long elapsed = randomIntBetween(current, Integer.MAX_VALUE); + final long seq = randomIntBetween(1, Integer.MAX_VALUE); + final ESLogger logger = mock(ESLogger.class); + when(logger.isWarnEnabled()).thenReturn(true); + when(logger.isInfoEnabled()).thenReturn(true); + when(logger.isDebugEnabled()).thenReturn(true); + JvmGcMonitorService.logGcOverhead(logger, threshold, current, elapsed, seq); + switch(threshold) { + case WARN: + verify(logger).isWarnEnabled(); + verify(logger).warn( + "[gc][{}] overhead, spent [{}] collecting in the last [{}]", + seq, + TimeValue.timeValueMillis(current), + TimeValue.timeValueMillis(elapsed)); + break; + case INFO: + verify(logger).isInfoEnabled(); + verify(logger).info( + "[gc][{}] overhead, spent [{}] collecting in the last [{}]", + seq, + TimeValue.timeValueMillis(current), + TimeValue.timeValueMillis(elapsed)); + break; + case DEBUG: + verify(logger).isDebugEnabled(); + verify(logger).debug( + "[gc][{}] overhead, spent [{}] collecting in the last [{}]", + seq, + TimeValue.timeValueMillis(current), + TimeValue.timeValueMillis(elapsed)); + break; + } + verifyNoMoreInteractions(logger); + } + } diff --git a/core/src/test/java/org/elasticsearch/monitor/jvm/JvmMonitorTests.java b/core/src/test/java/org/elasticsearch/monitor/jvm/JvmMonitorTests.java index 8d3ddeec84e..91862e9cd18 100644 --- a/core/src/test/java/org/elasticsearch/monitor/jvm/JvmMonitorTests.java +++ b/core/src/test/java/org/elasticsearch/monitor/jvm/JvmMonitorTests.java @@ -41,10 +41,12 @@ import static org.mockito.Mockito.when; public class JvmMonitorTests extends ESTestCase { + private static final JvmGcMonitorService.GcOverheadThreshold IGNORE = new JvmGcMonitorService.GcOverheadThreshold(0, 0, 0); + public void testMonitorFailure() { AtomicBoolean shouldFail = new AtomicBoolean(); AtomicBoolean invoked = new AtomicBoolean(); - JvmGcMonitorService.JvmMonitor monitor = new JvmGcMonitorService.JvmMonitor(Collections.emptyMap()) { + JvmGcMonitorService.JvmMonitor monitor = new JvmGcMonitorService.JvmMonitor(Collections.emptyMap(), IGNORE) { @Override void onMonitorFailure(Throwable t) { invoked.set(true); @@ -53,7 +55,7 @@ public class JvmMonitorTests extends ESTestCase { } @Override - synchronized void monitorLongGc() { + synchronized void monitorGc() { if (shouldFail.get()) { throw new RuntimeException("simulated"); } @@ -62,6 +64,10 @@ public class JvmMonitorTests extends ESTestCase { @Override void onSlowGc(final Threshold threshold, final long seq, final SlowGcEvent slowGcEvent) { } + + @Override + void onGcOverhead(Threshold threshold, long total, long elapsed, long seq) { + } }; monitor.run(); @@ -166,7 +172,7 @@ public class JvmMonitorTests extends ESTestCase { final AtomicInteger count = new AtomicInteger(); - JvmGcMonitorService.JvmMonitor monitor = new JvmGcMonitorService.JvmMonitor(gcThresholds) { + JvmGcMonitorService.JvmMonitor monitor = new JvmGcMonitorService.JvmMonitor(gcThresholds, IGNORE) { @Override void onMonitorFailure(Throwable t) { } @@ -198,6 +204,10 @@ public class JvmMonitorTests extends ESTestCase { } } + @Override + void onGcOverhead(Threshold threshold, long total, long elapsed, long seq) { + } + @Override long now() { return now.get(); @@ -213,7 +223,7 @@ public class JvmMonitorTests extends ESTestCase { now.set(start + TimeUnit.NANOSECONDS.convert(expectedElapsed, TimeUnit.MILLISECONDS)); jvmStats.set(monitorJvmStats); - monitor.monitorLongGc(); + monitor.monitorGc(); assertThat(count.get(), equalTo((youngGcThreshold ? 1 : 0) + (oldGcThreshold ? 1 : 0))); } @@ -235,14 +245,140 @@ public class JvmMonitorTests extends ESTestCase { private JvmStats jvmStats(JvmStats.GarbageCollector youngCollector, JvmStats.GarbageCollector oldCollector) { final JvmStats jvmStats = mock(JvmStats.class); - final JvmStats.GarbageCollectors initialGcs = mock(JvmStats.GarbageCollectors.class); - final JvmStats.GarbageCollector[] initialCollectors = new JvmStats.GarbageCollector[2]; - initialCollectors[0] = youngCollector; - initialCollectors[1] = oldCollector; - when(initialGcs.getCollectors()).thenReturn(initialCollectors); - when(jvmStats.getGc()).thenReturn(initialGcs); + final JvmStats.GarbageCollectors gcs = mock(JvmStats.GarbageCollectors.class); + final JvmStats.GarbageCollector[] collectors = new JvmStats.GarbageCollector[2]; + collectors[0] = youngCollector; + collectors[1] = oldCollector; + when(gcs.getCollectors()).thenReturn(collectors); + when(jvmStats.getGc()).thenReturn(gcs); when(jvmStats.getMem()).thenReturn(JvmStats.jvmStats().getMem()); return jvmStats; } + public void testMonitorGc() { + final int youngCollectionCount = randomIntBetween(1, 16); + final int youngCollectionIncrement = randomIntBetween(1, 16); + final int youngCollectionTime = randomIntBetween(1, 1 << 10); + final int youngCollectionTimeIncrement = randomIntBetween(1, 1 << 10); + final int oldCollectionCount = randomIntBetween(1, 16); + final int oldCollectionIncrement = randomIntBetween(1, 16); + final int oldCollectionTime = randomIntBetween(1, 1 << 10); + final int oldCollectionTimeIncrement = randomIntBetween(1, 1 << 10); + + final JvmStats.GarbageCollector lastYoungCollector = collector("young", youngCollectionCount, youngCollectionTime); + final JvmStats.GarbageCollector lastOldCollector = collector("old", oldCollectionCount, oldCollectionTime); + final JvmStats lastjvmStats = jvmStats(lastYoungCollector, lastOldCollector); + + final JvmStats.GarbageCollector currentYoungCollector = + collector("young", youngCollectionCount + youngCollectionIncrement, youngCollectionTime + youngCollectionTimeIncrement); + final JvmStats.GarbageCollector currentOldCollector = + collector("old", oldCollectionCount + oldCollectionIncrement, oldCollectionTime + oldCollectionTimeIncrement); + final JvmStats currentJvmStats = jvmStats(currentYoungCollector, currentOldCollector); + final long expectedElapsed = + randomIntBetween( + Math.max(youngCollectionTime + youngCollectionTimeIncrement, oldCollectionTime + oldCollectionTimeIncrement), + Integer.MAX_VALUE); + + final AtomicBoolean invoked = new AtomicBoolean(); + + final JvmGcMonitorService.JvmMonitor monitor = new JvmGcMonitorService.JvmMonitor(Collections.emptyMap(), IGNORE) { + + @Override + void onMonitorFailure(Throwable t) { + } + + @Override + void onSlowGc(Threshold threshold, long seq, SlowGcEvent slowGcEvent) { + } + + @Override + void onGcOverhead(Threshold threshold, long total, long elapsed, long seq) { + } + + @Override + void checkGcOverhead(long current, long elapsed, long seq) { + invoked.set(true); + assertThat(current, equalTo((long)(youngCollectionTimeIncrement + oldCollectionTimeIncrement))); + assertThat(elapsed, equalTo(expectedElapsed)); + } + + @Override + JvmStats jvmStats() { + return lastjvmStats; + } + }; + + monitor.monitorGcOverhead(currentJvmStats, expectedElapsed); + assertTrue(invoked.get()); + } + + private JvmStats.GarbageCollector collector(final String name, final int collectionCount, final int collectionTime) { + final JvmStats.GarbageCollector gc = mock(JvmStats.GarbageCollector.class); + when(gc.getName()).thenReturn(name); + when(gc.getCollectionCount()).thenReturn((long)collectionCount); + when(gc.getCollectionTime()).thenReturn(TimeValue.timeValueMillis(collectionTime)); + return gc; + } + + public void testCheckGcOverhead() { + final int debugThreshold = randomIntBetween(1, 98); + final int infoThreshold = randomIntBetween(debugThreshold + 1, 99); + final int warnThreshold = randomIntBetween(infoThreshold + 1, 100); + final JvmGcMonitorService.GcOverheadThreshold gcOverheadThreshold = + new JvmGcMonitorService.GcOverheadThreshold(warnThreshold, infoThreshold, debugThreshold); + + final JvmGcMonitorService.JvmMonitor.Threshold expectedThreshold; + int fraction = 0; + final long expectedCurrent; + final long expectedElapsed; + if (randomBoolean()) { + expectedThreshold = randomFrom(JvmGcMonitorService.JvmMonitor.Threshold.values()); + switch (expectedThreshold) { + case WARN: + fraction = randomIntBetween(warnThreshold, 100); + break; + case INFO: + fraction = randomIntBetween(infoThreshold, warnThreshold - 1); + break; + case DEBUG: + fraction = randomIntBetween(debugThreshold, infoThreshold - 1); + break; + } + } else { + expectedThreshold = null; + fraction = randomIntBetween(0, debugThreshold - 1); + } + + expectedElapsed = 100 * randomIntBetween(1, 1000); + expectedCurrent = fraction * expectedElapsed / 100; + + final AtomicBoolean invoked = new AtomicBoolean(); + final long expectedSeq = randomIntBetween(1, Integer.MAX_VALUE); + + final JvmGcMonitorService.JvmMonitor monitor = new JvmGcMonitorService.JvmMonitor(Collections.emptyMap(), gcOverheadThreshold) { + + @Override + void onMonitorFailure(final Throwable t) { + } + + @Override + void onSlowGc(Threshold threshold, long seq, SlowGcEvent slowGcEvent) { + } + + @Override + void onGcOverhead(final Threshold threshold, final long current, final long elapsed, final long seq) { + invoked.set(true); + assertThat(threshold, equalTo(expectedThreshold)); + assertThat(current, equalTo(expectedCurrent)); + assertThat(elapsed, equalTo(expectedElapsed)); + assertThat(seq, equalTo(expectedSeq)); + } + + }; + + monitor.checkGcOverhead(expectedCurrent, expectedElapsed, expectedSeq); + + assertThat(invoked.get(), equalTo(expectedThreshold != null)); + } + } From db4809d9061e6c4158d73eab1e7a9c82aec6521b Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Wed, 18 May 2016 11:03:00 -0400 Subject: [PATCH 06/12] Remove last vestigates of /bin/sh shebangs This commit removes the remaining /bin/sh shebangs in favor of /bin/bash. Relates #18448 --- buildSrc/src/main/resources/deb/postinst.ftl | 2 +- buildSrc/src/main/resources/deb/preinst.ftl | 2 +- .../src/main/resources/bin/elasticsearch-systemd-pre-exec | 2 +- distribution/src/main/resources/bin/elasticsearch.in.sh | 2 +- plugins/jvm-example/src/main/bin/test | 2 +- qa/vagrant/src/test/resources/packaging/scripts/modules.bash | 2 +- qa/vagrant/src/test/resources/packaging/scripts/os_package.bash | 2 +- .../test/resources/packaging/scripts/packaging_test_utils.bash | 2 +- qa/vagrant/src/test/resources/packaging/scripts/plugins.bash | 2 +- qa/vagrant/src/test/resources/packaging/scripts/tar.bash | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/buildSrc/src/main/resources/deb/postinst.ftl b/buildSrc/src/main/resources/deb/postinst.ftl index 5f67242c265..9acfc0f084e 100644 --- a/buildSrc/src/main/resources/deb/postinst.ftl +++ b/buildSrc/src/main/resources/deb/postinst.ftl @@ -1,2 +1,2 @@ -#!/bin/sh -e +#!/bin/bash -e <% commands.each {command -> %><%= command %><% } %> diff --git a/buildSrc/src/main/resources/deb/preinst.ftl b/buildSrc/src/main/resources/deb/preinst.ftl index 5f67242c265..9acfc0f084e 100644 --- a/buildSrc/src/main/resources/deb/preinst.ftl +++ b/buildSrc/src/main/resources/deb/preinst.ftl @@ -1,2 +1,2 @@ -#!/bin/sh -e +#!/bin/bash -e <% commands.each {command -> %><%= command %><% } %> diff --git a/distribution/src/main/resources/bin/elasticsearch-systemd-pre-exec b/distribution/src/main/resources/bin/elasticsearch-systemd-pre-exec index a51d639bf7d..5a5877598e6 100755 --- a/distribution/src/main/resources/bin/elasticsearch-systemd-pre-exec +++ b/distribution/src/main/resources/bin/elasticsearch-systemd-pre-exec @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # CONF_FILE setting was removed if [ ! -z "$CONF_FILE" ]; then diff --git a/distribution/src/main/resources/bin/elasticsearch.in.sh b/distribution/src/main/resources/bin/elasticsearch.in.sh index 8f1b5566f90..58b26a2d6eb 100644 --- a/distribution/src/main/resources/bin/elasticsearch.in.sh +++ b/distribution/src/main/resources/bin/elasticsearch.in.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # check in case a user was using this mechanism if [ "x$ES_CLASSPATH" != "x" ]; then diff --git a/plugins/jvm-example/src/main/bin/test b/plugins/jvm-example/src/main/bin/test index 76ba88943ac..13fdcce1e52 100755 --- a/plugins/jvm-example/src/main/bin/test +++ b/plugins/jvm-example/src/main/bin/test @@ -1,3 +1,3 @@ -#!/bin/sh +#!/bin/bash echo test diff --git a/qa/vagrant/src/test/resources/packaging/scripts/modules.bash b/qa/vagrant/src/test/resources/packaging/scripts/modules.bash index bd6da680da9..2e80fd648f3 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/modules.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/modules.bash @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This file contains some utilities to test the elasticsearch scripts, # the .deb/.rpm packages and the SysV/Systemd scripts. diff --git a/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash b/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash index 72c59c39324..ee6e491d169 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This file contains some utilities to test the elasticsearch scripts with # the .deb/.rpm packages. diff --git a/qa/vagrant/src/test/resources/packaging/scripts/packaging_test_utils.bash b/qa/vagrant/src/test/resources/packaging/scripts/packaging_test_utils.bash index 09d0190695e..5f50dfc2850 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/packaging_test_utils.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/packaging_test_utils.bash @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This file contains some utilities to test the elasticsearch scripts, # the .deb/.rpm packages and the SysV/Systemd scripts. diff --git a/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash b/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash index 4f1e574b905..afae7439057 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This file contains some utilities to test the elasticsearch scripts, # the .deb/.rpm packages and the SysV/Systemd scripts. diff --git a/qa/vagrant/src/test/resources/packaging/scripts/tar.bash b/qa/vagrant/src/test/resources/packaging/scripts/tar.bash index 277eee60f1a..798ec6c2997 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/tar.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/tar.bash @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This file contains some utilities to test the elasticsearch scripts, # the .deb/.rpm packages and the SysV/Systemd scripts. From a846ff93e91020b5a837c45a045191b1c58a86e7 Mon Sep 17 00:00:00 2001 From: markharwood Date: Tue, 17 May 2016 14:15:53 +0100 Subject: [PATCH 07/12] Aggregations fix: support include/exclude strings formatted for IP and date fields in terms and significant_terms aggregations. Closes #17705 --- .../SignificantTermsAggregatorFactory.java | 17 +++++-- .../bucket/terms/TermsAggregatorFactory.java | 15 ++++-- .../bucket/terms/support/IncludeExclude.java | 40 ++++++++++----- .../test/search.aggregation/20_terms.yaml | 50 +++++++++++++++++++ .../test/search.aggregation/30_sig_terms.yaml | 25 ++++++++++ 5 files changed, 125 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsAggregatorFactory.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsAggregatorFactory.java index 13126029b8e..4b9e3acb873 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsAggregatorFactory.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsAggregatorFactory.java @@ -211,7 +211,14 @@ public class SignificantTermsAggregatorFactory extends ValuesSourceAggregatorFac } } assert execution != null; - return execution.create(name, factories, valuesSource, config.format(), bucketCountThresholds, includeExclude, context, parent, + + DocValueFormat format = config.format(); + if ((includeExclude != null) && (includeExclude.isRegexBased()) && format != DocValueFormat.RAW) { + throw new AggregationExecutionException("Aggregation [" + name + "] cannot support regular expression style include/exclude " + + "settings as they can only be applied to string fields. Use an array of values for include/exclude clauses"); + } + + return execution.create(name, factories, valuesSource, format, bucketCountThresholds, includeExclude, context, parent, significanceHeuristic, this, pipelineAggregators, metaData); } @@ -227,7 +234,7 @@ public class SignificantTermsAggregatorFactory extends ValuesSourceAggregatorFac } IncludeExclude.LongFilter longFilter = null; if (includeExclude != null) { - longFilter = includeExclude.convertToLongFilter(); + longFilter = includeExclude.convertToLongFilter(config.format()); } return new SignificantLongTermsAggregator(name, factories, (ValuesSource.Numeric) valuesSource, config.format(), bucketCountThresholds, context, parent, significanceHeuristic, this, longFilter, pipelineAggregators, @@ -248,7 +255,7 @@ public class SignificantTermsAggregatorFactory extends ValuesSourceAggregatorFac AggregationContext aggregationContext, Aggregator parent, SignificanceHeuristic significanceHeuristic, SignificantTermsAggregatorFactory termsAggregatorFactory, List pipelineAggregators, Map metaData) throws IOException { - final IncludeExclude.StringFilter filter = includeExclude == null ? null : includeExclude.convertToStringFilter(); + final IncludeExclude.StringFilter filter = includeExclude == null ? null : includeExclude.convertToStringFilter(format); return new SignificantStringTermsAggregator(name, factories, valuesSource, format, bucketCountThresholds, filter, aggregationContext, parent, significanceHeuristic, termsAggregatorFactory, pipelineAggregators, metaData); } @@ -262,7 +269,7 @@ public class SignificantTermsAggregatorFactory extends ValuesSourceAggregatorFac AggregationContext aggregationContext, Aggregator parent, SignificanceHeuristic significanceHeuristic, SignificantTermsAggregatorFactory termsAggregatorFactory, List pipelineAggregators, Map metaData) throws IOException { - final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(); + final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(format); return new GlobalOrdinalsSignificantTermsAggregator(name, factories, (ValuesSource.Bytes.WithOrdinals.FieldData) valuesSource, format, bucketCountThresholds, filter, aggregationContext, parent, significanceHeuristic, termsAggregatorFactory, pipelineAggregators, metaData); @@ -277,7 +284,7 @@ public class SignificantTermsAggregatorFactory extends ValuesSourceAggregatorFac AggregationContext aggregationContext, Aggregator parent, SignificanceHeuristic significanceHeuristic, SignificantTermsAggregatorFactory termsAggregatorFactory, List pipelineAggregators, Map metaData) throws IOException { - final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(); + final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(format); return new GlobalOrdinalsSignificantTermsAggregator.WithHash(name, factories, (ValuesSource.Bytes.WithOrdinals.FieldData) valuesSource, format, bucketCountThresholds, filter, aggregationContext, parent, significanceHeuristic, termsAggregatorFactory, pipelineAggregators, metaData); diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java index 1ccf4a11570..62374ae7d19 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java @@ -150,8 +150,13 @@ public class TermsAggregatorFactory extends ValuesSourceAggregatorFactory pipelineAggregators, Map metaData) throws IOException { - final IncludeExclude.StringFilter filter = includeExclude == null ? null : includeExclude.convertToStringFilter(); + final IncludeExclude.StringFilter filter = includeExclude == null ? null : includeExclude.convertToStringFilter(format); return new StringTermsAggregator(name, factories, valuesSource, order, format, bucketCountThresholds, filter, aggregationContext, parent, subAggCollectMode, showTermDocCountError, pipelineAggregators, metaData); } @@ -211,7 +216,7 @@ public class TermsAggregatorFactory extends ValuesSourceAggregatorFactory pipelineAggregators, Map metaData) throws IOException { - final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(); + final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(format); return new GlobalOrdinalsStringTermsAggregator(name, factories, (ValuesSource.Bytes.WithOrdinals) valuesSource, order, format, bucketCountThresholds, filter, aggregationContext, parent, subAggCollectMode, showTermDocCountError, pipelineAggregators, metaData); @@ -231,7 +236,7 @@ public class TermsAggregatorFactory extends ValuesSourceAggregatorFactory pipelineAggregators, Map metaData) throws IOException { - final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(); + final IncludeExclude.OrdinalsFilter filter = includeExclude == null ? null : includeExclude.convertToOrdinalsFilter(format); return new GlobalOrdinalsStringTermsAggregator.WithHash(name, factories, (ValuesSource.Bytes.WithOrdinals) valuesSource, order, format, bucketCountThresholds, filter, aggregationContext, parent, subAggCollectMode, showTermDocCountError, pipelineAggregators, metaData); diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/support/IncludeExclude.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/support/IncludeExclude.java index 101291d01e1..209700b86d9 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/support/IncludeExclude.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/support/IncludeExclude.java @@ -43,6 +43,7 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.support.ValuesSource; import org.elasticsearch.search.aggregations.support.ValuesSource.Bytes.WithOrdinals; @@ -135,7 +136,8 @@ public class IncludeExclude implements Writeable, ToXContent { } public static abstract class OrdinalsFilter { - public abstract LongBitSet acceptedGlobalOrdinals(RandomAccessOrds globalOrdinals, ValuesSource.Bytes.WithOrdinals valueSource) throws IOException; + public abstract LongBitSet acceptedGlobalOrdinals(RandomAccessOrds globalOrdinals, ValuesSource.Bytes.WithOrdinals valueSource) + throws IOException; } @@ -152,7 +154,8 @@ public class IncludeExclude implements Writeable, ToXContent { * */ @Override - public LongBitSet acceptedGlobalOrdinals(RandomAccessOrds globalOrdinals, ValuesSource.Bytes.WithOrdinals valueSource) throws IOException { + public LongBitSet acceptedGlobalOrdinals(RandomAccessOrds globalOrdinals, ValuesSource.Bytes.WithOrdinals valueSource) + throws IOException { LongBitSet acceptedGlobalOrdinals = new LongBitSet(globalOrdinals.getValueCount()); TermsEnum globalTermsEnum; Terms globalTerms = new DocValuesTerms(globalOrdinals); @@ -179,7 +182,7 @@ public class IncludeExclude implements Writeable, ToXContent { @Override public LongBitSet acceptedGlobalOrdinals(RandomAccessOrds globalOrdinals, WithOrdinals valueSource) throws IOException { LongBitSet acceptedGlobalOrdinals = new LongBitSet(globalOrdinals.getValueCount()); - if(includeValues!=null){ + if (includeValues != null) { for (BytesRef term : includeValues) { long ord = globalOrdinals.lookupTerm(term); if (ord >= 0) { @@ -534,33 +537,46 @@ public class IncludeExclude implements Writeable, ToXContent { return a; } - public StringFilter convertToStringFilter() { + public StringFilter convertToStringFilter(DocValueFormat format) { if (isRegexBased()) { return new AutomatonBackedStringFilter(toAutomaton()); } - return new TermListBackedStringFilter(includeValues, excludeValues); + return new TermListBackedStringFilter(parseForDocValues(includeValues, format), parseForDocValues(excludeValues, format)); } - public OrdinalsFilter convertToOrdinalsFilter() { + private static SortedSet parseForDocValues(SortedSet endUserFormattedValues, DocValueFormat format) { + SortedSet result = endUserFormattedValues; + if (endUserFormattedValues != null) { + if (format != DocValueFormat.RAW) { + result = new TreeSet<>(); + for (BytesRef formattedVal : endUserFormattedValues) { + result.add(format.parseBytesRef(formattedVal.utf8ToString())); + } + } + } + return result; + } + + public OrdinalsFilter convertToOrdinalsFilter(DocValueFormat format) { if (isRegexBased()) { return new AutomatonBackedOrdinalsFilter(toAutomaton()); } - return new TermListBackedOrdinalsFilter(includeValues, excludeValues); + return new TermListBackedOrdinalsFilter(parseForDocValues(includeValues, format), parseForDocValues(excludeValues, format)); } - public LongFilter convertToLongFilter() { + public LongFilter convertToLongFilter(DocValueFormat format) { int numValids = includeValues == null ? 0 : includeValues.size(); int numInvalids = excludeValues == null ? 0 : excludeValues.size(); LongFilter result = new LongFilter(numValids, numInvalids); if (includeValues != null) { for (BytesRef val : includeValues) { - result.addAccept(Long.parseLong(val.utf8ToString())); + result.addAccept(format.parseLong(val.utf8ToString(), false, null)); } } if (excludeValues != null) { for (BytesRef val : excludeValues) { - result.addReject(Long.parseLong(val.utf8ToString())); + result.addReject(format.parseLong(val.utf8ToString(), false, null)); } } return result; @@ -572,13 +588,13 @@ public class IncludeExclude implements Writeable, ToXContent { LongFilter result = new LongFilter(numValids, numInvalids); if (includeValues != null) { for (BytesRef val : includeValues) { - double dval=Double.parseDouble(val.utf8ToString()); + double dval = Double.parseDouble(val.utf8ToString()); result.addAccept(NumericUtils.doubleToSortableLong(dval)); } } if (excludeValues != null) { for (BytesRef val : excludeValues) { - double dval=Double.parseDouble(val.utf8ToString()); + double dval = Double.parseDouble(val.utf8ToString()); result.addReject(NumericUtils.doubleToSortableLong(dval)); } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/20_terms.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/20_terms.yaml index 71d1a1e7ca2..c35e79e6cfe 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/20_terms.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/20_terms.yaml @@ -117,6 +117,33 @@ setup: - match: { aggregations.ip_terms.buckets.1.doc_count: 1 } + - do: + search: + body: { "size" : 0, "aggs" : { "ip_terms" : { "terms" : { "field" : "ip", "include" : [ "127.0.0.1" ] } } } } + + - match: { hits.total: 3 } + + - length: { aggregations.ip_terms.buckets: 1 } + + - match: { aggregations.ip_terms.buckets.0.key: "127.0.0.1" } + + - do: + search: + body: { "size" : 0, "aggs" : { "ip_terms" : { "terms" : { "field" : "ip", "exclude" : [ "127.0.0.1" ] } } } } + + - match: { hits.total: 3 } + + - length: { aggregations.ip_terms.buckets: 1 } + + - match: { aggregations.ip_terms.buckets.0.key: "::1" } + + - do: + catch: request + search: + body: { "size" : 0, "aggs" : { "ip_terms" : { "terms" : { "field" : "ip", "exclude" : "127.*" } } } } + + + --- "Boolean test": - do: @@ -300,4 +327,27 @@ setup: - match: { aggregations.date_terms.buckets.1.key_as_string: "2014-09-01T00:00:00.000Z" } - match: { aggregations.date_terms.buckets.1.doc_count: 1 } + + - do: + search: + body: { "size" : 0, "aggs" : { "date_terms" : { "terms" : { "field" : "date", "include" : [ "2016-05-03" ] } } } } + - match: { hits.total: 3 } + + - length: { aggregations.date_terms.buckets: 1 } + + - match: { aggregations.date_terms.buckets.0.key_as_string: "2016-05-03T00:00:00.000Z" } + + - match: { aggregations.date_terms.buckets.0.doc_count: 2 } + + - do: + search: + body: { "size" : 0, "aggs" : { "date_terms" : { "terms" : { "field" : "date", "exclude" : [ "2016-05-03" ] } } } } + + - match: { hits.total: 3 } + + - length: { aggregations.date_terms.buckets: 1 } + + - match: { aggregations.date_terms.buckets.0.key_as_string: "2014-09-01T00:00:00.000Z" } + + - match: { aggregations.date_terms.buckets.0.doc_count: 1 } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/30_sig_terms.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/30_sig_terms.yaml index 45c042baea4..a708ff19d7e 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/30_sig_terms.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/30_sig_terms.yaml @@ -121,3 +121,28 @@ - is_false: aggregations.ip_terms.buckets.0.key_as_string - match: { aggregations.ip_terms.buckets.0.doc_count: 1 } + + - do: + search: + body: { "query" : { "exists" : { "field" : "ip" } }, "aggs" : { "ip_terms" : { "significant_terms" : { "field" : "ip", "min_doc_count" : 1, "include" : [ "::1" ] } } } } + + - match: { hits.total: 1 } + + - length: { aggregations.ip_terms.buckets: 1 } + + - match: { aggregations.ip_terms.buckets.0.key: "::1" } + + - do: + search: + body: { "query" : { "exists" : { "field" : "ip" } }, "aggs" : { "ip_terms" : { "significant_terms" : { "field" : "ip", "min_doc_count" : 1, "exclude" : [ "::1" ] } } } } + + - match: { hits.total: 1 } + + - length: { aggregations.ip_terms.buckets: 0 } + + - do: + catch: request + search: + body: { "size" : 0, "aggs" : { "ip_terms" : { "significant_terms" : { "field" : "ip", "exclude" : "127.*" } } } } + + From 7c665a010b12152fef387fac5c1ad710dc467f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Sun, 15 May 2016 21:26:09 +0200 Subject: [PATCH 08/12] Fix TimeZoneRounding#nextRoundingValue for hour, minute and second units Currently rounding intervals obtained by nextRoundingValue() for hour, minute and second units can include an extra hour when happening at DST transitions that add an extra hour (eg CEST -> CET). This changes the rounding logic for time units smaller or equal to an hour to fix this. Closes #18326 --- .../common/rounding/DateTimeUnit.java | 9 +++ .../common/rounding/TimeZoneRounding.java | 25 ++++--- .../common/rounding/DateTimeUnitTests.java | 75 +++++++++++++++++++ .../rounding/TimeZoneRoundingTests.java | 58 ++++++++++++-- .../aggregations/bucket/DateHistogramIT.java | 24 ++++++ 5 files changed, 173 insertions(+), 18 deletions(-) create mode 100644 core/src/test/java/org/elasticsearch/common/rounding/DateTimeUnitTests.java diff --git a/core/src/main/java/org/elasticsearch/common/rounding/DateTimeUnit.java b/core/src/main/java/org/elasticsearch/common/rounding/DateTimeUnit.java index e02342ffdca..bd0c5506859 100644 --- a/core/src/main/java/org/elasticsearch/common/rounding/DateTimeUnit.java +++ b/core/src/main/java/org/elasticsearch/common/rounding/DateTimeUnit.java @@ -53,6 +53,15 @@ public enum DateTimeUnit { return field; } + /** + * @param unit the {@link DateTimeUnit} to check + * @return true if the unit is a day or longer + */ + public static boolean isDayOrLonger(DateTimeUnit unit) { + return (unit == DateTimeUnit.HOUR_OF_DAY || unit == DateTimeUnit.MINUTES_OF_HOUR + || unit == DateTimeUnit.SECOND_OF_MINUTE) == false; + } + public static DateTimeUnit resolve(byte id) { switch (id) { case 1: return WEEK_OF_WEEKYEAR; diff --git a/core/src/main/java/org/elasticsearch/common/rounding/TimeZoneRounding.java b/core/src/main/java/org/elasticsearch/common/rounding/TimeZoneRounding.java index 4189e412708..e0ffb89c8b0 100644 --- a/core/src/main/java/org/elasticsearch/common/rounding/TimeZoneRounding.java +++ b/core/src/main/java/org/elasticsearch/common/rounding/TimeZoneRounding.java @@ -46,8 +46,8 @@ public abstract class TimeZoneRounding extends Rounding { public static class Builder { - private DateTimeUnit unit; - private long interval = -1; + private final DateTimeUnit unit; + private final long interval; private DateTimeZone timeZone = DateTimeZone.UTC; @@ -142,10 +142,15 @@ public abstract class TimeZoneRounding extends Rounding { @Override public long nextRoundingValue(long time) { - long timeLocal = time; - timeLocal = timeZone.convertUTCToLocal(time); - long nextInLocalTime = durationField.add(timeLocal, 1); - return timeZone.convertLocalToUTC(nextInLocalTime, false); + if (DateTimeUnit.isDayOrLonger(unit)) { + time = timeZone.convertUTCToLocal(time); + } + long next = durationField.add(time, 1); + if (DateTimeUnit.isDayOrLonger(unit)) { + return timeZone.convertLocalToUTC(next, false); + } else { + return next; + } } @Override @@ -161,12 +166,12 @@ public abstract class TimeZoneRounding extends Rounding { out.writeByte(unit.id()); out.writeString(timeZone.getID()); } - + @Override public int hashCode() { return Objects.hash(unit, timeZone); } - + @Override public boolean equals(Object obj) { if (obj == null) { @@ -236,12 +241,12 @@ public abstract class TimeZoneRounding extends Rounding { out.writeVLong(interval); out.writeString(timeZone.getID()); } - + @Override public int hashCode() { return Objects.hash(interval, timeZone); } - + @Override public boolean equals(Object obj) { if (obj == null) { diff --git a/core/src/test/java/org/elasticsearch/common/rounding/DateTimeUnitTests.java b/core/src/test/java/org/elasticsearch/common/rounding/DateTimeUnitTests.java new file mode 100644 index 00000000000..79ef6929645 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/common/rounding/DateTimeUnitTests.java @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.elasticsearch.common.rounding; + +import org.elasticsearch.test.ESTestCase; + +import static org.elasticsearch.common.rounding.DateTimeUnit.WEEK_OF_WEEKYEAR; +import static org.elasticsearch.common.rounding.DateTimeUnit.YEAR_OF_CENTURY; +import static org.elasticsearch.common.rounding.DateTimeUnit.QUARTER; +import static org.elasticsearch.common.rounding.DateTimeUnit.MONTH_OF_YEAR; +import static org.elasticsearch.common.rounding.DateTimeUnit.DAY_OF_MONTH; +import static org.elasticsearch.common.rounding.DateTimeUnit.HOUR_OF_DAY; +import static org.elasticsearch.common.rounding.DateTimeUnit.MINUTES_OF_HOUR; +import static org.elasticsearch.common.rounding.DateTimeUnit.SECOND_OF_MINUTE; + +public class DateTimeUnitTests extends ESTestCase { + + /** + * test that we don't accidentally change enum ids + */ + public void testEnumIds() { + assertEquals(1, WEEK_OF_WEEKYEAR.id()); + assertEquals(WEEK_OF_WEEKYEAR, DateTimeUnit.resolve((byte) 1)); + + assertEquals(2, YEAR_OF_CENTURY.id()); + assertEquals(YEAR_OF_CENTURY, DateTimeUnit.resolve((byte) 2)); + + assertEquals(3, QUARTER.id()); + assertEquals(QUARTER, DateTimeUnit.resolve((byte) 3)); + + assertEquals(4, MONTH_OF_YEAR.id()); + assertEquals(MONTH_OF_YEAR, DateTimeUnit.resolve((byte) 4)); + + assertEquals(5, DAY_OF_MONTH.id()); + assertEquals(DAY_OF_MONTH, DateTimeUnit.resolve((byte) 5)); + + assertEquals(6, HOUR_OF_DAY.id()); + assertEquals(HOUR_OF_DAY, DateTimeUnit.resolve((byte) 6)); + + assertEquals(7, MINUTES_OF_HOUR.id()); + assertEquals(MINUTES_OF_HOUR, DateTimeUnit.resolve((byte) 7)); + + assertEquals(8, SECOND_OF_MINUTE.id()); + assertEquals(SECOND_OF_MINUTE, DateTimeUnit.resolve((byte) 8)); + } + + public void testIsDayOrLonger() { + for (DateTimeUnit unit : DateTimeUnit.values()) { + if (DateTimeUnit.isDayOrLonger(unit)) { + assertTrue(unit == DAY_OF_MONTH || + unit == MONTH_OF_YEAR || + unit == QUARTER || + unit == YEAR_OF_CENTURY || + unit == WEEK_OF_WEEKYEAR); + } + } + } + +} diff --git a/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java b/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java index 2c4d78adbd0..08a4ba11342 100644 --- a/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java +++ b/core/src/test/java/org/elasticsearch/common/rounding/TimeZoneRoundingTests.java @@ -25,6 +25,7 @@ import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.ISODateTimeFormat; +import java.util.ArrayList; import java.util.concurrent.TimeUnit; import static org.hamcrest.Matchers.equalTo; @@ -147,21 +148,37 @@ public class TimeZoneRoundingTests extends ESTestCase { Rounding tzRounding; // testing savings to non savings switch tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(DateTimeZone.forID("UTC")).build(); - assertThat(tzRounding.round(time("2014-10-26T01:01:01", DateTimeZone.forID("CET"))), - equalTo(time("2014-10-26T01:00:00", DateTimeZone.forID("CET")))); + assertThat(tzRounding.round(time("2014-10-26T01:01:01", DateTimeZone.forOffsetHours(2))), // CEST = UTC+2 + equalTo(time("2014-10-26T01:00:00", DateTimeZone.forOffsetHours(2)))); + assertThat(tzRounding.nextRoundingValue(time("2014-10-26T01:00:00", DateTimeZone.forOffsetHours(2))), + equalTo(time("2014-10-26T02:00:00", DateTimeZone.forOffsetHours(2)))); + assertThat(tzRounding.nextRoundingValue(time("2014-10-26T02:00:00", DateTimeZone.forOffsetHours(2))), + equalTo(time("2014-10-26T03:00:00", DateTimeZone.forOffsetHours(2)))); tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(DateTimeZone.forID("CET")).build(); - assertThat(tzRounding.round(time("2014-10-26T01:01:01", DateTimeZone.forID("CET"))), - equalTo(time("2014-10-26T01:00:00", DateTimeZone.forID("CET")))); + assertThat(tzRounding.round(time("2014-10-26T01:01:01", DateTimeZone.forOffsetHours(2))), // CEST = UTC+2 + equalTo(time("2014-10-26T01:00:00", DateTimeZone.forOffsetHours(2)))); + assertThat(tzRounding.nextRoundingValue(time("2014-10-26T01:00:00", DateTimeZone.forOffsetHours(2))), + equalTo(time("2014-10-26T02:00:00", DateTimeZone.forOffsetHours(2)))); + assertThat(tzRounding.nextRoundingValue(time("2014-10-26T02:00:00", DateTimeZone.forOffsetHours(2))), + equalTo(time("2014-10-26T03:00:00", DateTimeZone.forOffsetHours(2)))); // testing non savings to savings switch tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(DateTimeZone.forID("UTC")).build(); - assertThat(tzRounding.round(time("2014-03-30T01:01:01", DateTimeZone.forID("CET"))), - equalTo(time("2014-03-30T01:00:00", DateTimeZone.forID("CET")))); + assertThat(tzRounding.round(time("2014-03-30T01:01:01", DateTimeZone.forOffsetHours(1))), // CET = UTC+1 + equalTo(time("2014-03-30T01:00:00", DateTimeZone.forOffsetHours(1)))); + assertThat(tzRounding.nextRoundingValue(time("2014-03-30T01:00:00", DateTimeZone.forOffsetHours(1))), + equalTo(time("2014-03-30T02:00:00", DateTimeZone.forOffsetHours(1)))); + assertThat(tzRounding.nextRoundingValue(time("2014-03-30T02:00:00", DateTimeZone.forOffsetHours(1))), + equalTo(time("2014-03-30T03:00:00", DateTimeZone.forOffsetHours(1)))); tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(DateTimeZone.forID("CET")).build(); - assertThat(tzRounding.round(time("2014-03-30T01:01:01", DateTimeZone.forID("CET"))), - equalTo(time("2014-03-30T01:00:00", DateTimeZone.forID("CET")))); + assertThat(tzRounding.round(time("2014-03-30T01:01:01", DateTimeZone.forOffsetHours(1))), // CET = UTC+1 + equalTo(time("2014-03-30T01:00:00", DateTimeZone.forOffsetHours(1)))); + assertThat(tzRounding.nextRoundingValue(time("2014-03-30T01:00:00", DateTimeZone.forOffsetHours(1))), + equalTo(time("2014-03-30T02:00:00", DateTimeZone.forOffsetHours(1)))); + assertThat(tzRounding.nextRoundingValue(time("2014-03-30T02:00:00", DateTimeZone.forOffsetHours(1))), + equalTo(time("2014-03-30T03:00:00", DateTimeZone.forOffsetHours(1)))); // testing non savings to savings switch (America/Chicago) tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(DateTimeZone.forID("UTC")).build(); @@ -210,6 +227,31 @@ public class TimeZoneRoundingTests extends ESTestCase { } } + /** + * Test that nextRoundingValue() for hour rounding (and smaller) is equally spaced (see #18326) + * Start at a random date in a random time zone, then find the next zone offset transition (if any). + * From there, check that when we advance by using rounding#nextRoundingValue(), we always advance by the same + * amount of milliseconds. + */ + public void testSubHourNextRoundingEquallySpaced() { + String timeZone = randomFrom(new ArrayList<>(DateTimeZone.getAvailableIDs())); + DateTimeUnit unit = randomFrom(new DateTimeUnit[] { DateTimeUnit.HOUR_OF_DAY, DateTimeUnit.MINUTES_OF_HOUR, + DateTimeUnit.SECOND_OF_MINUTE }); + DateTimeZone tz = DateTimeZone.forID(timeZone); + TimeZoneRounding rounding = new TimeZoneRounding.TimeUnitRounding(unit, tz); + // move the random date to transition for timezones that have offset change due to dst transition + long nextTransition = tz.nextTransition(Math.abs(randomLong() % ((long) 10e11))); + final long millisPerUnit = unit.field().getDurationField().getUnitMillis(); + // start ten units before transition + long roundedDate = rounding.round(nextTransition - (10 * millisPerUnit)); + while (roundedDate < nextTransition + 10 * millisPerUnit) { + long delta = rounding.nextRoundingValue(roundedDate) - roundedDate; + assertEquals("Difference between rounded values not equally spaced for [" + unit.name() + "], [" + timeZone + "] at " + + new DateTime(roundedDate), millisPerUnit, delta); + roundedDate = rounding.nextRoundingValue(roundedDate); + } + } + /** * randomized test on TimeIntervalRounding with random interval and time zone offsets */ diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramIT.java index 76b5558df80..cdb722ff9dd 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramIT.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.mapper.core.DateFieldMapper; +import org.elasticsearch.index.query.MatchNoneQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.script.Script; @@ -1146,4 +1147,27 @@ public class DateHistogramIT extends ESIntegTestCase { Histogram histo = response.getAggregations().get("histo"); assertThat(histo.getBuckets().size(), greaterThan(0)); } + + /** + * When DST ends, local time turns back one hour, so between 2am and 4am wall time we should have four buckets: + * "2015-10-25T02:00:00.000+02:00", + * "2015-10-25T02:00:00.000+01:00", + * "2015-10-25T03:00:00.000+01:00", + * "2015-10-25T04:00:00.000+01:00". + */ + public void testDSTEndTransition() throws Exception { + SearchResponse response = client().prepareSearch("idx") + .setQuery(new MatchNoneQueryBuilder()) + .addAggregation(dateHistogram("histo").field("date").timeZone(DateTimeZone.forID("Europe/Oslo")) + .dateHistogramInterval(DateHistogramInterval.HOUR).minDocCount(0).extendedBounds( + new ExtendedBounds("2015-10-25T02:00:00.000+02:00", "2015-10-25T04:00:00.000+01:00"))) + .execute().actionGet(); + + Histogram histo = response.getAggregations().get("histo"); + List buckets = histo.getBuckets(); + assertThat(buckets.size(), equalTo(4)); + assertThat(((DateTime) buckets.get(1).getKey()).getMillis() - ((DateTime) buckets.get(0).getKey()).getMillis(), equalTo(3600000L)); + assertThat(((DateTime) buckets.get(2).getKey()).getMillis() - ((DateTime) buckets.get(1).getKey()).getMillis(), equalTo(3600000L)); + assertThat(((DateTime) buckets.get(3).getKey()).getMillis() - ((DateTime) buckets.get(2).getKey()).getMillis(), equalTo(3600000L)); + } } From cec9a94b96b194ce35e63c5616493153dc9c19e2 Mon Sep 17 00:00:00 2001 From: Clinton Gormley Date: Wed, 18 May 2016 14:48:51 +0200 Subject: [PATCH 09/12] Added version 2.3.3 with bwc indices --- .../main/java/org/elasticsearch/Version.java | 4 ++++ .../test/resources/indices/bwc/index-2.3.3.zip | Bin 0 -> 77612 bytes .../test/resources/indices/bwc/repo-2.3.3.zip | Bin 0 -> 75600 bytes 3 files changed, 4 insertions(+) create mode 100644 core/src/test/resources/indices/bwc/index-2.3.3.zip create mode 100644 core/src/test/resources/indices/bwc/repo-2.3.3.zip diff --git a/core/src/main/java/org/elasticsearch/Version.java b/core/src/main/java/org/elasticsearch/Version.java index 0e869d06149..9cc526d8f97 100644 --- a/core/src/main/java/org/elasticsearch/Version.java +++ b/core/src/main/java/org/elasticsearch/Version.java @@ -69,6 +69,8 @@ public class Version { public static final Version V_2_3_1 = new Version(V_2_3_1_ID, org.apache.lucene.util.Version.LUCENE_5_5_0); public static final int V_2_3_2_ID = 2030299; public static final Version V_2_3_2 = new Version(V_2_3_2_ID, org.apache.lucene.util.Version.LUCENE_5_5_0); + public static final int V_2_3_3_ID = 2030399; + public static final Version V_2_3_3 = new Version(V_2_3_3_ID, org.apache.lucene.util.Version.LUCENE_5_5_0); public static final int V_5_0_0_alpha1_ID = 5000001; public static final Version V_5_0_0_alpha1 = new Version(V_5_0_0_alpha1_ID, org.apache.lucene.util.Version.LUCENE_6_0_0); public static final int V_5_0_0_alpha2_ID = 5000002; @@ -94,6 +96,8 @@ public class Version { return V_5_0_0_alpha2; case V_5_0_0_alpha1_ID: return V_5_0_0_alpha1; + case V_2_3_3_ID: + return V_2_3_3; case V_2_3_2_ID: return V_2_3_2; case V_2_3_1_ID: diff --git a/core/src/test/resources/indices/bwc/index-2.3.3.zip b/core/src/test/resources/indices/bwc/index-2.3.3.zip new file mode 100644 index 0000000000000000000000000000000000000000..aced41714fdb5ac31cbe04e9051ccf5571132f68 GIT binary patch literal 77612 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%0A1oS=KO3^gN*z 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 literal 0 HcmV?d00001 diff --git a/core/src/test/resources/indices/bwc/repo-2.3.3.zip b/core/src/test/resources/indices/bwc/repo-2.3.3.zip new file mode 100644 index 0000000000000000000000000000000000000000..b94020ee80082bd9d56a3c20a392d17135ba88e1 GIT binary patch literal 75600 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
AH^8C>iJG=;*fk2#5dN6!OWr8Y=i6(}P!I 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 HXaf2tRZAf3 literal 0 HcmV?d00001 From 6e3b49c522c6cfffe6b797b63315ea6391ba66e4 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Wed, 18 May 2016 12:04:46 -0400 Subject: [PATCH 10/12] Fix inequality symbol in test assertion This commit fixes the inequality symbol used in a test assertion in RepositoryS3SettingsTests#testInvalidChunkBufferSizeRepositorySettings. The inequality symbol was previously backwards but fixed in commit cad0608cdb28e2b8485e5c01c26579a35cb84356 but fixing the inequality symbol here was missed in that commit. Closes #18449 --- .../org/elasticsearch/cloud/aws/RepositoryS3SettingsTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/repository-s3/src/test/java/org/elasticsearch/cloud/aws/RepositoryS3SettingsTests.java b/plugins/repository-s3/src/test/java/org/elasticsearch/cloud/aws/RepositoryS3SettingsTests.java index c5c617e8591..4cb8e4d3abb 100644 --- a/plugins/repository-s3/src/test/java/org/elasticsearch/cloud/aws/RepositoryS3SettingsTests.java +++ b/plugins/repository-s3/src/test/java/org/elasticsearch/cloud/aws/RepositoryS3SettingsTests.java @@ -316,7 +316,7 @@ public class RepositoryS3SettingsTests extends ESTestCase { "Failed to parse value [4mb] for setting [buffer_size] must be >= 5mb"); // chunk > 5tb should fail internalTestInvalidChunkBufferSizeSettings(new ByteSizeValue(5, ByteSizeUnit.MB), new ByteSizeValue(6, ByteSizeUnit.TB), - "Failed to parse value [6tb] for setting [chunk_size] must be =< 5tb"); + "Failed to parse value [6tb] for setting [chunk_size] must be <= 5tb"); } private Settings buildSettings(Settings... global) { From ee4e470f6000fda030ad1f6d9216efec70119227 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Wed, 18 May 2016 15:10:01 -0400 Subject: [PATCH 11/12] Add a wait_for_stats=yellow to a docs snippet It was making unstable tests. --- docs/reference/query-dsl/parent-id-query.asciidoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/reference/query-dsl/parent-id-query.asciidoc b/docs/reference/query-dsl/parent-id-query.asciidoc index 713e19c26ce..a29073dafa9 100644 --- a/docs/reference/query-dsl/parent-id-query.asciidoc +++ b/docs/reference/query-dsl/parent-id-query.asciidoc @@ -28,6 +28,8 @@ PUT /my_index } } } + +GET /_cluster/health?wait_for_status=yellow ------------------------------------------ // CONSOLE // TESTSETUP @@ -73,7 +75,7 @@ This query has two required parameters: `id`:: The required parent id select documents must referrer to. -`ignore_unmapped`:: When set to `true` this will ignore an unmapped `type` and will not match any +`ignore_unmapped`:: When set to `true` this will ignore an unmapped `type` and will not match any documents for this query. This can be useful when querying multiple indexes which might have different mappings. When set to `false` (the default value) the query will throw an exception if the `type` is not mapped. From 9a9301f7d8acd94f621e4bf88522c6e58cf63af2 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Wed, 18 May 2016 23:00:57 +0200 Subject: [PATCH 12/12] Remove dead BloomFilter code We don't use this class for a quite a while. lets trash it. --- .../common/util/BloomFilter.java | 629 ------------------ 1 file changed, 629 deletions(-) delete mode 100644 core/src/main/java/org/elasticsearch/common/util/BloomFilter.java diff --git a/core/src/main/java/org/elasticsearch/common/util/BloomFilter.java b/core/src/main/java/org/elasticsearch/common/util/BloomFilter.java deleted file mode 100644 index 6c471cddb55..00000000000 --- a/core/src/main/java/org/elasticsearch/common/util/BloomFilter.java +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.elasticsearch.common.util; - -import org.apache.lucene.store.DataInput; -import org.apache.lucene.store.DataOutput; -import org.apache.lucene.store.IndexInput; -import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.hash.MurmurHash3; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.unit.SizeValue; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Comparator; - -/** - * A bloom filter. Inspired by Guava bloom filter implementation though with some optimizations. - */ -public class BloomFilter { - - /** - * A factory that can use different fpp based on size. - */ - public static class Factory { - - public static final Factory DEFAULT = buildDefault(); - - private static Factory buildDefault() { - // Some numbers: - // 10k =0.001: 140.4kb , 10 Hashes - // 10k =0.01 : 93.6kb , 6 Hashes - // 100k=0.01 : 936.0kb , 6 Hashes - // 100k=0.03 : 712.7kb , 5 Hashes - // 500k=0.01 : 4.5mb , 6 Hashes - // 500k=0.03 : 3.4mb , 5 Hashes - // 500k=0.05 : 2.9mb , 4 Hashes - // 1m=0.01 : 9.1mb , 6 Hashes - // 1m=0.03 : 6.9mb , 5 Hashes - // 1m=0.05 : 5.9mb , 4 Hashes - // 5m=0.01 : 45.7mb , 6 Hashes - // 5m=0.03 : 34.8mb , 5 Hashes - // 5m=0.05 : 29.7mb , 4 Hashes - // 50m=0.01 : 457.0mb , 6 Hashes - // 50m=0.03 : 297.3mb , 4 Hashes - // 50m=0.10 : 228.5mb , 3 Hashes - return buildFromString("10k=0.01,1m=0.03"); - } - - /** - * Supports just passing fpp, as in "0.01", and also ranges, like "50k=0.01,1m=0.05". If - * its null, returns {@link #buildDefault()}. - */ - public static Factory buildFromString(@Nullable String config) { - if (config == null) { - return buildDefault(); - } - String[] sEntries = config.split(","); - if (sEntries.length == 0) { - if (config.length() > 0) { - return new Factory(new Entry[]{new Entry(0, Double.parseDouble(config))}); - } - return buildDefault(); - } - Entry[] entries = new Entry[sEntries.length]; - for (int i = 0; i < sEntries.length; i++) { - int index = sEntries[i].indexOf('='); - entries[i] = new Entry( - (int) SizeValue.parseSizeValue(sEntries[i].substring(0, index).trim()).singles(), - Double.parseDouble(sEntries[i].substring(index + 1).trim()) - ); - } - return new Factory(entries); - } - - private final Entry[] entries; - - public Factory(Entry[] entries) { - this.entries = entries; - // the order is from the upper most expected insertions to the lowest - Arrays.sort(this.entries, new Comparator() { - @Override - public int compare(Entry o1, Entry o2) { - return o2.expectedInsertions - o1.expectedInsertions; - } - }); - } - - public BloomFilter createFilter(int expectedInsertions) { - for (Entry entry : entries) { - if (expectedInsertions > entry.expectedInsertions) { - return BloomFilter.create(expectedInsertions, entry.fpp); - } - } - return BloomFilter.create(expectedInsertions, 0.03); - } - - public static class Entry { - public final int expectedInsertions; - public final double fpp; - - Entry(int expectedInsertions, double fpp) { - this.expectedInsertions = expectedInsertions; - this.fpp = fpp; - } - } - } - - /** - * Creates a bloom filter based on the with the expected number - * of insertions and expected false positive probability. - * - * @param expectedInsertions the number of expected insertions to the constructed - * @param fpp the desired false positive probability (must be positive and less than 1.0) - */ - public static BloomFilter create(int expectedInsertions, double fpp) { - return create(expectedInsertions, fpp, -1); - } - - /** - * Creates a bloom filter based on the expected number of insertions, expected false positive probability, - * and number of hash functions. - * - * @param expectedInsertions the number of expected insertions to the constructed - * @param fpp the desired false positive probability (must be positive and less than 1.0) - * @param numHashFunctions the number of hash functions to use (must be less than or equal to 255) - */ - public static BloomFilter create(int expectedInsertions, double fpp, int numHashFunctions) { - if (expectedInsertions == 0) { - expectedInsertions = 1; - } - /* - * TODO(user): Put a warning in the javadoc about tiny fpp values, - * since the resulting size is proportional to -log(p), but there is not - * much of a point after all, e.g. optimalM(1000, 0.0000000000000001) = 76680 - * which is less that 10kb. Who cares! - */ - long numBits = optimalNumOfBits(expectedInsertions, fpp); - - // calculate the optimal number of hash functions - if (numHashFunctions == -1) { - numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits); - } - - try { - return new BloomFilter(new BitArray(numBits), numHashFunctions, Hashing.DEFAULT); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Could not create BloomFilter of " + numBits + " bits", e); - } - } - - public static void skipBloom(IndexInput in) throws IOException { - int version = in.readInt(); // we do nothing with this now..., defaults to 0 - final int numLongs = in.readInt(); - in.seek(in.getFilePointer() + (numLongs * 8) + 4 + 4); // filter + numberOfHashFunctions + hashType - } - - public static BloomFilter deserialize(DataInput in) throws IOException { - int version = in.readInt(); // we do nothing with this now..., defaults to 0 - int numLongs = in.readInt(); - long[] data = new long[numLongs]; - for (int i = 0; i < numLongs; i++) { - data[i] = in.readLong(); - } - int numberOfHashFunctions = in.readInt(); - int hashType = in.readInt(); - return new BloomFilter(new BitArray(data), numberOfHashFunctions, Hashing.fromType(hashType)); - } - - public static void serilaize(BloomFilter filter, DataOutput out) throws IOException { - out.writeInt(0); // version - BitArray bits = filter.bits; - out.writeInt(bits.data.length); - for (long l : bits.data) { - out.writeLong(l); - } - out.writeInt(filter.numHashFunctions); - out.writeInt(filter.hashing.type()); // hashType - } - - public static BloomFilter readFrom(StreamInput in) throws IOException { - int version = in.readVInt(); // we do nothing with this now..., defaults to 0 - int numLongs = in.readVInt(); - long[] data = new long[numLongs]; - for (int i = 0; i < numLongs; i++) { - data[i] = in.readLong(); - } - int numberOfHashFunctions = in.readVInt(); - int hashType = in.readVInt(); // again, nothing to do now... - return new BloomFilter(new BitArray(data), numberOfHashFunctions, Hashing.fromType(hashType)); - } - - public static void writeTo(BloomFilter filter, StreamOutput out) throws IOException { - out.writeVInt(0); // version - BitArray bits = filter.bits; - out.writeVInt(bits.data.length); - for (long l : bits.data) { - out.writeLong(l); - } - out.writeVInt(filter.numHashFunctions); - out.writeVInt(filter.hashing.type()); // hashType - } - - /** - * The bit set of the BloomFilter (not necessarily power of 2!) - */ - final BitArray bits; - /** - * Number of hashes per element - */ - final int numHashFunctions; - - final Hashing hashing; - - BloomFilter(BitArray bits, int numHashFunctions, Hashing hashing) { - this.bits = bits; - this.numHashFunctions = numHashFunctions; - this.hashing = hashing; - /* - * This only exists to forbid BFs that cannot use the compact persistent representation. - * If it ever throws, at a user who was not intending to use that representation, we should - * reconsider - */ - if (numHashFunctions > 255) { - throw new IllegalArgumentException("Currently we don't allow BloomFilters that would use more than 255 hash functions"); - } - } - - public boolean put(BytesRef value) { - return hashing.put(value, numHashFunctions, bits); - } - - public boolean mightContain(BytesRef value) { - return hashing.mightContain(value, numHashFunctions, bits); - } - - public int getNumHashFunctions() { - return this.numHashFunctions; - } - - public long getSizeInBytes() { - return bits.ramBytesUsed(); - } - - @Override - public int hashCode() { - return bits.hashCode() + numHashFunctions; - } - - /* - * Cheat sheet: - * - * m: total bits - * n: expected insertions - * b: m/n, bits per insertion - - * p: expected false positive probability - * - * 1) Optimal k = b * ln2 - * 2) p = (1 - e ^ (-kn/m))^k - * 3) For optimal k: p = 2 ^ (-k) ~= 0.6185^b - * 4) For optimal k: m = -nlnp / ((ln2) ^ 2) - */ - - /** - * Computes the optimal k (number of hashes per element inserted in Bloom filter), given the - * expected insertions and total number of bits in the Bloom filter. - *

- * See http://en.wikipedia.org/wiki/File:Bloom_filter_fp_probability.svg for the formula. - * - * @param n expected insertions (must be positive) - * @param m total number of bits in Bloom filter (must be positive) - */ - static int optimalNumOfHashFunctions(long n, long m) { - return Math.max(1, (int) Math.round(m / n * Math.log(2))); - } - - /** - * Computes m (total bits of Bloom filter) which is expected to achieve, for the specified - * expected insertions, the required false positive probability. - *

- * See http://en.wikipedia.org/wiki/Bloom_filter#Probability_of_false_positives for the formula. - * - * @param n expected insertions (must be positive) - * @param p false positive rate (must be 0 < p < 1) - */ - static long optimalNumOfBits(long n, double p) { - if (p == 0) { - p = Double.MIN_VALUE; - } - return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2))); - } - - // Note: We use this instead of java.util.BitSet because we need access to the long[] data field - static final class BitArray { - final long[] data; - final long bitSize; - long bitCount; - - BitArray(long bits) { - this(new long[size(bits)]); - } - - private static int size(long bits) { - long quotient = bits / 64; - long remainder = bits - quotient * 64; - return Math.toIntExact(remainder == 0 ? quotient : 1 + quotient); - } - - // Used by serialization - BitArray(long[] data) { - this.data = data; - long bitCount = 0; - for (long value : data) { - bitCount += Long.bitCount(value); - } - this.bitCount = bitCount; - this.bitSize = data.length * Long.SIZE; - } - - /** Returns true if the bit changed value. */ - boolean set(long index) { - if (!get(index)) { - data[(int) (index >>> 6)] |= (1L << index); - bitCount++; - return true; - } - return false; - } - - boolean get(long index) { - return (data[(int) (index >>> 6)] & (1L << index)) != 0; - } - - /** Number of bits */ - long bitSize() { - return bitSize; - } - - /** Number of set bits (1s) */ - long bitCount() { - return bitCount; - } - - BitArray copy() { - return new BitArray(data.clone()); - } - - /** Combines the two BitArrays using bitwise OR. */ - void putAll(BitArray array) { - bitCount = 0; - for (int i = 0; i < data.length; i++) { - data[i] |= array.data[i]; - bitCount += Long.bitCount(data[i]); - } - } - - @Override public boolean equals(Object o) { - if (o instanceof BitArray) { - BitArray bitArray = (BitArray) o; - return Arrays.equals(data, bitArray.data); - } - return false; - } - - @Override public int hashCode() { - return Arrays.hashCode(data); - } - - public long ramBytesUsed() { - return Long.BYTES * data.length + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER + 16; - } - } - - static enum Hashing { - - V0() { - @Override - protected boolean put(BytesRef value, int numHashFunctions, BitArray bits) { - long bitSize = bits.bitSize(); - long hash64 = hash3_x64_128(value.bytes, value.offset, value.length, 0); - int hash1 = (int) hash64; - int hash2 = (int) (hash64 >>> 32); - boolean bitsChanged = false; - for (int i = 1; i <= numHashFunctions; i++) { - int nextHash = hash1 + i * hash2; - if (nextHash < 0) { - nextHash = ~nextHash; - } - bitsChanged |= bits.set(nextHash % bitSize); - } - return bitsChanged; - } - - @Override - protected boolean mightContain(BytesRef value, int numHashFunctions, BitArray bits) { - long bitSize = bits.bitSize(); - long hash64 = hash3_x64_128(value.bytes, value.offset, value.length, 0); - int hash1 = (int) hash64; - int hash2 = (int) (hash64 >>> 32); - for (int i = 1; i <= numHashFunctions; i++) { - int nextHash = hash1 + i * hash2; - if (nextHash < 0) { - nextHash = ~nextHash; - } - if (!bits.get(nextHash % bitSize)) { - return false; - } - } - return true; - } - - @Override - protected int type() { - return 0; - } - }, - V1() { - @Override - protected boolean put(BytesRef value, int numHashFunctions, BitArray bits) { - long bitSize = bits.bitSize(); - MurmurHash3.Hash128 hash128 = MurmurHash3.hash128(value.bytes, value.offset, value.length, 0, new MurmurHash3.Hash128()); - - boolean bitsChanged = false; - long combinedHash = hash128.h1; - for (int i = 0; i < numHashFunctions; i++) { - // Make the combined hash positive and indexable - bitsChanged |= bits.set((combinedHash & Long.MAX_VALUE) % bitSize); - combinedHash += hash128.h2; - } - return bitsChanged; - } - - @Override - protected boolean mightContain(BytesRef value, int numHashFunctions, BitArray bits) { - long bitSize = bits.bitSize(); - MurmurHash3.Hash128 hash128 = MurmurHash3.hash128(value.bytes, value.offset, value.length, 0, new MurmurHash3.Hash128()); - - long combinedHash = hash128.h1; - for (int i = 0; i < numHashFunctions; i++) { - // Make the combined hash positive and indexable - if (!bits.get((combinedHash & Long.MAX_VALUE) % bitSize)) { - return false; - } - combinedHash += hash128.h2; - } - return true; - } - - @Override - protected int type() { - return 1; - } - } - ; - - protected abstract boolean put(BytesRef value, int numHashFunctions, BitArray bits); - - protected abstract boolean mightContain(BytesRef value, int numHashFunctions, BitArray bits); - - protected abstract int type(); - - public static final Hashing DEFAULT = Hashing.V1; - - public static Hashing fromType(int type) { - if (type == 0) { - return Hashing.V0; - } if (type == 1) { - return Hashing.V1; - } else { - throw new IllegalArgumentException("no hashing type matching " + type); - } - } - } - - // START : MURMUR 3_128 USED FOR Hashing.V0 - // NOTE: don't replace this code with the o.e.common.hashing.MurmurHash3 method which returns a different hash - - protected static long getblock(byte[] key, int offset, int index) { - int i_8 = index << 3; - int blockOffset = offset + i_8; - return ((long) key[blockOffset + 0] & 0xff) + (((long) key[blockOffset + 1] & 0xff) << 8) + - (((long) key[blockOffset + 2] & 0xff) << 16) + (((long) key[blockOffset + 3] & 0xff) << 24) + - (((long) key[blockOffset + 4] & 0xff) << 32) + (((long) key[blockOffset + 5] & 0xff) << 40) + - (((long) key[blockOffset + 6] & 0xff) << 48) + (((long) key[blockOffset + 7] & 0xff) << 56); - } - - protected static long rotl64(long v, int n) { - return ((v << n) | (v >>> (64 - n))); - } - - protected static long fmix(long k) { - k ^= k >>> 33; - k *= 0xff51afd7ed558ccdL; - k ^= k >>> 33; - k *= 0xc4ceb9fe1a85ec53L; - k ^= k >>> 33; - - return k; - } - - @SuppressWarnings("fallthrough") // Uses fallthrough to implement a well know hashing algorithm - public static long hash3_x64_128(byte[] key, int offset, int length, long seed) { - final int nblocks = length >> 4; // Process as 128-bit blocks. - - long h1 = seed; - long h2 = seed; - - long c1 = 0x87c37b91114253d5L; - long c2 = 0x4cf5ad432745937fL; - - //---------- - // body - - for (int i = 0; i < nblocks; i++) { - long k1 = getblock(key, offset, i * 2 + 0); - long k2 = getblock(key, offset, i * 2 + 1); - - k1 *= c1; - k1 = rotl64(k1, 31); - k1 *= c2; - h1 ^= k1; - - h1 = rotl64(h1, 27); - h1 += h2; - h1 = h1 * 5 + 0x52dce729; - - k2 *= c2; - k2 = rotl64(k2, 33); - k2 *= c1; - h2 ^= k2; - - h2 = rotl64(h2, 31); - h2 += h1; - h2 = h2 * 5 + 0x38495ab5; - } - - //---------- - // tail - - // Advance offset to the unprocessed tail of the data. - offset += nblocks * 16; - - long k1 = 0; - long k2 = 0; - - switch (length & 15) { - case 15: - k2 ^= ((long) key[offset + 14]) << 48; - case 14: - k2 ^= ((long) key[offset + 13]) << 40; - case 13: - k2 ^= ((long) key[offset + 12]) << 32; - case 12: - k2 ^= ((long) key[offset + 11]) << 24; - case 11: - k2 ^= ((long) key[offset + 10]) << 16; - case 10: - k2 ^= ((long) key[offset + 9]) << 8; - case 9: - k2 ^= ((long) key[offset + 8]) << 0; - k2 *= c2; - k2 = rotl64(k2, 33); - k2 *= c1; - h2 ^= k2; - - case 8: - k1 ^= ((long) key[offset + 7]) << 56; - case 7: - k1 ^= ((long) key[offset + 6]) << 48; - case 6: - k1 ^= ((long) key[offset + 5]) << 40; - case 5: - k1 ^= ((long) key[offset + 4]) << 32; - case 4: - k1 ^= ((long) key[offset + 3]) << 24; - case 3: - k1 ^= ((long) key[offset + 2]) << 16; - case 2: - k1 ^= ((long) key[offset + 1]) << 8; - case 1: - k1 ^= (key[offset]); - k1 *= c1; - k1 = rotl64(k1, 31); - k1 *= c2; - h1 ^= k1; - } - - //---------- - // finalization - - h1 ^= length; - h2 ^= length; - - h1 += h2; - h2 += h1; - - h1 = fmix(h1); - h2 = fmix(h2); - - h1 += h2; - h2 += h1; - - //return (new long[]{h1, h2}); - // SAME AS GUAVA, they take the first long out of the 128bit - return h1; - } - - // END: MURMUR 3_128 -}