Skip to content

Commit d1bde0a

Browse files
darrenfoongjasontedor
authored andcommitted
Improve warning value extraction performance in Response (#50208)
This commit improves the performance of warning value extraction in the low-level REST client, and is similar to the approach taken in #24114. There are some differences since the low-level REST client might be connected to Elasticsearch through a proxy that injects its own warnings.
1 parent 1a32d71 commit d1bde0a

File tree

2 files changed

+92
-5
lines changed

2 files changed

+92
-5
lines changed

client/rest/src/main/java/org/elasticsearch/client/Response.java

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,95 @@ public HttpEntity getEntity() {
116116
"GMT" + // GMT
117117
"\")?"); // closing quote (optional, since an older version can still send a warn-date)
118118

119+
/**
120+
* Optimized regular expression to test if a string matches the RFC 1123 date
121+
* format (with quotes and leading space). Start/end of line characters and
122+
* atomic groups are used to prevent backtracking.
123+
*/
124+
private static final Pattern WARNING_HEADER_DATE_PATTERN = Pattern.compile(
125+
"^ " + // start of line, leading space
126+
// quoted RFC 1123 date format
127+
"\"" + // opening quote
128+
"(?>Mon|Tue|Wed|Thu|Fri|Sat|Sun), " + // day of week, atomic group to prevent backtracking
129+
"\\d{2} " + // 2-digit day
130+
"(?>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " + // month, atomic group to prevent backtracking
131+
"\\d{4} " + // 4-digit year
132+
"\\d{2}:\\d{2}:\\d{2} " + // (two-digit hour):(two-digit minute):(two-digit second)
133+
"GMT" + // GMT
134+
"\"$"); // closing quote (optional, since an older version can still send a warn-date), end of line
135+
136+
/**
137+
* Length of RFC 1123 format (with quotes and leading space), used in
138+
* matchWarningHeaderPatternByPrefix(String).
139+
*/
140+
private static final int WARNING_HEADER_DATE_LENGTH = 0
141+
+ 1
142+
+ 1
143+
+ 3 + 1 + 1
144+
+ 2 + 1
145+
+ 3 + 1
146+
+ 4 + 1
147+
+ 2 + 1 + 2 + 1 + 2 + 1
148+
+ 3
149+
+ 1;
150+
151+
/**
152+
* Tests if a string matches the RFC 7234 specification for warning headers.
153+
* This assumes that the warn code is always 299 and the warn agent is always
154+
* Elasticsearch.
155+
*
156+
* @param s the value of a warning header formatted according to RFC 7234
157+
* @return {@code true} if the input string matches the specification
158+
*/
159+
private static boolean matchWarningHeaderPatternByPrefix(final String s) {
160+
return s.startsWith("299 Elasticsearch-");
161+
}
162+
163+
/**
164+
* Refer to org.elasticsearch.common.logging.DeprecationLogger
165+
*/
166+
private static String extractWarningValueFromWarningHeader(final String s) {
167+
String warningHeader = s;
168+
169+
/*
170+
* The following block tests for the existence of a RFC 1123 date in the warning header. If the date exists, it is removed for
171+
* extractWarningValueFromWarningHeader(String) to work properly (as it does not handle dates).
172+
*/
173+
if (s.length() > WARNING_HEADER_DATE_LENGTH) {
174+
final String possibleDateString = s.substring(s.length() - WARNING_HEADER_DATE_LENGTH);
175+
final Matcher matcher = WARNING_HEADER_DATE_PATTERN.matcher(possibleDateString);
176+
177+
if (matcher.matches()) {
178+
warningHeader = warningHeader.substring(0, s.length() - WARNING_HEADER_DATE_LENGTH);
179+
}
180+
}
181+
182+
final int firstQuote = warningHeader.indexOf('\"');
183+
final int lastQuote = warningHeader.length() - 1;
184+
final String warningValue = warningHeader.substring(firstQuote + 1, lastQuote);
185+
assert assertWarningValue(s, warningValue);
186+
return warningValue;
187+
}
188+
189+
/**
190+
* Refer to org.elasticsearch.common.logging.DeprecationLogger
191+
*/
192+
private static boolean assertWarningValue(final String s, final String warningValue) {
193+
final Matcher matcher = WARNING_HEADER_PATTERN.matcher(s);
194+
final boolean matches = matcher.matches();
195+
assert matches;
196+
return matcher.group(1).equals(warningValue);
197+
}
198+
119199
/**
120200
* Returns a list of all warning headers returned in the response.
121201
*/
122202
public List<String> getWarnings() {
123203
List<String> warnings = new ArrayList<>();
124204
for (Header header : response.getHeaders("Warning")) {
125205
String warning = header.getValue();
126-
final Matcher matcher = WARNING_HEADER_PATTERN.matcher(warning);
127-
if (matcher.matches()) {
128-
warnings.add(matcher.group(1));
206+
if (matchWarningHeaderPatternByPrefix(warning)) {
207+
warnings.add(extractWarningValueFromWarningHeader(warning));
129208
} else {
130209
warnings.add(warning);
131210
}

client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostTests.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ public void testHeaders() throws Exception {
424424
public void testDeprecationWarnings() throws Exception {
425425
String chars = randomAsciiAlphanumOfLength(5);
426426
assertDeprecationWarnings(singletonList("poorly formatted " + chars), singletonList("poorly formatted " + chars));
427+
assertDeprecationWarnings(singletonList(formatWarningWithoutDate(chars)), singletonList(chars));
427428
assertDeprecationWarnings(singletonList(formatWarning(chars)), singletonList(chars));
428429
assertDeprecationWarnings(
429430
Arrays.asList(formatWarning(chars), "another one", "and another"),
@@ -433,6 +434,9 @@ public void testDeprecationWarnings() throws Exception {
433434
Arrays.asList("ignorable one", "and another"));
434435
assertDeprecationWarnings(singletonList("exact"), singletonList("exact"));
435436
assertDeprecationWarnings(Collections.<String>emptyList(), Collections.<String>emptyList());
437+
438+
String proxyWarning = "112 - \"network down\" \"Sat, 25 Aug 2012 23:34:45 GMT\"";
439+
assertDeprecationWarnings(singletonList(proxyWarning), singletonList(proxyWarning));
436440
}
437441

438442
private enum DeprecationWarningOption {
@@ -518,9 +522,13 @@ private void assertDeprecationWarnings(List<String> warningHeaderTexts, List<Str
518522
* Emulates Elasticsearch's DeprecationLogger.formatWarning in simple
519523
* cases. We don't have that available because we're testing against 1.7.
520524
*/
521-
private static String formatWarning(String warningBody) {
525+
private static String formatWarningWithoutDate(String warningBody) {
522526
final String hash = new String(new byte[40], StandardCharsets.UTF_8).replace('\0', 'e');
523-
return "299 Elasticsearch-1.2.2-SNAPSHOT-" + hash + " \"" + warningBody + "\" \"Mon, 01 Jan 2001 00:00:00 GMT\"";
527+
return "299 Elasticsearch-1.2.2-SNAPSHOT-" + hash + " \"" + warningBody + "\"";
528+
}
529+
530+
private static String formatWarning(String warningBody) {
531+
return formatWarningWithoutDate(warningBody) + " \"Mon, 01 Jan 2001 00:00:00 GMT\"";
524532
}
525533

526534
private HttpUriRequest performRandomRequest(String method) throws Exception {

0 commit comments

Comments
 (0)