001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.common.util; 017 018import org.modeshape.common.annotation.GuardedBy; 019import org.modeshape.common.annotation.ThreadSafe; 020 021/** 022 * This is a generator of simple unique and (non-monotonically) increasing long-value keys that incorporate the time in which they 023 * were generated. A single generator instance will never return two identical keys, and all keys are unique and naturally sorted 024 * in time. The generator is safe to be called concurrently from multiple threads. 025 * <p> 026 * Each long key value contains the time (in milliseconds) at which the key is generated, left-shifted by 16 bits. Those 16 bits 027 * are then used to store a counter value that is unique for each millisecond. When a new key is needed, the current time is 028 * compared to the last time for which a key was generated. If the times are different, then the counter is reset to 0; otherwise, 029 * the counter is incremented. 030 * </p> 031 * <p> 032 * Use a single generator instance for each sequence of keys. 033 * </p> 034 * <p> 035 * To obtain a unique value, simply call: 036 * 037 * <pre> 038 * TimeBasedKeys keys = TimeBasedKeys.create(); 039 * ... 040 * long key = keys.nextKey(); 041 * </pre> 042 * 043 * Because the keys are time-based, the generator can also identify the range of keys that were created before or after a given 044 * instant in time, or within a range of times. For example, all keys obtained after January 10, 2014 at 12:12:41.845-06:00 (which 045 * has a <code>System.currentTimeMillis()</code> value of {@code 1389378406}) will be greater than or equal to the following 046 * value: 047 * 048 * <pre> 049 * long timeInMillis = 1389378406L; 050 * long minKey = keys.getKeyStartingAt(timeInMillis); 051 * </pre> 052 * 053 * Using this and similar methods, one can obtain all counter values that might have been generated, for example, sometime during 054 * 2012: 055 * 056 * <pre> 057 * long janFirst2012 = 1325397600L; // Jan 1 2012 at 00:00.000 UTC 058 * long janFirst2013 = 1357020000L; // Jan 1 2013 at 00:00.000 UTC 059 * long smallestKey = keys.getKeyStartingAt(janFirst2012); 060 * long justLargerKey = keys.getKeyStartingAt(janFirst2013); 061 * </pre> 062 * 063 * Then all keys generated during 2012 will therefore satisfy: 064 * 065 * <pre> 066 * smallestKey >= key && key < justLargerKey 067 * </pre> 068 * 069 * </p> 070 * 071 * @author Randall Hauch (rhauch@redhat.com) 072 */ 073@ThreadSafe 074public final class TimeBasedKeys { 075 076 /** 077 * By default each {@link TimeBasedKeys} instance will use 16 bits for the counter. That results in a maximum of of 65535 078 * distinct values per millisecond (which is likely sufficient), while also leaving enough bits in the long to store a value 079 * well past the year 10,000. 080 */ 081 public static final short DEFAULT_BITS_IN_COUNTER = 16; 082 083 /** 084 * Create a new generator that uses 16 bits for the counter portion of the keys. 085 * 086 * @return the generator instance; never null 087 */ 088 public static TimeBasedKeys create() { 089 return new TimeBasedKeys(DEFAULT_BITS_IN_COUNTER); 090 } 091 092 /** 093 * Create a new generator that uses the specified number of bits for the counter portion of the keys. 094 * 095 * @param bitsUsedInCounter the number of bits in the counter portion of the keys; must be a positive number for which theere 096 * is enough space to left shift without overflowing. 097 * @return the generator instance; never null 098 */ 099 public static TimeBasedKeys create( int bitsUsedInCounter ) { 100 CheckArg.isPositive(bitsUsedInCounter, "bitsUsedInCounter"); 101 int maxAvailableBitsToShift = Long.numberOfLeadingZeros(System.currentTimeMillis()); 102 CheckArg.isLessThan(bitsUsedInCounter, maxAvailableBitsToShift, "bitsUsedInCounter"); 103 return new TimeBasedKeys((short)bitsUsedInCounter); 104 } 105 106 /** 107 * The number of bits used in the counter portion of the key. 108 */ 109 private final short counterBits; 110 111 /** 112 * The maximum counter portion of the key given the number of {@link #counterBits}. 113 */ 114 private final long maximumCounterValue; 115 116 /** 117 * The last millis in UTC that was seen. This is only accessed and modified within the synchronized {@link #counterFor(long)} 118 * method. 119 */ 120 @GuardedBy( "this" ) 121 private volatile long lastMillis; 122 123 /** 124 * The last counter that was used with the current value of {@link #lastMillis}. This is only accessed and modified within the 125 * synchronized {@link #counterFor(long)} method. 126 */ 127 @GuardedBy( "this" ) 128 private volatile int counter; 129 130 /** 131 * Create a new key generator. 132 * 133 * @param bitsUsedInCounter the number of bits to be used in the counter. 134 */ 135 protected TimeBasedKeys( short bitsUsedInCounter ) { 136 this.counterBits = bitsUsedInCounter; 137 this.maximumCounterValue = (1L << bitsUsedInCounter) - 1L; 138 } 139 140 /** 141 * Get the next key for the current time in UTC. 142 * 143 * @return a long that is determined by the current time in UTC and a unique counter value for the current time. 144 */ 145 public long nextKey() { 146 // Note that per Oracle the currentTimeMillis is the current number of seconds past the epoch 147 // in UTC (not in local time). Therefore, processes with exactly synchronized clocks will 148 // always get the same value regardless of their timezone ... 149 final long timestamp = System.currentTimeMillis(); 150 final int increment = counterFor(timestamp); 151 if (increment <= maximumCounterValue) { 152 return (timestamp << counterBits) + increment; 153 } 154 // The counter is surprisingly too high, so try again (repeatedly) until we get to the next millisecond ... 155 return this.nextKey(); 156 } 157 158 /** 159 * Obtain the first (earliest) key that would have been generated <em>at</em> the specified UTC time. The resulting key is 160 * equal to or smaller than all keys generated at or since that time. 161 * 162 * @param millisInUtc the number of milliseconds (in UTC) past epoch, and the time at which {@link #nextKey()} might have been 163 * called 164 * @return a long value that is the earliest possible key for the given time 165 */ 166 public long getCounterStartingAt( long millisInUtc ) { 167 return (millisInUtc << counterBits); 168 } 169 170 /** 171 * Obtain the largest (latest) key that would have been generated <em>at</em> the specified UTC time. The resulting key is 172 * equal to or greater than all keys generated at or before that time. 173 * 174 * @param millisInUtc the number of milliseconds (in UTC) past epoch, and the time at which {@link #nextKey()} might have been 175 * called 176 * @return a long value that is the latest possible key for the given time 177 */ 178 public long getCounterEndingAt( long millisInUtc ) { 179 return (millisInUtc << counterBits) + maximumCounterValue; 180 } 181 182 /** 183 * Obtain the first (earliest) key that would have been generated <em>after</em> the specified UTC time. The resulting key is 184 * greater than all keys generated at or before that time. 185 * 186 * @param millisInUtc the number of milliseconds (in UTC) past epoch, and the time at which {@link #nextKey()} might have been 187 * called 188 * @return a long value that is the latest possible key for the given time 189 */ 190 public long getCounterEndingAfter( long millisInUtc ) { 191 return (millisInUtc + 1) << counterBits; 192 } 193 194 /** 195 * Obtain the milliseconds since epoch in UTC that the supplied key was generated. The value is the same value that would have 196 * been returned by {@link System#currentTimeMillis()} when the key was generated. 197 * 198 * @param key the key 199 * @return the generated time, in millseconds past epoch 200 */ 201 public long getTimeGenerated( long key ) { 202 return key < maximumCounterValue ? 0 : key >> counterBits; 203 } 204 205 /** 206 * Determine the counter portion of the key given the supplied time. This method is synchronized to ensure that the 207 * {@link #counter} and {@link #lastMillis} are updated atomically. 208 * 209 * @param timestamp the current timestamp, and the new value for the {@link #lastMillis} field 210 * @return the next available counter for the given timestamp 211 */ 212 private synchronized int counterFor( long timestamp ) { 213 if (timestamp == lastMillis) { 214 // Just increment the counter... 215 counter += 1; 216 } else { 217 // Otherwise, the timestamp has changed, so set it and reset the counter ... 218 lastMillis = timestamp; 219 counter = 0; 220 } 221 return counter; 222 } 223}