1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.baidu.fsg.uid.impl;
17
18 import java.util.Date;
19 import java.util.concurrent.TimeUnit;
20
21 import org.apache.commons.lang.StringUtils;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import org.springframework.beans.factory.InitializingBean;
25
26 import com.baidu.fsg.uid.BitsAllocator;
27 import com.baidu.fsg.uid.UidGenerator;
28 import com.baidu.fsg.uid.exception.UidGenerateException;
29 import com.baidu.fsg.uid.utils.DateUtils;
30 import com.baidu.fsg.uid.worker.WorkerIdAssigner;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class DefaultUidGenerator implements UidGenerator, InitializingBean {
62 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultUidGenerator.class);
63
64
65 protected int timeBits = 28;
66 protected int workerBits = 22;
67 protected int seqBits = 13;
68
69
70 protected String epochStr = "2016-05-20";
71 protected long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1463673600000L);
72
73
74 protected BitsAllocator bitsAllocator;
75 protected long workerId;
76
77
78 protected long sequence = 0L;
79 protected long lastSecond = -1L;
80
81
82 protected WorkerIdAssigner workerIdAssigner;
83
84 @Override
85 public void afterPropertiesSet() throws Exception {
86
87 bitsAllocator = new BitsAllocator(timeBits, workerBits, seqBits);
88
89
90 workerId = workerIdAssigner.assignWorkerId();
91 if (workerId > bitsAllocator.getMaxWorkerId()) {
92 throw new RuntimeException("Worker id " + workerId + " exceeds the max " + bitsAllocator.getMaxWorkerId());
93 }
94
95 LOGGER.info("Initialized bits(1, {}, {}, {}) for workerID:{}", timeBits, workerBits, seqBits, workerId);
96 }
97
98 @Override
99 public long getUID() throws UidGenerateException {
100 try {
101 return nextId();
102 } catch (Exception e) {
103 LOGGER.error("Generate unique id exception. ", e);
104 throw new UidGenerateException(e);
105 }
106 }
107
108 @Override
109 public String parseUID(long uid) {
110 long totalBits = BitsAllocator.TOTAL_BITS;
111 long signBits = bitsAllocator.getSignBits();
112 long timestampBits = bitsAllocator.getTimestampBits();
113 long workerIdBits = bitsAllocator.getWorkerIdBits();
114 long sequenceBits = bitsAllocator.getSequenceBits();
115
116
117 long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
118 long workerId = (uid << (timestampBits + signBits)) >>> (totalBits - workerIdBits);
119 long deltaSeconds = uid >>> (workerIdBits + sequenceBits);
120
121 Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
122 String thatTimeStr = DateUtils.formatByDateTimePattern(thatTime);
123
124
125 return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
126 uid, thatTimeStr, workerId, sequence);
127 }
128
129
130
131
132
133
134
135 protected synchronized long nextId() {
136 long currentSecond = getCurrentSecond();
137
138
139 if (currentSecond < lastSecond) {
140 long refusedSeconds = lastSecond - currentSecond;
141 throw new UidGenerateException("Clock moved backwards. Refusing for %d seconds", refusedSeconds);
142 }
143
144
145 if (currentSecond == lastSecond) {
146 sequence = (sequence + 1) & bitsAllocator.getMaxSequence();
147
148 if (sequence == 0) {
149 currentSecond = getNextSecond(lastSecond);
150 }
151
152
153 } else {
154 sequence = 0L;
155 }
156
157 lastSecond = currentSecond;
158
159
160 return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);
161 }
162
163
164
165
166 private long getNextSecond(long lastTimestamp) {
167 long timestamp = getCurrentSecond();
168 while (timestamp <= lastTimestamp) {
169 timestamp = getCurrentSecond();
170 }
171
172 return timestamp;
173 }
174
175
176
177
178 private long getCurrentSecond() {
179 long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
180 if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {
181 throw new UidGenerateException("Timestamp bits is exhausted. Refusing UID generate. Now: " + currentSecond);
182 }
183
184 return currentSecond;
185 }
186
187
188
189
190 public void setWorkerIdAssigner(WorkerIdAssigner workerIdAssigner) {
191 this.workerIdAssigner = workerIdAssigner;
192 }
193
194 public void setTimeBits(int timeBits) {
195 if (timeBits > 0) {
196 this.timeBits = timeBits;
197 }
198 }
199
200 public void setWorkerBits(int workerBits) {
201 if (workerBits > 0) {
202 this.workerBits = workerBits;
203 }
204 }
205
206 public void setSeqBits(int seqBits) {
207 if (seqBits > 0) {
208 this.seqBits = seqBits;
209 }
210 }
211
212 public void setEpochStr(String epochStr) {
213 if (StringUtils.isNotBlank(epochStr)) {
214 this.epochStr = epochStr;
215 this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(DateUtils.parseByDayPattern(epochStr).getTime());
216 }
217 }
218 }