13
13
* See the License for the specific language governing permissions and
14
14
* limitations under the License.
15
15
*/
16
- package com .mongodb .internal ;
16
+ package com .mongodb .internal . time ;
17
17
18
18
import com .mongodb .annotations .Immutable ;
19
+ import com .mongodb .internal .VisibleForTesting ;
19
20
20
21
import java .util .Objects ;
21
22
import java .util .concurrent .TimeUnit ;
22
23
23
24
import static com .mongodb .assertions .Assertions .assertFalse ;
24
- import static com .mongodb .assertions .Assertions .assertNotNull ;
25
25
import static com .mongodb .assertions .Assertions .assertTrue ;
26
26
import static com .mongodb .internal .VisibleForTesting .AccessModifier .PRIVATE ;
27
27
import static java .util .concurrent .TimeUnit .MILLISECONDS ;
28
28
import static java .util .concurrent .TimeUnit .NANOSECONDS ;
29
29
30
30
/**
31
31
* A <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html">value-based</a> class
32
- * useful for tracking timeouts.
33
- *
34
- * <p> This class is not part of the public API and may be removed or changed at any time</p>
32
+ * for tracking timeouts.
33
+ * <p>
34
+ * This class is not part of the public API and may be removed or changed at any time. </p>
35
35
*/
36
36
@ Immutable
37
37
public final class Timeout {
38
- private static final Timeout INFINITE = new Timeout (-1 , 0 );
39
- private static final Timeout IMMEDIATE = new Timeout (0 , 0 );
38
+ private static final Timeout INFINITE = new Timeout (-1 , Timer . useless () );
39
+ private static final Timeout IMMEDIATE = new Timeout (0 , Timer . useless () );
40
40
41
41
private final long durationNanos ;
42
- private final long startNanos ;
42
+ private final Timer timer ;
43
43
44
- private Timeout (final long durationNanos , final long startNanos ) {
44
+ private Timeout (final long durationNanos , final Timer timer ) {
45
45
this .durationNanos = durationNanos ;
46
- this .startNanos = startNanos ;
46
+ this .timer = timer ;
47
47
}
48
48
49
49
/**
50
- * Converts the specified {@code duration} from {@code unit}s to {@link TimeUnit#NANOSECONDS} via {@link TimeUnit#toNanos(long)}
51
- * and then acts identically to {@link #startNow (long)}.
50
+ * Converts the specified {@code duration} from {@code unit}s to {@link TimeUnit#NANOSECONDS}
51
+ * as specified by {@link TimeUnit#toNanos(long)} and then acts identically to {@link #started (long, Timer )}.
52
52
* <p>
53
53
* Note that the contract of this method is also used in some places to specify the behavior of methods that accept
54
54
* {@code (long timeout, TimeUnit unit)}, e.g., {@link com.mongodb.internal.connection.ConcurrentPool#get(long, TimeUnit)},
55
- * so it cannot be changed without updating those methods.
56
- * @see #startNow (long)
55
+ * so it cannot be changed without updating those methods.</p>
56
+ * @see #started (long, Timer )
57
57
*/
58
- public static Timeout startNow (final long duration , final TimeUnit unit ) {
59
- assertNotNull (unit );
60
- return startNow (unit .toNanos (duration ));
58
+ public static Timeout started (final long duration , final TimeUnit unit , final Timer timer ) {
59
+ return started (unit .toNanos (duration ), timer );
61
60
}
62
61
63
62
/**
64
63
* Returns an {@linkplain #isInfinite() infinite} timeout if {@code durationNanos} is either negative
65
64
* or is equal to {@link Long#MAX_VALUE},
66
65
* an {@linkplain #isImmediate() immediate} timeout if {@code durationNanos} is 0,
67
- * otherwise an object that represents the specified {@code durationNanos}.
66
+ * otherwise a timeout of {@code durationNanos}.
68
67
* <p>
69
68
* Note that the contract of this method is also used in some places to specify the behavior of methods that accept
70
69
* {@code (long timeout, TimeUnit unit)}, e.g., {@link com.mongodb.internal.connection.ConcurrentPool#get(long, TimeUnit)},
71
- * so it cannot be changed without updating those methods.
70
+ * so it cannot be changed without updating those methods.</p>
72
71
*/
73
- public static Timeout startNow (final long durationNanos ) {
72
+ public static Timeout started (final long durationNanos , final Timer timer ) {
74
73
if (durationNanos < 0 || durationNanos == Long .MAX_VALUE ) {
75
74
return infinite ();
76
75
} else if (durationNanos == 0 ) {
77
76
return immediate ();
78
77
} else {
79
- return new Timeout (durationNanos , System . nanoTime () );
78
+ return new Timeout (durationNanos , timer );
80
79
}
81
80
}
82
81
83
82
/**
84
- * @see #startNow (long)
83
+ * @see #started (long, Timer )
85
84
*/
86
85
public static Timeout infinite () {
87
86
return INFINITE ;
88
87
}
89
88
90
89
/**
91
- * @see #startNow (long)
90
+ * @see #started (long, Timer )
92
91
*/
93
92
public static Timeout immediate () {
94
93
return IMMEDIATE ;
95
94
}
96
95
97
- /**
98
- * Must not be called on {@linkplain #isInfinite() infinite} or {@linkplain #isImmediate() immediate} timeouts.
99
- * <p>
100
- * Returns {@code currentNanos} - {@link #startNanos}:
101
- * <ul>
102
- * <li>
103
- * A negative value means either of the following
104
- * <ol>
105
- * <li>the clock from which {@code currentNanos} was read jumped backwards,
106
- * in which case the behaviour of this class is undefined;</li>
107
- * <li>(n * 2<sup>63</sup> - 1; (n + 1) * 2<sup>63</sup>)<sup>(*)</sup> nanoseconds has elapsed,
108
- * in which case the timeout has expired.</li>
109
- * </ol>
110
- * </li>
111
- * <li>
112
- * 0 means either of the following
113
- * <ol>
114
- * <li>0 nanoseconds has elapsed;</li>
115
- * <li>(n + 1) * 2<sup>63</sup><sup>(*)</sup> nanoseconds has elapsed,
116
- * in which case the timeout has expired.</li>
117
- * </ol>
118
- * Since it is impossible to differentiate the former from the latter, and the former is much more likely to happen in practice,
119
- * this class interprets 0 value as 0 elapsed nanoseconds.
120
- * </li>
121
- * <li>
122
- * A positive value means either of the following
123
- * <ol>
124
- * <li>this exact number of nanoseconds has elapsed;</li>
125
- * <li>((n + 1) * 2<sup>63</sup>; (n + 2) * 2<sup>63</sup> - 1]<sup>(*)</sup> nanoseconds has elapsed,
126
- * in which case the timeout has expired.</li>
127
- * </ol>
128
- * Since it is impossible to differentiate the former from the latter, and the former is much more likely to happen in practice,
129
- * this class interprets a positive value as the exact number of elapsed nanoseconds.
130
- * </li>
131
- * </ul>
132
- * <hr>
133
- * <sup>(*)</sup> n is positive and odd.
134
- */
135
- private long elapsedNanos (final long currentNanos ) {
136
- assertFalse (isInfinite () || isImmediate ());
137
- return currentNanos - startNanos ;
138
- }
139
-
140
96
/**
141
97
* Returns 0 or a positive value.
142
98
* 0 means that the timeout has expired.
143
- * <p>
144
- * Must not be called on {@linkplain #isInfinite() infinite} timeouts.
99
+ *
100
+ * @throws AssertionError If the timeout is {@linkplain #isInfinite() infinite} or {@linkplain #isImmediate() immediate},
101
+ * because such timeouts use {@link Timer#useless()}.
145
102
*/
146
103
@ VisibleForTesting (otherwise = PRIVATE )
147
- long remainingNanos (final long currentNanos ) {
104
+ long nonNegativeRemainingNanos (final long currentNanos ) {
148
105
assertFalse (isInfinite () || isImmediate ());
149
- long elapsedNanos = elapsedNanos (currentNanos );
150
- return elapsedNanos < 0 ? 0 : Math .max (0 , durationNanos - elapsedNanos );
106
+ return Math .max (0 , durationNanos - timer .elapsedNanos (currentNanos ));
151
107
}
152
108
153
109
/**
154
110
* Returns 0 or a positive value converted to the specified {@code unit}s.
155
111
* Use {@link #expired(long)} to check if the returned value signifies that a timeout is expired.
156
112
*
157
113
* @param unit If not {@link TimeUnit#NANOSECONDS}, then coarsening conversion is done that may result in returning a value
158
- * that represents a longer time duration than is actually remaining (this is done to prevent treating a timeout as
159
- * {@linkplain #expired(long) expired} when it is not). Consequently, one should specify {@code unit} as small as
160
- * practically possible. Such rounding up happens if and only if the remaining time cannot be
161
- * represented exactly as an integral number of the {@code unit}s specified. It may result in
162
- * {@link #expired()} returning {@code true} and after that (in the happens-before order)
163
- * {@link #expired(long) expired}{@code (}{@link #remaining(TimeUnit) remaining(...)}{@code )}
164
- * returning {@code false}. If such a discrepancy is observed,
165
- * the result of the {@link #expired()} method should be preferred.
114
+ * that represents a longer time duration than is actually remaining (this is done to prevent treating a timeout as
115
+ * {@linkplain #expired(long) expired} when it is not). Consequently, one should specify {@code unit} as small as
116
+ * practically possible. Such rounding up happens if and only if the remaining time cannot be
117
+ * represented exactly as an integral number of the {@code unit}s specified. It may result in
118
+ * {@link #expired()} returning {@code true} and after that (in the happens-before order)
119
+ * {@link #expired(long) expired}{@code (}{@link #remaining(TimeUnit) remaining(...)}{@code )}
120
+ * returning {@code false}. If such a discrepancy is observed,
121
+ * the result of the {@link #expired()} method should be preferred.
166
122
*
167
123
* @throws AssertionError If the timeout is {@linkplain #isInfinite() infinite}.
168
124
* @see #remainingOrInfinite(TimeUnit)
169
125
*/
170
126
public long remaining (final TimeUnit unit ) {
171
- assertNotNull (unit );
172
127
assertFalse (isInfinite ());
173
- return isImmediate () ? 0 : convertRoundUp (remainingNanos (System .nanoTime ()), unit );
128
+ return isImmediate () ? 0 : convertRoundUp (nonNegativeRemainingNanos (System .nanoTime ()), unit );
174
129
}
175
130
176
131
/**
@@ -181,7 +136,6 @@ public long remaining(final TimeUnit unit) {
181
136
* @see #remaining(TimeUnit)
182
137
*/
183
138
public long remainingOrInfinite (final TimeUnit unit ) {
184
- assertNotNull (unit );
185
139
return isInfinite () ? -1 : remaining (unit );
186
140
}
187
141
@@ -226,12 +180,12 @@ public boolean equals(final Object o) {
226
180
return false ;
227
181
}
228
182
Timeout other = (Timeout ) o ;
229
- return durationNanos == other .durationNanos && startNanos == other .startNanos ;
183
+ return durationNanos == other .durationNanos && timer == other .timer ;
230
184
}
231
185
232
186
@ Override
233
187
public int hashCode () {
234
- return Objects .hash (durationNanos , startNanos );
188
+ return Objects .hash (durationNanos , timer );
235
189
}
236
190
237
191
/**
@@ -243,7 +197,7 @@ public int hashCode() {
243
197
public String toString () {
244
198
return "Timeout{"
245
199
+ "durationNanos=" + durationNanos
246
- + ", startNanos =" + startNanos
200
+ + ", timer =" + timer
247
201
+ '}' ;
248
202
}
249
203
@@ -268,8 +222,8 @@ long durationNanos() {
268
222
}
269
223
270
224
@ VisibleForTesting (otherwise = PRIVATE )
271
- long startNanos () {
272
- return startNanos ;
225
+ Timer timer () {
226
+ return timer ;
273
227
}
274
228
275
229
@ VisibleForTesting (otherwise = PRIVATE )
0 commit comments