diff --git a/Rust/source/.gitignore b/Rust/source/.gitignore index 1e8572c..2db4c9f 100644 --- a/Rust/source/.gitignore +++ b/Rust/source/.gitignore @@ -39,7 +39,6 @@ TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ -dlldata.c # DNX project.lock.json @@ -252,7 +251,7 @@ paket-files/ # JetBrains Rider .idea/ *.sln.iml - +target/ # macOS .DS_Store diff --git a/Rust/source/Cargo.lock b/Rust/source/Cargo.lock new file mode 100644 index 0000000..5ac6d3c --- /dev/null +++ b/Rust/source/Cargo.lock @@ -0,0 +1,98 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "RS-SnowF" +version = "0.1.0" +dependencies = [ + "chrono", + "lazy_static", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Rust/source/Cargo.toml b/Rust/source/Cargo.toml new file mode 100644 index 0000000..7ea58de --- /dev/null +++ b/Rust/source/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "RS-SnowF" +version = "0.1.0" +authors = ["zhouzj "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +chrono = "0.4.10" +lazy_static = "1.4.0" + diff --git a/Rust/source/src/main.rs b/Rust/source/src/main.rs new file mode 100644 index 0000000..3d13bc4 --- /dev/null +++ b/Rust/source/src/main.rs @@ -0,0 +1,51 @@ +mod yitgen; + +use yitgen::contract::*; +use yitgen::gen::*; +use std::thread; +use chrono::Utc; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use std::ops::Deref; + +fn main() { + println!("Hello, world! Rust"); + + // 全局设置一次运行参数 + let mut options = IdGeneratorOptions::New(1); + options.WorkerId = 1; + options.WorkerIdBitLength = 1; + options.SeqBitLength = 6; + //... 可以继续设置其它 options 参数 + YitIdHelper::SetIdGenerator(options); + + // 以下开始测试生成数据,默认5W,单线程,可以修改 multiThread=true 启用多线程。 + loop { + let mut i = 0; + let mut id: i64 = 0; + let multiThread = false; + let start = Utc::now().timestamp_millis(); + + while i < 50000 { + i += 1; + if multiThread { // 这是多线程 + thread::spawn(move || { + id = YitIdHelper::NextId(); + println!("{}, id: {}", i, id); + }); + } else { // 这是单线程 + id = YitIdHelper::NextId(); + } + } + + println!("最后生成的id: {}", id); + if !multiThread { + // 多线程情况下,时间统计不准确 + let end = Utc::now().timestamp_millis(); + println!("单线程用时 {} ms", end - start); + } + + thread::sleep(std::time::Duration::from_millis(1000)); + } +} + diff --git a/Rust/source/src/yitgen/contract/i_snow_worker.rs b/Rust/source/src/yitgen/contract/i_snow_worker.rs new file mode 100644 index 0000000..303d553 --- /dev/null +++ b/Rust/source/src/yitgen/contract/i_snow_worker.rs @@ -0,0 +1,7 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +pub trait ISnowWorker { + fn NextId(&self) -> u64; +} \ No newline at end of file diff --git a/Rust/source/src/yitgen/contract/id_generator_options.rs b/Rust/source/src/yitgen/contract/id_generator_options.rs new file mode 100644 index 0000000..164ec83 --- /dev/null +++ b/Rust/source/src/yitgen/contract/id_generator_options.rs @@ -0,0 +1,42 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +use std::{thread, time}; +use std::net::UdpSocket; +use std::sync::{Arc, Mutex}; +use chrono::Utc; + +pub struct IdGeneratorOptions { + /// 雪花计算方法,(1-漂移算法|2-传统算法),默认1 + pub Method: u8, + /// 基础时间,不能超过当前系统时间 + pub BaseTime: i64, + /// 机器码,与 WorkerIdBitLength 有关系 + pub WorkerId: u16, + /// 机器码位长,范围:1-21(要求:序列数位长+机器码位长不超过22) + pub WorkerIdBitLength: u8, + /// 序列数位长,范围:2-21(要求:序列数位长+机器码位长不超过22) + pub SeqBitLength: u8, + /// 最大序列数(含),(由 SeqBitLength 计算的最大值) + pub MaxSeqNumber: u32, + /// 最小序列数(含),默认5,不小于1,不大于 MaxSeqNumber + pub MinSeqNumber: u32, + /// 最大漂移次数(含),默认2000,推荐范围 500-20000(与计算能力有关) + pub TopOverCostCount: u32, +} + +impl IdGeneratorOptions { + pub fn New(workerId: u16) -> IdGeneratorOptions { + return IdGeneratorOptions { + Method: 1, + WorkerId: workerId, + BaseTime: 1582136402000, + WorkerIdBitLength: 6, + SeqBitLength: 6, + MaxSeqNumber: 0, + MinSeqNumber: 5, + TopOverCostCount: 2000, + }; + } +} \ No newline at end of file diff --git a/Rust/source/src/yitgen/contract/mod.rs b/Rust/source/src/yitgen/contract/mod.rs new file mode 100644 index 0000000..769f846 --- /dev/null +++ b/Rust/source/src/yitgen/contract/mod.rs @@ -0,0 +1,13 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +mod id_generator_options; +mod i_snow_worker; +mod over_cost_action_arg; + +pub use id_generator_options::IdGeneratorOptions; +pub use i_snow_worker::ISnowWorker; +pub use over_cost_action_arg::OverCostActionArg; + + diff --git a/Rust/source/src/yitgen/contract/over_cost_action_arg.rs b/Rust/source/src/yitgen/contract/over_cost_action_arg.rs new file mode 100644 index 0000000..79f704d --- /dev/null +++ b/Rust/source/src/yitgen/contract/over_cost_action_arg.rs @@ -0,0 +1,12 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +pub struct OverCostActionArg { + ActionType: u32, + TimeTick: u64, + WorkerId: u16, + OverCostCountInOneTerm: u32, + GenCountInOneTerm: u32, + TermIndex: u32, +} \ No newline at end of file diff --git a/Rust/source/src/yitgen/core/mod.rs b/Rust/source/src/yitgen/core/mod.rs new file mode 100644 index 0000000..0dec16d --- /dev/null +++ b/Rust/source/src/yitgen/core/mod.rs @@ -0,0 +1,10 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +mod snow_worker_m1; +mod snow_worker_m2; + +pub use snow_worker_m1::SnowWorkerM1; +pub use snow_worker_m2::SnowWorkerM2; + diff --git a/Rust/source/src/yitgen/core/snow_worker_m1.rs b/Rust/source/src/yitgen/core/snow_worker_m1.rs new file mode 100644 index 0000000..acfcda7 --- /dev/null +++ b/Rust/source/src/yitgen/core/snow_worker_m1.rs @@ -0,0 +1,263 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +use super::super::contract::*; +use std::{thread}; +use chrono::Utc; +use std::sync::Mutex; +use std::sync::Arc; +use std::ops::Add; +use std::thread::sleep; +use std::sync::mpsc::channel; +use lazy_static::lazy_static; + +pub struct SnowWorkerM1 { + ///基础时间 + pub BaseTime: i64, + ///机器码 + pub WorkerId: u16, + ///机器码位长 + pub WorkerIdBitLength: u8, + ///自增序列数位长 + pub SeqBitLength: u8, + ///最大序列数(含) + pub MaxSeqNumber: u32, + ///最小序列数(含) + pub MinSeqNumber: u32, + ///最大漂移次数 + pub TopOverCostCount: u32, + + _TimestampShift: u8, + _CurrentSeqNumber: u32, + _LastTimeTick: i64, + _TurnBackTimeTick: i64, + _TurnBackIndex: u8, + _IsOverCost: bool, + _OverCostCountInOneTerm: u32, + _GenCountInOneTerm: u32, + _TermIndex: u32, +} + +impl SnowWorkerM1 { + pub fn Default() -> SnowWorkerM1 { + let options = IdGeneratorOptions::New(1); + return SnowWorkerM1::New(options); + } + + pub fn SetOptions(&mut self, options: IdGeneratorOptions) { + + // BaseTime + if options.BaseTime == 0 { + self.BaseTime = 1582136402000; + } else if options.BaseTime < 631123200000 || options.BaseTime > Utc::now().timestamp_millis() { + panic!("BaseTime error.") + } else { + self.BaseTime = options.BaseTime; + } + + // WorkerIdBitLength + if options.WorkerIdBitLength <= 0 + { + panic!("WorkerIdBitLength error.(range:[1, 21])"); + } + if options.SeqBitLength + options.WorkerIdBitLength > 22 { + panic!("error:WorkerIdBitLength + SeqBitLength <= 22") + } else { + self.WorkerIdBitLength = options.WorkerIdBitLength; + // self.WorkerIdBitLength = if options.WorkerIdBitLength == 0 { 6 } else { options.WorkerIdBitLength }; + } + + // WorkerId + let maxWorkerIdNumber = (2 as u16).pow(options.WorkerIdBitLength as u32) - 1; + if options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber { + panic!("WorkerId error. (range:[0, {} ]", if maxWorkerIdNumber <= 0 { 63 } else { maxWorkerIdNumber }) + } else { + self.WorkerId = options.WorkerId; + } + + // SeqBitLength + if options.SeqBitLength < 2 || options.SeqBitLength > 21 { + panic!("SeqBitLength error. (range:[2, 21])") + } else { + self.SeqBitLength = options.SeqBitLength; + // self.SeqBitLength = if options.SeqBitLength == 0 { 6 } else { options.SeqBitLength }; + } + + // MaxSeqNumber + let maxSeqNumber = (2 as u32).pow(options.SeqBitLength as u32) - 1; + if options.MaxSeqNumber > maxSeqNumber { + panic!("MaxSeqNumber error. (range:[1, {}]", maxSeqNumber) + } else { + self.MaxSeqNumber = if options.MaxSeqNumber <= 0 { (2 as u32).pow(options.SeqBitLength as u32) - 1 } else { options.MaxSeqNumber }; + } + + // MinSeqNumber + if options.MinSeqNumber > maxSeqNumber { + panic!("MinSeqNumber error. (range:[1, {}]", maxSeqNumber) + } else { + self.MinSeqNumber = options.MinSeqNumber; + } + + self.TopOverCostCount = if options.TopOverCostCount == 0 { 2000 } else { options.TopOverCostCount }; + self._TimestampShift = options.WorkerIdBitLength + options.SeqBitLength; + self._CurrentSeqNumber = options.MinSeqNumber; + + if options.Method == 1 { + sleep(std::time::Duration::from_millis(500)) + } + } + + pub fn New(options: IdGeneratorOptions) -> SnowWorkerM1 { + let mut worker = SnowWorkerM1 { + BaseTime: 1582136402000, + WorkerId: 0, + WorkerIdBitLength: 0, + SeqBitLength: 0, + MaxSeqNumber: 0, + MinSeqNumber: 0, + TopOverCostCount: 0, + _TimestampShift: 0, + _CurrentSeqNumber: 0, + _LastTimeTick: 0, + _TurnBackTimeTick: 0, + _TurnBackIndex: 0, + _IsOverCost: false, + _OverCostCountInOneTerm: 0, + _GenCountInOneTerm: 0, + _TermIndex: 0, + }; + + worker.SetOptions(options); + return worker; + } + + pub fn NextId(&mut self) -> i64 { + if self._IsOverCost { self.NextOverCostId() } else { self.NextNormalId() } + } + + fn DoGenIdAction(&self, arg: OverCostActionArg) {} + + fn BeginOverCostAction(&self, useTimeTick: i64) {} + + fn EndOverCostAction(&mut self, useTimeTick: i64) { + if self._TermIndex > 10000 { + self._TermIndex = 0; + } + } + + fn BeginTurnBackAction(&self, useTimeTick: i64) {} + + fn EndTurnBackAction(&self, useTimeTick: i64) {} + + fn NextOverCostId(&mut self) -> i64 { + let currentTimeTick = self.GetCurrentTimeTick(); + + if currentTimeTick > self._LastTimeTick { + self.EndOverCostAction(currentTimeTick); + self._LastTimeTick = currentTimeTick; + self._CurrentSeqNumber = self.MinSeqNumber; + self._IsOverCost = false; + self._OverCostCountInOneTerm = 0; + self._GenCountInOneTerm = 0; + + return self.CalcId(self._LastTimeTick); + } + + if self._OverCostCountInOneTerm >= self.TopOverCostCount { + self.EndOverCostAction(currentTimeTick); + self._LastTimeTick = self.GetNextTimeTick(); + self._CurrentSeqNumber = self.MinSeqNumber; + self._IsOverCost = false; + self._OverCostCountInOneTerm = 0; + self._GenCountInOneTerm = 0; + + return self.CalcId(self._LastTimeTick); + } + + if self._CurrentSeqNumber > self.MaxSeqNumber { + self._LastTimeTick += 1; + self._CurrentSeqNumber = self.MinSeqNumber; + self._IsOverCost = true; + self._OverCostCountInOneTerm += 1; + self._GenCountInOneTerm += 1; + + return self.CalcId(self._LastTimeTick); + } + + self._GenCountInOneTerm += 1; + return self.CalcId(self._LastTimeTick); + } + + fn NextNormalId(&mut self) -> i64 { + let currentTimeTick = self.GetCurrentTimeTick(); + + if currentTimeTick < self._LastTimeTick { + if self._TurnBackTimeTick < 1 { + self._TurnBackTimeTick = self._LastTimeTick - 1; + self._TurnBackIndex += 1; + // 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序 + // 最多4次回拨(防止回拨重叠) + if self._TurnBackIndex > 4 { + self._TurnBackIndex = 1; + } + self.BeginTurnBackAction(self._TurnBackTimeTick); + } + + thread::sleep(std::time::Duration::from_millis(10)); + return self.CalcTurnBackId(self._TurnBackTimeTick); + } + + // 时间追平时,_TurnBackTimeTick清零 + if self._TurnBackTimeTick > 0 { + self.EndTurnBackAction(self._TurnBackTimeTick); + self._TurnBackTimeTick = 0; + } + + if currentTimeTick > self._LastTimeTick { + self._LastTimeTick = currentTimeTick; + self._CurrentSeqNumber = self.MinSeqNumber; + return self.CalcId(self._LastTimeTick); + } + + if self._CurrentSeqNumber > self.MaxSeqNumber { + self.BeginOverCostAction(currentTimeTick); + self._TermIndex += 1; + self._LastTimeTick += 1; + self._CurrentSeqNumber = self.MinSeqNumber; + self._IsOverCost = true; + self._OverCostCountInOneTerm = 1; + self._GenCountInOneTerm = 1; + + return self.CalcId(self._LastTimeTick); + } + + return self.CalcId(self._LastTimeTick); + } + + fn CalcId(&mut self, useTimeTick: i64) -> i64 { + let result = (useTimeTick << self._TimestampShift) + (self.WorkerId << self.SeqBitLength) as i64 + (self._CurrentSeqNumber) as i64; + self._CurrentSeqNumber += 1; + return result; + } + + fn CalcTurnBackId(&mut self, useTimeTick: i64) -> i64 { + let result = (useTimeTick << self._TimestampShift) + (self.WorkerId << self.SeqBitLength) as i64 + (self._TurnBackIndex) as i64; + self._TurnBackTimeTick -= 1; + return result; + } + + fn GetCurrentTimeTick(&self) -> i64 { + return Utc::now().timestamp_millis() - self.BaseTime; + } + + fn GetNextTimeTick(&self) -> i64 { + let mut tempTimeTicker = self.GetCurrentTimeTick(); + + while tempTimeTicker <= self._LastTimeTick { + tempTimeTicker = self.GetCurrentTimeTick(); + } + + return tempTimeTicker; + } +} \ No newline at end of file diff --git a/Rust/source/src/yitgen/core/snow_worker_m2.rs b/Rust/source/src/yitgen/core/snow_worker_m2.rs new file mode 100644 index 0000000..a9093c1 --- /dev/null +++ b/Rust/source/src/yitgen/core/snow_worker_m2.rs @@ -0,0 +1,9 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +use super::super::contract::ISnowWorker; + +pub struct SnowWorkerM2 { + +} \ No newline at end of file diff --git a/Rust/source/src/yitgen/gen/default_id_generator.rs b/Rust/source/src/yitgen/gen/default_id_generator.rs new file mode 100644 index 0000000..c566b5a --- /dev/null +++ b/Rust/source/src/yitgen/gen/default_id_generator.rs @@ -0,0 +1,25 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +use std::{thread, time}; +use std::net::UdpSocket; +use chrono::Utc; +use super::super::contract::*; +use super::super::core::*; +use super::*; +use std::sync::Mutex; +use std::sync::Arc; +use std::borrow::BorrowMut; + +static mut instance2: Option>> = None; + +pub struct DefaultIdGenerator { + pub Worker: SnowWorkerM1, +} + +impl DefaultIdGenerator { + pub fn Default() -> DefaultIdGenerator { + DefaultIdGenerator { Worker: SnowWorkerM1::Default() } + } +} diff --git a/Rust/source/src/yitgen/gen/mod.rs b/Rust/source/src/yitgen/gen/mod.rs new file mode 100644 index 0000000..c0d329c --- /dev/null +++ b/Rust/source/src/yitgen/gen/mod.rs @@ -0,0 +1,9 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +mod default_id_generator; +mod yit_id_helper; + +pub use yit_id_helper::YitIdHelper; +pub use default_id_generator::DefaultIdGenerator; diff --git a/Rust/source/src/yitgen/gen/yit_id_helper.rs b/Rust/source/src/yitgen/gen/yit_id_helper.rs new file mode 100644 index 0000000..18b5d78 --- /dev/null +++ b/Rust/source/src/yitgen/gen/yit_id_helper.rs @@ -0,0 +1,37 @@ +/* + * 版权属于:yitter(yitter@126.com) + * 开源地址:https://gitee.com/yitter/idgenerator + */ +use super::super::contract::*; +use super::super::core::*; +use super::*; +use std::sync::Mutex; +use std::sync::Arc; +use lazy_static::lazy_static; + + +pub struct YitIdHelper; + +static mut idGenInstance: Option>> = None; + +impl YitIdHelper { + fn IdGenInstance() -> Arc> { + unsafe { + idGenInstance.get_or_insert_with(|| { + Arc::new(Mutex::new(DefaultIdGenerator::Default())) + }).clone() + } + } + + pub fn SetIdGenerator(options: IdGeneratorOptions) { + let mut idgenArc = YitIdHelper::IdGenInstance(); + let mut idgen = idgenArc.lock().unwrap(); + idgen.Worker.SetOptions(options); + } + + pub fn NextId() -> i64 { + let mut idgenArc = YitIdHelper::IdGenInstance(); + let mut idgen = idgenArc.lock().unwrap(); + idgen.Worker.NextId() + } +} diff --git a/Rust/source/src/yitgen/mod.rs b/Rust/source/src/yitgen/mod.rs new file mode 100644 index 0000000..b12d01c --- /dev/null +++ b/Rust/source/src/yitgen/mod.rs @@ -0,0 +1,3 @@ +pub mod contract; +pub mod core; +pub mod gen;