├── .classpath ├── .project ├── README.md ├── lib ├── commons-codec-1.6.jar └── uuid-3.2.1-SNAPSHOT.jar └── src └── uniq └── UniqueId.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | flake-java 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unique Id generator 2 | 3 | Based on http://blog.boundary.com/2012/01/12/Flake-A-decentralized-k-ordered-id-generation-service-in-Erlang.html 4 | which is in turn based on Twitter's Snowflake project: http://engineering.twitter.com/2010/06/announcing-snowflake.html 5 | 6 | Generates unique ids based on the current epoch time, current machine identity, 7 | and a counter. The result are mostly ordered unique ids that require no 8 | synchronization between machines. 9 | 10 | 11 | # Compile and run 12 | 13 | javac -cp .:./lib/uuid-3.2.1-SNAPSHOT.jar:./lib/commons-codec-1.6.jar src/uniq/UniqueId.java 14 | java -cp .:./lib/uuid-3.2.1-SNAPSHOT.jar:./lib/commons-codec-1.6.jar:src uniq.UniqueId 15 | 16 | # Performance 17 | 18 | 2011 MacBook Pro, 2.8Ghz i7 19 | 20 | ## Cat to file 21 | 22 | $ time java -cp .:./lib/uuid-3.2.1-SNAPSHOT.jar:./lib/commons-codec-1.6.jar:src uniq.UniqueId 10000000 > out 23 | 24 | real 0m18.498s 25 | user 0m5.662s 26 | sys 0m12.973s 27 | 28 | $ ls -lh out 29 | -rw-r--r-- 1 mumrah staff 153M May 22 10:52 out 30 | 31 | 540 id/ms 32 | 33 | Since each id is 128 bits, the I/O rate comes out to 8640000 bytes per second, or 8.24 MB/s. 34 | Compare this to 66.59 MB/s which is the speed that the same system can "yes > omgyes". I guess that order of 35 | magnitude difference is the price of safety/synchronization. 36 | 37 | ## Pipe to /dev/null 38 | 39 | $ time java -cp .:./lib/uuid-3.2.1-SNAPSHOT.jar:./lib/commons-codec-1.6.jar:src uniq.UniqueId 10000000 > /dev/null 40 | 41 | real 0m7.794s 42 | user 0m4.688s 43 | sys 0m3.253s 44 | 45 | 1280 id/ms 46 | 47 | ## Pipe to fifo, fifo to /dev/null 48 | 49 | $ time java -cp .:./lib/uuid-3.2.1-SNAPSHOT.jar:./lib/commons-codec-1.6.jar:src uniq.UniqueId 10000000 > foo 50 | 51 | real 0m18.051s 52 | user 0m5.594s 53 | sys 0m12.594s 54 | 55 | 554 id/ms 56 | 57 | 58 | -------------------------------------------------------------------------------- /lib/commons-codec-1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumrah/flake-java/59515e66db968dd473e30c7427c28386aefa5d73/lib/commons-codec-1.6.jar -------------------------------------------------------------------------------- /lib/uuid-3.2.1-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumrah/flake-java/59515e66db968dd473e30c7427c28386aefa5d73/lib/uuid-3.2.1-SNAPSHOT.jar -------------------------------------------------------------------------------- /src/uniq/UniqueId.java: -------------------------------------------------------------------------------- 1 | package uniq; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | 6 | import com.eaio.uuid.UUIDGen; 7 | 8 | public class UniqueId { 9 | 10 | // Get the MAC address (i.e., the "node" from a UUID1) 11 | private final long clockSeqAndNode = UUIDGen.getClockSeqAndNode(); 12 | private final byte[] node = new byte[]{ 13 | (byte)((clockSeqAndNode >> 40) & 0xff), 14 | (byte)((clockSeqAndNode >> 32) & 0xff), 15 | (byte)((clockSeqAndNode >> 24) & 0xff), 16 | (byte)((clockSeqAndNode >> 16) & 0xff), 17 | (byte)((clockSeqAndNode >> 8) & 0xff), 18 | (byte)((clockSeqAndNode >> 0) & 0xff), 19 | }; 20 | private final ThreadLocal tlbb = new ThreadLocal() { 21 | @Override 22 | public ByteBuffer initialValue() { 23 | return ByteBuffer.allocate(16); 24 | } 25 | }; 26 | 27 | private volatile int seq; 28 | private volatile long lastTimestamp; 29 | private final Object lock = new Object(); 30 | 31 | private final int maxShort = (int)0xffff; 32 | 33 | public byte[] getId() { 34 | if(seq == maxShort) { 35 | throw new RuntimeException("Too fast"); 36 | } 37 | 38 | long time; 39 | synchronized(lock) { 40 | time = System.currentTimeMillis(); 41 | if(time != lastTimestamp) { 42 | lastTimestamp = time; 43 | seq = 0; 44 | } 45 | seq++; 46 | ByteBuffer bb = tlbb.get(); 47 | bb.rewind(); 48 | bb.putLong(time); 49 | bb.put(node); 50 | bb.putShort((short)seq); 51 | return bb.array(); 52 | } 53 | } 54 | 55 | public String getStringId() { 56 | byte[] ba = getId(); 57 | ByteBuffer bb = ByteBuffer.wrap(ba); 58 | long ts = bb.getLong(); 59 | int node_0 = bb.getInt(); 60 | short node_1 = bb.getShort(); 61 | short seq = bb.getShort(); 62 | return String.format("%016d-%s%s-%04d", ts, Integer.toHexString(node_0), Integer.toHexString(node_1), seq); 63 | } 64 | 65 | public static void main(String[] args) throws IOException { 66 | UniqueId uid = new UniqueId(); 67 | int n = Integer.parseInt(args[0]); 68 | 69 | for(int i=0; i