Modify repo to use concurrent dictionaries for thread safety during backup
This commit is contained in:
parent
e8a7cc588f
commit
f958ba5ddd
|
@ -1,4 +1,5 @@
|
|||
using System.Runtime.Serialization;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.Json;
|
||||
using AccessQueueService.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
@ -7,9 +8,9 @@ namespace AccessQueueService.Data
|
|||
{
|
||||
public class TakeANumberAccessQueueRepo : IAccessQueueRepo
|
||||
{
|
||||
private Dictionary<string, AccessTicket> _accessTickets = [];
|
||||
private Dictionary<string, ulong> _queueNumbers = [];
|
||||
private Dictionary<ulong, AccessTicket> _accessQueue = [];
|
||||
private ConcurrentDictionary<string, AccessTicket> _accessTickets = new();
|
||||
private ConcurrentDictionary<string, ulong> _queueNumbers = new();
|
||||
private ConcurrentDictionary<ulong, AccessTicket> _accessQueue = new();
|
||||
|
||||
internal ulong _nowServing = 0;
|
||||
internal ulong _nextUnusedTicket = 0;
|
||||
|
@ -47,12 +48,12 @@ namespace AccessQueueService.Data
|
|||
public int DeleteExpiredTickets()
|
||||
{
|
||||
var cutoff = DateTime.UtcNow;
|
||||
var expiredTickets = _accessTickets.Where(t => t.Value.ExpiresOn < cutoff);
|
||||
var expiredTickets = _accessTickets.Where(t => t.Value.ExpiresOn < cutoff).ToList();
|
||||
int count = 0;
|
||||
foreach (var ticket in expiredTickets)
|
||||
{
|
||||
count++;
|
||||
_accessTickets.Remove(ticket.Key);
|
||||
_accessTickets.TryRemove(ticket.Key, out _);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -70,13 +71,13 @@ namespace AccessQueueService.Data
|
|||
int filledSpots = 0;
|
||||
while (filledSpots < openSpots && _nowServing < _nextUnusedTicket)
|
||||
{
|
||||
if (_accessQueue.TryGetValue(_nowServing, out var nextUser))
|
||||
if (_accessQueue.TryRemove(_nowServing, out var nextUser))
|
||||
{
|
||||
_accessQueue.Remove(_nowServing);
|
||||
_queueNumbers.Remove(nextUser.UserId);
|
||||
_queueNumbers.TryRemove(nextUser.UserId, out _);
|
||||
if (nextUser.LastActive < activeCutoff)
|
||||
{
|
||||
// User is inactive, throw away their ticket
|
||||
_nowServing++;
|
||||
continue;
|
||||
}
|
||||
_accessTickets[nextUser.UserId] = new AccessTicket
|
||||
|
@ -104,24 +105,25 @@ namespace AccessQueueService.Data
|
|||
|
||||
public bool RemoveUser(string userId)
|
||||
{
|
||||
if (_queueNumbers.TryGetValue(userId, out var queueNumber))
|
||||
if (_queueNumbers.TryRemove(userId, out var queueNumber))
|
||||
{
|
||||
_accessQueue.Remove(queueNumber);
|
||||
_queueNumbers.Remove(userId);
|
||||
_accessQueue.TryRemove(queueNumber, out _);
|
||||
}
|
||||
return _accessTickets.Remove(userId);
|
||||
return _accessTickets.TryRemove(userId, out _);
|
||||
}
|
||||
|
||||
internal void Optimize()
|
||||
{
|
||||
var newQueue = new Dictionary<ulong, AccessTicket>();
|
||||
var newQueueNumbers = new Dictionary<string, ulong>();
|
||||
var newQueue = new ConcurrentDictionary<ulong, AccessTicket>();
|
||||
var newQueueNumbers = new ConcurrentDictionary<string, ulong>();
|
||||
ulong newIndex = 0;
|
||||
for (ulong i = _nowServing; i < _nextUnusedTicket; i++)
|
||||
{
|
||||
var user = _accessQueue[i];
|
||||
newQueue[newIndex] = user;
|
||||
newQueueNumbers[user.UserId] = newIndex++;
|
||||
if (_accessQueue.TryGetValue(i, out var user))
|
||||
{
|
||||
newQueue[newIndex] = user;
|
||||
newQueueNumbers[user.UserId] = newIndex++;
|
||||
}
|
||||
}
|
||||
_accessQueue = newQueue;
|
||||
_queueNumbers = newQueueNumbers;
|
||||
|
@ -133,10 +135,9 @@ namespace AccessQueueService.Data
|
|||
{
|
||||
var state = new TakeANumberAccessQueueRepoState
|
||||
{
|
||||
AccessTickets = _accessTickets,
|
||||
AccessQueue = _accessQueue,
|
||||
AccessTickets = new Dictionary<string, AccessTicket>(_accessTickets),
|
||||
AccessQueue = new Dictionary<ulong, AccessTicket>(_accessQueue),
|
||||
};
|
||||
|
||||
return JsonSerializer.Serialize(state);
|
||||
}
|
||||
|
||||
|
@ -148,14 +149,14 @@ namespace AccessQueueService.Data
|
|||
return new();
|
||||
}
|
||||
|
||||
var _accessTickets = state.AccessTickets;
|
||||
var _accessQueue = state.AccessQueue;
|
||||
var _accessTickets = new ConcurrentDictionary<string, AccessTicket>(state.AccessTickets);
|
||||
var _accessQueue = new ConcurrentDictionary<ulong, AccessTicket>(state.AccessQueue);
|
||||
var _nextUnusedTicket = 0ul;
|
||||
var _nowServing = ulong.MaxValue;
|
||||
Dictionary<string, ulong> _queueNumbers = [];
|
||||
var _queueNumbers = new ConcurrentDictionary<string, ulong>();
|
||||
foreach (var queueItem in state.AccessQueue)
|
||||
{
|
||||
_queueNumbers.Add(queueItem.Value.UserId, queueItem.Key);
|
||||
_queueNumbers[queueItem.Value.UserId] = queueItem.Key;
|
||||
_nextUnusedTicket = Math.Max(_nextUnusedTicket, queueItem.Key + 1);
|
||||
_nowServing = Math.Min(_nowServing, queueItem.Key);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue