1 /*
2  * Copyright (C) 2015 Brett Wooldridge
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package com.zaxxer.hikari.util;
18
19 import static java.util.concurrent.TimeUnit.DAYS;
20 import static java.util.concurrent.TimeUnit.HOURS;
21 import static java.util.concurrent.TimeUnit.MICROSECONDS;
22 import static java.util.concurrent.TimeUnit.MILLISECONDS;
23 import static java.util.concurrent.TimeUnit.MINUTES;
24 import static java.util.concurrent.TimeUnit.NANOSECONDS;
25 import static java.util.concurrent.TimeUnit.SECONDS;
26
27 import java.util.concurrent.TimeUnit;
28
29 /**
30  * A resolution-independent provider of current time-stamps and elapsed time
31  * calculations.
32  *
33  * @author Brett Wooldridge
34  */

35 public interface ClockSource
36 {
37    static ClockSource CLOCK = Factory.create();
38
39    /**
40     * Get the current time-stamp (resolution is opaque).
41     *
42     * @return the current time-stamp
43     */

44    static long currentTime() {
45       return CLOCK.currentTime0();
46    }
47
48    long currentTime0();
49
50    /**
51     * Convert an opaque time-stamp returned by currentTime() into
52     * milliseconds.
53     *
54     * @param time an opaque time-stamp returned by an instance of this class
55     * @return the time-stamp in milliseconds
56     */

57    static long toMillis(long time) {
58       return CLOCK.toMillis0(time);
59    }
60
61    long toMillis0(long time);
62
63    /**
64     * Convert an opaque time-stamp returned by currentTime() into
65     * nanoseconds.
66     *
67     * @param time an opaque time-stamp returned by an instance of this class
68     * @return the time-stamp in nanoseconds
69     */

70    static long toNanos(long time) {
71       return CLOCK.toNanos0(time);
72    }
73
74    long toNanos0(long time);
75
76    /**
77     * Convert an opaque time-stamp returned by currentTime() into an
78     * elapsed time in milliseconds, based on the current instant in time.
79     *
80     * @param startTime an opaque time-stamp returned by an instance of this class
81     * @return the elapsed time between startTime and now in milliseconds
82     */

83    static long elapsedMillis(long startTime) {
84       return CLOCK.elapsedMillis0(startTime);
85    }
86
87    long elapsedMillis0(long startTime);
88
89    /**
90     * Get the difference in milliseconds between two opaque time-stamps returned
91     * by currentTime().
92     *
93     * @param startTime an opaque time-stamp returned by an instance of this class
94     * @param endTime an opaque time-stamp returned by an instance of this class
95     * @return the elapsed time between startTime and endTime in milliseconds
96     */

97    static long elapsedMillis(long startTime, long endTime) {
98       return CLOCK.elapsedMillis0(startTime, endTime);
99    }
100
101    long elapsedMillis0(long startTime, long endTime);
102
103    /**
104     * Convert an opaque time-stamp returned by currentTime() into an
105     * elapsed time in milliseconds, based on the current instant in time.
106     *
107     * @param startTime an opaque time-stamp returned by an instance of this class
108     * @return the elapsed time between startTime and now in milliseconds
109     */

110    static long elapsedNanos(long startTime) {
111       return CLOCK.elapsedNanos0(startTime);
112    }
113
114    long elapsedNanos0(long startTime);
115
116    /**
117     * Get the difference in nanoseconds between two opaque time-stamps returned
118     * by currentTime().
119     *
120     * @param startTime an opaque time-stamp returned by an instance of this class
121     * @param endTime an opaque time-stamp returned by an instance of this class
122     * @return the elapsed time between startTime and endTime in nanoseconds
123     */

124    static long elapsedNanos(long startTime, long endTime) {
125       return CLOCK.elapsedNanos0(startTime, endTime);
126    }
127
128    long elapsedNanos0(long startTime, long endTime);
129
130    /**
131     * Return the specified opaque time-stamp plus the specified number of milliseconds.
132     *
133     * @param time an opaque time-stamp
134     * @param millis milliseconds to add
135     * @return a new opaque time-stamp
136     */

137    static long plusMillis(long time, long millis) {
138       return CLOCK.plusMillis0(time, millis);
139    }
140
141    long plusMillis0(long time, long millis);
142
143    /**
144     * Get the TimeUnit the ClockSource is denominated in.
145     * @return
146     */

147    static TimeUnit getSourceTimeUnit() {
148       return CLOCK.getSourceTimeUnit0();
149    }
150
151    TimeUnit getSourceTimeUnit0();
152
153    /**
154     * Get a String representation of the elapsed time in appropriate magnitude terminology.
155     *
156     * @param startTime an opaque time-stamp
157     * @param endTime an opaque time-stamp
158     * @return a string representation of the elapsed time interval
159     */

160    static String elapsedDisplayString(long startTime, long endTime) {
161       return CLOCK.elapsedDisplayString0(startTime, endTime);
162    }
163
164    default String elapsedDisplayString0(long startTime, long endTime) {
165       long elapsedNanos = elapsedNanos0(startTime, endTime);
166
167       StringBuilder sb = new StringBuilder(elapsedNanos < 0 ? "-" : "");
168       elapsedNanos = Math.abs(elapsedNanos);
169
170       for (TimeUnit unit : TIMEUNITS_DESCENDING) {
171          long converted = unit.convert(elapsedNanos, NANOSECONDS);
172          if (converted > 0) {
173             sb.append(converted).append(TIMEUNIT_DISPLAY_VALUES[unit.ordinal()]);
174             elapsedNanos -= NANOSECONDS.convert(converted, unit);
175          }
176       }
177
178       return sb.toString();
179    }
180
181    TimeUnit[] TIMEUNITS_DESCENDING = {DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS};
182
183    String[] TIMEUNIT_DISPLAY_VALUES = {"ns""µs""ms""s""m""h""d"};
184
185    /**
186     * Factory class used to create a platform-specific ClockSource.
187     */

188    class Factory
189    {
190       private static ClockSource create() {
191          String os = System.getProperty("os.name");
192          if ("Mac OS X".equals(os)) {
193             return new MillisecondClockSource();
194          }
195
196          return new NanosecondClockSource();
197       }
198    }
199
200    final class MillisecondClockSource implements ClockSource
201    {
202       /** {@inheritDoc} */
203       @Override
204       public long currentTime0() {
205          return System.currentTimeMillis();
206       }
207
208       /** {@inheritDoc} */
209       @Override
210       public long elapsedMillis0(final long startTime) {
211          return System.currentTimeMillis() - startTime;
212       }
213
214       /** {@inheritDoc} */
215       @Override
216       public long elapsedMillis0(final long startTime, final long endTime) {
217          return endTime - startTime;
218       }
219
220       /** {@inheritDoc} */
221       @Override
222       public long elapsedNanos0(final long startTime) {
223          return MILLISECONDS.toNanos(System.currentTimeMillis() - startTime);
224       }
225
226       /** {@inheritDoc} */
227       @Override
228       public long elapsedNanos0(final long startTime, final long endTime) {
229          return MILLISECONDS.toNanos(endTime - startTime);
230       }
231
232       /** {@inheritDoc} */
233       @Override
234       public long toMillis0(final long time) {
235          return time;
236       }
237
238       /** {@inheritDoc} */
239       @Override
240       public long toNanos0(final long time) {
241          return MILLISECONDS.toNanos(time);
242       }
243
244       /** {@inheritDoc} */
245       @Override
246       public long plusMillis0(final long time, final long millis) {
247          return time + millis;
248       }
249
250       /** {@inheritDoc} */
251       @Override
252       public TimeUnit getSourceTimeUnit0() {
253          return MILLISECONDS;
254       }
255    }
256
257    class NanosecondClockSource implements ClockSource
258    {
259       /** {@inheritDoc} */
260       @Override
261       public long currentTime0() {
262          return System.nanoTime();
263       }
264
265       /** {@inheritDoc} */
266       @Override
267       public long toMillis0(final long time) {
268          return NANOSECONDS.toMillis(time);
269       }
270
271       /** {@inheritDoc} */
272       @Override
273       public long toNanos0(final long time) {
274          return time;
275       }
276
277       /** {@inheritDoc} */
278       @Override
279       public long elapsedMillis0(final long startTime) {
280          return NANOSECONDS.toMillis(System.nanoTime() - startTime);
281       }
282
283       /** {@inheritDoc} */
284       @Override
285       public long elapsedMillis0(final long startTime, final long endTime) {
286          return NANOSECONDS.toMillis(endTime - startTime);
287       }
288
289       /** {@inheritDoc} */
290       @Override
291       public long elapsedNanos0(final long startTime) {
292          return System.nanoTime() - startTime;
293       }
294
295       /** {@inheritDoc} */
296       @Override
297       public long elapsedNanos0(final long startTime, final long endTime) {
298          return endTime - startTime;
299       }
300
301       /** {@inheritDoc} */
302       @Override
303       public long plusMillis0(final long time, final long millis) {
304          return time + MILLISECONDS.toNanos(millis);
305       }
306
307       /** {@inheritDoc} */
308       @Override
309       public TimeUnit getSourceTimeUnit0() {
310          return NANOSECONDS;
311       }
312    }
313 }
314