2023-12-28 15:18:03 +08:00
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2024-02-10 17:12:26 +08:00
|
|
|
|
using TaskExtensions = MesETL.Shared.Helper.TaskExtensions;
|
2023-12-28 15:18:03 +08:00
|
|
|
|
|
2024-02-02 17:14:41 +08:00
|
|
|
|
namespace MesETL.App.Services;
|
2023-12-28 15:18:03 +08:00
|
|
|
|
|
2024-01-04 09:00:44 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 数据队列
|
|
|
|
|
/// </summary>
|
2023-12-29 16:16:05 +08:00
|
|
|
|
public class DataRecordQueue : IDisposable
|
2023-12-28 15:18:03 +08:00
|
|
|
|
{
|
2023-12-29 16:16:05 +08:00
|
|
|
|
private readonly BlockingCollection<DataRecord> _queue;
|
2023-12-28 15:18:03 +08:00
|
|
|
|
|
2024-02-09 19:08:57 +08:00
|
|
|
|
private long _currentCharCount;
|
|
|
|
|
private readonly long _maxCharCount = 2_147_483_648; // 4GiB
|
|
|
|
|
|
2023-12-29 16:16:05 +08:00
|
|
|
|
public int Count => _queue.Count;
|
|
|
|
|
public bool IsCompleted => _queue.IsCompleted;
|
|
|
|
|
public bool IsAddingCompleted => _queue.IsAddingCompleted;
|
2023-12-28 15:18:03 +08:00
|
|
|
|
|
2024-02-10 00:05:50 +08:00
|
|
|
|
public long LongestFieldCharCount { get; private set; }
|
|
|
|
|
|
2023-12-29 16:16:05 +08:00
|
|
|
|
public event Action? OnRecordWrite;
|
|
|
|
|
public event Action? OnRecordRead;
|
|
|
|
|
|
2024-02-09 19:08:57 +08:00
|
|
|
|
public DataRecordQueue() : this(500_000, 2_147_483_648) // 默认容量最大500K
|
2023-12-28 15:18:03 +08:00
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-09 19:08:57 +08:00
|
|
|
|
public DataRecordQueue(int boundedCapacity, long maxCharCount)
|
2024-01-29 09:29:16 +08:00
|
|
|
|
{
|
|
|
|
|
_queue = new BlockingCollection<DataRecord>(boundedCapacity);
|
2024-02-09 19:08:57 +08:00
|
|
|
|
_maxCharCount = maxCharCount;
|
2023-12-28 15:18:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-09 19:08:57 +08:00
|
|
|
|
public void CompleteAdding() => _queue.CompleteAdding();
|
|
|
|
|
|
2023-12-29 16:16:05 +08:00
|
|
|
|
public bool TryDequeue([MaybeNullWhen(false)] out DataRecord record)
|
2023-12-28 15:18:03 +08:00
|
|
|
|
{
|
2023-12-29 16:16:05 +08:00
|
|
|
|
if (_queue.TryTake(out record))
|
|
|
|
|
{
|
2024-12-20 10:43:05 +08:00
|
|
|
|
// if (record.Database is not null)
|
|
|
|
|
// {
|
|
|
|
|
// Console.WriteLine("out " + record.Database);
|
|
|
|
|
// }
|
2024-02-09 19:08:57 +08:00
|
|
|
|
Interlocked.Add(ref _currentCharCount, -record.FieldCharCount);
|
2023-12-29 16:16:05 +08:00
|
|
|
|
OnRecordRead?.Invoke();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-12-28 15:18:03 +08:00
|
|
|
|
|
2023-12-29 16:16:05 +08:00
|
|
|
|
return false;
|
2023-12-28 15:18:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 16:16:05 +08:00
|
|
|
|
|
2024-02-09 19:08:57 +08:00
|
|
|
|
public async Task EnqueueAsync(DataRecord record)
|
2023-12-28 15:18:03 +08:00
|
|
|
|
{
|
2024-02-09 19:08:57 +08:00
|
|
|
|
var charCount = record.FieldCharCount;
|
2024-02-10 00:05:50 +08:00
|
|
|
|
LongestFieldCharCount = Math.Max(LongestFieldCharCount, charCount);
|
2024-12-12 10:55:17 +08:00
|
|
|
|
if (_currentCharCount + charCount > _maxCharCount)
|
|
|
|
|
{
|
|
|
|
|
// 不用Task.WaitUntil是为了防止产生Lambda闭包
|
|
|
|
|
while (!(_currentCharCount + charCount < _maxCharCount))
|
|
|
|
|
{
|
|
|
|
|
await Task.Delay(50);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-29 16:16:05 +08:00
|
|
|
|
_queue.Add(record);
|
2024-02-09 19:08:57 +08:00
|
|
|
|
Interlocked.Add(ref _currentCharCount, charCount);
|
2023-12-29 16:16:05 +08:00
|
|
|
|
OnRecordWrite?.Invoke();
|
2023-12-28 15:18:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-12-29 16:16:05 +08:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
_queue.Dispose();
|
|
|
|
|
}
|
2023-12-28 15:18:03 +08:00
|
|
|
|
}
|