From e65013c07b2127f10aee8e6be6027d71cbfdcb9b Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Wed, 15 Jan 2025 09:45:55 +0700 Subject: [PATCH] changed code converting senses to avoid a cache stampede --- backend/LfClassicData/LfClassicMiniLcmApi.cs | 28 +++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/backend/LfClassicData/LfClassicMiniLcmApi.cs b/backend/LfClassicData/LfClassicMiniLcmApi.cs index 717b1a405..a0a68dca1 100644 --- a/backend/LfClassicData/LfClassicMiniLcmApi.cs +++ b/backend/LfClassicData/LfClassicMiniLcmApi.cs @@ -99,7 +99,7 @@ public async IAsyncEnumerable GetPartsOfSpeech() return _partsOfSpeechCacheByGuid.GetValueOrDefault(id); } - public async Task GetPartOfSpeech(string key) + public async ValueTask GetPartOfSpeech(string key) { if (_partsOfSpeechCacheByStringKey is null) { @@ -246,18 +246,20 @@ private async IAsyncEnumerable Query(QueryOptions? options = null, string }))); } - private async Task ToEntry(Entities.Entry entry) + private async ValueTask ToEntry(Entities.Entry entry) { - Sense[] senses; - if (entry.Senses is null) + List senses = new(entry.Senses?.Count ?? 0); + if (entry.Senses is not (null or [])) { - senses = []; - } - else - { - var senseTasks = entry.Senses.OfType().Select(sense => ToSense(entry.Guid, sense)); - senses = await Task.WhenAll(senseTasks); + foreach (var sense in entry.Senses) + { + if (sense is null) continue; + //explicitly doing this sequentially + //to avoid concurrency issues as ToSense calls GetPartOfSpeech which is cached + senses.Add(await ToSense(entry.Guid, sense)); + } } + return new Entry { Id = entry.Guid, @@ -269,15 +271,17 @@ private async Task ToEntry(Entities.Entry entry) }; } - private async Task ToSense(Guid entryId, Entities.Sense sense) + private async ValueTask ToSense(Guid entryId, Entities.Sense sense) { + var partOfSpeech = sense.PartOfSpeech is null ? null : await GetPartOfSpeech(sense.PartOfSpeech.Value); return new Sense { Id = sense.Guid, EntryId = entryId, Gloss = ToMultiString(sense.Gloss), Definition = ToMultiString(sense.Definition), - PartOfSpeech = sense.PartOfSpeech is null ? null : await GetPartOfSpeech(sense.PartOfSpeech.Value), + PartOfSpeech = partOfSpeech, + PartOfSpeechId = partOfSpeech?.Id, SemanticDomains = (sense.SemanticDomain?.Values ?? []) .Select(sd => new SemanticDomain { Id = Guid.Empty, Code = sd, Name = new MultiString { { "en", sd } } }) .ToList(),