From 277b54711ccd038290dc7463874fc9fc948fe424 Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 16 Mar 2023 09:36:49 +0800 Subject: [PATCH] feat: add snowflake --- Cargo.lock | 4 +++ Cargo.toml | 1 + crates/snowflake/Cargo.toml | 8 +++++ crates/snowflake/src/lib.rs | 63 +++++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 crates/snowflake/Cargo.toml create mode 100644 crates/snowflake/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 20c7d1d7..52ec66d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2522,6 +2522,10 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "snowflake" +version = "0.1.0" + [[package]] name = "socket2" version = "0.4.9" diff --git a/Cargo.toml b/Cargo.toml index fe1fd495..43daccac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,4 +77,5 @@ path = "src/lib.rs" members = [ "crates/token", "crates/revdb", + "crates/snowflake", ] \ No newline at end of file diff --git a/crates/snowflake/Cargo.toml b/crates/snowflake/Cargo.toml new file mode 100644 index 00000000..576e15ca --- /dev/null +++ b/crates/snowflake/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "snowflake" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crates/snowflake/src/lib.rs b/crates/snowflake/src/lib.rs new file mode 100644 index 00000000..8a63d8f1 --- /dev/null +++ b/crates/snowflake/src/lib.rs @@ -0,0 +1,63 @@ +use std::time::{Duration, SystemTime}; + +const EPOCH: u64 = 1420070400000; +const NODE_ID_BITS: u64 = 10; +const SEQUENCE_BITS: u64 = 12; +const NODE_ID_SHIFT: u64 = SEQUENCE_BITS; +const TIMESTAMP_SHIFT: u64 = NODE_ID_BITS + SEQUENCE_BITS; +const SEQUENCE_MASK: u64 = (1 << SEQUENCE_BITS) - 1; +const MAX_NODE_ID: u64 = (1 << NODE_ID_BITS) - 1; + +struct Snowflake { + node_id: u64, + sequence: u64, + last_timestamp: u64, +} + +impl Snowflake { + pub fn new(node_id: u64) -> Snowflake { + Snowflake { + node_id, + sequence: 0, + last_timestamp: 0, + } + } + + pub fn next_id(&mut self) -> u64 { + let timestamp = self.timestamp(); + if timestamp < self.last_timestamp { + panic!("Clock moved backwards!"); + } + + if timestamp == self.last_timestamp { + self.sequence = (self.sequence + 1) & SEQUENCE_MASK; + if self.sequence == 0 { + self.wait_next_millis(); + } + } else { + self.sequence = 0; + } + + self.last_timestamp = timestamp; + (timestamp - EPOCH) << TIMESTAMP_SHIFT | self.node_id << NODE_ID_SHIFT | self.sequence + } + + fn wait_next_millis(&self) { + let mut timestamp = self.timestamp(); + while timestamp == self.last_timestamp { + timestamp = self.timestamp(); + } + } + + fn timestamp(&self) -> u64 { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_millis() as u64 + } +} + +fn main() { + let mut snowflake = Snowflake::new(1); + println!("{}", snowflake.next_id()); +}