diff --git a/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/GenericCache.cs b/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/GenericCache.cs index 519d3823cc..c53db3bdaa 100644 --- a/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/GenericCache.cs +++ b/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/GenericCache.cs @@ -3,7 +3,9 @@ using ECS.StreamableLoading.Cache.Disk; using ECS.StreamableLoading.Cache.InMemory; using System; +using System.Collections.Generic; using System.Threading; +using Utility; using Utility.Types; namespace ECS.StreamableLoading.Cache.Generic @@ -14,6 +16,7 @@ public class GenericCache : IGenericCache private readonly IDiskCache diskCache; private readonly Func stringifyFunc; private readonly string extension; + private readonly Dictionary readingKeys; public GenericCache(IMemoryCache memoryCache, IDiskCache diskCache, Func stringifyFunc, string extension) { @@ -21,6 +24,7 @@ public GenericCache(IMemoryCache memoryCache, IDiskCache diskCache, this.diskCache = diskCache; this.stringifyFunc = stringifyFunc; this.extension = extension; + readingKeys = new Dictionary(); } public UniTask> PutAsync(TKey key, T value, CancellationToken token) @@ -29,13 +33,20 @@ public UniTask> PutAsync(TKey key, T value, CancellationTo return diskCache.PutAsync(stringifyFunc(key)!, extension, value, token); } - public async UniTask, TaskError>> ContentAsync(TKey key, CancellationToken token) + public UniTask, TaskError>> ReadFromCache(TKey key, CancellationToken token) { if (memoryCache.TryGet(key, out T result)) - return EnumResult, TaskError>.SuccessResult(Option.Some(result)); + return UniTask.FromResult(EnumResult, TaskError>.SuccessResult(Option.Some(result))); + return UniTask.FromResult(EnumResult, TaskError>.SuccessResult(Option.None)); + } + + public async UniTask, TaskError>> ReadFromDisk(TKey key, CancellationToken token) + { string stringKey = stringifyFunc(key)!; + readingKeys!.SyncTryAdd(stringKey, null); + var diskResult = await diskCache.ContentAsync(stringKey, extension, token); if (diskResult.Success) @@ -54,7 +65,10 @@ public async UniTask, TaskError>> ContentAsync(TKey key, Ca $"Error getting disk cache content for '{key}' - {diskResult.Error!.Value.State} {diskResult.Error!.Value.Message}" ); + readingKeys.SyncRemove(stringKey); + return EnumResult, TaskError>.SuccessResult(Option.None); } + } } diff --git a/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/IGenericCache.cs b/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/IGenericCache.cs index d1c0f81d53..9aa43cc9c3 100644 --- a/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/IGenericCache.cs +++ b/Explorer/Assets/Scripts/ECS/StreamableLoading/Cache/Generic/IGenericCache.cs @@ -12,7 +12,10 @@ public interface IGenericCache { UniTask> PutAsync(TKey key, T value, CancellationToken token); - UniTask, TaskError>> ContentAsync(TKey key, CancellationToken token); + UniTask, TaskError>> ReadFromCache(TKey key, CancellationToken token); + + UniTask, TaskError>> ReadFromDisk(TKey key, CancellationToken token); + } public static class GenericCacheExtensions @@ -25,7 +28,7 @@ public static async UniTask, TaskError>> ContentOrFetchAsyn CancellationToken token ) { - var result = await cache.ContentAsync(key, token); + var result = await cache.ReadFromCache(key, token); if (result.Success == false || result.Value.Has) return result; diff --git a/Explorer/Assets/Scripts/ECS/StreamableLoading/Common/Systems/LoadSystemBase.cs b/Explorer/Assets/Scripts/ECS/StreamableLoading/Common/Systems/LoadSystemBase.cs index 5dccfdb400..41147f4829 100644 --- a/Explorer/Assets/Scripts/ECS/StreamableLoading/Common/Systems/LoadSystemBase.cs +++ b/Explorer/Assets/Scripts/ECS/StreamableLoading/Common/Systems/LoadSystemBase.cs @@ -13,6 +13,7 @@ using System; using System.Runtime.CompilerServices; using System.Threading; +using UnityEngine; using Utility; namespace ECS.StreamableLoading.Common.Systems @@ -150,12 +151,12 @@ CancellationToken disposalCt } } - var cachedContent = await genericCache.ContentAsync(intention, disposalCt); - + // Try load from cache first + var cachedContent = await genericCache.ReadFromCache(intention, disposalCt); + if (cachedContent.Success) { var option = cachedContent.Value; - if (option.Has) { result = new StreamableLoadingResult(option.Value); @@ -163,7 +164,6 @@ CancellationToken disposalCt } } - // Try load from cache first // If the given URL failed irrecoverably just return the failure if (cache.IrrecoverableFailures.TryGetValue(intention.CommonArguments.GetCacheableURL(), out var failure)) @@ -278,20 +278,31 @@ private void IncreaseRefCount(in TIntention intention, TAsset asset) try { - result = await RepeatLoopAsync(intention, acquiredBudget, partition, ct); - + var cachedContentFromDisk = await genericCache.ReadFromDisk(intention, ct); + if (cachedContentFromDisk.Success) + { + var option = cachedContentFromDisk.Value; + if (option.Has) + result = new StreamableLoadingResult(option.Value); + else + result = await RepeatLoopAsync(intention, acquiredBudget, partition, ct); + } + else + { + result = await RepeatLoopAsync(intention, acquiredBudget, partition, ct); + } + // Ensure that we returned to the main thread await UniTask.SwitchToMainThread(ct); // before firing the continuation of the ongoing request // Add result to the cache if (result is { Succeeded: true }) - genericCache - .PutAsync(intention, result.Value.Asset!, ct) - .Forget( - static e => - ReportHub.LogError(ReportCategory.STREAMABLE_LOADING, $"Error putting cache content: {e.Message}") - ); + { + await genericCache + .PutAsync(intention, result.Value.Asset!, ct); + } + // Set result for the reusable source // Remove from the ongoing requests immediately because finally will be called later than