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.ArrayList;
19 import java.util.List;
20
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 import org.springframework.beans.factory.DisposableBean;
24 import org.springframework.util.Assert;
25
26 import com.baidu.fsg.uid.BitsAllocator;
27 import com.baidu.fsg.uid.UidGenerator;
28 import com.baidu.fsg.uid.buffer.BufferPaddingExecutor;
29 import com.baidu.fsg.uid.buffer.RejectedPutBufferHandler;
30 import com.baidu.fsg.uid.buffer.RejectedTakeBufferHandler;
31 import com.baidu.fsg.uid.buffer.RingBuffer;
32 import com.baidu.fsg.uid.exception.UidGenerateException;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class CachedUidGenerator extends DefaultUidGenerator implements DisposableBean {
52 private static final Logger LOGGER = LoggerFactory.getLogger(CachedUidGenerator.class);
53 private static final int DEFAULT_BOOST_POWER = 3;
54
55
56 private int boostPower = DEFAULT_BOOST_POWER;
57 private int paddingFactor = RingBuffer.DEFAULT_PADDING_PERCENT;
58 private Long scheduleInterval;
59
60 private RejectedPutBufferHandler rejectedPutBufferHandler;
61 private RejectedTakeBufferHandler rejectedTakeBufferHandler;
62
63
64 private RingBuffer ringBuffer;
65 private BufferPaddingExecutor bufferPaddingExecutor;
66
67 @Override
68 public void afterPropertiesSet() throws Exception {
69
70 super.afterPropertiesSet();
71
72
73 this.initRingBuffer();
74 LOGGER.info("Initialized RingBuffer successfully.");
75 }
76
77 @Override
78 public long getUID() {
79 try {
80 return ringBuffer.take();
81 } catch (Exception e) {
82 LOGGER.error("Generate unique id exception. ", e);
83 throw new UidGenerateException(e);
84 }
85 }
86
87 @Override
88 public String parseUID(long uid) {
89 return super.parseUID(uid);
90 }
91
92 @Override
93 public void destroy() throws Exception {
94 bufferPaddingExecutor.shutdown();
95 }
96
97
98
99
100
101
102
103 protected List<Long> nextIdsForOneSecond(long currentSecond) {
104
105 int listSize = (int) bitsAllocator.getMaxSequence() + 1;
106 List<Long> uidList = new ArrayList<>(listSize);
107
108
109 long firstSeqUid = bitsAllocator.allocate(currentSecond - epochSeconds, workerId, 0L);
110 for (int offset = 0; offset < listSize; offset++) {
111 uidList.add(firstSeqUid + offset);
112 }
113
114 return uidList;
115 }
116
117
118
119
120 private void initRingBuffer() {
121
122 int bufferSize = ((int) bitsAllocator.getMaxSequence() + 1) << boostPower;
123 this.ringBuffer = new RingBuffer(bufferSize, paddingFactor);
124 LOGGER.info("Initialized ring buffer size:{}, paddingFactor:{}", bufferSize, paddingFactor);
125
126
127 boolean usingSchedule = (scheduleInterval != null);
128 this.bufferPaddingExecutor = new BufferPaddingExecutor(ringBuffer, this::nextIdsForOneSecond, usingSchedule);
129 if (usingSchedule) {
130 bufferPaddingExecutor.setScheduleInterval(scheduleInterval);
131 }
132
133 LOGGER.info("Initialized BufferPaddingExecutor. Using schdule:{}, interval:{}", usingSchedule, scheduleInterval);
134
135
136 this.ringBuffer.setBufferPaddingExecutor(bufferPaddingExecutor);
137 if (rejectedPutBufferHandler != null) {
138 this.ringBuffer.setRejectedPutHandler(rejectedPutBufferHandler);
139 }
140 if (rejectedTakeBufferHandler != null) {
141 this.ringBuffer.setRejectedTakeHandler(rejectedTakeBufferHandler);
142 }
143
144
145 bufferPaddingExecutor.paddingBuffer();
146
147
148 bufferPaddingExecutor.start();
149 }
150
151
152
153
154 public void setBoostPower(int boostPower) {
155 Assert.isTrue(boostPower > 0, "Boost power must be positive!");
156 this.boostPower = boostPower;
157 }
158
159 public void setRejectedPutBufferHandler(RejectedPutBufferHandler rejectedPutBufferHandler) {
160 Assert.notNull(rejectedPutBufferHandler, "RejectedPutBufferHandler can't be null!");
161 this.rejectedPutBufferHandler = rejectedPutBufferHandler;
162 }
163
164 public void setRejectedTakeBufferHandler(RejectedTakeBufferHandler rejectedTakeBufferHandler) {
165 Assert.notNull(rejectedTakeBufferHandler, "RejectedTakeBufferHandler can't be null!");
166 this.rejectedTakeBufferHandler = rejectedTakeBufferHandler;
167 }
168
169 public void setScheduleInterval(long scheduleInterval) {
170 Assert.isTrue(scheduleInterval > 0, "Schedule interval must positive!");
171 this.scheduleInterval = scheduleInterval;
172 }
173
174 }