Last active
March 1, 2022 18:08
-
-
Save Nican/5764d109e1ffc322d2f8b0ba88044fc1 to your computer and use it in GitHub Desktop.
Test `FOR UPDATE` for CRDB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Dapper; | |
using Npgsql; | |
using System.Diagnostics; | |
int quantity = 100; | |
var connStringBuilder = new NpgsqlConnectionStringBuilder(); | |
connStringBuilder.Host = "55.55.55.20"; | |
connStringBuilder.Port = 26257; | |
connStringBuilder.Username = "root"; | |
connStringBuilder.Database = "nican_test"; | |
connStringBuilder.SslMode = SslMode.Disable; | |
connStringBuilder.IncludeErrorDetail = true; | |
connStringBuilder.MaxPoolSize = 150; | |
await using var conn = new NpgsqlConnection(connStringBuilder.ConnectionString); | |
await conn.OpenAsync(); | |
await conn.QueryAsync("DROP TABLE IF EXISTS products"); | |
await conn.QueryAsync("CREATE TABLE products (id INT PRIMARY KEY, quantity INT NOT NULL)"); | |
await conn.QueryAsync($"INSERT INTO products(id,quantity) VALUES (1,{quantity})"); | |
var watch = new Stopwatch(); | |
watch.Start(); | |
int workers = 0; | |
var results = await Task.WhenAll(Enumerable.Range(0, quantity).Select(async id => | |
{ | |
try | |
{ | |
var conn2 = new NpgsqlConnection(connStringBuilder.ConnectionString); | |
await conn2.OpenAsync(); | |
using var trans = await conn2.BeginTransactionAsync(); | |
await conn2.QueryAsync("SELECT * FROM products WHERE id=1 FOR UPDATE ", transaction: trans); | |
int count = Interlocked.Increment(ref workers); | |
if(count > 1) | |
{ | |
Console.WriteLine($"Too many workers in the critical zone: Worker#{id}"); | |
} | |
await Task.Delay(TimeSpan.FromMilliseconds(10)); | |
Interlocked.Decrement(ref workers); | |
await conn2.QueryAsync($"UPDATE products SET quantity=quantity-1 WHERE id=1", transaction: trans); | |
await trans.CommitAsync(); | |
return true; | |
} | |
catch (Exception ex) when (ex.Message.Contains("WriteTooOldError")) | |
{ | |
Console.WriteLine($"Failed id: Worker#{id}"); | |
return false; | |
} | |
})); | |
var success = results.Where(t => t).Count(); | |
Console.WriteLine($"Total success: {success}/{quantity}"); | |
Console.WriteLine($"Time taken: {watch.Elapsed.TotalMilliseconds}ms"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment