-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8309939: HttpClient should not use Instant.now() as Instant source for deadlines #14450
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
Conversation
|
👋 Welcome back dfuchs! A progress list of the required criteria for merging this PR into |
Webrevs
|
| * There should be one of these per HttpClient. | ||
| */ | ||
| private ConnectionPool(String tag) { | ||
| ConnectionPool(long clientId, TimeSource timeSource) { |
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.
Hello Daniel, as far as I can see, no one calls this constructor outside of this very class and this seems to be always passed a constant TimeSource.source(). So maybe we don't have to have a timeSource field in this class and instead just use TimeSource.now() at call sites within this class (and ExpiryList) whenever we want now()?
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 constructor should in fact take an InstantSource, not a TimeSource. It was added in case we wanted to upgrade the whitebox ConnectionPoolTest to create an instance of ConnectionPool with a custom InstantSource.
| return now; | ||
| } | ||
|
|
||
| // @ForceInline |
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 these couple of commented out @ForceInline be deleted?
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.
Done
| // around. | ||
| // The use of Integer.MAX_VALUE is arbitrary. | ||
| // Any value not too close to Long.MAX_VALUE | ||
| // would do. |
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.
The Integer.MAX_VALUE gets used in isInWindow() method implementation, through the use of TIME_WINDOW member. Should this comment about Integer.MAX_VALUE instead be moved as a field comment for TIME_WINDOW? That way it's closer to where the Integer.MAX_VALUE is actually used.
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.
Done
| private NanoSource localSource = nanoSource; | ||
| private static final TimeSource SOURCE = new TimeSource(); | ||
|
|
||
| private static final class NanoSource implements InstantSource { |
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 class doesn't need to implement InstantSource
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.
Good point
| } | ||
|
|
||
| @Override | ||
| public Instant instant() { |
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 method is not used anywhere
| * of {@link System#nanoTime()}. This time source has the same property | ||
| * of monotonicity than the {@link System#nanoTime()} it is based on. | ||
| */ | ||
| public final class TimeSource implements InstantSource { |
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.
Given that all instances of TimeSource are essentially the same (through the use of shared nanoSource), can we add a private constructor and make this class a singleton?
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.
Good point. That's an oversight.
| * instants returned by this time source solely for the purpose of | ||
| * comparing them with other instants returned by this same time source. |
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.
Do not use Instant as the value from this time source. It is not comparable with the real Instants and would be misleading and cause bugs.
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.
OK. Here is a version that uses a new class "Deadline" instead of "Instant".
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.
Wrapping the Instant is safe/fine.
However, it could quite a bit simpler (it seems) to just use the raw long nanoTime values.
Though milliseconds or seconds would be sufficient for the timeouts.
The complexity of the volatile read and needing to reset the nanoSource could be avoided.
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.
Working with Instant (now Deadline) and Duration is much safer and easier than working with longs representing nano time, especially when you have a sorted list of deadlines. I'd argue that the complexity is when working with raw long nanoTime values.
|
|
||
| @Override | ||
| public String toString() { | ||
| return deadline.toString(); |
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'm not sure about using Instant.toString here; if we ever log a Deadline instance along with the current time and the clock skews, we will need to read the code along with the logs to figure out which date represents a deadline and which one represents an instant.
I guess the problem would also go away if we initialized the first NanoSource with something other than Instant.now().
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 can modify the toString to be
return "Deadline(" + deadline.toString() + ")";
if you think it's better.
But I do believe that using a fake instant for the origin of the NanoSource would be way more confusing.
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.
We can also avoid using that method. I guess we can always deal with it later if it proves to be a problem.
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.
Using nanoTime as @RogerRiggs suggested is worth exploring, but IMO the current version is good enough for internal use.
|
@dfuch This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 57 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
|
/integrate |
|
Going to push as commit f8f8bfb.
Your commit was automatically rebased without conflicts. |
The HttpClient uses
Instant.now()to create deadlines for timeouts. This could have undesirable effects sinceInstant.now()is linked to the wall clock, which is not monotonic. This fix changes the HttpClient to use a monotonic instant source based onSystem.nanoTime()for the purpose of setting and comparing deadlines.Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/14450/head:pull/14450$ git checkout pull/14450Update a local copy of the PR:
$ git checkout pull/14450$ git pull https://git.openjdk.org/jdk.git pull/14450/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 14450View PR using the GUI difftool:
$ git pr show -t 14450Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/14450.diff
Webrev
Link to Webrev Comment