Skip to content

Commit 93d7552

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 be connected to Elasticsearch through a proxy that injects its own warnings.
1 parent 2acb910 commit 93d7552

File tree

2 files changed

+91
-4
lines changed

2 files changed

+91
-4
lines changed

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

+82-3
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,95 @@ public HttpEntity getEntity() {
114114
"GMT" + // GMT
115115
"\")?"); // closing quote (optional, since an older version can still send a warn-date)
116116

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

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ public void testHeaders() throws IOException {
392392
public void testDeprecationWarnings() throws IOException {
393393
String chars = randomAsciiAlphanumOfLength(5);
394394
assertDeprecationWarnings(singletonList("poorly formatted " + chars), singletonList("poorly formatted " + chars));
395+
assertDeprecationWarnings(singletonList(formatWarningWithoutDate(chars)), singletonList(chars));
395396
assertDeprecationWarnings(singletonList(formatWarning(chars)), singletonList(chars));
396397
assertDeprecationWarnings(
397398
Arrays.asList(formatWarning(chars), "another one", "and another"),
@@ -401,6 +402,9 @@ public void testDeprecationWarnings() throws IOException {
401402
Arrays.asList("ignorable one", "and another"));
402403
assertDeprecationWarnings(singletonList("exact"), singletonList("exact"));
403404
assertDeprecationWarnings(Collections.<String>emptyList(), Collections.<String>emptyList());
405+
406+
String proxyWarning = "112 - \"network down\" \"Sat, 25 Aug 2012 23:34:45 GMT\"";
407+
assertDeprecationWarnings(singletonList(proxyWarning), singletonList(proxyWarning));
404408
}
405409

406410
private enum DeprecationWarningOption {
@@ -486,8 +490,12 @@ private void assertDeprecationWarnings(List<String> warningHeaderTexts, List<Str
486490
* Emulates Elasticsearch's DeprecationLogger.formatWarning in simple
487491
* cases. We don't have that available because we're testing against 1.7.
488492
*/
493+
private static String formatWarningWithoutDate(String warningBody) {
494+
return "299 Elasticsearch-1.2.2-SNAPSHOT-eeeeeee \"" + warningBody + "\"";
495+
}
496+
489497
private static String formatWarning(String warningBody) {
490-
return "299 Elasticsearch-1.2.2-SNAPSHOT-eeeeeee \"" + warningBody + "\" \"Mon, 01 Jan 2001 00:00:00 GMT\"";
498+
return formatWarningWithoutDate(warningBody) + " \"Mon, 01 Jan 2001 00:00:00 GMT\"";
491499
}
492500

493501
private HttpUriRequest performRandomRequest(String method) throws Exception {

0 commit comments

Comments
 (0)