Merged branch 'jetty-11.0.x' into 'jetty-12.0.x'.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2023-07-17 23:51:40 +02:00
commit c19a5817f9
No known key found for this signature in database
GPG Key ID: 1677D141BCF3584D
3 changed files with 152 additions and 79 deletions

View File

@ -91,7 +91,7 @@ import org.slf4j.LoggerFactory;
* that says that a hunter should eat (i.e. consume) what they kill (i.e. produced).</p>
*/
@ManagedObject("Adaptive execution strategy")
public class AdaptiveExecutionStrategy extends ContainerLifeCycle implements ExecutionStrategy
public class AdaptiveExecutionStrategy extends ContainerLifeCycle implements ExecutionStrategy, Runnable
{
private static final Logger LOG = LoggerFactory.getLogger(AdaptiveExecutionStrategy.class);
@ -133,7 +133,6 @@ public class AdaptiveExecutionStrategy extends ContainerLifeCycle implements Exe
private final Executor _executor;
private final TryExecutor _tryExecutor;
private final Executor _virtualExecutor;
private final Runnable _runPendingProducer = () -> tryProduce(true);
private final AtomicBiInteger _state = new AtomicBiInteger();
/**
@ -187,7 +186,7 @@ public class AdaptiveExecutionStrategy extends ContainerLifeCycle implements Exe
if (LOG.isDebugEnabled())
LOG.debug("{} dispatch {}", this, execute);
if (execute)
_executor.execute(_runPendingProducer);
_executor.execute(this);
}
@Override
@ -196,6 +195,12 @@ public class AdaptiveExecutionStrategy extends ContainerLifeCycle implements Exe
tryProduce(false);
}
@Override
public void run()
{
tryProduce(true);
}
/**
* Tries to become the producing thread and then produces and consumes tasks.
*
@ -330,7 +335,7 @@ public class AdaptiveExecutionStrategy extends ContainerLifeCycle implements Exe
int pending = AtomicBiInteger.getHi(biState);
// If a pending producer is available or one can be started
if (tryExecuted || pending <= 0 && _tryExecutor.tryExecute(_runPendingProducer))
if (tryExecuted || pending <= 0 && _tryExecutor.tryExecute(this))
{
tryExecuted = true;
pending++;
@ -371,7 +376,7 @@ public class AdaptiveExecutionStrategy extends ContainerLifeCycle implements Exe
int pending = AtomicBiInteger.getHi(biState);
// If a pending producer is available or one can be started
if (tryExecuted || pending <= 0 && _tryExecutor.tryExecute(_runPendingProducer))
if (tryExecuted || pending <= 0 && _tryExecutor.tryExecute(this))
{
tryExecuted = true;
pending++;

View File

@ -79,6 +79,8 @@ public class ServletChannel
private final AtomicLong _requests = new AtomicLong();
private final HttpInput _httpInput;
private final HttpOutput _httpOutput;
private final Dispatchable _requestDispatchable;
private final Dispatchable _asyncDispatchable;
private ServletContextRequest _servletContextRequest;
private Request _request;
private Response _response;
@ -99,6 +101,8 @@ public class ServletChannel
_state = new ServletRequestState(this);
_httpInput = new HttpInput(this);
_httpOutput = new HttpOutput(this);
_requestDispatchable = new RequestDispatchable();
_asyncDispatchable = new AsyncDispatchable();
}
public ConnectionMetaData getConnectionMetaData()
@ -476,73 +480,13 @@ public class ServletChannel
case DISPATCH:
{
dispatch(() ->
{
try
{
_context.getServletContextHandler().requestInitialized(_servletContextRequest, _servletContextRequest.getServletApiRequest());
ServletHandler servletHandler = _context.getServletContextHandler().getServletHandler();
ServletHandler.MappedServlet mappedServlet = _servletContextRequest.getMatchedResource().getResource();
mappedServlet.handle(servletHandler, Request.getPathInContext(_servletContextRequest), _servletContextRequest.getServletApiRequest(), _servletContextRequest.getHttpServletResponse());
}
finally
{
_context.getServletContextHandler().requestDestroyed(_servletContextRequest, _servletContextRequest.getServletApiRequest());
}
});
dispatch(_requestDispatchable);
break;
}
case ASYNC_DISPATCH:
{
dispatch(() ->
{
try
{
_context.getServletContextHandler().requestInitialized(_servletContextRequest, _servletContextRequest.getServletApiRequest());
HttpURI uri;
String pathInContext;
AsyncContextEvent asyncContextEvent = _state.getAsyncContextEvent();
String dispatchString = asyncContextEvent.getDispatchPath();
if (dispatchString != null)
{
String contextPath = _context.getContextPath();
HttpURI.Immutable dispatchUri = HttpURI.from(dispatchString);
pathInContext = URIUtil.canonicalPath(dispatchUri.getPath());
uri = HttpURI.build(_servletContextRequest.getHttpURI())
.path(URIUtil.addPaths(contextPath, pathInContext))
.query(dispatchUri.getQuery());
}
else
{
uri = asyncContextEvent.getBaseURI();
if (uri == null)
{
uri = _servletContextRequest.getHttpURI();
pathInContext = Request.getPathInContext(_servletContextRequest);
}
else
{
pathInContext = uri.getCanonicalPath();
if (_context.getContextPath().length() > 1)
pathInContext = pathInContext.substring(_context.getContextPath().length());
}
}
// We first worked with the core pathInContext above, but now need to convert to servlet style
String decodedPathInContext = URIUtil.decodePath(pathInContext);
Dispatcher dispatcher = new Dispatcher(getServletContextHandler(), uri, decodedPathInContext);
dispatcher.async(asyncContextEvent.getSuppliedRequest(), asyncContextEvent.getSuppliedResponse());
}
finally
{
_context.getServletContextHandler().requestDestroyed(_servletContextRequest, _servletContextRequest.getServletApiRequest());
}
});
dispatch(_asyncDispatchable);
break;
}
@ -591,7 +535,7 @@ public class ServletChannel
{
// We do not notify ServletRequestListener on this dispatch because it might not
// be dispatched to an error page, so we delegate this responsibility to the ErrorHandler.
dispatch(() -> errorHandler.handle(_servletContextRequest, getServletContextResponse(), blocker));
dispatch(new ErrorDispatchable(errorHandler, blocker));
blocker.block();
}
}
@ -949,4 +893,97 @@ public class ServletChannel
{
void dispatch() throws Exception;
}
private class RequestDispatchable implements Dispatchable
{
@Override
public void dispatch() throws Exception
{
ServletContextHandler servletContextHandler = getServletContextHandler();
ServletContextRequest servletContextRequest = getServletContextRequest();
ServletApiRequest servletApiRequest = servletContextRequest.getServletApiRequest();
try
{
servletContextHandler.requestInitialized(servletContextRequest, servletApiRequest);
ServletHandler servletHandler = servletContextHandler.getServletHandler();
ServletHandler.MappedServlet mappedServlet = servletContextRequest.getMatchedResource().getResource();
mappedServlet.handle(servletHandler, Request.getPathInContext(servletContextRequest), servletApiRequest, servletContextRequest.getHttpServletResponse());
}
finally
{
servletContextHandler.requestDestroyed(servletContextRequest, servletApiRequest);
}
}
}
private class AsyncDispatchable implements Dispatchable
{
@Override
public void dispatch() throws Exception
{
ServletContextHandler servletContextHandler = getServletContextHandler();
ServletContextRequest servletContextRequest = getServletContextRequest();
ServletApiRequest servletApiRequest = servletContextRequest.getServletApiRequest();
try
{
servletContextHandler.requestInitialized(servletContextRequest, servletApiRequest);
HttpURI uri;
String pathInContext;
AsyncContextEvent asyncContextEvent = _state.getAsyncContextEvent();
String dispatchString = asyncContextEvent.getDispatchPath();
if (dispatchString != null)
{
String contextPath = _context.getContextPath();
HttpURI.Immutable dispatchUri = HttpURI.from(dispatchString);
pathInContext = URIUtil.canonicalPath(dispatchUri.getPath());
uri = HttpURI.build(servletContextRequest.getHttpURI())
.path(URIUtil.addPaths(contextPath, pathInContext))
.query(dispatchUri.getQuery());
}
else
{
uri = asyncContextEvent.getBaseURI();
if (uri == null)
{
uri = servletContextRequest.getHttpURI();
pathInContext = Request.getPathInContext(servletContextRequest);
}
else
{
pathInContext = uri.getCanonicalPath();
int length = _context.getContextPath().length();
if (length > 1)
pathInContext = pathInContext.substring(length);
}
}
// We first worked with the core pathInContext above, but now need to convert to servlet style
String decodedPathInContext = URIUtil.decodePath(pathInContext);
Dispatcher dispatcher = new Dispatcher(servletContextHandler, uri, decodedPathInContext);
dispatcher.async(asyncContextEvent.getSuppliedRequest(), asyncContextEvent.getSuppliedResponse());
}
finally
{
servletContextHandler.requestDestroyed(servletContextRequest, servletApiRequest);
}
}
}
private class ErrorDispatchable implements Dispatchable
{
private final Request.Handler _errorHandler;
private final Callback _callback;
private ErrorDispatchable(Request.Handler errorHandler, Callback callback)
{
_errorHandler = errorHandler;
_callback = callback;
}
@Override
public void dispatch() throws Exception
{
_errorHandler.handle(getServletContextRequest(), getServletContextResponse(), _callback);
}
}
}

View File

@ -84,6 +84,8 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
private final Request _request;
private final Response _response;
private final Listener _combinedListener;
private final Dispatchable _requestDispatcher;
private final Dispatchable _asyncDispatcher;
@Deprecated
private final List<Listener> _transientListeners = new ArrayList<>();
private MetaData.Response _committedMetaData;
@ -109,8 +111,9 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
_request = new Request(this, newHttpInput());
_response = new Response(this, newHttpOutput());
_executor = _connector.getServer().getThreadPool();
_combinedListener = new HttpChannelListeners(_connector.getBeans(Listener.class));
_requestDispatcher = new RequestDispatchable();
_asyncDispatcher = new AsyncDispatchable();
if (LOG.isDebugEnabled())
LOG.debug("new {} -> {},{},{}",
@ -567,17 +570,14 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (!_request.hasMetaData())
throw new IllegalStateException("state=" + _state);
dispatch(DispatcherType.REQUEST, () ->
{
_contextHandler.handle(HttpChannel.this);
});
dispatch(DispatcherType.REQUEST, _requestDispatcher);
break;
}
case ASYNC_DISPATCH:
{
dispatch(DispatcherType.ASYNC, () -> _contextHandler.handleAsync(this));
dispatch(DispatcherType.ASYNC, _asyncDispatcher);
break;
}
@ -616,11 +616,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
break;
}
dispatch(DispatcherType.ERROR, () ->
{
errorHandler.handle(null, _request, _request, _response);
_request.setHandled(true);
});
dispatch(DispatcherType.ERROR, new ErrorDispatchable(errorHandler));
}
catch (Throwable x)
{
@ -1661,4 +1657,39 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
request.getHttpChannel().notifyEvent1(listener -> listener::onComplete, request);
}
}
private class RequestDispatchable implements Dispatchable
{
@Override
public void dispatch() throws IOException, ServletException
{
_contextHandler.handle(HttpChannel.this);
}
}
private class AsyncDispatchable implements Dispatchable
{
@Override
public void dispatch() throws IOException, ServletException
{
_contextHandler.handleAsync(HttpChannel.this);
}
}
private class ErrorDispatchable implements Dispatchable
{
private final ErrorHandler _errorHandler;
public ErrorDispatchable(ErrorHandler errorHandler)
{
_errorHandler = errorHandler;
}
@Override
public void dispatch() throws IOException, ServletException
{
_errorHandler.handle(null, _request, _request, _response);
_request.setHandled(true);
}
}
}