HttpConversionUtils avoid intermediate collection allocation

Modifications:
HttpConversionUtil#toLowercaseMap requires an intermediate List to be allocated. This can be avoided with the recently added value iterator methods.

Modifications:
- Use HttpHeaders#valueCharSequenceIterator instead of getAll

Result:
Less intermediate object allocation and copying.
This commit is contained in:
Scott Mitchell 2017-11-20 09:16:42 -08:00
parent 907ed79069
commit a3e41ba6eb

View File

@ -38,7 +38,6 @@ import io.netty.util.internal.UnstableApi;
import java.net.URI; import java.net.URI;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import static io.netty.handler.codec.http.HttpScheme.HTTP; import static io.netty.handler.codec.http.HttpScheme.HTTP;
@ -413,14 +412,13 @@ public final class HttpConversionUtil {
return out; return out;
} }
private static CharSequenceMap<AsciiString> toLowercaseMap(List<String> values) { private static CharSequenceMap<AsciiString> toLowercaseMap(Iterator<? extends CharSequence> valuesIter,
int arraySizeHint) {
UnsupportedValueConverter<AsciiString> valueConverter = UnsupportedValueConverter.<AsciiString>instance(); UnsupportedValueConverter<AsciiString> valueConverter = UnsupportedValueConverter.<AsciiString>instance();
CharSequenceMap<AsciiString> result = CharSequenceMap<AsciiString> result = new CharSequenceMap<AsciiString>(true, valueConverter, arraySizeHint);
new CharSequenceMap<AsciiString>(true, valueConverter, values.size());
// we iterate because the underlying list is probably a linked list while (valuesIter.hasNext()) {
for (CharSequence value : values) { AsciiString lowerCased = AsciiString.of(valuesIter.next()).toLowerCase();
AsciiString lowerCased = AsciiString.of(value).toLowerCase();
try { try {
int index = lowerCased.forEachByte(FIND_COMMA); int index = lowerCased.forEachByte(FIND_COMMA);
if (index != -1) { if (index != -1) {
@ -429,7 +427,7 @@ public final class HttpConversionUtil {
result.add(lowerCased.subSequence(start, index, false).trim(), EMPTY_STRING); result.add(lowerCased.subSequence(start, index, false).trim(), EMPTY_STRING);
start = index + 1; start = index + 1;
} while (start < lowerCased.length() && } while (start < lowerCased.length() &&
(index = lowerCased.forEachByte(start, value.length() - start, FIND_COMMA)) != -1); (index = lowerCased.forEachByte(start, lowerCased.length() - start, FIND_COMMA)) != -1);
result.add(lowerCased.subSequence(start, lowerCased.length(), false).trim(), EMPTY_STRING); result.add(lowerCased.subSequence(start, lowerCased.length(), false).trim(), EMPTY_STRING);
} else { } else {
result.add(lowerCased.trim(), EMPTY_STRING); result.add(lowerCased.trim(), EMPTY_STRING);
@ -445,8 +443,10 @@ public final class HttpConversionUtil {
public static void toHttp2Headers(HttpHeaders inHeaders, Http2Headers out) { public static void toHttp2Headers(HttpHeaders inHeaders, Http2Headers out) {
Iterator<Entry<CharSequence, CharSequence>> iter = inHeaders.iteratorCharSequence(); Iterator<Entry<CharSequence, CharSequence>> iter = inHeaders.iteratorCharSequence();
// Choose 8 as a default size because it is unlikely we will see more than 4 Connection headers values, but
// still allowing for "enough" space in the map to reduce the chance of hash code collision.
CharSequenceMap<AsciiString> connectionBlacklist = CharSequenceMap<AsciiString> connectionBlacklist =
toLowercaseMap(inHeaders.getAll(HttpHeaderNames.CONNECTION)); toLowercaseMap(inHeaders.valueCharSequenceIterator(HttpHeaderNames.CONNECTION), 8);
while (iter.hasNext()) { while (iter.hasNext()) {
Entry<CharSequence, CharSequence> entry = iter.next(); Entry<CharSequence, CharSequence> entry = iter.next();
final AsciiString aName = AsciiString.of(entry.getKey()).toLowerCase(); final AsciiString aName = AsciiString.of(entry.getKey()).toLowerCase();