Replace Dictionary + locks with ConcurrentDictionary (#143)

This commit is contained in:
rlauuzo 2024-05-08 16:27:16 +02:00 committed by GitHub
parent e0aca4785a
commit 9d4cb0a4ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 41 additions and 103 deletions

View File

@ -128,7 +128,7 @@ public class SkipIntroController : ControllerBase
Plugin.Instance!.Credits.Clear(); Plugin.Instance!.Credits.Clear();
} }
Plugin.Instance!.SaveTimestamps(); Plugin.Instance!.SaveTimestamps(mode);
return NoContent(); return NoContent();
} }

View File

@ -139,11 +139,12 @@ public class VisualizationController : ControllerBase
foreach (var e in episodes) foreach (var e in episodes)
{ {
Plugin.Instance!.Intros.Remove(e.EpisodeId); Plugin.Instance!.Intros.TryRemove(e.EpisodeId, out _);
Plugin.Instance!.Credits.Remove(e.EpisodeId); Plugin.Instance!.Credits.TryRemove(e.EpisodeId, out _);
} }
Plugin.Instance!.SaveTimestamps(); Plugin.Instance!.SaveTimestamps(AnalysisMode.Introduction);
Plugin.Instance!.SaveTimestamps(AnalysisMode.Credits);
return NoContent(); return NoContent();
} }
@ -160,7 +161,7 @@ public class VisualizationController : ControllerBase
{ {
var tr = new TimeRange(timestamps.IntroStart, timestamps.IntroEnd); var tr = new TimeRange(timestamps.IntroStart, timestamps.IntroEnd);
Plugin.Instance!.Intros[id] = new Intro(id, tr); Plugin.Instance!.Intros[id] = new Intro(id, tr);
Plugin.Instance.SaveTimestamps(); Plugin.Instance.SaveTimestamps(AnalysisMode.Introduction);
return NoContent(); return NoContent();
} }

View File

