Use offset finding eol avoid repeated scaning.

Motivation:

A large frame will be componsed by many packages. Every time the package
arrived, findEndOfLine will be called from the start of the buffer. It
will cause the complexity of reading frame equal to  O(n^2). This can be
eliminated by using a offset to mark the last scan position, when new
package arrived, just find the delimter from the mark. The complexity
will be O(n).

Modification:

Add a offset to mark the last scan position.

Result:

Better performance for read large frame.
This commit is contained in:
Jackie.Meng 2017-09-13 16:40:33 +08:00 committed by Norman Maurer
parent 282aa35682
commit 80b8a91b70
2 changed files with 32 additions and 4 deletions

View File

@ -39,6 +39,9 @@ public class LineBasedFrameDecoder extends ByteToMessageDecoder {
private boolean discarding;
private int discardedBytes;
/** Last scan position. */
private int offset;
/**
* Creates a new decoder.
* @param maxLength the maximum length of the decoded frame.
@ -114,6 +117,7 @@ public class LineBasedFrameDecoder extends ByteToMessageDecoder {
discardedBytes = length;
buffer.readerIndex(buffer.writerIndex());
discarding = true;
offset = 0;
if (failFast) {
fail(ctx, "over " + discardedBytes);
}
@ -152,10 +156,16 @@ public class LineBasedFrameDecoder extends ByteToMessageDecoder {
* Returns the index in the buffer of the end of line found.
* Returns -1 if no end of line was found in the buffer.
*/
private static int findEndOfLine(final ByteBuf buffer) {
int i = buffer.forEachByte(ByteProcessor.FIND_LF);
if (i > 0 && buffer.getByte(i - 1) == '\r') {
i--;
private int findEndOfLine(final ByteBuf buffer) {
int totalLength = buffer.readableBytes();
int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);
if (i >= 0) {
offset = 0;
if (i > 0 && buffer.getByte(i - 1) == '\r') {
i--;
}
} else {
offset = totalLength;
}
return i;
}

View File

@ -167,4 +167,22 @@ public class LineBasedFrameDecoderTest {
buf.release();
buf2.release();
}
@Test
public void testEmptyLine() throws Exception {
EmbeddedChannel ch = new EmbeddedChannel(new LineBasedFrameDecoder(8192, true, false));
assertTrue(ch.writeInbound(copiedBuffer("\nabcna\r\n", CharsetUtil.US_ASCII)));
ByteBuf buf = ch.readInbound();
assertEquals("", buf.toString(CharsetUtil.US_ASCII));
ByteBuf buf2 = ch.readInbound();
assertEquals("abcna", buf2.toString(CharsetUtil.US_ASCII));
assertFalse(ch.finishAndReleaseAll());
buf.release();
buf2.release();
}
}