├── .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