解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
4.70 KiB
X
using System.Threading.Tasks.Sources;
using NewLife.Collections;
using NewLife.Log;

namespace NewLife.Net;

/// <summary>池化的异步完成源。基于 ManualResetValueTaskSourceCore 实现,避免每次 SendMessageAsync 分配 TaskCompletionSource</summary>
/// <remarks>
/// 生命周期:Rent → AttachSpan/RegisterCancellation → 设置到匹配队列 → SetResult/SetCanceled → 消费者 await 完成 → GetResult 内自动释放资源并归还到池。
/// 线程安全:通过 CAS 保证 SetResult/SetCanceled 只成功一次。
/// 非异步模式:SendMessageAsync 无需 async/await,直接返回 ValueTask,消除状态机分配。
/// </remarks>
sealed class PooledValueTaskSource : IValueTaskSource<Object>
{
    private ManualResetValueTaskSourceCore<Object> _core;
    private volatile Int32 _completed;

    /// <summary>关联的性能追踪 Span,在 GetResult 中自动释放</summary>
    private ISpan? _span;

    /// <summary>取消令牌注册,在 GetResult 中自动释放</summary>
    private CancellationTokenRegistration _registration;

    private static readonly Pool<PooledValueTaskSource> _pool = new();

    /// <summary>从池中借出</summary>
    public static PooledValueTaskSource Rent()
    {
        var source = _pool.Get();
        // 在借出时重置完成标志,而非 GetResult 中重置,避免匹配队列残留引用对已回收源重复操作
        source._completed = 0;
        // 对齐旧 TCS(TaskCreationOptions.RunContinuationsAsynchronously)行为,避免续体在接收线程同步执行
        source._core.RunContinuationsAsynchronously = true;
        return source;
    }

    /// <summary>当前版本号</summary>
    public Int16 Version => _core.Version;

    /// <summary>是否已完成</summary>
    public Boolean IsCompleted => _core.GetStatus(_core.Version) != ValueTaskSourceStatus.Pending;

    /// <summary>获取可等待的 ValueTask</summary>
    public ValueTask<Object> ValueTask => new(this, _core.Version);

    /// <summary>关联性能追踪 Span,将在 GetResult 中自动 Dispose</summary>
    /// <param name="span">追踪 Span</param>
    public void AttachSpan(ISpan? span) => _span = span;

    /// <summary>注册取消令牌,将在 GetResult 中自动 Dispose 注册</summary>
    /// <param name="cancellationToken">取消令牌</param>
    public void RegisterCancellation(CancellationToken cancellationToken)
    {
        if (cancellationToken.CanBeCanceled)
            _registration = cancellationToken.Register(static s => ((PooledValueTaskSource)s!).TrySetCanceled(), this);
    }

    /// <summary>尝试设置成功结果(仅首次调用生效)</summary>
    /// <param name="result">结果值</param>
    /// <returns>是否成功设置</returns>
    public Boolean TrySetResult(Object result)
    {
        if (Interlocked.CompareExchange(ref _completed, 1, 0) != 0) return false;
        _core.SetResult(result);
        return true;
    }

    /// <summary>尝试设置取消(仅首次调用生效)</summary>
    /// <returns>是否成功设置</returns>
    public Boolean TrySetCanceled()
    {
        if (Interlocked.CompareExchange(ref _completed, 1, 0) != 0) return false;
        _core.SetException(new TaskCanceledException());
        return true;
    }

    /// <summary>尝试设置异常(仅首次调用生效)</summary>
    /// <param name="exception">异常</param>
    /// <returns>是否成功设置</returns>
    public Boolean TrySetException(Exception exception)
    {
        if (Interlocked.CompareExchange(ref _completed, 1, 0) != 0) return false;
        _core.SetException(exception);
        return true;
    }

    Object IValueTaskSource<Object>.GetResult(Int16 token)
    {
        try
        {
            return _core.GetResult(token);
        }
        catch (TaskCanceledException ex)
        {
            _span?.AppendTag(ex.Message);
            throw;
        }
        catch (Exception ex)
        {
            _span?.SetError(ex, null);
            throw;
        }
        finally
        {
            // 释放关联资源
            _registration.Dispose();
            _span?.Dispose();

            // 重置状态并归还到池
            // 不重置 _completed,保留为 1,防止匹配队列残留引用对已回收源重复调用 TrySetCanceled
            _span = null;
            _registration = default;
            _core.Reset();
            _pool.Return(this);
        }
    }

    ValueTaskSourceStatus IValueTaskSource<Object>.GetStatus(Int16 token) => _core.GetStatus(token);

    void IValueTaskSource<Object>.OnCompleted(Action<Object?> continuation, Object? state, Int16 token, ValueTaskSourceOnCompletedFlags flags) =>
        _core.OnCompleted(continuation, state, token, flags);
}