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 }