Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce header cache memory usage on non persistent requests #6494

Merged
merged 3 commits into from Jul 7, 2021
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 33 additions & 8 deletions jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
Expand Up @@ -15,6 +15,7 @@

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
Expand Down Expand Up @@ -246,6 +247,7 @@ public enum State
private final StringBuilder _string = new StringBuilder();
private int _headerCacheSize = 1024;
private boolean _headerCacheCaseSensitive;
private List<HttpField> _cacheableFields;

private static HttpCompliance compliance()
{
Expand Down Expand Up @@ -746,6 +748,7 @@ private boolean parseLine(ByteBuffer buffer)
break;

case LF:
checkHeaderCache();
setState(State.HEADER);
_responseHandler.startResponse(_version, _responseStatus, null);
break;
Expand Down Expand Up @@ -851,6 +854,7 @@ else if (n == HttpTokens.LINE_FEED)
case LF:
if (_responseHandler != null)
{
checkHeaderCache();
setState(State.HEADER);
_responseHandler.startResponse(_version, _responseStatus, null);
}
Expand Down Expand Up @@ -881,7 +885,7 @@ else if (n == HttpTokens.LINE_FEED)
_version = HttpVersion.CACHE.get(takeString());
}
checkVersion();

checkHeaderCache();
setState(State.HEADER);

_requestHandler.startRequest(_methodString, _uri.toString(), _version);
Expand All @@ -905,6 +909,7 @@ else if (n == HttpTokens.LINE_FEED)
{
case LF:
String reason = takeString();
checkHeaderCache();
setState(State.HEADER);
_responseHandler.startResponse(_version, _responseStatus, reason);
continue;
Expand Down Expand Up @@ -937,6 +942,21 @@ else if (n == HttpTokens.LINE_FEED)
return handle;
}

private void checkHeaderCache()
{
if (_fieldCache == null && _cacheableFields != null)
{
_fieldCache = Index.buildCaseSensitiveMutableVisibleAsciiAlphabet(getHeaderCacheSize());
for (HttpField f : _cacheableFields)
{
if (!_fieldCache.put(f))
break;
}
_cacheableFields.clear();
_cacheableFields = null;
}
}

private void checkVersion()
{
if (_version == null)
Expand Down Expand Up @@ -1026,7 +1046,7 @@ else if (_endOfContent == EndOfContent.CHUNKED_CONTENT)
_field = new HostPortHttpField(_header,
CASE_SENSITIVE_FIELD_NAME.isAllowedBy(_complianceMode) ? _headerString : _header.asString(),
_valueString);
addToFieldCache = true;
addToFieldCache = getHeaderCacheSize() > 0;
}
break;

Expand All @@ -1046,22 +1066,26 @@ else if (_endOfContent == EndOfContent.CHUNKED_CONTENT)
case COOKIE:
case CACHE_CONTROL:
case USER_AGENT:
addToFieldCache = _field == null;
addToFieldCache = _field == null && getHeaderCacheSize() > 0 && _valueString.length() < getHeaderCacheSize();
break;

default:
break;
}

// Cache field?
if (addToFieldCache && _header != null && _valueString != null)
if (addToFieldCache && _fieldCache != NO_CACHE && _header != null && _valueString != null)
{
if (_fieldCache == null)
_fieldCache = Index.buildCaseSensitiveMutableVisibleAsciiAlphabet(getHeaderCacheSize());

if (_field == null)
_field = new HttpField(_header, caseInsensitiveHeader(_headerString, _header.asString()), _valueString);
if (_field.getValue().length() < getHeaderCacheSize() && !_fieldCache.put(_field))

if (_fieldCache == null)
{
if (_cacheableFields == null)
_cacheableFields = new ArrayList<>();
_cacheableFields.add(_field);
}
else if (!_fieldCache.put(_field))
{
_fieldCache.clear();
_fieldCache.put(_field);
Expand Down Expand Up @@ -1911,6 +1935,7 @@ protected void setState(FieldState state)

public Index<HttpField> getFieldCache()
{
checkHeaderCache();
return _fieldCache;
}

Expand Down