452465 - 100% CPU spin on page reload.

Fixed by adding a MetaData.recycle() method that properly recycles
the MetaData.Request object so that HttpChannelOverHttp.earlyEOF()
properly closes the connection when it's idle.
This commit is contained in:
Simone Bordet 2014-11-20 13:00:02 +01:00
parent 2eb6e06387
commit 57f90ae7d1
2 changed files with 109 additions and 148 deletions

View File

@ -18,109 +18,119 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.Objects;
public class MetaData implements Iterable<HttpField> public class MetaData implements Iterable<HttpField>
{ {
private HttpVersion _httpVersion; private HttpVersion _httpVersion;
private HttpFields _fields; private HttpFields _fields;
long _contentLength=Long.MIN_VALUE; private long _contentLength;
/* ------------------------------------------------------------ */
public MetaData() public MetaData()
{ {
this(null, null);
} }
/* ------------------------------------------------------------ */
public MetaData(HttpVersion version, HttpFields fields) public MetaData(HttpVersion version, HttpFields fields)
{ {
_httpVersion = version; this(version, fields, Long.MIN_VALUE);
_fields = fields;
} }
/* ------------------------------------------------------------ */
public MetaData(HttpVersion version, HttpFields fields, long contentLength) public MetaData(HttpVersion version, HttpFields fields, long contentLength)
{ {
_httpVersion = version; _httpVersion = version;
_fields = fields; _fields = fields;
_contentLength=contentLength; _contentLength = contentLength;
}
protected void recycle()
{
_httpVersion = null;
if (_fields != null)
_fields.clear();
_contentLength = Long.MIN_VALUE;
} }
/* ------------------------------------------------------------ */
public boolean isRequest() public boolean isRequest()
{ {
return false; return false;
} }
/* ------------------------------------------------------------ */
public boolean isResponse() public boolean isResponse()
{ {
return false; return false;
} }
/* ------------------------------------------------------------ */ /**
/** Get the httpVersion. * @return the HTTP version of this MetaData object
* @return the httpVersion
*/ */
public HttpVersion getVersion() public HttpVersion getVersion()
{ {
return _httpVersion; return _httpVersion;
} }
/* ------------------------------------------------------------ */ /**
/** Set the httpVersion. * @param httpVersion the HTTP version to set
* @param httpVersion the httpVersion to set
*/ */
public void setHttpVersion(HttpVersion httpVersion) public void setHttpVersion(HttpVersion httpVersion)
{ {
_httpVersion = httpVersion; _httpVersion = httpVersion;
} }
/* ------------------------------------------------------------ */ /**
/** Get the fields. * @return the HTTP fields of this MetaData object
* @return the fields
*/ */
public HttpFields getFields() public HttpFields getFields()
{ {
return _fields; return _fields;
} }
/* ------------------------------------------------------------ */ /**
/** Set the fields. * @param fields the HTTP fields to set
* @param fields the fields to set
*/ */
public void setFields(HttpFields fields) public void setFields(HttpFields fields)
{ {
_fields = fields; _fields = fields;
_contentLength=Long.MIN_VALUE; _contentLength = Long.MIN_VALUE;
} }
/* ------------------------------------------------------------ */ /**
* @return the content length if available, otherwise {@link Long#MIN_VALUE}
*/
public long getContentLength() public long getContentLength()
{ {
if (_contentLength==Long.MIN_VALUE) if (_contentLength == Long.MIN_VALUE)
{ {
HttpField cl = _fields.getField(HttpHeader.CONTENT_LENGTH); if (_fields != null)
_contentLength=(cl==null)?-1:cl.getLongValue(); {
HttpField field = _fields.getField(HttpHeader.CONTENT_LENGTH);
_contentLength = field == null ? -1 : field.getLongValue();
}
} }
return _contentLength; return _contentLength;
} }
/* ------------------------------------------------------------ */ /**
* @return an iterator over the HTTP fields
* @see #getFields()
*/
public Iterator<HttpField> iterator() public Iterator<HttpField> iterator()
{ {
return getFields().iterator(); HttpFields fields = getFields();
return fields == null ? Collections.<HttpField>emptyIterator() : fields.iterator();
} }
/* ------------------------------------------------------------ */
@Override @Override
public int hashCode() public int hashCode()
{ {
return 31 * getVersion().hashCode() + getFields().hashCode(); HttpVersion version = getVersion();
int hash = version == null ? 0 : version.hashCode();
HttpFields fields = getFields();
return 31 * hash + (fields == null ? 0 : fields.hashCode());
} }
/* ------------------------------------------------------------ */
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
@ -128,140 +138,122 @@ public class MetaData implements Iterable<HttpField>
return true; return true;
if (!(o instanceof MetaData)) if (!(o instanceof MetaData))
return false; return false;
MetaData that = (MetaData)o; MetaData that = (MetaData)o;
if (getVersion() != that.getVersion()) if (getVersion() != that.getVersion())
return false; return false;
return getFields().equals(that.getFields()); return Objects.equals(getFields(), that.getFields());
} }
/* ------------------------------------------------------------ */
@Override @Override
public String toString() public String toString()
{ {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
for (HttpField field: this) for (HttpField field : this)
out.append(field).append(System.lineSeparator()); out.append(field).append(System.lineSeparator());
return out.toString(); return out.toString();
} }
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
public static class Request extends MetaData public static class Request extends MetaData
{ {
private String _method; private String _method;
private HttpURI _uri; private HttpURI _uri;
public Request() public Request()
{ {
} }
/* ------------------------------------------------------------ */
/**
* @param method
* @param uri
* @param version
* @param fields
*/
public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields) public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields)
{ {
this(method,uri,version,fields,Long.MIN_VALUE); this(method, uri, version, fields, Long.MIN_VALUE);
} }
/* ------------------------------------------------------------ */
/**
* @param method
* @param uri
* @param version
* @param fields
*/
public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength) public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength)
{ {
super(version,fields,contentLength); super(version, fields, contentLength);
_method = method; _method = method;
_uri = uri; _uri = uri;
} }
/* ------------------------------------------------------------ */
public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields) public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields)
{ {
this(method,new HttpURI(scheme==null?null:scheme.asString(),hostPort.getHost(),hostPort.getPort(),uri),version,fields); this(method, new HttpURI(scheme == null ? null : scheme.asString(), hostPort.getHost(), hostPort.getPort(), uri), version, fields);
} }
/* ------------------------------------------------------------ */
public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength) public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength)
{ {
this(method,new HttpURI(scheme==null?null:scheme.asString(),hostPort.getHost(),hostPort.getPort(),uri),version,fields,contentLength); this(method, new HttpURI(scheme == null ? null : scheme.asString(), hostPort.getHost(), hostPort.getPort(), uri), version, fields, contentLength);
} }
/* ------------------------------------------------------------ */
public Request(String method, String scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength) public Request(String method, String scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength)
{ {
this(method,new HttpURI(scheme,hostPort.getHost(),hostPort.getPort(),uri),version,fields,contentLength); this(method, new HttpURI(scheme, hostPort.getHost(), hostPort.getPort(), uri), version, fields, contentLength);
}
public void recycle()
{
super.recycle();
_method = null;
if (_uri != null)
_uri.clear();
} }
/* ------------------------------------------------------------ */
@Override @Override
public boolean isRequest() public boolean isRequest()
{ {
return true; return true;
} }
/* ------------------------------------------------------------ */ /**
/** Get the method. * @return the HTTP method
* @return the method
*/ */
public String getMethod() public String getMethod()
{ {
return _method; return _method;
} }
/* ------------------------------------------------------------ */ /**
/** Set the method. * @param method the HTTP method to set
* @param method the method to set
*/ */
public void setMethod(String method) public void setMethod(String method)
{ {
_method = method; _method = method;
} }
/* ------------------------------------------------------------ */ /**
/** Get the uri. * @return the HTTP URI
* @return the uri
*/ */
public HttpURI getURI() public HttpURI getURI()
{ {
return _uri; return _uri;
} }
/* ------------------------------------------------------------ */ /**
/** Get the uri. * @return the HTTP URI in string form
* @return the uri
*/ */
public String getURIString() public String getURIString()
{ {
return _uri==null?null:_uri.toString(); return _uri == null ? null : _uri.toString();
} }
/* ------------------------------------------------------------ */ /**
/** Set the uri. * @param uri the HTTP URI to set
* @param uri the uri to set
*/ */
public void setURI(HttpURI uri) public void setURI(HttpURI uri)
{ {
_uri = uri; _uri = uri;
} }
/* ------------------------------------------------------------ */
@Override @Override
public int hashCode() public int hashCode()
{ {
return ((super.hashCode()*31)+_method.hashCode())*31+_uri.hashCode(); int hash = super.hashCode();
hash = hash * 31 + (_method == null ? 0 : _method.hashCode());
return hash * 31 + (_uri == null ? 0 : _uri.hashCode());
} }
/* ------------------------------------------------------------ */
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
@ -270,13 +262,12 @@ public class MetaData implements Iterable<HttpField>
if (!(o instanceof MetaData.Request)) if (!(o instanceof MetaData.Request))
return false; return false;
MetaData.Request that = (MetaData.Request)o; MetaData.Request that = (MetaData.Request)o;
if (!getMethod().equals(that.getMethod()) || if (!Objects.equals(getMethod(), that.getMethod()) ||
!getURI().equals(that.getURI())) !Objects.equals(getURI(), that.getURI()))
return false; return false;
return super.equals(o); return super.equals(o);
} }
/* ------------------------------------------------------------ */
@Override @Override
public String toString() public String toString()
{ {
@ -285,9 +276,6 @@ public class MetaData implements Iterable<HttpField>
} }
} }
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
public static class Response extends MetaData public static class Response extends MetaData
{ {
private int _status; private int _status;
@ -295,95 +283,71 @@ public class MetaData implements Iterable<HttpField>
public Response() public Response()
{ {
this(null, 0, null);
} }
/* ------------------------------------------------------------ */
/**
* @param version
* @param fields
* @param status
*/
public Response(HttpVersion version, int status, HttpFields fields) public Response(HttpVersion version, int status, HttpFields fields)
{ {
this(version,status,fields,Long.MIN_VALUE); this(version, status, fields, Long.MIN_VALUE);
} }
/* ------------------------------------------------------------ */ public Response(HttpVersion version, int status, HttpFields fields, long contentLength)
/**
* @param version
* @param fields
* @param status
*/
public Response(HttpVersion version, int status, HttpFields fields,long contentLength)
{ {
super(version,fields,contentLength); super(version, fields, contentLength);
_status=status; _status = status;
} }
/* ------------------------------------------------------------ */ public Response(HttpVersion version, int status, String reason, HttpFields fields, long contentLength)
/** {
* @param version super(version, fields, contentLength);
* @param fields _reason = reason;
* @param status _status = status;
*/
public Response(HttpVersion version, int status, String reason, HttpFields fields,long contentLength)
{
super(version,fields,contentLength);
_reason=reason;
_status=status;
} }
/* ------------------------------------------------------------ */
@Override @Override
public boolean isResponse() public boolean isResponse()
{ {
return true; return true;
} }
/* ------------------------------------------------------------ */ /**
/** Get the status. * @return the HTTP status
* @return the status
*/ */
public int getStatus() public int getStatus()
{ {
return _status; return _status;
} }
/* ------------------------------------------------------------ */ /**
/** Get the reason. * @return the HTTP reason
* @return the status
*/ */
public String getReason() public String getReason()
{ {
return _reason; return _reason;
} }
/* ------------------------------------------------------------ */ /**
/** Set the status. * @param status the HTTP status to set
* @param status the status to set
*/ */
public void setStatus(int status) public void setStatus(int status)
{ {
_status = status; _status = status;
} }
/* ------------------------------------------------------------ */ /**
/** Set the reason. * @param reason the HTTP reason to set
* @param reason the reason to set
*/ */
public void setReason(String reason) public void setReason(String reason)
{ {
_reason = reason; _reason = reason;
} }
/* ------------------------------------------------------------ */
@Override @Override
public int hashCode() public int hashCode()
{ {
return 31 * getStatus() + super.hashCode(); return 31 * super.hashCode() + getStatus();
} }
/* ------------------------------------------------------------ */
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
@ -397,12 +361,10 @@ public class MetaData implements Iterable<HttpField>
return super.equals(o); return super.equals(o);
} }
/* ------------------------------------------------------------ */
@Override @Override
public String toString() public String toString()
{ {
return String.format("%s %d%s%s",getVersion(), getStatus(), System.lineSeparator(), super.toString()); return String.format("%s %d%s%s", getVersion(), getStatus(), System.lineSeparator(), super.toString());
} }
} }
} }

View File

@ -20,7 +20,6 @@
package org.eclipse.jetty.server; package org.eclipse.jetty.server;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HostPortHttpField;
@ -71,7 +70,7 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl
_expect = false; _expect = false;
_expect100Continue = false; _expect100Continue = false;
_expect102Processing = false; _expect102Processing = false;
_metadata.getURI().clear(); _metadata.recycle();
_connection=null; _connection=null;
_fields.clear(); _fields.clear();
} }