[#2656] Minimize ByteBuf.writeBytes(...) calls by pack the separator into the HttpHeaderEntity.

Motivation:
Currently we do 4 ByteBuf.writeBytes(...) calls per header line. This is can be improved.

Modification:
Introduce two new HttpHeaders methods to allow create HttpHeaderEntity which contains the separator. With this we can minimize it to 2 ByteBuf.writeBytes(...) calls per header line

Result:
Performance improvement.
This commit is contained in:
Norman Maurer 2014-07-15 10:22:40 +02:00
parent c4d0a87e19
commit 8fe3d97d8d
2 changed files with 52 additions and 9 deletions

View File

@ -23,11 +23,25 @@ final class HttpHeaderEntity implements CharSequence {
private final String name;
private final int hash;
private final byte[] bytes;
private final int separatorLen;
public HttpHeaderEntity(String name) {
this(name, null);
}
public HttpHeaderEntity(String name, byte[] separator) {
this.name = name;
hash = HttpHeaders.hash(name);
bytes = name.getBytes(CharsetUtil.US_ASCII);
byte[] nameBytes = name.getBytes(CharsetUtil.US_ASCII);
if (separator == null) {
bytes = nameBytes;
separatorLen = 0;
} else {
separatorLen = separator.length;
bytes = new byte[nameBytes.length + separator.length];
System.arraycopy(nameBytes, 0, bytes, 0, nameBytes.length);
System.arraycopy(separator, 0, bytes, nameBytes.length, separator.length);
}
}
int hash() {
@ -36,11 +50,14 @@ final class HttpHeaderEntity implements CharSequence {
@Override
public int length() {
return bytes.length;
return bytes.length - separatorLen;
}
@Override
public char charAt(int index) {
if ((bytes.length - separatorLen) <= index) {
throw new IndexOutOfBoundsException();
}
return (char) bytes[index];
}
@ -54,7 +71,8 @@ final class HttpHeaderEntity implements CharSequence {
return name;
}
void encode(ByteBuf buf) {
boolean encode(ByteBuf buf) {
buf.writeBytes(bytes);
return separatorLen > 0;
}
}

View File

@ -1363,17 +1363,20 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
@SuppressWarnings("deprecation")
static void encode(CharSequence key, CharSequence value, ByteBuf buf) {
encodeAscii(key, buf);
buf.writeBytes(HEADER_SEPERATOR);
encodeAscii(value, buf);
buf.writeBytes(CRLF);
if (!encodeAscii(key, buf)) {
buf.writeBytes(HEADER_SEPERATOR);
}
if (!encodeAscii(value, buf)) {
buf.writeBytes(CRLF);
}
}
public static void encodeAscii(CharSequence seq, ByteBuf buf) {
public static boolean encodeAscii(CharSequence seq, ByteBuf buf) {
if (seq instanceof HttpHeaderEntity) {
((HttpHeaderEntity) seq).encode(buf);
return ((HttpHeaderEntity) seq).encode(buf);
} else {
encodeAscii0(seq, buf);
return false;
}
}
@ -1395,6 +1398,28 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
return new HttpHeaderEntity(name);
}
/**
* Create a new {@link CharSequence} which is optimized for reuse as {@link HttpHeaders} name.
* So if you have a Header name that you want to reuse you should make use of this.
*/
public static CharSequence newNameEntity(String name) {
if (name == null) {
throw new NullPointerException("name");
}
return new HttpHeaderEntity(name, HEADER_SEPERATOR);
}
/**
* Create a new {@link CharSequence} which is optimized for reuse as {@link HttpHeaders} value.
* So if you have a Header value that you want to reuse you should make use of this.
*/
public static CharSequence newValueEntity(String name) {
if (name == null) {
throw new NullPointerException("name");
}
return new HttpHeaderEntity(name, CRLF);
}
protected HttpHeaders() { }
/**