From 7dbc7640cb42b2d93f5698853c1171a16dcbca97 Mon Sep 17 00:00:00 2001 From: think_ya Date: Tue, 8 Nov 2022 09:29:23 +0800 Subject: [PATCH] fix #732 --- aspnet-core/LINGYUN.MicroService.All.sln | 7 +++ .../Snowflake/SnowflakeIdGenerator.cs | 4 +- .../AuthServerHttpApiHostModule.Configure.cs | 4 +- .../AuthServerModule.Configure.cs | 4 +- ...BackendAdminHttpApiHostModule.Configure.cs | 4 +- ...onManagementHttpApiHostModule.Configure.cs | 4 +- ...rmManagementHttpApiHostModule.Configure.cs | 4 +- ...ltimeMessageHttpApiHostModule.Configure.cs | 4 +- ...entityServerHttpApiHostModule.Configure.cs | 4 +- .../IdentityServerModule.Configure.cs | 4 +- .../LINGYUN.Abp.IdGenerator.Tests.csproj | 18 +++++++ .../Abp/IdGenerator/AbpIdGeneratorTestBase.cs | 42 +++++++++++++++ .../IdGenerator/AbpIdGeneratorTestModule.cs | 21 ++++++++ .../Abp/IdGenerator/IdGeneratorTests.cs | 34 +++++++++++++ .../IdGenerator/SnowflakeIdGeneratorTests.cs | 51 +++++++++++++++++++ 15 files changed, 191 insertions(+), 18 deletions(-) create mode 100644 aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN.Abp.IdGenerator.Tests.csproj create mode 100644 aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestBase.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestModule.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/IdGeneratorTests.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/SnowflakeIdGeneratorTests.cs diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index 6909487da..f0a6a91ec 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -500,6 +500,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenIddict.Sms" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenIddict.WeChat", "modules\openIddict\LINGYUN.Abp.OpenIddict.WeChat\LINGYUN.Abp.OpenIddict.WeChat.csproj", "{427382F6-3153-47A2-BBC4-88F6EA116A8F}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.IdGenerator.Tests", "tests\LINGYUN.Abp.IdGenerator.Tests\LINGYUN.Abp.IdGenerator.Tests.csproj", "{2BFFE9C3-E022-4B57-9E4D-0A0408424B1A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1294,6 +1296,10 @@ Global {427382F6-3153-47A2-BBC4-88F6EA116A8F}.Debug|Any CPU.Build.0 = Debug|Any CPU {427382F6-3153-47A2-BBC4-88F6EA116A8F}.Release|Any CPU.ActiveCfg = Release|Any CPU {427382F6-3153-47A2-BBC4-88F6EA116A8F}.Release|Any CPU.Build.0 = Release|Any CPU + {2BFFE9C3-E022-4B57-9E4D-0A0408424B1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BFFE9C3-E022-4B57-9E4D-0A0408424B1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BFFE9C3-E022-4B57-9E4D-0A0408424B1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BFFE9C3-E022-4B57-9E4D-0A0408424B1A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1539,6 +1545,7 @@ Global {15EC4A03-D172-4984-B9CA-2C73929838DE} = {83E698F6-F8CD-4604-AB80-01A203389501} {74C13BCC-A5A5-40FA-81E8-83DCCF760148} = {83E698F6-F8CD-4604-AB80-01A203389501} {427382F6-3153-47A2-BBC4-88F6EA116A8F} = {83E698F6-F8CD-4604-AB80-01A203389501} + {2BFFE9C3-E022-4B57-9E4D-0A0408424B1A} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdGenerator/LINGYUN/Abp/IdGenerator/Snowflake/SnowflakeIdGenerator.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdGenerator/LINGYUN/Abp/IdGenerator/Snowflake/SnowflakeIdGenerator.cs index e7c48b106..8c450de2c 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IdGenerator/LINGYUN/Abp/IdGenerator/Snowflake/SnowflakeIdGenerator.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdGenerator/LINGYUN/Abp/IdGenerator/Snowflake/SnowflakeIdGenerator.cs @@ -42,7 +42,7 @@ namespace LINGYUN.Abp.IdGenerator.Snowflake MaxDatacenterId = -1L ^ (-1L << options.DatacenterIdBits) }; - if (idGenerator.WorkerId == 0 || (int)Math.Log10(options.WorkerId) + 1 > idGenerator.MaxWorkerId) + if (idGenerator.WorkerId <= 0 || options.WorkerId > idGenerator.MaxWorkerId) { if (!int.TryParse(Environment.GetEnvironmentVariable("WORKERID", EnvironmentVariableTarget.Machine), out var workerId)) { @@ -57,7 +57,7 @@ namespace LINGYUN.Abp.IdGenerator.Snowflake idGenerator.WorkerId = workerId; } - if (idGenerator.DatacenterId == 0 || (int)Math.Log10(options.DatacenterId) + 1 > idGenerator.MaxDatacenterId) + if (idGenerator.DatacenterId <= 0 || options.DatacenterId > idGenerator.MaxDatacenterId) { if (!int.TryParse(Environment.GetEnvironmentVariable("DATACENTERID", EnvironmentVariableTarget.Machine), out var datacenterId)) { diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs index fe14ee5e3..202cac417 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs @@ -58,8 +58,8 @@ public partial class AuthServerHttpApiHostModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 30015; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 30015 - 30000; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs index 4db15adfb..22887d99b 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs @@ -54,8 +54,8 @@ public partial class AuthServerModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 44385; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 1; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs index 49d5201f3..7f9726b84 100644 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs @@ -57,8 +57,8 @@ public partial class BackendAdminHttpApiHostModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 30010; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 30010 - 30000; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs index 75b686f2f..2f513eb03 100644 --- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs @@ -51,8 +51,8 @@ public partial class LocalizationManagementHttpApiHostModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 30030; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 30030 - 30000; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs index a20e7343c..841067ccd 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs @@ -55,8 +55,8 @@ public partial class PlatformManagementHttpApiHostModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 30025; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 30025 - 30000; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs index ff3a8e99c..5426ff878 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs @@ -57,8 +57,8 @@ public partial class RealtimeMessageHttpApiHostModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 30020; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 30020 - 30000; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs index 7bb3d5899..00ed22ae9 100644 --- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs @@ -56,8 +56,8 @@ public partial class IdentityServerHttpApiHostModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 30015; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 30015 - 30000; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs index b578f93f6..b27e14df7 100644 --- a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs @@ -54,8 +54,8 @@ public partial class IdentityServerModule PreConfigure(options => { - // 以开放端口区别 - options.SnowflakeIdOptions.WorkerId = 44385; + // 以开放端口区别,应在0-31之间 + options.SnowflakeIdOptions.WorkerId = 1; options.SnowflakeIdOptions.WorkerIdBits = 5; options.SnowflakeIdOptions.DatacenterId = 1; }); diff --git a/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN.Abp.IdGenerator.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN.Abp.IdGenerator.Tests.csproj new file mode 100644 index 000000000..17494db2d --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN.Abp.IdGenerator.Tests.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + + false + + + + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestBase.cs new file mode 100644 index 000000000..77c32f926 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestBase.cs @@ -0,0 +1,42 @@ +using LINGYUN.Abp.Tests; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.IdGenerator; + +public class AbpIdGeneratorModuleTestBase : AbpTestsBase +{ + protected IDistributedIdGenerator DistributedIdGenerator { get; set; } + + private void GenerateId(long[] idArray, int startIndex, int endIndex) + { + for (int i = startIndex; i < endIndex; i++) + { + idArray[i] = DistributedIdGenerator.Create(); + } + } + + protected long[] GenerateIdInSingleThread(int countIds) + { + long[] ids = new long[countIds]; + + GenerateId(ids, 0, ids.Length); + + return ids; + } + + protected long[] GenerateIdInMutiThread(int countThreads, int countIdsPerThread) + { + List tasks = new(); + long[] idArray = new long[countThreads * countIdsPerThread]; + + for (int i = 0; i < countThreads; i++) + { + int threadId = i; + tasks.Add(Task.Run(() => GenerateId(idArray, threadId * countIdsPerThread, (threadId + 1) * countIdsPerThread))); + } + Task.WaitAll(tasks.ToArray()); + + return idArray; + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestModule.cs new file mode 100644 index 000000000..dc13beb91 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/AbpIdGeneratorTestModule.cs @@ -0,0 +1,21 @@ +using LINGYUN.Abp.IdGenerator.Snowflake; +using LINGYUN.Abp.Tests; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.IdGenerator; + +[DependsOn( + typeof(AbpIdGeneratorModule), + typeof(AbpTestsBaseModule))] +public class AbpIdGeneratorModuleTestModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(options => + { + options.WorkerId = 30010 - 30000; + options.WorkerIdBits = 5; + options.DatacenterId = 1; + }); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/IdGeneratorTests.cs b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/IdGeneratorTests.cs new file mode 100644 index 000000000..69bff8e7d --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/IdGeneratorTests.cs @@ -0,0 +1,34 @@ +using Shouldly; +using System.Linq; +using Xunit; + +namespace LINGYUN.Abp.IdGenerator; + +public class IdGeneratorTests : AbpIdGeneratorModuleTestBase +{ + public IdGeneratorTests() + { + DistributedIdGenerator = GetRequiredService(); + } + + [Fact] + public void IdShouldBeUnique_SingleThread() + { + const int countIds = 50000; + long[] ids = GenerateIdInSingleThread(countIds); + + var finalIds = ids.GroupBy(id => id).Select(d => d.Key).ToArray(); + finalIds.Length.ShouldBe(countIds); + } + + [Fact] + public void IdShouldBeUnique_MultiThread() + { + const int countIdsPerThread = 50000; + const int countThreads = 8; + long[] ids = GenerateIdInMutiThread(countThreads, countIdsPerThread); + + var finalIds = ids.GroupBy(id => id).Select(d => d.Key).ToArray(); + finalIds.Length.ShouldBe(countThreads * countIdsPerThread); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/SnowflakeIdGeneratorTests.cs b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/SnowflakeIdGeneratorTests.cs new file mode 100644 index 000000000..1cbfd616a --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.IdGenerator.Tests/LINGYUN/Abp/IdGenerator/SnowflakeIdGeneratorTests.cs @@ -0,0 +1,51 @@ +using LINGYUN.Abp.IdGenerator.Snowflake; +using System; +using System.Linq; +using Shouldly; +using Xunit; + +namespace LINGYUN.Abp.IdGenerator; + +public class SnowflakeIdGeneratorTests : AbpIdGeneratorModuleTestBase +{ + public SnowflakeIdGeneratorTests() + { + DistributedIdGenerator = null; + } + + [Theory] + [InlineData(-1, 5)] + [InlineData(0, 5)] + [InlineData(10, 5)] + [InlineData(31, 5)] + [InlineData(32, 5)] + [InlineData(30010, 5)] + public void WorkerIdShouldInRange(int workerId, int workerIdBits) + { + var snowflakeIdGenerator = SnowflakeIdGenerator.Create(new SnowflakeIdOptions + { + WorkerId = workerId, + WorkerIdBits = workerIdBits + }); + + snowflakeIdGenerator.WorkerId.ShouldBeInRange(0, (long)Math.Pow(2, workerIdBits) - 1); + } + + [Fact] + public void BiggerWorkerIdMakeIdRepeated() + { + var snowflakeIdGenerator = SnowflakeIdGenerator.Create(new SnowflakeIdOptions + { + WorkerId = 30010, + WorkerIdBits = 5 + }); + snowflakeIdGenerator.GetType().GetProperty("WorkerId").SetValue(snowflakeIdGenerator, 30010); + DistributedIdGenerator = snowflakeIdGenerator; + + const int countIds = 50000; + long[] ids = GenerateIdInSingleThread(countIds); + + var finalIds = ids.GroupBy(id => id).Select(d => d.Key).ToArray(); + finalIds.Length.ShouldBeLessThan(countIds); + } +}