diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e65dbdf29b1f..0473a086d91eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Add min, max, average and thread info to resource stats in tasks API ([#7673](https://github.com/opensearch-project/OpenSearch/pull/7673)) - Compress and cache cluster state during validate join request ([#7321](https://github.com/opensearch-project/OpenSearch/pull/7321)) - [Snapshot Interop] Add Changes in Create Snapshot Flow for remote store interoperability. ([#7118](https://github.com/opensearch-project/OpenSearch/pull/7118)) +- Add new query profile collector fields with concurrent search execution ([#7898](https://github.com/opensearch-project/OpenSearch/pull/7898)) ### Deprecated diff --git a/server/src/main/java/org/opensearch/search/profile/query/CollectorResult.java b/server/src/main/java/org/opensearch/search/profile/query/CollectorResult.java index f345fe8b9a427..a624cbc0bb7d6 100644 --- a/server/src/main/java/org/opensearch/search/profile/query/CollectorResult.java +++ b/server/src/main/java/org/opensearch/search/profile/query/CollectorResult.java @@ -32,6 +32,7 @@ package org.opensearch.search.profile.query; +import org.opensearch.Version; import org.opensearch.core.ParseField; import org.opensearch.common.io.stream.StreamInput; import org.opensearch.common.io.stream.StreamOutput; @@ -66,11 +67,17 @@ public class CollectorResult implements ToXContentObject, Writeable { public static final String REASON_SEARCH_MULTI = "search_multi"; public static final String REASON_AGGREGATION = "aggregation"; public static final String REASON_AGGREGATION_GLOBAL = "aggregation_global"; + public static final String COLLECTOR_MANAGER = "CollectorManager"; private static final ParseField NAME = new ParseField("name"); private static final ParseField REASON = new ParseField("reason"); private static final ParseField TIME = new ParseField("time"); private static final ParseField TIME_NANOS = new ParseField("time_in_nanos"); + private static final ParseField REDUCE_TIME_NANOS = new ParseField("reduce_time_in_nanos"); + private static final ParseField MAX_SLICE_TIME_NANOS = new ParseField("max_slice_time_in_nanos"); + private static final ParseField MIN_SLICE_TIME_IN_NANOS = new ParseField("min_slice_time_in_nanos"); + private static final ParseField AVG_SLICE_TIME_IN_NANOS = new ParseField("avg_slice_time_in_nanos"); + private static final ParseField SLICE_COUNT = new ParseField("slice_count"); private static final ParseField CHILDREN = new ParseField("children"); /** @@ -86,17 +93,61 @@ public class CollectorResult implements ToXContentObject, Writeable { /** * The total elapsed time for this Collector */ - private final Long time; + private final long time; + + /** + * The total elapsed time in reduce phase for this CollectorManager + */ + private final long reduceTime; + + /** + * The maximum slice time for this CollectorManager + */ + private final long maxSliceTime; + + /** + * The minimum slice time for this CollectorManager + */ + private final long minSliceTime; + + /** + * The average slice time for this CollectorManager + */ + private final long avgSliceTime; + + /** + * The segment slice count for this CollectorManager + */ + private final int sliceCount; /** * A list of children collectors "embedded" inside this collector */ private List children; - public CollectorResult(String collectorName, String reason, Long time, List children) { + public CollectorResult(String collectorName, String reason, long time, List children) { + this(collectorName, reason, time, 0L, time, time, time, 1, children); + } + + public CollectorResult( + String collectorName, + String reason, + long time, + long reduceTime, + long maxSliceTime, + long minSliceTime, + long avgSliceTime, + int sliceCount, + List children + ) { this.collectorName = collectorName; this.reason = reason; this.time = time; + this.reduceTime = reduceTime; + this.maxSliceTime = maxSliceTime; + this.minSliceTime = minSliceTime; + this.avgSliceTime = avgSliceTime; + this.sliceCount = sliceCount; this.children = children; } @@ -113,6 +164,19 @@ public CollectorResult(StreamInput in) throws IOException { CollectorResult child = new CollectorResult(in); this.children.add(child); } + if (in.getVersion().onOrAfter(Version.V_3_0_0)) { + this.reduceTime = in.readLong(); + this.maxSliceTime = in.readLong(); + this.minSliceTime = in.readLong(); + this.avgSliceTime = in.readLong(); + this.sliceCount = in.readVInt(); + } else { + this.reduceTime = 0L; + this.maxSliceTime = this.time; + this.minSliceTime = this.time; + this.avgSliceTime = this.time; + this.sliceCount = 1; + } } @Override @@ -124,31 +188,73 @@ public void writeTo(StreamOutput out) throws IOException { for (CollectorResult child : children) { child.writeTo(out); } + if (out.getVersion().onOrAfter(Version.V_3_0_0)) { + out.writeLong(reduceTime); + out.writeLong(maxSliceTime); + out.writeLong(minSliceTime); + out.writeLong(avgSliceTime); + out.writeVInt(sliceCount); + } } /** - * @return the profiled time for this collector (inclusive of children) + * @return the profiled time for this collector/collector manager (inclusive of children) */ public long getTime() { return this.time; } /** - * @return a human readable "hint" about what this collector was used for + * @return the profiled reduce time for this collector manager (inclusive of children) + */ + public long getReduceTime() { + return this.reduceTime; + } + + /** + * @return the profiled maximum slice time for this collector manager (inclusive of children) + */ + public long getMaxSliceTime() { + return this.maxSliceTime; + } + + /** + * @return the profiled minimum slice time for this collector manager (inclusive of children) + */ + public long getMinSliceTime() { + return this.minSliceTime; + } + + /** + * @return the profiled average slice time for this collector manager (inclusive of children) + */ + public long getAvgSliceTime() { + return this.avgSliceTime; + } + + /** + * @return the profiled segment slice count for this collector manager (inclusive of children) + */ + public int getSliceCount() { + return this.sliceCount; + } + + /** + * @return a human readable "hint" about what this collector/collector manager was used for */ public String getReason() { return this.reason; } /** - * @return the lucene class name of the collector + * @return the lucene class name of the collector/collector manager */ public String getName() { return this.collectorName; } /** - * @return a list of children collectors + * @return a list of children collectors/collector managers */ public List getProfiledChildren() { return children; @@ -163,6 +269,13 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par builder.field(TIME.getPreferredName(), new TimeValue(getTime(), TimeUnit.NANOSECONDS).toString()); } builder.field(TIME_NANOS.getPreferredName(), getTime()); + if (getName().contains(COLLECTOR_MANAGER)) { + builder.field(REDUCE_TIME_NANOS.getPreferredName(), getReduceTime()); + builder.field(MAX_SLICE_TIME_NANOS.getPreferredName(), getMaxSliceTime()); + builder.field(MIN_SLICE_TIME_IN_NANOS.getPreferredName(), getMinSliceTime()); + builder.field(AVG_SLICE_TIME_IN_NANOS.getPreferredName(), getAvgSliceTime()); + builder.field(SLICE_COUNT.getPreferredName(), getSliceCount()); + } if (!children.isEmpty()) { builder = builder.startArray(CHILDREN.getPreferredName()); @@ -181,6 +294,11 @@ public static CollectorResult fromXContent(XContentParser parser) throws IOExcep String currentFieldName = null; String name = null, reason = null; long time = -1; + long reduceTime = -1; + long maxSliceTime = -1; + long minSliceTime = -1; + long avgSliceTime = -1; + int sliceCount = 0; List children = new ArrayList<>(); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { @@ -195,6 +313,16 @@ public static CollectorResult fromXContent(XContentParser parser) throws IOExcep parser.text(); } else if (TIME_NANOS.match(currentFieldName, parser.getDeprecationHandler())) { time = parser.longValue(); + } else if (REDUCE_TIME_NANOS.match(currentFieldName, parser.getDeprecationHandler())) { + reduceTime = parser.longValue(); + } else if (MAX_SLICE_TIME_NANOS.match(currentFieldName, parser.getDeprecationHandler())) { + maxSliceTime = parser.longValue(); + } else if (MIN_SLICE_TIME_IN_NANOS.match(currentFieldName, parser.getDeprecationHandler())) { + minSliceTime = parser.longValue(); + } else if (AVG_SLICE_TIME_IN_NANOS.match(currentFieldName, parser.getDeprecationHandler())) { + avgSliceTime = parser.longValue(); + } else if (SLICE_COUNT.match(currentFieldName, parser.getDeprecationHandler())) { + sliceCount = parser.intValue(); } else { parser.skipChildren(); } @@ -210,6 +338,6 @@ public static CollectorResult fromXContent(XContentParser parser) throws IOExcep parser.skipChildren(); } } - return new CollectorResult(name, reason, time, children); + return new CollectorResult(name, reason, time, reduceTime, maxSliceTime, minSliceTime, avgSliceTime, sliceCount, children); } } diff --git a/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollector.java b/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollector.java index 1300782ae1194..8b860c3a58cea 100644 --- a/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollector.java +++ b/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollector.java @@ -87,6 +87,13 @@ public long getTime() { return collector.getTime(); } + /** + * @return the profiled start time for this collector (inclusive of children) + */ + public long getSliceStartTime() { + return collector.getSliceStartTime(); + } + /** * @return a human readable "hint" about what this collector was used for */ diff --git a/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollectorManager.java b/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollectorManager.java index 2732b2ccffc79..074738d2491ec 100644 --- a/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollectorManager.java +++ b/server/src/main/java/org/opensearch/search/profile/query/InternalProfileCollectorManager.java @@ -31,6 +31,13 @@ public class InternalProfileCollectorManager private final String reason; private final List children; private long time = 0; + private long reduceTime = 0; + private long maxSliceEndTime = Long.MIN_VALUE; + private long minSliceStartTime = Long.MAX_VALUE; + private long maxSliceTime = 0; + private long minSliceTime = Long.MAX_VALUE; + private long avgSliceTime = 0; + private int sliceCount = 0; public InternalProfileCollectorManager( CollectorManager manager, @@ -50,14 +57,27 @@ public InternalProfileCollector newCollector() throws IOException { @SuppressWarnings("unchecked") @Override public ReduceableSearchResult reduce(Collection collectors) throws IOException { - final Collection subs = new ArrayList<>(); + final long reduceStart = System.nanoTime(); + try { + final Collection subs = new ArrayList<>(); - for (final InternalProfileCollector collector : collectors) { - subs.add(collector.getCollector()); - time += collector.getTime(); + for (final InternalProfileCollector collector : collectors) { + subs.add(collector.getCollector()); + maxSliceEndTime = Math.max(maxSliceEndTime, collector.getSliceStartTime() + collector.getTime()); + minSliceStartTime = Math.min(minSliceStartTime, collector.getSliceStartTime()); + maxSliceTime = Math.max(maxSliceTime, collector.getTime()); + minSliceTime = Math.min(minSliceTime, collector.getTime()); + avgSliceTime += collector.getTime(); + } + time = maxSliceEndTime - minSliceStartTime; + sliceCount = collectors.size(); + avgSliceTime = sliceCount == 0 ? 0 : avgSliceTime / sliceCount; + + return ((CollectorManager) manager).reduce(subs); + } finally { + reduceTime = Math.max(1, System.nanoTime() - reduceStart); } - return ((CollectorManager) manager).reduce(subs); } @Override @@ -70,6 +90,26 @@ public long getTime() { return time; } + public long getReduceTime() { + return reduceTime; + } + + public long getMaxSliceTime() { + return maxSliceTime; + } + + public long getMinSliceTime() { + return minSliceTime; + } + + public long getAvgSliceTime() { + return avgSliceTime; + } + + public int getSliceCount() { + return sliceCount; + } + @Override public Collection children() { return children; @@ -82,7 +122,26 @@ public String getName() { @Override public CollectorResult getCollectorTree() { - return InternalProfileCollector.doGetCollectorTree(this); + return doGetCollectorManagerTree(this); + } + + static CollectorResult doGetCollectorManagerTree(InternalProfileCollectorManager collector) { + List childResults = new ArrayList<>(collector.children().size()); + for (InternalProfileComponent child : collector.children()) { + CollectorResult result = doGetCollectorManagerTree((InternalProfileCollectorManager) child); + childResults.add(result); + } + return new CollectorResult( + collector.getName(), + collector.getReason(), + collector.getTime(), + collector.getReduceTime(), + collector.getMaxSliceTime(), + collector.getMinSliceTime(), + collector.getAvgSliceTime(), + collector.getSliceCount(), + childResults + ); } @Override diff --git a/server/src/main/java/org/opensearch/search/profile/query/ProfileCollector.java b/server/src/main/java/org/opensearch/search/profile/query/ProfileCollector.java index 837145c287faf..198b1586a7c58 100644 --- a/server/src/main/java/org/opensearch/search/profile/query/ProfileCollector.java +++ b/server/src/main/java/org/opensearch/search/profile/query/ProfileCollector.java @@ -50,6 +50,8 @@ final class ProfileCollector extends FilterCollector { private long time; + private long sliceStartTime; + private boolean isStarted; /** Sole constructor. */ ProfileCollector(Collector in) { @@ -67,6 +69,10 @@ public ScoreMode scoreMode() { try { return super.scoreMode(); } finally { + if (isStarted == false) { + sliceStartTime = start; + isStarted = true; + } time += Math.max(1, System.nanoTime() - start); } } @@ -78,6 +84,10 @@ public LeafCollector getLeafCollector(LeafReaderContext context) throws IOExcept try { inLeafCollector = super.getLeafCollector(context); } finally { + if (isStarted == false) { + sliceStartTime = start; + isStarted = true; + } time += Math.max(1, System.nanoTime() - start); } return new FilterLeafCollector(inLeafCollector) { @@ -109,4 +119,8 @@ public long getTime() { return time; } + /** Return the start time on this collector. */ + public long getSliceStartTime() { + return sliceStartTime; + } } diff --git a/server/src/test/java/org/opensearch/search/profile/query/CollectorResultTests.java b/server/src/test/java/org/opensearch/search/profile/query/CollectorResultTests.java index 29e9d0a4ef013..6cdcf3a9690c9 100644 --- a/server/src/test/java/org/opensearch/search/profile/query/CollectorResultTests.java +++ b/server/src/test/java/org/opensearch/search/profile/query/CollectorResultTests.java @@ -53,7 +53,7 @@ public class CollectorResultTests extends OpenSearchTestCase { - public static CollectorResult createTestItem(int depth) { + public static CollectorResult createTestItem(int depth, boolean concurrentSearchEnabled) { String name = randomAlphaOfLengthBetween(5, 10); String reason = randomAlphaOfLengthBetween(5, 10); long time = randomNonNegativeLong(); @@ -61,26 +61,47 @@ public static CollectorResult createTestItem(int depth) { // also often use relatively "small" values, otherwise we will mostly test huge longs time = time % 100000; } + long reduceTime = time; + long maxSliceTime = time; + long minSliceTime = time; + long avgSliceTime = time; + int sliceCount = randomIntBetween(1, 10); int size = randomIntBetween(0, 5); List children = new ArrayList<>(size); if (depth > 0) { for (int i = 0; i < size; i++) { - children.add(createTestItem(depth - 1)); + children.add(createTestItem(depth - 1, concurrentSearchEnabled)); } } + + if (concurrentSearchEnabled) { + return new CollectorResult( + "defaultCollectorManager", + "some reason", + time, + reduceTime, + maxSliceTime, + minSliceTime, + avgSliceTime, + sliceCount, + children + ); + } return new CollectorResult(name, reason, time, children); } public void testFromXContent() throws IOException { - doFromXContentTestWithRandomFields(false); + doFromXContentTestWithRandomFields(false, false); + doFromXContentTestWithRandomFields(false, true); } public void testFromXContentWithRandomFields() throws IOException { - doFromXContentTestWithRandomFields(true); + doFromXContentTestWithRandomFields(true, false); + doFromXContentTestWithRandomFields(true, true); } - private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException { - CollectorResult collectorResult = createTestItem(1); + private void doFromXContentTestWithRandomFields(boolean addRandomFields, boolean concurrentSearchEnabled) throws IOException { + CollectorResult collectorResult = createTestItem(1, concurrentSearchEnabled); XContentType xContentType = randomFrom(XContentType.values()); boolean humanReadable = randomBoolean(); BytesReference originalBytes = toShuffledXContent(collectorResult, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); @@ -177,5 +198,33 @@ public void testToXContent() throws IOException { + "}", Strings.toString(builder) ); + + result = new CollectorResult( + "defaultCollectorManager", + "some reason", + 123456789L, + 123456789L, + 123456789L, + 123456789L, + 123456789L, + 3, + Collections.emptyList() + ); + builder = XContentFactory.jsonBuilder().prettyPrint().humanReadable(true); + result.toXContent(builder, ToXContent.EMPTY_PARAMS); + assertEquals( + "{\n" + + " \"name\" : \"defaultCollectorManager\",\n" + + " \"reason\" : \"some reason\",\n" + + " \"time\" : \"123.4ms\",\n" + + " \"time_in_nanos\" : 123456789,\n" + + " \"reduce_time_in_nanos\" : 123456789,\n" + + " \"max_slice_time_in_nanos\" : 123456789,\n" + + " \"min_slice_time_in_nanos\" : 123456789,\n" + + " \"avg_slice_time_in_nanos\" : 123456789,\n" + + " \"slice_count\" : 3\n" + + "}", + Strings.toString(builder) + ); } } diff --git a/server/src/test/java/org/opensearch/search/profile/query/QueryProfileShardResultTests.java b/server/src/test/java/org/opensearch/search/profile/query/QueryProfileShardResultTests.java index 39fd8a4480415..a878acc8868c3 100644 --- a/server/src/test/java/org/opensearch/search/profile/query/QueryProfileShardResultTests.java +++ b/server/src/test/java/org/opensearch/search/profile/query/QueryProfileShardResultTests.java @@ -56,7 +56,7 @@ public static QueryProfileShardResult createTestItem() { for (int i = 0; i < size; i++) { queryProfileResults.add(ProfileResultTests.createTestItem(1)); } - CollectorResult profileCollector = CollectorResultTests.createTestItem(2); + CollectorResult profileCollector = CollectorResultTests.createTestItem(2, false); long rewriteTime = randomNonNegativeLong(); if (randomBoolean()) { rewriteTime = rewriteTime % 1000; // make sure to often test this with small values too diff --git a/server/src/test/java/org/opensearch/search/profile/query/QueryProfilerTests.java b/server/src/test/java/org/opensearch/search/profile/query/QueryProfilerTests.java index 81c6612875e46..8a8700d853ad7 100644 --- a/server/src/test/java/org/opensearch/search/profile/query/QueryProfilerTests.java +++ b/server/src/test/java/org/opensearch/search/profile/query/QueryProfilerTests.java @@ -238,14 +238,19 @@ public void testCollector() throws IOException { TotalHitCountCollector collector = new TotalHitCountCollector(); ProfileCollector profileCollector = new ProfileCollector(collector); assertEquals(0, profileCollector.getTime()); + assertEquals(0, profileCollector.getSliceStartTime()); final LeafCollector leafCollector = profileCollector.getLeafCollector(reader.leaves().get(0)); assertThat(profileCollector.getTime(), greaterThan(0L)); + assertThat(profileCollector.getSliceStartTime(), greaterThan(0L)); long time = profileCollector.getTime(); + long sliceStartTime = profileCollector.getSliceStartTime(); leafCollector.setScorer(null); assertThat(profileCollector.getTime(), greaterThan(time)); + assertEquals(sliceStartTime, profileCollector.getSliceStartTime()); time = profileCollector.getTime(); leafCollector.collect(0); assertThat(profileCollector.getTime(), greaterThan(time)); + assertEquals(sliceStartTime, profileCollector.getSliceStartTime()); } private static class DummyQuery extends Query { diff --git a/server/src/test/java/org/opensearch/search/query/QueryProfilePhaseTests.java b/server/src/test/java/org/opensearch/search/query/QueryProfilePhaseTests.java index 5bd2cd5ee8beb..b1fc5f1354039 100644 --- a/server/src/test/java/org/opensearch/search/query/QueryProfilePhaseTests.java +++ b/server/src/test/java/org/opensearch/search/query/QueryProfilePhaseTests.java @@ -161,6 +161,13 @@ public void testPostFilterDisablesCountOptimization() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -171,9 +178,23 @@ public void testPostFilterDisablesCountOptimization() throws Exception { assertProfileData(context, collector -> { assertThat(collector.getReason(), equalTo("search_post_filter")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_count")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }, (query) -> { assertThat(query.getQueryName(), equalTo("MatchNoDocsQuery")); assertThat(query.getTimeBreakdown().keySet(), not(empty())); @@ -224,12 +245,33 @@ public void testTerminateAfterWithFilter() throws Exception { assertProfileData(context, collector -> { assertThat(collector.getReason(), equalTo("search_post_filter")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_terminate_after_count")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren().get(0).getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getProfiledChildren().get(0).getReason(), equalTo("search_top_hits")); assertThat(collector.getProfiledChildren().get(0).getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }, (query) -> { assertThat(query.getQueryName(), equalTo("TermQuery")); assertThat(query.getTimeBreakdown().keySet(), not(empty())); @@ -277,6 +319,13 @@ public void testMinScoreDisablesCountOptimization() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -293,9 +342,23 @@ public void testMinScoreDisablesCountOptimization() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_min_score")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_count")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); reader.close(); @@ -338,6 +401,13 @@ public void testInOrderScrollOptimization() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -359,6 +429,13 @@ public void testInOrderScrollOptimization() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(0)); }); @@ -404,9 +481,23 @@ public void testTerminateAfterEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_terminate_after_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_top_hits")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); context.setSize(0); @@ -425,9 +516,23 @@ public void testTerminateAfterEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_terminate_after_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_count")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); } @@ -446,9 +551,23 @@ public void testTerminateAfterEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_terminate_after_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_top_hits")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); } { @@ -481,9 +600,23 @@ public void testTerminateAfterEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_terminate_after_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_top_hits")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); context.setSize(0); context.parsedQuery(new ParsedQuery(bq)); @@ -529,9 +662,23 @@ public void testTerminateAfterEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_terminate_after_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_count")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); } @@ -571,9 +718,23 @@ public void testTerminateAfterEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_terminate_after_count")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_top_hits")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); } @@ -624,6 +785,13 @@ public void testIndexSortingEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -638,9 +806,23 @@ public void testIndexSortingEarlyTermination() throws Exception { assertProfileData(context, collector -> { assertThat(collector.getReason(), equalTo("search_post_filter")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_top_hits")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }, (query) -> { assertThat(query.getQueryName(), equalTo("MinDocQuery")); assertThat(query.getTimeBreakdown().keySet(), not(empty())); @@ -680,6 +862,13 @@ public void testIndexSortingEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -699,6 +888,13 @@ public void testIndexSortingEarlyTermination() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); } @@ -756,6 +952,13 @@ public void testIndexSortScrollOptimization() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -785,6 +988,13 @@ public void testIndexSortScrollOptimization() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); FieldDoc firstDoc = (FieldDoc) context.queryResult().topDocs().topDocs.scoreDocs[0]; @@ -848,6 +1058,13 @@ public void testDisableTopScoreCollection() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -869,6 +1086,13 @@ public void testDisableTopScoreCollection() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -924,9 +1148,23 @@ public void testMinScore() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_min_score")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), hasSize(1)); assertThat(collector.getProfiledChildren().get(0).getReason(), equalTo("search_top_hits")); assertThat(collector.getProfiledChildren().get(0).getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getProfiledChildren().get(0).getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getProfiledChildren().get(0).getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getProfiledChildren().get(0).getSliceCount(), greaterThanOrEqualTo(1)); }); reader.close(); @@ -987,6 +1225,13 @@ public void testMaxScore() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -1015,6 +1260,13 @@ public void testMaxScore() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -1068,6 +1320,13 @@ public void testCollapseQuerySearchResults() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); }); @@ -1088,6 +1347,13 @@ public void testCollapseQuerySearchResults() throws Exception { }, collector -> { assertThat(collector.getReason(), equalTo("search_top_hits")); assertThat(collector.getTime(), greaterThan(0L)); + if (collector.getName().contains("CollectorManager")) { + assertThat(collector.getReduceTime(), greaterThan(0L)); + } + assertThat(collector.getMaxSliceTime(), greaterThan(0L)); + assertThat(collector.getMinSliceTime(), greaterThan(0L)); + assertThat(collector.getAvgSliceTime(), greaterThan(0L)); + assertThat(collector.getSliceCount(), greaterThanOrEqualTo(1)); assertThat(collector.getProfiledChildren(), empty()); });