1
0
mirror of synced 2026-02-08 05:57:55 +08:00

auto commit

This commit is contained in:
yitter
2021-08-31 11:52:53 +08:00
parent 2308932d25
commit c669af4cbe
8 changed files with 37 additions and 37 deletions

4
JavaScript/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.vscode
node_modules
package-lock.json
env.config.js

28
JavaScript/README.md Normal file
View File

@@ -0,0 +1,28 @@
# ❄ idgenerator-Node.js
## 介绍
项目更多介绍参照https://github.com/yitter/idgenerator
代码贡献者bubao 布宝
执行测试代码
```bash
node test/test2.js
```
## 使用
```js
const GenId = require("./index.js")
const genid = new GenId({ WorkerId: 1 });
for (let index = 0; index < 5000; index++) {
console.log(genid.NextId());
}
```
## 其他帮助
在mysql中int类型最大长度是10位数字由于本算法默认生成的是15位最短也是11位所以在mysql中需要使用bigint数据类型

210
JavaScript/index.js Normal file
View File

@@ -0,0 +1,210 @@
/**
* @description:
* @author: bubao
*/
class Genid {
/**
*Creates an instance of Genid.
* @author bubao
* @param {{
* Method: 1, // 雪花计算方法1-漂移算法|2-传统算法),默认 1
* BaseTime: 1577836800000, // 基础时间ms 单位),不能超过当前系统时间
* WorkerId: Number, // 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
* WorkerIdBitLength: 6, // 机器码位长,默认值 6取值范围 [1, 15](要求:序列数位长+机器码位长不超过 22)
* SeqBitLength: 6, // 序列数位长,默认值 6取值范围 [3, 21](要求:序列数位长+机器码位长不超过 22)
* MaxSeqNumber: 5, // 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值 0表示最大序列数取最大值2^SeqBitLength-1]
* MinSeqNumber: 5, // 最小序列数(含),默认值 5取值范围 [5, MaxSeqNumber],每毫秒的前 5 个序列数对应编号 0-4 是保留位,其中 1-4 是时间回拨相应预留位0 是手工新值预留位
* TopOverCostCount: 2000// 最大漂移次数(含),默认 2000推荐范围 500-10000与计算能力有关
* }} options
* @memberof Genid
*/
constructor(options) {
if (options.WorkerId === undefined) {
throw new Error("lost WorkerId");
}
// 1.BaseTime
const BaseTime = 1577836800000;
if (!options.BaseTime || options.BaseTime < 0) {
options.BaseTime = BaseTime;
}
// 2.WorkerIdBitLength
const WorkerIdBitLength = 6;
if (!options.WorkerIdBitLength || options.WorkerIdBitLength < 0) {
options.WorkerIdBitLength = WorkerIdBitLength;
}
// 4.SeqBitLength
const SeqBitLength = 6;
if (!options.SeqBitLength || options.SeqBitLength < 0) {
options.SeqBitLength = SeqBitLength;
}
// 5.MaxSeqNumber
const MaxSeqNumber = (1 << SeqBitLength) - 1;
if (options.MaxSeqNumber <= 0 || options.MaxSeqNumber === undefined) {
options.MaxSeqNumber = MaxSeqNumber;
}
// 6.MinSeqNumber
const MinSeqNumber = 5;
if (!options.MinSeqNumber || options.MinSeqNumber < 0) {
options.MinSeqNumber = MinSeqNumber;
}
// 7.Others
const topOverCostCount = 2000;
if (!options.TopOverCostCount || options.TopOverCostCount < 0) {
options.TopOverCostCount = topOverCostCount;
}
if (options.Method !== 2) {
options.Method = 1;
} else {
options.Method = 2;
}
this.Method = BigInt(options.Method);
this.BaseTime = BigInt(options.BaseTime);
this.WorkerId = BigInt(options.WorkerId);
this.WorkerIdBitLength = BigInt(options.WorkerIdBitLength);
this.SeqBitLength = BigInt(options.SeqBitLength);
this.MaxSeqNumber = BigInt(options.MaxSeqNumber);
this.MinSeqNumber = BigInt(options.MinSeqNumber);
this.TopOverCostCount = BigInt(options.TopOverCostCount);
const timestampShift = this.WorkerIdBitLength + this.SeqBitLength;
const currentSeqNumber = this.MinSeqNumber;
this._TimestampShift = timestampShift;
this._CurrentSeqNumber = currentSeqNumber;
this._LastTimeTick = 0;
this._TurnBackTimeTick = 0;
this._TurnBackIndex = 0;
this._IsOverCost = false;
this._OverCostCountInOneTerm = 0;
}
// DoGenIDAction .
DoGenIdAction(OverCostActionArg) { }
BeginOverCostAction(useTimeTick) { }
EndOverCostAction(useTimeTick) {
// if m1._TermIndex > 10000 {
// m1._TermIndex = 0
// }
}
BeginTurnBackAction(useTimeTick) { }
EndTurnBackAction(useTimeTick) { }
NextOverCostId() {
const currentTimeTick = this.GetCurrentTimeTick();
if (currentTimeTick > this._LastTimeTick) {
// this.EndOverCostAction(currentTimeTick)
this._LastTimeTick = currentTimeTick;
this._CurrentSeqNumber = this.MinSeqNumber;
this._IsOverCost = false;
this._OverCostCountInOneTerm = 0;
// this._GenCountInOneTerm = 0
return this.CalcId(this._LastTimeTick);
}
if (this._OverCostCountInOneTerm >= this.TopOverCostCount) {
// this.EndOverCostAction(currentTimeTick)
this._LastTimeTick = this.GetNextTimeTick();
this._CurrentSeqNumber = this.MinSeqNumber;
this._IsOverCost = false;
this._OverCostCountInOneTerm = 0;
// this._GenCountInOneTerm = 0
return this.CalcId(this._LastTimeTick);
}
if (this._CurrentSeqNumber > this.MaxSeqNumber) {
this._LastTimeTick++;
this._CurrentSeqNumber = this.MinSeqNumber;
this._IsOverCost = true;
this._OverCostCountInOneTerm++;
// this._GenCountInOneTerm++
return this.CalcId(this._LastTimeTick);
}
// this._GenCountInOneTerm++
return this.CalcId(this._LastTimeTick);
}
NextNormalId() {
const currentTimeTick = this.GetCurrentTimeTick();
if (currentTimeTick < this._LastTimeTick) {
if (this._TurnBackTimeTick < 1) {
this._TurnBackTimeTick = this._LastTimeTick - 1;
this._TurnBackIndex++;
// 每毫秒序列数的前 5 位是预留位0 用于手工新值1-4 是时间回拨次序
// 支持 4 次回拨次序(避免回拨重叠导致 ID 重复),可无限次回拨(次序循环使用)。
if (this._TurnBackIndex > 4) {
this._TurnBackIndex = 1;
}
this.BeginTurnBackAction(this._TurnBackTimeTick);
}
return this.CalcTurnBackId(this._TurnBackTimeTick);
}
// 时间追平时_TurnBackTimeTick 清零
if (this._TurnBackTimeTick > 0) {
this.EndTurnBackAction(this._TurnBackTimeTick);
this._TurnBackTimeTick = 0;
}
if (currentTimeTick > this._LastTimeTick) {
this._LastTimeTick = currentTimeTick;
this._CurrentSeqNumber = this.MinSeqNumber;
return this.CalcId(this._LastTimeTick);
}
if (this._CurrentSeqNumber > this.MaxSeqNumber) {
this.BeginOverCostAction(currentTimeTick);
// this._TermIndex++
this._LastTimeTick++;
this._CurrentSeqNumber = this.MinSeqNumber;
this._IsOverCost = true;
this._OverCostCountInOneTerm = 1;
// this._GenCountInOneTerm = 1
return this.CalcId(this._LastTimeTick);
}
return this.CalcId(this._LastTimeTick);
}
CalcId(useTimeTick) {
const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._CurrentSeqNumber);
this._CurrentSeqNumber++;
return result;
}
CalcTurnBackId(useTimeTick) {
const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._TurnBackIndex);
this._TurnBackTimeTick--;
return result;
}
GetCurrentTimeTick() {
const millis = BigInt((new Date()).valueOf());
return millis - this.BaseTime;
}
GetNextTimeTick() {
let tempTimeTicker = this.GetCurrentTimeTick();
while (tempTimeTicker <= this._LastTimeTick) {
tempTimeTicker = this.GetCurrentTimeTick();
}
return tempTimeTicker;
}
NextId() {
if (this._IsOverCost) {
return parseInt(this.NextOverCostId());
} else {
return parseInt(this.NextNormalId());
}
}
}
module.exports = Genid;

