using Disco.Data.Repository; using Disco.Models.Repository; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace Disco.Services.Jobs.JobQueues { internal class Cache { private ConcurrentDictionary _Cache; private Dictionary> _SubjectCache; private ReadOnlyCollection> _SlaOptions; public Cache(DiscoDataContext Database) { Initialize(Database); } private void Initialize(DiscoDataContext Database) { // Queues from Database var queues = Database.JobQueues.ToList(); // Add Queues to In-Memory Cache _Cache = new ConcurrentDictionary(queues.Select(q => new KeyValuePair(q.Id, JobQueueToken.FromJobQueue(q)))); // Calculate Queue Subject Cache CalculateSubjectCache(); #region Predefined Options // SLA Options if (_SlaOptions == null) { _SlaOptions = new List>() { new KeyValuePair(0, ""), new KeyValuePair(15, "15 minutes"), new KeyValuePair(30, "30 minutes"), new KeyValuePair(60, "1 hour"), new KeyValuePair(60 * 2, "2 hours"), new KeyValuePair(60 * 4, "4 hours"), new KeyValuePair(60 * 8, "8 hours"), new KeyValuePair(60 * 24, "1 day"), new KeyValuePair(60 * 24 * 2, "2 days"), new KeyValuePair(60 * 24 * 3, "3 days"), new KeyValuePair(60 * 24 * 4, "4 days"), new KeyValuePair(60 * 24 * 5, "5 days"), new KeyValuePair(60 * 24 * 6, "6 days"), new KeyValuePair(60 * 24 * 7, "1 week"), new KeyValuePair(60 * 24 * 7 * 2, "2 weeks"), new KeyValuePair(60 * 24 * 7 * 3, "3 weeks"), new KeyValuePair(60 * 24 * 7 * 4, "4 weeks"), new KeyValuePair(60 * 24 * 7 * 4 * 2, "2 months"), new KeyValuePair(60 * 24 * 7 * 4 * 3, "3 months"), new KeyValuePair(60 * 24 * 7 * 4 * 4, "4 months"), new KeyValuePair(60 * 24 * 7 * 4 * 5, "5 months"), new KeyValuePair(60 * 24 * 7 * 4 * 6, "6 months") }.AsReadOnly(); } #endregion } private void CalculateSubjectCache() { _SubjectCache = _Cache.Values.ToList() .SelectMany(t => t.SubjectIds, (t, s) => new { t, s }) .GroupBy(i => i.s, StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Key, g => g.Select(i => i.t).ToList(), StringComparer.OrdinalIgnoreCase); } public ReadOnlyCollection> SlaOptions { get { return _SlaOptions; } } public JobQueueToken UpdateQueue(JobQueue JobQueue) { var token = JobQueueToken.FromJobQueue(JobQueue); if (_Cache.TryGetValue(JobQueue.Id, out var existingToken)) { if (_Cache.TryUpdate(JobQueue.Id, token, existingToken)) { if (existingToken.JobQueue.SubjectIds != token.JobQueue.SubjectIds) CalculateSubjectCache(); return token; } else return null; } else { if (_Cache.TryAdd(JobQueue.Id, token)) { CalculateSubjectCache(); return token; } else return null; } } public bool RemoveQueue(int JobQueueId) { if (_Cache.TryRemove(JobQueueId, out _)) { CalculateSubjectCache(); return true; } else { return false; } } public JobQueueToken GetQueue(int JobQueueId) { if (_Cache.TryGetValue(JobQueueId, out var token)) return token; else return null; } public ReadOnlyCollection GetQueues() { return _Cache.Values.ToList().AsReadOnly(); } private IEnumerable GetQueuesForSubject(string SubjectId) { if (_SubjectCache.TryGetValue(SubjectId, out var tokens)) return tokens; else return Enumerable.Empty(); } public ReadOnlyCollection GetQueuesForSubject(IEnumerable SubjectIds) { return SubjectIds.SelectMany(sid => GetQueuesForSubject(sid)).Distinct().ToList().AsReadOnly(); } public void ReInitializeCache(DiscoDataContext Database) { Initialize(Database); } } }