using System.Data.Common;
using Microsoft.EntityFrameworkCore.Diagnostics;
namespace BuildFlow.Monitoring.Tests.Sync;
///
/// 统计同步记录查询和 UPSERT 命令,并可让两个旧式先查后写查询在同一点汇合以稳定复现竞争。
///
public sealed class CountingUpsertInterceptor(int concurrentSelectParticipants = 0) : DbCommandInterceptor
{
private readonly TaskCompletionSource _selectBarrier =
new(TaskCreationOptions.RunContinuationsAsynchronously);
private int _recordSelectCount;
private int _upsertCommandCount;
private int _parameterlessUpsertCount;
private int _selectBarrierArrivals;
/// 访问同步记录表的 SELECT 命令数。
public int RecordSelectCount => Volatile.Read(ref _recordSelectCount);
/// 包含 ON CONFLICT 的同步记录 INSERT 命令数。
public int UpsertCommandCount => Volatile.Read(ref _upsertCommandCount);
/// 所有 UPSERT 是否都通过数据库参数传值。
public bool AllUpsertsParameterized => Volatile.Read(ref _parameterlessUpsertCount) == 0;
public override InterceptionResult ReaderExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult result)
{
Count(command);
return result;
}
public override async ValueTask> ReaderExecutingAsync(
DbCommand command,
CommandEventData eventData,
InterceptionResult result,
CancellationToken cancellationToken = default)
{
Count(command);
if (concurrentSelectParticipants > 0 && IsRecordSelect(command))
{
var arrivals = Interlocked.Increment(ref _selectBarrierArrivals);
if (arrivals == concurrentSelectParticipants)
{
_selectBarrier.TrySetResult();
}
if (arrivals <= concurrentSelectParticipants)
{
await _selectBarrier.Task.WaitAsync(TimeSpan.FromSeconds(10), cancellationToken);
}
}
return result;
}
public override InterceptionResult NonQueryExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult result)
{
Count(command);
return result;
}
public override ValueTask> NonQueryExecutingAsync(
DbCommand command,
CommandEventData eventData,
InterceptionResult result,
CancellationToken cancellationToken = default)
{
Count(command);
return ValueTask.FromResult(result);
}
public override InterceptionResult