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 System.Text.Json;
|
||||||
using AccessQueueService.Models;
|
using AccessQueueService.Models;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -7,9 +8,9 @@ namespace AccessQueueService.Data
|
||||||
{
|
{
|
||||||
public class TakeANumberAccessQueueRepo : IAccessQueueRepo
|
public class TakeANumberAccessQueueRepo : IAccessQueueRepo
|
||||||
{
|
{
|
||||||
private Dictionary<string, AccessTicket> _accessTickets = [];
|
private ConcurrentDictionary<string, AccessTicket> _accessTickets = new();
|
||||||
private Dictionary<string, ulong> _queueNumbers = [];
|
private ConcurrentDictionary<string, ulong> _queueNumbers = new();
|
||||||
private Dictionary<ulong, AccessTicket> _accessQueue = [];
|
private ConcurrentDictionary<ulong, AccessTicket> _accessQueue = new();
|
||||||
|
|
||||||
internal ulong _nowServing = 0;
|
internal ulong _nowServing = 0;
|
||||||
internal ulong _nextUnusedTicket = 0;
|
internal ulong _nextUnusedTicket = 0;
|
||||||
|
@ -47,12 +48,12 @@ namespace AccessQueueService.Data
|
||||||
public int DeleteExpiredTickets()
|
public int DeleteExpiredTickets()
|
||||||
{
|
{
|
||||||
var cutoff = DateTime.UtcNow;
|
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;
|
int count = 0;
|
||||||
foreach (var ticket in expiredTickets)
|
foreach (var ticket in expiredTickets)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
_accessTickets.Remove(ticket.Key);
|
_accessTickets.TryRemove(ticket.Key, out _);
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -70,13 +71,13 @@ namespace AccessQueueService.Data
|
||||||
int filledSpots = 0;
|
int filledSpots = 0;
|
||||||
while (filledSpots < openSpots && _nowServing < _nextUnusedTicket)
|
while (filledSpots < openSpots && _nowServing < _nextUnusedTicket)
|
||||||
{
|
{
|
||||||
if (_accessQueue.TryGetValue(_nowServing, out var nextUser))
|
if (_accessQueue.TryRemove(_nowServing, out var nextUser))
|
||||||
{
|
{
|
||||||
_accessQueue.Remove(_nowServing);
|
_queueNumbers.TryRemove(nextUser.UserId, out _);
|
||||||
_queueNumbers.Remove(nextUser.UserId);
|
|
||||||
if (nextUser.LastActive < activeCutoff)
|
if (nextUser.LastActive < activeCutoff)
|
||||||
{
|
{
|
||||||
// User is inactive, throw away their ticket
|
// User is inactive, throw away their ticket
|
||||||
|
_nowServing++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_accessTickets[nextUser.UserId] = new AccessTicket
|
_accessTickets[nextUser.UserId] = new AccessTicket
|
||||||
|
@ -104,25 +105,26 @@ namespace AccessQueueService.Data
|
||||||
|
|
||||||
public bool RemoveUser(string userId)
|
public bool RemoveUser(string userId)
|
||||||
{
|
{
|
||||||
if (_queueNumbers.TryGetValue(userId, out var queueNumber))
|
if (_queueNumbers.TryRemove(userId, out var queueNumber))
|
||||||
{
|
{
|
||||||
_accessQueue.Remove(queueNumber);
|
_accessQueue.TryRemove(queueNumber, out _);
|
||||||
_queueNumbers.Remove(userId);
|
|
||||||
}
|
}
|
||||||
return _accessTickets.Remove(userId);
|
return _accessTickets.TryRemove(userId, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Optimize()
|
internal void Optimize()
|
||||||
{
|
{
|
||||||
var newQueue = new Dictionary<ulong, AccessTicket>();
|
var newQueue = new ConcurrentDictionary<ulong, AccessTicket>();
|
||||||
var newQueueNumbers = new Dictionary<string, ulong>();
|
var newQueueNumbers = new ConcurrentDictionary<string, ulong>();
|
||||||
ulong newIndex = 0;
|
ulong newIndex = 0;
|
||||||
for (ulong i = _nowServing; i < _nextUnusedTicket; i++)
|
for (ulong i = _nowServing; i < _nextUnusedTicket; i++)
|
||||||
{
|
{
|
||||||
var user = _accessQueue[i];
|
if (_accessQueue.TryGetValue(i, out var user))
|
||||||
|
{
|
||||||
newQueue[newIndex] = user;
|
newQueue[newIndex] = user;
|
||||||
newQueueNumbers[user.UserId] = newIndex++;
|
newQueueNumbers[user.UserId] = newIndex++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_accessQueue = newQueue;
|
_accessQueue = newQueue;
|
||||||
_queueNumbers = newQueueNumbers;
|
_queueNumbers = newQueueNumbers;
|
||||||
_nowServing = 0;
|
_nowServing = 0;
|
||||||
|
@ -133,10 +135,9 @@ namespace AccessQueueService.Data
|
||||||
{
|
{
|
||||||
var state = new TakeANumberAccessQueueRepoState
|
var state = new TakeANumberAccessQueueRepoState
|
||||||
{
|
{
|
||||||
AccessTickets = _accessTickets,
|
AccessTickets = new Dictionary<string, AccessTicket>(_accessTickets),
|
||||||
AccessQueue = _accessQueue,
|
AccessQueue = new Dictionary<ulong, AccessTicket>(_accessQueue),
|
||||||
};
|
};
|
||||||
|
|
||||||
return JsonSerializer.Serialize(state);
|
return JsonSerializer.Serialize(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,14 +149,14 @@ namespace AccessQueueService.Data
|
||||||
return new();
|
return new();
|
||||||
}
|
}
|
||||||
|
|
||||||
var _accessTickets = state.AccessTickets;
|
var _accessTickets = new ConcurrentDictionary<string, AccessTicket>(state.AccessTickets);
|
||||||
var _accessQueue = state.AccessQueue;
|
var _accessQueue = new ConcurrentDictionary<ulong, AccessTicket>(state.AccessQueue);
|
||||||
var _nextUnusedTicket = 0ul;
|
var _nextUnusedTicket = 0ul;
|
||||||
var _nowServing = ulong.MaxValue;
|
var _nowServing = ulong.MaxValue;
|
||||||
Dictionary<string, ulong> _queueNumbers = [];
|
var _queueNumbers = new ConcurrentDictionary<string, ulong>();
|
||||||
foreach (var queueItem in state.AccessQueue)
|
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);
|
_nextUnusedTicket = Math.Max(_nextUnusedTicket, queueItem.Key + 1);
|
||||||
_nowServing = Math.Min(_nowServing, queueItem.Key);
|
_nowServing = Math.Min(_nowServing, queueItem.Key);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue