View Javadoc
1   /*
2    * Copyright (C) 2016, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.util.time;
12  
13  import static java.util.concurrent.TimeUnit.MICROSECONDS;
14  import static java.util.concurrent.TimeUnit.MILLISECONDS;
15  
16  import java.sql.Timestamp;
17  import java.time.Duration;
18  import java.time.Instant;
19  import java.util.Date;
20  import java.util.Iterator;
21  import java.util.concurrent.TimeUnit;
22  import java.util.concurrent.TimeoutException;
23  
24  /**
25   * A timestamp generated by
26   * {@link org.eclipse.jgit.util.time.MonotonicClock#propose()}.
27   * <p>
28   * ProposedTimestamp implements AutoCloseable so that implementations can
29   * release resources associated with obtaining certainty about time elapsing.
30   * For example the constructing MonotonicClock may start network IO with peers
31   * when creating the ProposedTimestamp, and {@link #close()} can ensure those
32   * network resources are released in a timely fashion.
33   *
34   * @since 4.6
35   */
36  public abstract class ProposedTimestamp implements AutoCloseable {
37  	/**
38  	 * Wait for several timestamps.
39  	 *
40  	 * @param times
41  	 *            timestamps to wait on.
42  	 * @param maxWait
43  	 *            how long to wait for the timestamps.
44  	 * @throws java.lang.InterruptedException
45  	 *             current thread was interrupted before the waiting process
46  	 *             completed normally.
47  	 * @throws java.util.concurrent.TimeoutException
48  	 *             the timeout was reached without the proposed timestamp become
49  	 *             certainly in the past.
50  	 */
51  	public static void blockUntil(Iterable<ProposedTimestamp> times,
52  			Duration maxWait) throws TimeoutException, InterruptedException {
53  		Iterator<ProposedTimestamp> itr = times.iterator();
54  		if (!itr.hasNext()) {
55  			return;
56  		}
57  
58  		long now = System.currentTimeMillis();
59  		long deadline = now + maxWait.toMillis();
60  		for (;;) {
61  			long w = deadline - now;
62  			if (w < 0) {
63  				throw new TimeoutException();
64  			}
65  			itr.next().blockUntil(Duration.ofMillis(w));
66  			if (itr.hasNext()) {
67  				now = System.currentTimeMillis();
68  			} else {
69  				break;
70  			}
71  		}
72  	}
73  
74  	/**
75  	 * Read the timestamp as {@code unit} since the epoch.
76  	 * <p>
77  	 * The timestamp value for a specific {@code ProposedTimestamp} object never
78  	 * changes, and can be read before {@link #blockUntil(Duration)}.
79  	 *
80  	 * @param unit
81  	 *            what unit to return the timestamp in. The timestamp will be
82  	 *            rounded if the unit is bigger than the clock's granularity.
83  	 * @return {@code unit} since the epoch.
84  	 */
85  	public abstract long read(TimeUnit unit);
86  
87  	/**
88  	 * Wait for this proposed timestamp to be certainly in the recent past.
89  	 * <p>
90  	 * This method forces the caller to wait up to {@code timeout} for
91  	 * {@code this} to pass sufficiently into the past such that the creating
92  	 * {@link org.eclipse.jgit.util.time.MonotonicClock} instance will not
93  	 * create an earlier timestamp.
94  	 *
95  	 * @param maxWait
96  	 *            how long the implementation may block the caller.
97  	 * @throws java.lang.InterruptedException
98  	 *             current thread was interrupted before the waiting process
99  	 *             completed normally.
100 	 * @throws java.util.concurrent.TimeoutException
101 	 *             the timeout was reached without the proposed timestamp
102 	 *             becoming certainly in the past.
103 	 */
104 	public abstract void blockUntil(Duration maxWait)
105 			throws InterruptedException, TimeoutException;
106 
107 	/**
108 	 * Get milliseconds since epoch; {@code read(MILLISECONDS}).
109 	 *
110 	 * @return milliseconds since epoch; {@code read(MILLISECONDS}).
111 	 */
112 	public long millis() {
113 		return read(MILLISECONDS);
114 	}
115 
116 	/**
117 	 * Get microseconds since epoch; {@code read(MICROSECONDS}).
118 	 *
119 	 * @return microseconds since epoch; {@code read(MICROSECONDS}).
120 	 */
121 	public long micros() {
122 		return read(MICROSECONDS);
123 	}
124 
125 	/**
126 	 * Get time since epoch, with up to microsecond resolution.
127 	 *
128 	 * @return time since epoch, with up to microsecond resolution.
129 	 */
130 	public Instant instant() {
131 		long usec = micros();
132 		long secs = usec / 1000000L;
133 		long nanos = (usec % 1000000L) * 1000L;
134 		return Instant.ofEpochSecond(secs, nanos);
135 	}
136 
137 	/**
138 	 * Get time since epoch, with up to microsecond resolution.
139 	 *
140 	 * @return time since epoch, with up to microsecond resolution.
141 	 */
142 	public Timestamp timestamp() {
143 		return Timestamp.from(instant());
144 	}
145 
146 	/**
147 	 * Get time since epoch, with up to millisecond resolution.
148 	 *
149 	 * @return time since epoch, with up to millisecond resolution.
150 	 */
151 	public Date date() {
152 		return new Date(millis());
153 	}
154 
155 	/**
156 	 * {@inheritDoc}
157 	 * <p>
158 	 * Release resources allocated by this timestamp.
159 	 */
160 	@Override
161 	public void close() {
162 		// Do nothing by default.
163 	}
164 
165 	/** {@inheritDoc} */
166 	@Override
167 	public String toString() {
168 		return instant().toString();
169 	}
170 }