Refactor DataBufferUtils Matcher implementation

The existing implementation was exposed to very poor performance when matching
with multiple delimiters against a large buffer with many delimiters. In that
case all matchers are invoked many times (as many as the number of delimiters)
even though some of them found no match at all on the first pass.

The revised implementation uses a single index and advances all matchers
together, checking one byte a time, and not letting any one of them search to
the end of the entire buffer on a single pass.

Closes gh-25915
This commit is contained in:
Rossen Stoyanchev
2020-10-23 13:23:51 +01:00
parent 6946fe2f74
commit fb4363e4e0
2 changed files with 276 additions and 152 deletions

View File

@@ -886,18 +886,38 @@ class DataBufferUtilsTests extends AbstractDataBufferAllocatingTests {
void matcher2(String displayName, DataBufferFactory bufferFactory) {
super.bufferFactory = bufferFactory;
DataBuffer foo = stringBuffer("fooobar");
DataBuffer foo = stringBuffer("foooobar");
byte[] delims = "oo".getBytes(StandardCharsets.UTF_8);
DataBufferUtils.Matcher matcher = DataBufferUtils.matcher(delims);
int result = matcher.match(foo);
assertThat(result).isEqualTo(2);
foo.readPosition(2);
result = matcher.match(foo);
assertThat(result).isEqualTo(3);
foo.readPosition(3);
result = matcher.match(foo);
assertThat(result).isEqualTo(-1);
int endIndex = matcher.match(foo);
assertThat(endIndex).isEqualTo(2);
foo.readPosition(endIndex + 1);
endIndex = matcher.match(foo);
assertThat(endIndex).isEqualTo(4);
foo.readPosition(endIndex + 1);
endIndex = matcher.match(foo);
assertThat(endIndex).isEqualTo(-1);
release(foo);
}
@ParameterizedDataBufferAllocatingTest
void matcher3(String displayName, DataBufferFactory bufferFactory) {
super.bufferFactory = bufferFactory;
DataBuffer foo = stringBuffer("foooobar");
byte[] delims = "oo".getBytes(StandardCharsets.UTF_8);
DataBufferUtils.Matcher matcher = DataBufferUtils.matcher(delims);
int endIndex = matcher.match(foo);
assertThat(endIndex).isEqualTo(2);
foo.readPosition(endIndex + 1);
endIndex = matcher.match(foo);
assertThat(endIndex).isEqualTo(4);
foo.readPosition(endIndex + 1);
endIndex = matcher.match(foo);
assertThat(endIndex).isEqualTo(-1);
release(foo);
}