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

Jetty 12 handler as boolean processor #9035

Merged
merged 36 commits into from
Dec 19, 2022

Conversation

gregw
Copy link
Contributor

@gregw gregw commented Dec 11, 2022

Another alternative Handler architecture inspired by #8978 for #8929

This PR removed the modal nature of Request, Response and Callback, so that they need not be accepted (via API or returning a Processor) before they are fully active. Not only does this avoid a lot of locking on many methods and on the state change, but it also allows for a boolean return from process to no longer be a race condition.

If a handler.process(request,response,callback) returns true, then the callback will be called and the caller must no longer act on the request/response/callback. If false is returned, then the handler will never act on the request/response/callback so the caller must either handle the request itself (e.g. 404) or it is free to try another handler.
If an exception is thrown, then the caller cannot know if the callback will be called and must assume not and race with any lingering async process to write an error and complete the callback.

In #8978, I tried having a separate Handler.Conditional type that would have a method on it to accept requests and only then call process which had to handle the request. This is probably workable but had several cons:

  • difficult to pass state/workings/wrappers from the conditional test to the process method, so some work is done twice or we need wrappers just to carry extra state.
  • It was difficult to wrap conditional handlers with non conditional handlers.
  • callers had to do instanceof test of handlers before knowing how to call them.

So this branch is simpler, as essentially all handlers are conditional.

@gregw gregw requested review from sbordet, joakime and lachlan-roberts and removed request for sbordet and joakime December 11, 2022 01:21
@gregw gregw added the Jetty 12 label Dec 11, 2022
@gregw gregw force-pushed the jetty-12-handler-as-boolean-processor branch from a35b2e9 to c6d691d Compare December 11, 2022 01:26
@gregw gregw marked this pull request as ready for review December 11, 2022 05:43
VERSION.txt Outdated Show resolved Hide resolved
All Handlers are Processors, which now return a boolean to indicate the request has been accepted.
The request/response/callback are no longer modal, so there is no race with the boolean return.
@gregw gregw force-pushed the jetty-12-handler-as-boolean-processor branch from 0ed443b to 4b4a46a Compare December 11, 2022 21:47
Comment on lines 14 to 17
<properties>
<bundle-symbolic-name>${project.groupId}.asciidoctor.extensions</bundle-symbolic-name>
</properties>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I've still missed some changes in HEAD?

Copy link
Contributor

@janbartel janbartel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the way this is going. The code is much simpler. It has to also be faster.

Minor renames to reduce differences
Comment on lines -761 to -765
"Core enter http://0.0.0.0/",
"EE9 enter /",
"EE9 exit /",
"Core exit http://0.0.0.0/",
// Enter again for process(request, response, callback)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one makes me smile :)

@gregw
Copy link
Contributor Author

gregw commented Dec 13, 2022

@sbordet @lorban I've been looking at redoing this branch from HEAD, and I really don't think that is the right way to go. There is a lot of work and consideration in this branch that will take a huge effort to redo from scratch. I know there is some risk of some changes being lost in this branch, but I honestly think that is less if we review this branch and check for them, than if we redo the changes to the many hundreds of handlers. Whilst much of it can be done with tools, ultimately you need to visit most of the handlers to check them. I've visited many hundreds of handlers and believe I have them mostly right. Redoing all that work will not remove the need for a detailed review to recheck them all.

I don't think there is any significant kruft from previous branches left, and if there is it needs to be reviewed, identified and labelled as kruft anyway (rather than a change to be remade). Again, I don't think it is less work to redo the branch rather than review this one.

Avoid iterations if only ServletPathSpec instances
Avoid tests for empty mappings.
Better reset implementation
Avoid iterations if only ServletPathSpec instances
Avoid tests for empty mappings.
Better reset implementation
Improve suffix matching
Improve exact matching
Copy link
Contributor

@sbordet sbordet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I have a few nits, but I'll fix them myself.

* which is appropriate for wall clock time.</p>
* @return The timestamp that the request was received/created in nanoseconds, relative to {@link System#nanoTime()}.
*/
default long getNanoTimeStamp()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to getNanoTime().

*/
default long getNanoTimeStamp()
{
return NanoTime.now() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis() - getTimeStamp());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this implementation is correct, since currentTimeMillis() can drift.
Must use another field to store the creation/received nanoTime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sbordet we do. It is in the HttpStream. This is just used for test code.

if (stream != null)
return stream.getNanoTimeStamp();

return NanoTime.now() - TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis() - getTimeStamp());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should call super instead?
As we don't want to duplicate the (wrong) logic here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does super call a default implementation? I don't think so.

Renamed HttpStream.getNanoTimeStamp() to getNanoTime().

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
…sor'.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
Copy link
Contributor

@lorban lorban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
@sbordet sbordet merged commit c18e790 into jetty-12.0.x Dec 19, 2022
@sbordet sbordet deleted the jetty-12-handler-as-boolean-processor branch December 19, 2022 15:02
@gregw gregw restored the jetty-12-handler-as-boolean-processor branch December 19, 2022 20:20
@gregw gregw deleted the jetty-12-handler-as-boolean-processor branch December 19, 2022 20:21
@gregw gregw mentioned this pull request Jan 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants