Skip to content

Commit beae09c

Browse files
dzane17Peter Alfonsi
authored andcommitted
Handle negative search request nodes stats (opensearch-project#19340)
Signed-off-by: David Zane <[email protected]>
1 parent 004feb7 commit beae09c

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
8686
- Implement SslHandler retrieval logic for transport-reactor-netty4 plugin ([#19458](https://github.com/opensearch-project/OpenSearch/pull/19458))
8787
- Cache serialised cluster state based on cluster state version and node version.([#19307](https://github.com/opensearch-project/OpenSearch/pull/19307))
8888

89+
- Handle negative search request nodes stats ([#19340](https://github.com/opensearch-project/OpenSearch/pull/19340))
8990

9091
### Dependencies
9192
- Bump `com.gradleup.shadow:shadow-gradle-plugin` from 8.3.5 to 8.3.9 ([#19400](https://github.com/opensearch-project/OpenSearch/pull/19400))

server/src/main/java/org/opensearch/index/search/stats/SearchStats.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
package org.opensearch.index.search.stats;
3434

35+
import org.apache.logging.log4j.LogManager;
36+
import org.apache.logging.log4j.Logger;
3537
import org.opensearch.Version;
3638
import org.opensearch.action.search.SearchPhaseName;
3739
import org.opensearch.action.search.SearchRequestStats;
@@ -67,7 +69,7 @@ public class SearchStats implements Writeable, ToXContentFragment {
6769
*/
6870
@PublicApi(since = "1.0.0")
6971
public static class PhaseStatsLongHolder implements Writeable {
70-
72+
private static final Logger logger = LogManager.getLogger(PhaseStatsLongHolder.class);
7173
long current;
7274
long total;
7375
long timeInMillis;
@@ -86,7 +88,11 @@ public long getTimeInMillis() {
8688

8789
@Override
8890
public void writeTo(StreamOutput out) throws IOException {
89-
out.writeVLong(current);
91+
if (current < 0) {
92+
out.writeVLong(0);
93+
} else {
94+
out.writeVLong(current);
95+
}
9096
out.writeVLong(total);
9197
out.writeVLong(timeInMillis);
9298
}
@@ -179,7 +185,7 @@ public RequestStatsLongHolder getRequestStatsLongHolder() {
179185
return requestStatsLongHolder;
180186
}
181187

182-
private Stats() {
188+
Stats() {
183189
// for internal use, initializes all counts to 0
184190
}
185191

@@ -560,6 +566,15 @@ public void writeTo(StreamOutput out) throws IOException {
560566
if (requestStatsLongHolder == null) {
561567
requestStatsLongHolder = new RequestStatsLongHolder();
562568
}
569+
requestStatsLongHolder.requestStatsHolder.forEach((phaseName, phaseStats) -> {
570+
if (phaseStats.current < 0) {
571+
PhaseStatsLongHolder.logger.warn(
572+
"SearchRequestStats 'current' is negative for phase '{}': {}",
573+
phaseName,
574+
phaseStats.current
575+
);
576+
}
577+
});
563578
out.writeMap(
564579
requestStatsLongHolder.getRequestStatsHolder(),
565580
StreamOutput::writeString,

server/src/test/java/org/opensearch/index/search/stats/SearchStatsTests.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@
3737
import org.opensearch.action.search.SearchPhaseName;
3838
import org.opensearch.action.search.SearchRequestOperationsListenerSupport;
3939
import org.opensearch.action.search.SearchRequestStats;
40+
import org.opensearch.common.io.stream.BytesStreamOutput;
4041
import org.opensearch.common.settings.ClusterSettings;
4142
import org.opensearch.common.settings.Settings;
4243
import org.opensearch.index.search.stats.SearchStats.Stats;
4344
import org.opensearch.test.OpenSearchTestCase;
45+
import org.junit.Assert;
4446

4547
import java.util.HashMap;
4648
import java.util.Map;
@@ -162,4 +164,45 @@ private static void assertStats(Stats stats, long equalTo) {
162164
// avg_concurrency is not summed up across stats
163165
assertEquals(1, stats.getConcurrentAvgSliceCount(), 0);
164166
}
167+
168+
public void testNegativeRequestStats() throws Exception {
169+
SearchStats searchStats = new SearchStats(new Stats(), 0, new HashMap<>());
170+
171+
long paramValue = randomIntBetween(2, 50);
172+
173+
// Testing for request stats
174+
ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
175+
SearchRequestStats testRequestStats = new SearchRequestStats(clusterSettings);
176+
SearchPhaseContext ctx = mock(SearchPhaseContext.class);
177+
for (SearchPhaseName searchPhaseName : SearchPhaseName.values()) {
178+
SearchPhase mockSearchPhase = mock(SearchPhase.class);
179+
when(ctx.getCurrentPhase()).thenReturn(mockSearchPhase);
180+
when(mockSearchPhase.getStartTimeInNanos()).thenReturn(System.nanoTime() - TimeUnit.SECONDS.toNanos(paramValue));
181+
when(mockSearchPhase.getSearchPhaseNameOptional()).thenReturn(Optional.ofNullable(searchPhaseName));
182+
for (int iterator = 0; iterator < paramValue; iterator++) {
183+
onPhaseStart(testRequestStats, ctx);
184+
onPhaseEnd(testRequestStats, ctx);
185+
onPhaseEnd(testRequestStats, ctx); // call onPhaseEnd() twice to make 'current' negative
186+
}
187+
}
188+
searchStats.setSearchRequestStats(testRequestStats);
189+
for (SearchPhaseName searchPhaseName : SearchPhaseName.values()) {
190+
Assert.assertNotNull(searchStats.getTotal().getRequestStatsLongHolder());
191+
assertEquals(
192+
-1 * paramValue, // current is negative, equals -1 * paramValue (num loop iterations)
193+
searchStats.getTotal().getRequestStatsLongHolder().getRequestStatsHolder().get(searchPhaseName.getName()).current
194+
);
195+
assertEquals(
196+
2 * paramValue,
197+
searchStats.getTotal().getRequestStatsLongHolder().getRequestStatsHolder().get(searchPhaseName.getName()).total
198+
);
199+
assertThat(
200+
searchStats.getTotal().getRequestStatsLongHolder().getRequestStatsHolder().get(searchPhaseName.getName()).timeInMillis,
201+
greaterThanOrEqualTo(paramValue)
202+
);
203+
}
204+
205+
// Ensure writeTo() does not throw error with negative 'current'
206+
searchStats.writeTo(new BytesStreamOutput(10));
207+
}
165208
}

0 commit comments

Comments
 (0)