package hu.sztaki.ilab.longneck.bootstrap;
import java.util.Calendar;
import java.util.GregorianCalendar;
/**
*
* @author Molnár Péter <molnarp@sztaki.mta.hu>
*/
public class DecimalKeyGenerator implements KeyGenerator {
/** Number of bits representing the node. */
private int nodePlaces = 0;
/** Number of bits representing the current timestamp. */
private int timestampPlaces = 13;
/** Counter for records processed at the same millisecond. */
private int serialPlaces = 5;
/** The last timestamp. */
private long lastTimestamp;
/** Last issued serial. */
private long lastSerial = 0;
/** The highest serial number available. */
private long maxSerial;
/** The calendar to query milliseconds from. */
private Calendar calendar = new GregorianCalendar();
/** The id of the current node. */
private long nodeId = 0;
public DecimalKeyGenerator() {
}
public DecimalKeyGenerator(long nodeId) {
//assert nodePlaces >= 1;
//assert (nodeId < IMath.lpow(10, nodePlaces));
// Assign node id and check, if it fits into node bits
this.maxSerial = lpow(10, serialPlaces) - 1;
}
/**
* Initializes the key generator.
*
* @param nodeId The numeric id of the node.
* @param nodeBits The number of bits for the node id.
* @param timestampBits The number of bits used for the timestamp.
* @param serialBits The number of bits used for the serial number.
* @throws AssertionError If the parts of the key do not fit into the bits specified.
*/
public DecimalKeyGenerator(long nodeId, int nodePlaces, int timestampPlaces, int serialPlaces) {
this(nodeId);
//assert nodePlaces >= 1;
//assert (nodeId < IMath.lpow(10, nodePlaces));
assert timestampPlaces >= 1;
assert calendar.getTimeInMillis() < lpow(10, timestampPlaces);
assert serialPlaces >= 1;
assert ((timestampPlaces + serialPlaces) <= 18);
// Assign node id and check, if it fits into node bits
this.nodeId = nodeId;
// this.nodePlaces = nodePlaces;
this.timestampPlaces = timestampPlaces;
this.serialPlaces = serialPlaces;
this.maxSerial = lpow(10, serialPlaces) - 1;
}
/**
* Returns the next key.
*
* @return The generated key.
* @throws AssertionError If serial incrementation results in overflow.
*/
@Override
public long getNext() {
long timestamp = calendar.getTimeInMillis();
if (lastTimestamp < timestamp) {
lastTimestamp = timestamp;
lastSerial = 0;
} else {
++lastSerial;
}
assert (lastSerial <= maxSerial);
return (
//(IMath.lpow(10, timestampPlaces + serialPlaces) * nodeId) +
(lpow(10, serialPlaces) * lastTimestamp) +
lastSerial);
}
/**
* Thread-safe implementation of next key.
*
* @return The generated key.
* @throws AssertionError If serial incrementation results in overflow.
*/
@Override
public synchronized long getNextThreadSafe() {
return getNext();
}
public static long lpow(long base, long exp) {
int result = 1;
while (exp > 0) {
if ((exp & 1) > 0)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
}