Skip to content

Commit

Permalink
Apply appropriate methods for writing CharSequence into ByteBuf
Browse files Browse the repository at this point in the history
Motivation:

1. `ByteBuf` contains methods to writing `CharSequence` which optimized for UTF-8 and ASCII encodings. We can also apply optimization for ISO-8859-1.
2. In many places appropriate methods are not used.

Modifications:

1. Apply optimization for ISO-8859-1 encoding in the `ByteBuf#setCharSequence` realizations.
2. Apply appropriate methods for writing `CharSequences` into buffers.

Result:

Reduce overhead from string-to-bytes conversion.
  • Loading branch information
fenik17 authored and normanmaurer committed Jun 27, 2017
1 parent 322fe8e commit ba3616d
Show file tree
Hide file tree
Showing 18 changed files with 74 additions and 105 deletions.
2 changes: 1 addition & 1 deletion buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ public int setCharSequence(int index, CharSequence sequence, Charset charset) {
ensureWritable(ByteBufUtil.utf8MaxBytes(sequence));
return ByteBufUtil.writeUtf8(this, index, sequence, sequence.length());
}
if (charset.equals(CharsetUtil.US_ASCII)) {
if (charset.equals(CharsetUtil.US_ASCII) || charset.equals(CharsetUtil.ISO_8859_1)) {
int len = sequence.length();
ensureWritable(len);
return ByteBufUtil.writeAscii(this, index, sequence, len);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ public int setCharSequence(int index, CharSequence sequence, Charset charset) {
checkIndex0(index, ByteBufUtil.utf8MaxBytes(sequence));
return ByteBufUtil.writeUtf8(this, idx(index), sequence, sequence.length());
}
if (charset.equals(CharsetUtil.US_ASCII)) {
if (charset.equals(CharsetUtil.US_ASCII) || charset.equals(CharsetUtil.ISO_8859_1)) {
int len = sequence.length();
checkIndex0(index, len);
return ByteBufUtil.writeAscii(this, idx(index), sequence, len);
Expand Down
11 changes: 10 additions & 1 deletion buffer/src/main/java/io/netty/buffer/ByteBufUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ static int writeAscii(AbstractByteBuf buffer, int writerIndex, CharSequence seq,
// We can use the _set methods as these not need to do any index checks and reference checks.
// This is possible as we called ensureWritable(...) before.
for (int i = 0; i < len; i++) {
buffer._setByte(writerIndex++, (byte) seq.charAt(i));
buffer._setByte(writerIndex++, AsciiString.c2b(seq.charAt(i)));
}
return len;
}
Expand Down Expand Up @@ -739,6 +739,15 @@ public static byte[] getBytes(ByteBuf buf, int start, int length, boolean copy)
return v;
}

/**
* Copies the all content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
* @param src The source of the data to copy.
* @param dst the destination byte array.
*/
public static void copy(AsciiString src, ByteBuf dst) {
copy(src, 0, dst, src.length());
}

/**
* Copies the content of {@code src} to a {@link ByteBuf} using {@link ByteBuf#writeBytes(byte[], int, int)}.
* @param src The source of the data to copy.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.netty.handler.codec.DateFormatter;
import io.netty.handler.codec.Headers;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;

import java.text.ParseException;
import java.util.Calendar;
Expand Down Expand Up @@ -1148,19 +1149,12 @@ public static boolean equalsIgnoreCase(CharSequence name1, CharSequence name2) {
return AsciiString.contentEqualsIgnoreCase(name1, name2);
}

static void encode(HttpHeaders headers, ByteBuf buf) throws Exception {
Iterator<Entry<CharSequence, CharSequence>> iter = headers.iteratorCharSequence();
while (iter.hasNext()) {
Entry<CharSequence, CharSequence> header = iter.next();
HttpHeadersEncoder.encoderHeader(header.getKey(), header.getValue(), buf);
}
}

@Deprecated
public static void encodeAscii(CharSequence seq, ByteBuf buf) {
if (seq instanceof AsciiString) {
ByteBufUtil.copy((AsciiString) seq, 0, buf, seq.length());
} else {
HttpUtil.encodeAscii0(seq, buf);
buf.writeCharSequence(seq, CharsetUtil.US_ASCII);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.AsciiString;
import static io.netty.util.AsciiString.c2b;
import io.netty.util.CharsetUtil;

final class HttpHeadersEncoder {

Expand All @@ -32,28 +32,22 @@ static void encoderHeader(CharSequence name, CharSequence value, ByteBuf buf) th
final int entryLen = nameLen + valueLen + 4;
buf.ensureWritable(entryLen);
int offset = buf.writerIndex();
writeAscii(buf, offset, name, nameLen);
writeAscii(buf, offset, name);
offset += nameLen;
buf.setByte(offset ++, ':');
buf.setByte(offset ++, ' ');
writeAscii(buf, offset, value, valueLen);
writeAscii(buf, offset, value);
offset += valueLen;
buf.setByte(offset ++, '\r');
buf.setByte(offset ++, '\n');
buf.writerIndex(offset);
}

private static void writeAscii(ByteBuf buf, int offset, CharSequence value, int valueLen) {
private static void writeAscii(ByteBuf buf, int offset, CharSequence value) {
if (value instanceof AsciiString) {
ByteBufUtil.copy((AsciiString) value, 0, buf, offset, valueLen);
ByteBufUtil.copy((AsciiString) value, 0, buf, offset, value.length());
} else {
writeCharSequence(buf, offset, value, valueLen);
}
}

private static void writeCharSequence(ByteBuf buf, int offset, CharSequence value, int valueLen) {
for (int i = 0; i < valueLen; ++i) {
buf.setByte(offset ++, c2b(value.charAt(i)));
buf.setCharSequence(offset, value, CharsetUtil.US_ASCII);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@ protected void encodeHeaders(HttpHeaders headers, ByteBuf buf) throws Exception

private void encodeChunkedContent(ChannelHandlerContext ctx, Object msg, long contentLength, List<Object> out) {
if (contentLength > 0) {
byte[] length = Long.toHexString(contentLength).getBytes(CharsetUtil.US_ASCII);
ByteBuf buf = ctx.alloc().buffer(length.length + 2);
buf.writeBytes(length);
String lengthHex = Long.toHexString(contentLength);
ByteBuf buf = ctx.alloc().buffer(lengthHex.length() + 2);
buf.writeCharSequence(lengthHex, CharsetUtil.US_ASCII);
buf.writeBytes(CRLF);
out.add(buf);
out.add(encodeAndRetain(msg));
Expand Down Expand Up @@ -239,7 +239,7 @@ private static long contentLength(Object msg) {

@Deprecated
protected static void encodeAscii(String s, ByteBuf buf) {
HttpUtil.encodeAscii0(s, buf);
buf.writeCharSequence(s, CharsetUtil.US_ASCII);
}

protected abstract void encodeInitialLine(ByteBuf buf, H message) throws Exception;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;

import static io.netty.handler.codec.http.HttpConstants.SP;
Expand All @@ -37,8 +36,7 @@ public boolean acceptOutboundMessage(Object msg) throws Exception {

@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
AsciiString method = request.method().asciiName();
ByteBufUtil.copy(method, method.arrayOffset(), buf, method.length());
ByteBufUtil.copy(request.method().asciiName(), buf);
buf.writeByte(SP);

// Add / as absolute path if no is present.
Expand Down Expand Up @@ -71,7 +69,7 @@ protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Except
}
}

buf.writeBytes(uri.getBytes(CharsetUtil.UTF_8));
buf.writeCharSequence(uri, CharsetUtil.UTF_8);

buf.writeByte(SP);
request.protocolVersion().encode(buf);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import static io.netty.handler.codec.http.HttpConstants.SP;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.AsciiString;
import io.netty.util.ByteProcessor;
import io.netty.util.CharsetUtil;
Expand Down Expand Up @@ -667,18 +668,18 @@ public int compareTo(HttpResponseStatus o) {

@Override
public String toString() {
return new StringBuilder(reasonPhrase.length() + 5)
.append(code)
return new StringBuilder(reasonPhrase.length() + 4)
.append(codeAsText)
.append(' ')
.append(reasonPhrase)
.toString();
}

void encode(ByteBuf buf) {
if (bytes == null) {
HttpUtil.encodeAscii0(String.valueOf(code()), buf);
ByteBufUtil.copy(codeAsText, buf);
buf.writeByte(SP);
HttpUtil.encodeAscii0(String.valueOf(reasonPhrase()), buf);
buf.writeCharSequence(reasonPhrase, CharsetUtil.US_ASCII);
} else {
buf.writeBytes(bytes);
}
Expand Down
20 changes: 4 additions & 16 deletions codec-http/src/main/java/io/netty/handler/codec/http/HttpUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.netty.handler.codec.http;

import io.netty.buffer.ByteBuf;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;

Expand Down Expand Up @@ -353,7 +352,7 @@ public static void setTransferEncodingChunked(HttpMessage m, boolean chunked) {
* Fetch charset from message's Content-Type header.
*
* @param message entity to fetch Content-Type header from
* @return the charset from message's Content-Type header or {@link io.netty.util.CharsetUtil#ISO_8859_1}
* @return the charset from message's Content-Type header or {@link CharsetUtil#ISO_8859_1}
* if charset is not presented or unparsable
*/
public static Charset getCharset(HttpMessage message) {
Expand All @@ -364,7 +363,7 @@ public static Charset getCharset(HttpMessage message) {
* Fetch charset from Content-Type header value.
*
* @param contentTypeValue Content-Type header value to parse
* @return the charset from message's Content-Type header or {@link io.netty.util.CharsetUtil#ISO_8859_1}
* @return the charset from message's Content-Type header or {@link CharsetUtil#ISO_8859_1}
* if charset is not presented or unparsable
*/
public static Charset getCharset(CharSequence contentTypeValue) {
Expand All @@ -379,7 +378,7 @@ public static Charset getCharset(CharSequence contentTypeValue) {
* Fetch charset from message's Content-Type header.
*
* @param message entity to fetch Content-Type header from
* @param defaultCharset result to use in case of empty, incorrect or doesn't conain required part header value
* @param defaultCharset result to use in case of empty, incorrect or doesn't contain required part header value
* @return the charset from message's Content-Type header or {@code defaultCharset}
* if charset is not presented or unparsable
*/
Expand All @@ -406,7 +405,7 @@ public static Charset getCharset(CharSequence contentTypeValue, Charset defaultC
if (charsetCharSequence != null) {
try {
return Charset.forName(charsetCharSequence.toString());
} catch (UnsupportedCharsetException unsupportedException) {
} catch (UnsupportedCharsetException ignored) {
return defaultCharset;
}
} else {
Expand Down Expand Up @@ -520,15 +519,4 @@ public static CharSequence getMimeType(CharSequence contentTypeValue) {
return contentTypeValue.length() > 0 ? contentTypeValue : null;
}
}

static void encodeAscii0(CharSequence seq, ByteBuf buf) {
int length = seq.length();
for (int i = 0 ; i < length; i++) {
buf.writeByte(c2b(seq.charAt(i)));
}
}

private static byte c2b(char c) {
return c > 255 ? (byte) '?' : (byte) c;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public int compareTo(HttpVersion o) {

void encode(ByteBuf buf) {
if (bytes == null) {
HttpUtil.encodeAscii0(text, buf);
buf.writeCharSequence(text, CharsetUtil.US_ASCII);
} else {
buf.writeBytes(bytes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.StringUtil;

/**
* Web Socket Frame for closing the connection
Expand Down Expand Up @@ -75,15 +75,14 @@ public CloseWebSocketFrame(boolean finalFragment, int rsv, int statusCode, Strin
}

private static ByteBuf newBinaryData(int statusCode, String reasonText) {
byte[] reasonBytes = EmptyArrays.EMPTY_BYTES;
if (reasonText != null) {
reasonBytes = reasonText.getBytes(CharsetUtil.UTF_8);
if (reasonText == null) {
reasonText = StringUtil.EMPTY_STRING;
}

ByteBuf binaryData = Unpooled.buffer(2 + reasonBytes.length);
ByteBuf binaryData = Unpooled.buffer(2 + reasonText.length());
binaryData.writeShort(statusCode);
if (reasonBytes.length > 0) {
binaryData.writeBytes(reasonBytes);
if (!reasonText.isEmpty()) {
binaryData.writeCharSequence(reasonText, CharsetUtil.UTF_8);
}

binaryData.readerIndex(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import static io.netty.handler.codec.http.HttpConstants.LF;
import static io.netty.handler.codec.http.HttpConstants.SP;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.handler.codec.UnsupportedMessageTypeException;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpObjectEncoder;
import io.netty.handler.codec.http.HttpRequest;
Expand Down Expand Up @@ -50,22 +50,19 @@ protected void encodeInitialLine(final ByteBuf buf, final HttpMessage message)
throws Exception {
if (message instanceof HttpRequest) {
HttpRequest request = (HttpRequest) message;
HttpHeaders.encodeAscii(request.method().toString(), buf);
ByteBufUtil.copy(request.method().asciiName(), buf);
buf.writeByte(SP);
buf.writeBytes(request.uri().getBytes(CharsetUtil.UTF_8));
buf.writeCharSequence(request.uri(), CharsetUtil.UTF_8);
buf.writeByte(SP);
HttpHeaders.encodeAscii(request.protocolVersion().toString(), buf);
buf.writeCharSequence(request.protocolVersion().toString(), CharsetUtil.US_ASCII);
buf.writeBytes(CRLF);
} else if (message instanceof HttpResponse) {
HttpResponse response = (HttpResponse) message;
HttpHeaders.encodeAscii(response.protocolVersion().toString(),
buf);
buf.writeCharSequence(response.protocolVersion().toString(), CharsetUtil.US_ASCII);
buf.writeByte(SP);
buf.writeBytes(String.valueOf(response.status().code())
.getBytes(CharsetUtil.US_ASCII));
ByteBufUtil.copy(response.status().codeAsText(), buf);
buf.writeByte(SP);
HttpHeaders.encodeAscii(String.valueOf(response.status().reasonPhrase()),
buf);
buf.writeCharSequence(response.status().reasonPhrase(), CharsetUtil.US_ASCII);
buf.writeBytes(CRLF);
} else {
throw new UnsupportedMessageTypeException("Unsupported type "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public String password() {
public void encodeAsByteBuf(ByteBuf byteBuf) {
byteBuf.writeByte(SUBNEGOTIATION_VERSION.byteValue());
byteBuf.writeByte(username.length());
byteBuf.writeBytes(username.getBytes(CharsetUtil.US_ASCII));
byteBuf.writeCharSequence(username, CharsetUtil.US_ASCII);
byteBuf.writeByte(password.length());
byteBuf.writeBytes(password.getBytes(CharsetUtil.US_ASCII));
byteBuf.writeCharSequence(password, CharsetUtil.US_ASCII);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public void encodeAsByteBuf(ByteBuf byteBuf) {

case DOMAIN: {
byteBuf.writeByte(host.length());
byteBuf.writeBytes(host.getBytes(CharsetUtil.US_ASCII));
byteBuf.writeCharSequence(host, CharsetUtil.US_ASCII);
byteBuf.writeShort(port);
break;
}
Expand Down
Loading

0 comments on commit ba3616d

Please sign in to comment.