use chrono::prelude::*;
use std::sync::atomic::{AtomicU64,Ordering};
static OFFSET: u64 = 1546300800;
static WORKER_ID: u64 = 1;
static WORKER_ID_BITS: u64 = 3;
static SEQUENCE_ID_BITS: u64 = 14;
static WORKER_SHIFT_BITS: u64 = SEQUENCE_ID_BITS;
static OFFSET_SHIFT_BITS: u64 = SEQUENCE_ID_BITS + WORKER_ID_BITS;
#[allow(dead_code)]
static WORKER_ID_MAX: u64 = ((1 << WORKER_ID_BITS) - 1) >> 1;
static BACK_WORKER_ID_BEGIN: u64 = (1 << WORKER_ID_BITS) >> 1;
static SEQUENCE_MAX: u64 = (1 << SEQUENCE_ID_BITS) - 1;
static BACK_TIME_MAX: u64 = 1;
static LAST_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
static SEQUENCE: AtomicU64 = AtomicU64::new(0);
static LAST_TIMESTAMP_BAK: AtomicU64 = AtomicU64::new(0);
static SEQUENCE_BAK: AtomicU64 = AtomicU64::new(0);
pub struct IdSeq {}
impl IdSeq {
pub fn next_id() -> u64 {
let now: DateTime<Local> = Local::now();
let mills: u64 = now.timestamp_millis().try_into().unwrap();
return Self::next_seid(mills / 1000);
}
pub fn next_seid(timestamp: u64) -> u64 {
if timestamp < LAST_TIMESTAMP.load(Ordering::Relaxed) {
println!(
"时钟回拨, 启用备份机器ID: now: [{}] last: [{}]",
timestamp, LAST_TIMESTAMP.load(Ordering::Relaxed)
);
return Self::next_id_backup(timestamp);
}
if timestamp != LAST_TIMESTAMP.load(Ordering::Relaxed) {
}
SEQUENCE.fetch_add(1, Ordering::Relaxed);
if 0 == (SEQUENCE.load(Ordering::Relaxed) & SEQUENCE_MAX) {
SEQUENCE.fetch_sub(1, Ordering::Relaxed);
return Self::next_id_backup(timestamp);
}
println!("timestamp: {} OFFSET:{}",×tamp,&OFFSET);
((timestamp - OFFSET) << OFFSET_SHIFT_BITS) | (WORKER_ID << WORKER_SHIFT_BITS) | SEQUENCE.load(Ordering::Relaxed)
}
pub fn next_id_backup(mut timestamp: u64) -> u64 {
if timestamp < LAST_TIMESTAMP_BAK.load(Ordering::Relaxed) {
let now: DateTime<Local> = Local::now();
let mills: u64 = now.timestamp_millis().try_into().unwrap();
if (LAST_TIMESTAMP_BAK.load(Ordering::Relaxed) - mills / 1000) <= BACK_TIME_MAX {
timestamp = LAST_TIMESTAMP_BAK.load(Ordering::Relaxed);
} else {
}
}
if timestamp != LAST_TIMESTAMP_BAK.load(Ordering::Relaxed) {
}
SEQUENCE_BAK.fetch_add(1, Ordering::Relaxed);
if 0 == (SEQUENCE_BAK.load(Ordering::Relaxed) & SEQUENCE_MAX) {
return Self::next_id_backup(timestamp + 1);
}
((timestamp - OFFSET) << OFFSET_SHIFT_BITS)
| ((WORKER_ID ^ BACK_WORKER_ID_BEGIN) << WORKER_SHIFT_BITS)
| SEQUENCE_BAK.load(Ordering::Relaxed)
}
}