22
JavaScript/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "cherry-id",
"version": "0.0.3",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "node ./test/test.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/bubao/cherry-id-js.git"
},
"author": "bubao",
"license": "MIT",
"bugs": {
"url": "https://github.com/bubao/cherry-id-js/issues"
},
"homepage": "https://github.com/bubao/cherry-id-js#readme",
"description": ""
}

View File

@@ -0,0 +1,54 @@
/**
* @description:
* @author: bubao
* @date: 2021-04-27 23:38:30
* @last author: bubao
* @last edit time: 2021-04-28 10:35:20
*/
const Redis = require("ioredis");
const { spawn } = require("child_process");
const config = require("../env.config.js");
const redis = new Redis(config);
//保存被子进程实例数组
var workers = {};
//这里的被子进程理论上可以无限多
// var appsPath = [__dirname+'/service/clickService.js',__dirname+'/service/showService.js'];
var createWorker = function (appPath, i) {
//保存spawn返回的进程实例
var worker = spawn('node', [appPath, i]);
//监听子进程exit事件
worker.on('exit', async function () {
console.info('worker:' + worker.pid + 'exited');
delete workers[worker.pid];
// createWorker(appPath);
if (Object.keys(workers).length === 0) {
console.log(await redis.scard('setTest'));
await redis.del("setTest");
redis.end();
}
});
workers[worker.pid] = worker;
console.info('create worker:' + worker.pid);
};
redis.del("setTest").then(() => {
//启动所有子进程
for (var i = 10; i > 0; i--) {
createWorker(__dirname + '/test.js', i);
}
});
//父进程退出时杀死所有子进程
process.on('exit', async function () {
console.info('parent exit.');
for (var pid in workers) {
workers[pid].kill('SIGHUP');
}
if (Object.keys(workers).length===0&&redis.status!=="end") {
console.log(await redis.scard('setTest'));
await redis.del("setTest");
redis.end();
}
});

21
JavaScript/test/test.js Normal file
View File

@@ -0,0 +1,21 @@
/**
* @description:
* @author: bubao
* @date: 2021-04-27 17:23:36
* @last author: bubao
* @last edit time: 2021-04-28 10:34:24
*/
const GenId = require('..')
const Redis = require("ioredis");
const config = require("../env.config.js");
const redis = new Redis(config);
const genid = new GenId({ WorkerId: (process.argv[2] || 1) - 0 });
(async () => {
for (let index = 0; index < 5000; index++) {
await redis.sadd("setTest", genid.NextId());
}
redis.end();
})();

20
JavaScript/test/test2.js Normal file
View File

@@ -0,0 +1,20 @@
const GenId = require('..')
function test1() {
const genid = new GenId({ WorkerId: 1 })
for (let index = 0; index < 5000; index++) {
console.log(genid.NextId());
}
}
function test2() {
const genid = new GenId({ WorkerId: 1 })
const id = genid.NextId()
console.log(typeof (id))
console.log(id, id.toString().length)
}
function main() {
test2()
}
main()