-
Notifications
You must be signed in to change notification settings - Fork 25.1k
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
Move some security APIs to using promises in place of callbacks #123812
base: main
Are you sure you want to change the base?
Move some security APIs to using promises in place of callbacks #123812
Conversation
We ahve some incredibly deep callstacks in security that seem to visibly raise context switch costs, make profiling more complicated and generally make the code rather hard to follow. Since the methods adjusted here return a result synchronously we can both save overhead and make things a little easier to follow by using promises as returns in place of consuming callbacks.
Pinging @elastic/es-security (Team:Security) |
server/src/main/java/org/elasticsearch/action/support/SubscribableListener.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we do something similar to flatten out RequestFilterChain#proceed
rather than using recursion there too?
try { | ||
res.rawResult(); | ||
} catch (Exception e) { | ||
listener.onFailure(e); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather add something like this to SubscribableListener
over exposing rawResult()
:
public boolean completeIfFailed(ActionListener<?> listener) {
final Object currentState = state;
if (currentState instanceof FailureResult result) {
listener.onFailure(result.exception());
return true;
} else {
return false;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went for just an isSuccess
now like other solutions have. There isn't much of a reason to be tricky for the failure path and this way we have a fast solution for the hot success path. Let me know what you think :) Combining this approach with the get-results on listenable futures would allow neat simplifications + speedups in some places I believe (by avoiding allocating new listeners).
...ugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java
Outdated
Show resolved
Hide resolved
...ugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java
Outdated
Show resolved
Hide resolved
I think we should yea, gotta be a little careful maybe because of thread-context though. That kind of thing is made it impossible to go further with this kind of change in security for the time being when I tried because any thread-local context that only exists around the |
public final boolean isSuccess() { | ||
return state instanceof SuccessResult; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bit LGTM, I'll leave the rest to the security team
We ahve some incredibly deep callstacks in security that seem to visibly raise context switch costs, make profiling more complicated and generally make the code rather hard to follow.
Also, deeply nested listener chains tend to make logic consume more heap because we almost inevitably continue holding on to things we no longer need as we go down the stack.
Since the methods adjusted here mostly return a result synchronously on the hot path, we can both save overhead (we can do a couple follow-ups to that effect) and make things a little easier to follow by using promises as returns in place of consuming callbacks.
A good example of the effects of this change would be this piece of search request REST handling that flattens out enormously.
Before:

After:
