diff --git a/.github/workflows/slo.yml b/.github/workflows/slo.yml index cf4fe1a5..621d4be7 100644 --- a/.github/workflows/slo.yml +++ b/.github/workflows/slo.yml @@ -20,6 +20,7 @@ jobs: - AdoNet - Dapper - EF + - Linq2db.Slo include: - workload: AdoNet read_rps: 1000 @@ -30,7 +31,10 @@ jobs: - workload: EF read_rps: 1000 write_rps: 100 - + - workload: Linq2db.Slo + read_rps: 1000 + write_rps: 100 + concurrency: group: slo-${{ github.ref }}-${{ matrix.workload }} cancel-in-progress: true diff --git a/slo/src/Linq2db.Slo/Linq2db.Slo.csproj b/slo/src/Linq2db.Slo/Linq2db.Slo.csproj new file mode 100644 index 00000000..e5c41c89 --- /dev/null +++ b/slo/src/Linq2db.Slo/Linq2db.Slo.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + Linq2db + + + + + + + + + + + \ No newline at end of file diff --git a/slo/src/Linq2db.Slo/Program.cs b/slo/src/Linq2db.Slo/Program.cs new file mode 100644 index 00000000..2fdddd57 --- /dev/null +++ b/slo/src/Linq2db.Slo/Program.cs @@ -0,0 +1,4 @@ +using Internal; +using Linq2db; + +await Cli.Run(new SloTableContext(), args); \ No newline at end of file diff --git a/slo/src/Linq2db.Slo/SloTableContext.cs b/slo/src/Linq2db.Slo/SloTableContext.cs new file mode 100644 index 00000000..ca434151 --- /dev/null +++ b/slo/src/Linq2db.Slo/SloTableContext.cs @@ -0,0 +1,105 @@ +using Internal; +using Linq2db.Ydb; +using Linq2db.Ydb.Internal; +using LinqToDB; +using LinqToDB.Async; +using LinqToDB.Data; +using LinqToDB.Mapping; + +namespace Linq2db; + +public sealed class SloTableContext : SloTableContext +{ + protected override string Job => "Linq2db"; + + static SloTableContext() + { + YdbSdkRetryPolicyRegistration.UseGloballyWithIdempotence(); + DataConnection.AddProviderDetector(YdbTools.ProviderDetector); + } + + public sealed class Linq2dbClient(string connectionString) + { + public DataConnection Open() + => new(new DataOptions().UseConnectionString("YDB", connectionString)); + } + + protected override Linq2dbClient CreateClient(Config config) => new(config.ConnectionString); + + protected override async Task Create(Linq2dbClient client, int operationTimeout) + { + await using var db = client.Open(); + db.CommandTimeout = operationTimeout; + + await db.ExecuteAsync($@" + CREATE TABLE `{SloTable.Name}` ( + Guid Uuid, + Id Int32, + PayloadStr Text, + PayloadDouble Double, + PayloadTimestamp Timestamp, + PRIMARY KEY (Guid, Id) + )"); + + await db.ExecuteAsync(SloTable.Options); + } + + protected override async Task Save(Linq2dbClient client, SloTable sloTable, int writeTimeout) + { + await using var db = client.Open(); + db.CommandTimeout = writeTimeout; + + var sql = $@" +UPSERT INTO `{SloTable.Name}` (Guid, Id, PayloadStr, PayloadDouble, PayloadTimestamp) +VALUES (@Guid, @Id, @PayloadStr, @PayloadDouble, @PayloadTimestamp);"; + + var affected = await db.ExecuteAsync( + sql, + new DataParameter("Guid", sloTable.Guid, DataType.Guid), + new DataParameter("Id", sloTable.Id, DataType.Int32), + new DataParameter("PayloadStr", sloTable.PayloadStr, DataType.NVarChar), + new DataParameter("PayloadDouble", sloTable.PayloadDouble, DataType.Double), + new DataParameter("PayloadTimestamp", sloTable.PayloadTimestamp, DataType.DateTime2) + ); + + return affected > 0 ? affected : 1; + } + + protected override async Task Select(Linq2dbClient client, (Guid Guid, int Id) select, int readTimeout) + { + await using var db = client.Open(); + db.CommandTimeout = readTimeout; + + var t = db.GetTable(); + + var row = await t + .Where(r => r.Guid == select.Guid && r.Id == select.Id) + .Select(r => new + { + r.Guid, + r.Id, + r.PayloadStr, + r.PayloadDouble, + r.PayloadTimestamp + }) + .FirstOrDefaultAsync(); + + return row; + } + + protected override async Task SelectCount(Linq2dbClient client) + { + await using var db = client.Open(); + return await db.GetTable().CountAsync(); + } + + [Table(SloTable.Name)] + private sealed class SloRow(Guid guid, int id, string? payloadStr, double payloadDouble, DateTime payloadTimestamp) + { + [Column] public Guid Guid { get; } = guid; + [Column] public int Id { get; } = id; + [Column] public string? PayloadStr { get; } = payloadStr; + [Column] public double PayloadDouble { get; } = payloadDouble; + [Column] public DateTime PayloadTimestamp { get; } = payloadTimestamp; + } +} \ No newline at end of file diff --git a/slo/src/src.sln b/slo/src/src.sln index 68acb0f7..b6cdb57f 100644 --- a/slo/src/src.sln +++ b/slo/src/src.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EF", "EF\EF.csproj", "{291A EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdoNet.Dapper", "Dapper\AdoNet.Dapper.csproj", "{A6B9B4F1-4C7C-42C1-A212-B71A9B0D67F7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Linq2db.Slo", "Linq2db.Slo\Linq2db.Slo.csproj", "{59758BC9-E53B-46C8-84AC-62670DD559D4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,10 @@ Global {A6B9B4F1-4C7C-42C1-A212-B71A9B0D67F7}.Debug|Any CPU.Build.0 = Debug|Any CPU {A6B9B4F1-4C7C-42C1-A212-B71A9B0D67F7}.Release|Any CPU.ActiveCfg = Release|Any CPU {A6B9B4F1-4C7C-42C1-A212-B71A9B0D67F7}.Release|Any CPU.Build.0 = Release|Any CPU + {59758BC9-E53B-46C8-84AC-62670DD559D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59758BC9-E53B-46C8-84AC-62670DD559D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59758BC9-E53B-46C8-84AC-62670DD559D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59758BC9-E53B-46C8-84AC-62670DD559D4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE