From 1650a037676b15758134418fce9017878d57a637 Mon Sep 17 00:00:00 2001 From: Evgenii Burmistrov Date: Mon, 14 Oct 2024 15:52:59 +0300 Subject: [PATCH] mutex --- ClubDoorman/BadMessageManager.cs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ClubDoorman/BadMessageManager.cs b/ClubDoorman/BadMessageManager.cs index 5d11ff2..44f2889 100644 --- a/ClubDoorman/BadMessageManager.cs +++ b/ClubDoorman/BadMessageManager.cs @@ -6,7 +6,7 @@ namespace ClubDoorman; internal sealed class BadMessageManager { private const string Path = "data/bad-messages.txt"; - private readonly SemaphoreSlim _semaphore = new(1); + private readonly SemaphoreSlim _fileLock = new(1); // with our data size, we would never need O(1), in fact if this ever bloats I'd rather limit this to ~2048 last messages // space savings are very moderate, base64 string takes up ~128 bytes while byte[] takes only 64, but then again it's @@ -15,22 +15,31 @@ internal sealed class BadMessageManager public BadMessageManager() { - foreach (var item in File.ReadAllLines(Path)) - _bad.Add(Convert.FromBase64String(item)); + lock (_bad) + { + foreach (var item in File.ReadAllLines(Path)) + _bad.Add(Convert.FromBase64String(item)); + } } - public bool KnownBadMessage(string message) => _bad.Contains(ComputeHash(message)); + public bool KnownBadMessage(string message) + { + lock (_bad) + return _bad.Contains(ComputeHash(message)); + } public async ValueTask MarkAsBad(string message) { if (string.IsNullOrWhiteSpace(message)) return; var hash = ComputeHash(message); - if (_bad.Add(hash)) - { - using var token = await SemaphoreHelper.AwaitAsync(_semaphore); - await File.AppendAllLinesAsync(Path, [Convert.ToBase64String(hash)]); - } + bool added; + lock (_bad) + added = _bad.Add(hash); + if (!added) + return; + using var token = await SemaphoreHelper.AwaitAsync(_fileLock); + await File.AppendAllLinesAsync(Path, [Convert.ToBase64String(hash)]); } private static byte[] ComputeHash(string message) => SHA512.HashData(Encoding.UTF8.GetBytes(message));