@ -33,7 +33,7 @@ public static class FFmpegWrapper
private static Dictionary<string, string> ChromaprintLogs { get; set; } = new(); private static Dictionary<string, string> ChromaprintLogs { get; set; } = new();
private static ConcurrentDictionary<AnalysisMode, ConcurrentDictionary<Guid, Dictionary<uint, int>>> InvertedIndexCache { get; set; } = new(); private static ConcurrentDictionary<(Guid Id, AnalysisMode Mode), Dictionary<uint, int>> InvertedIndexCache { get; set; } = new();
/// <summary> /// <summary>
/// Check that the installed version of ffmpeg supports chromaprint. /// Check that the installed version of ffmpeg supports chromaprint.
@ -140,10 +140,7 @@ public static class FFmpegWrapper
/// <returns>Inverted index.</returns> /// <returns>Inverted index.</returns>
public static Dictionary<uint, int> CreateInvertedIndex(Guid id, uint[] fingerprint, AnalysisMode mode) public static Dictionary<uint, int> CreateInvertedIndex(Guid id, uint[] fingerprint, AnalysisMode mode)
{ {
var innerDictionary = InvertedIndexCache.GetOrAdd(mode, _ => new ConcurrentDictionary<Guid, Dictionary<uint, int>>()); if (InvertedIndexCache.TryGetValue((id, mode), out var cached))
// Check if cached for the ID
if (innerDictionary.TryGetValue(id, out var cached))
{ {
return cached; return cached;
} }
@ -159,7 +156,7 @@ public static class FFmpegWrapper
invIndex[point] = i; invIndex[point] = i;
} }
innerDictionary[id] = invIndex; InvertedIndexCache[(id, mode)] = invIndex;
return invIndex; return invIndex;
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -140,17 +141,17 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
/// <summary> /// <summary>
/// Gets the results of fingerprinting all episodes. /// Gets the results of fingerprinting all episodes.
/// </summary> /// </summary>
public Dictionary<Guid, Intro> Intros { get; } = new(); public ConcurrentDictionary<Guid, Intro> Intros { get; } = new();
/// <summary> /// <summary>
/// Gets all discovered ending credits. /// Gets all discovered ending credits.
/// </summary> /// </summary>
public Dictionary<Guid, Intro> Credits { get; } = new(); public ConcurrentDictionary<Guid, Intro> Credits { get; } = new();
/// <summary> /// <summary>
/// Gets the most recent media item queue. /// Gets the most recent media item queue.
/// </summary> /// </summary>
public Dictionary<Guid, List<QueuedEpisode>> QueuedMediaItems { get; } = new(); public ConcurrentDictionary<Guid, List<QueuedEpisode>> QueuedMediaItems { get; } = new();
/// <summary> /// <summary>
/// Gets or sets the total number of episodes in the queue. /// Gets or sets the total number of episodes in the queue.
@ -183,91 +184,33 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
/// </summary> /// </summary>
public static Plugin? Instance { get; private set; } public static Plugin? Instance { get; private set; }
/// <summary>
/// Save timestamps to disk.
/// </summary>
public void SaveTimestamps()
{
lock (_serializationLock)
{
var introList = new List<Intro>();
// Serialize intros
foreach (var intro in Instance!.Intros)
{
introList.Add(intro.Value);
}
try
{
XmlSerializationHelper.SerializeToXml(introList, _introPath);
}
catch (Exception e)
{
_logger.LogError("SaveTimestamps intros {Message}", e.Message);
}
// Serialize credits
introList.Clear();
foreach (var intro in Instance.Credits)
{
introList.Add(intro.Value);
}
try
{
XmlSerializationHelper.SerializeToXml(introList, _creditsPath);
}
catch (Exception e)
{
_logger.LogError("SaveTimestamps credits {Message}", e.Message);
}
}
}
/// <summary> /// <summary>
/// Save timestamps to disk. /// Save timestamps to disk.
/// </summary> /// </summary>
/// <param name="mode">Mode.</param> /// <param name="mode">Mode.</param>
public void SaveTimestamps(AnalysisMode mode) public void SaveTimestamps(AnalysisMode mode)
{ {
List<Intro> introList = new List<Intro>();
var filePath = mode == AnalysisMode.Introduction
? _introPath
: _creditsPath;
lock (_introsLock)
{
introList.AddRange(mode == AnalysisMode.Introduction
? Instance!.Intros.Values
: Instance!.Credits.Values);
}
lock (_serializationLock) lock (_serializationLock)
{ {
var introList = new List<Intro>();
// Serialize intros
if (mode == AnalysisMode.Introduction)
{
foreach (var intro in Instance!.Intros)
{
introList.Add(intro.Value);
}
try try
{ {
XmlSerializationHelper.SerializeToXml(introList, _introPath); XmlSerializationHelper.SerializeToXml(introList, filePath);
} }
catch (Exception e) catch (Exception e)
{ {
_logger.LogError("SaveTimestamps intros {Message}", e.Message); _logger.LogError("SaveTimestamps {Message}", e.Message);
}
}
else if (mode == AnalysisMode.Credits)
{
foreach (var intro in Instance!.Credits)
{
introList.Add(intro.Value);
}
try
{
XmlSerializationHelper.SerializeToXml(introList, _creditsPath);
}
catch (Exception e)
{
_logger.LogError("SaveTimestamps credits {Message}", e.Message);
}
} }
} }
} }
@ -284,7 +227,7 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
foreach (var intro in introList) foreach (var intro in introList)
{ {
Instance!.Intros[intro.EpisodeId] = intro; Instance!.Intros.TryAdd(intro.EpisodeId, intro);
} }
} }
@ -294,7 +237,7 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
foreach (var credit in creditList) foreach (var credit in creditList)
{ {
Instance!.Credits[credit.EpisodeId] = credit; Instance!.Credits.TryAdd(credit.EpisodeId, credit);
} }
} }
} }
@ -393,23 +336,20 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
} }
internal void UpdateTimestamps(Dictionary<Guid, Intro> newTimestamps, AnalysisMode mode) internal void UpdateTimestamps(Dictionary<Guid, Intro> newTimestamps, AnalysisMode mode)
{
lock (_introsLock)
{ {
foreach (var intro in newTimestamps) foreach (var intro in newTimestamps)
{ {
if (mode == AnalysisMode.Introduction) if (mode == AnalysisMode.Introduction)
{ {
Instance!.Intros[intro.Key] = intro.Value; Instance!.Intros.AddOrUpdate(intro.Key, intro.Value, (key, oldValue) => intro.Value);
} }
else if (mode == AnalysisMode.Credits) else if (mode == AnalysisMode.Credits)
{ {
Instance!.Credits[intro.Key] = intro.Value; Instance!.Credits.AddOrUpdate(intro.Key, intro.Value, (key, oldValue) => intro.Value);
} }
} }
Instance!.SaveTimestamps(mode); SaveTimestamps(mode);
}
} }
/// <summary> /// <summary>

View File

@ -84,7 +84,7 @@ public class QueueManager
Plugin.Instance.QueuedMediaItems.Clear(); Plugin.Instance.QueuedMediaItems.Clear();
foreach (var kvp in _queuedEpisodes) foreach (var kvp in _queuedEpisodes)
{ {
Plugin.Instance.QueuedMediaItems[kvp.Key] = kvp.Value; Plugin.Instance.QueuedMediaItems.TryAdd(kvp.Key, kvp.Value);
} }
return new(_queuedEpisodes); return new(_queuedEpisodes);