@Service
@Scope(value="singleton")
public class SequenceGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(SequenceGenerator.class);
private final float REDUNDANCY = 0.85F;
@Autowired
private JdbcTemplate jdbcTemplate;
private int machineID;
private long seq = 0;
private long maxSeq = 100000;
private int stepSeq = 100000;
private long deathLine = (long)(maxSeq * REDUNDANCY);
private boolean initFlag = false;
private boolean updateFlag = false;
private Map<String, Long> container = new HashMap();
public void init(int machineID) throws DataAccessException {
this.machineID = machineID;
List<Map<String, Object>> rows = jdbcTemplate.queryForList("SELECT * FROM chat WHERE machine_id = ?", new Object[] { machineID });
if (rows.size() == 0) {
initFlag = true;
String dateString = DateUtil.getNowString();
jdbcTemplate.update(
"INSERT INTO chat (machine_id, max_value, step_value, created_at, updated_at) VALUES (?, ?, ?, ?, ?)",
new Object[] {machineID, maxSeq, stepSeq, dateString, dateString}
);
LOGGER.info(toString());
return;
}
seq = (long) rows.get(0).get("max_value");
maxSeq = (long) rows.get(0).get("max_value");
stepSeq = (int) rows.get(0).get("step_value");
updateSeq();
initFlag = true;
}
private void updateSeq() throws DataAccessException {
LOGGER.info("Update sequence starting...");
String dateString = DateUtil.getNowString();
long _maxSeq = maxSeq + stepSeq;
long _deathLine = (long)(_maxSeq * REDUNDANCY);
jdbcTemplate.update(
"UPDATE chat SET max_value = ?, updated_at = ? WHERE machine_id = ?",
new Object[] {_maxSeq, dateString, machineID}
);
maxSeq = _maxSeq;
deathLine = _deathLine;
LOGGER.info(toString());
LOGGER.info("Update sequence finish");
}
public synchronized long getSeq(String groupID) {
if (!initFlag) {
throw new RuntimeException("The generator not initialized yet");
}
long _seq = container.getOrDefault(groupID, seq);
_seq++;
if (_seq >= deathLine) {
startUpdateSeq();
}
if (_seq >= maxSeq) {
throw new RuntimeException("The sequence has reached its limit");
}
container.put(groupID, _seq);
return _seq;
}
private synchronized void startUpdateSeq() {
if (updateFlag) {
return;
}
updateFlag = true;
new Thread(() -> {
try {
updateSeq();
} catch (DataAccessException dae) {
LOGGER.error(dae.getMessage());
} finally {
updateFlag = false;
}
}).start();
}
@Override
public String toString() {
return "SequenceGenerator{" +
"machineID=" + machineID +
", seq=" + seq +
", maxSeq=" + maxSeq +
", stepSeq=" + stepSeq +
", deathLine=" + deathLine +
'}';
}
}
我不确定我实现的跟那篇文章的想法有没有对上
不过我不是以 uid 当区分,我用的是 gid(两人私聊也可以当作是一种群聊)
但我对以下这部分有点存疑
public synchronized long getSeq(String groupID) {
if (!initFlag) {
throw new RuntimeException("The generator not initialized yet");
}
long _seq = container.getOrDefault(groupID, seq);
_seq++;
if (_seq >= deathLine) {
startUpdateSeq();
}
if (_seq >= maxSeq) {
throw new RuntimeException("The sequence has reached its limit");
}
container.put(groupID, _seq);
return _seq;
}