/*
* Long.MAX_VALUE : 9 2 2 3 3 7 2 0 3 6 8 5 4 7 7 5 8 0 7 Total 19 digits
*
* lets use fist 2 digit for peer id
* now we are left with 17 digits
* if we restrict peer id between 10 - 91
*
* then rest all 17 could be all 9's to hold in long
*
* lets create 10 UIDGenerator Objects each with unique id [0-9]
*
* so now we are left with 16 digits
*
* so if we start at some time
* System.currentTimeMillis() : 1360443174566 (13 digit)
*
* ID : XXY1360443174566TTT
* XX : peer id
* Y : object instance ID
* 1360443174566 : System.currentMillis(); //seed will change on every restart
* TTT : 000 Allowing to generate 999 message max per millisecond
*
* so we can generate max 999 unique ids per millisecond
* means safe to generate approx: 1000 per millisecond, to overcome uniqueness over jvm restart
*
* we can generate 9999999999999999-1360443174566000 = 863955682543999 * 10 unique ids
* (Aprox:8000 Trillion )before getting duplicate if we start on 1360443174566
*
* Possible Failure
* 1. system time is reset
* 2. generating more than 10000 per millisecond then does not gives guarantee over jvm restart.
*/
public class UIDUtil {
private static UIDUtil instance;
private UIDGenerator[] uidGenerators;
private static short MAX_ALLOWED_PEER_ID = 91;
private static short MIN_ALLOWED_PEER_ID = 10;
private long totalIdsGenerated;
private long startTime;
private UIDUtil() {
short peerId = loadPeerId();
uidGenerators = new UIDGenerator[10];
for(byte i=0; i<10; i++) {
uidGenerators[i] = new UIDGenerator(peerId, i);
}
startTime = System.currentTimeMillis();
}
public static UIDUtil getInstance() {
if(instance == null)
instance = new UIDUtil();
return instance;
}
public long getNextId() {
return uidGenerators[(int) ((totalIdsGenerated++)%10)].getNextID();
}
private short loadPeerId() {
//TODO: load peerId from properties, db, remote etc
short peerId = 90;
if(peerId > MAX_ALLOWED_PEER_ID || peerId < MIN_ALLOWED_PEER_ID) {
peerId = (short) (MIN_ALLOWED_PEER_ID + (short)(Math.random() * ((MAX_ALLOWED_PEER_ID - MIN_ALLOWED_PEER_ID) + 1)));
try {
throw new Exception("Peer ID must be in the range : "+MIN_ALLOWED_PEER_ID+"-"+MAX_ALLOWED_PEER_ID+" inclusive");
} catch (Exception e) {
e.printStackTrace();
}
}
return peerId;
}
public long getTotalIdsGenerated() {
return totalIdsGenerated;
}
public double getIdProducingRate() {
long elapsedTime = System.currentTimeMillis()-startTime;
if(elapsedTime == 0)
elapsedTime = 1;
return (double) (totalIdsGenerated/elapsedTime)*1000;
}
}
public class UIDGenerator {
private long variableId ;
private long fixedId;
private static long MAX_ALLOWED_VARIABLE_ID = 9999999999999999l;
public UIDGenerator(short peerId, byte index) {
//place peer on proper decimal location
fixedId = (long) (peerId*Math.pow(10, 17));//exp : 9100000000000000000
fixedId += (long) (index*Math.pow(10, 16));//exp : 9130000000000000000
//initialise with 16 digit seed
variableId = loadVariableId();
}
public synchronized long getNextID() {
long newId = variableId++;
if(newId == MAX_ALLOWED_VARIABLE_ID) {
variableId = loadVariableId();
}
return (fixedId + newId);
}
private long loadVariableId() {
long currentTime = System.currentTimeMillis();
long temp = currentTime;
byte digits = 0;
while(temp > 0) {
temp /= 10;
digits++;
}
return (long) (currentTime*Math.pow(10, 16-digits));
}
}
No comments:
Post a Comment