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 &gt;= key &amp;&amp; key &lt; 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}