From a8510fb835dcc5e1142d700164ce5a4bd44e1a25 Mon Sep 17 00:00:00 2001 From: vman Date: Sun, 30 Oct 2022 02:28:12 -0400 Subject: Add project files. --- .../SessionCacheClient.cs | 159 +++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 Libs/VNLib.Plugins.Sessions.Cache.Client/SessionCacheClient.cs (limited to 'Libs/VNLib.Plugins.Sessions.Cache.Client/SessionCacheClient.cs') diff --git a/Libs/VNLib.Plugins.Sessions.Cache.Client/SessionCacheClient.cs b/Libs/VNLib.Plugins.Sessions.Cache.Client/SessionCacheClient.cs new file mode 100644 index 0000000..de0e370 --- /dev/null +++ b/Libs/VNLib.Plugins.Sessions.Cache.Client/SessionCacheClient.cs @@ -0,0 +1,159 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using VNLib.Utils; +using VNLib.Utils.Memory.Caching; +using VNLib.Net.Http; +using VNLib.Net.Messaging.FBM.Client; +using VNLib.Plugins.Essentials.Sessions; + +#nullable enable + +namespace VNLib.Plugins.Sessions.Cache.Client +{ + + /// + /// A client that allows access to sessions located on external servers + /// + public abstract class SessionCacheClient : VnDisposeable, ICacheHolder + { + public class LRUSessionStore : LRUCache where T : ISession, ICacheable + { + public override bool IsReadOnly => false; + protected override int MaxCapacity { get; } + + public LRUSessionStore(int maxCapacity) : base(StringComparer.Ordinal) => MaxCapacity = maxCapacity; + + protected override bool CacheMiss(string key, [NotNullWhen(true)] out T? value) + { + value = default; + return false; + } + protected override void Evicted(KeyValuePair evicted) + { + //Evice record + evicted.Value.Evicted(); + } + } + + protected readonly LRUSessionStore CacheTable; + protected readonly object CacheLock; + protected readonly int MaxLoadedEntires; + + protected FBMClient Client { get; } + + /// + /// Initializes a new + /// + /// + /// The maximum number of sessions to keep in memory + public SessionCacheClient(FBMClient client, int maxCacheItems) + { + MaxLoadedEntires = maxCacheItems; + CacheLock = new(); + CacheTable = new(maxCacheItems); + Client = client; + //Listen for close events + Client.ConnectionClosed += Client_ConnectionClosed; + } + + private void Client_ConnectionClosed(object? sender, EventArgs e) => CacheHardClear(); + + /// + /// Attempts to get a session from the cache identified by its sessionId asynchronously + /// + /// The connection/request to attach the session to + /// The ID of the session to retrieve + /// A token to cancel the operation + /// A that resolves the remote session + /// + public virtual async ValueTask GetSessionAsync(IHttpEvent entity, string sessionId, CancellationToken cancellationToken) + { + Check(); + try + { + RemoteSession? session; + //Aquire lock on cache + lock (CacheLock) + { + //See if session is loaded into cache + if (!CacheTable.TryGetValue(sessionId, out session)) + { + //Init new record + session = SessionCtor(sessionId); + //Add to cache + CacheTable.Add(session.SessionID, session); + } + //Valid entry found in cache + } + try + { + //Load session-data + await session.WaitAndLoadAsync(entity, cancellationToken); + return session; + } + catch + { + //Remove the invalid cached session + lock (CacheLock) + { + _ = CacheTable.Remove(sessionId); + } + throw; + } + } + catch (SessionException) + { + throw; + } + catch (OperationCanceledException) + { + throw; + } + //Wrap exceptions + catch (Exception ex) + { + throw new SessionException("An unhandled exception was raised", ex); + } + } + + /// + /// Gets a new instances for the given sessionId, + /// and places it a the head of internal cache + /// + /// The session identifier + /// The new session for the given ID + protected abstract RemoteSession SessionCtor(string sessionId); + + /// + public void CacheClear() + { + + } + /// + public void CacheHardClear() + { + //Cleanup cache when disconnected + lock (CacheLock) + { + CacheTable.Clear(); + foreach (RemoteSession session in (IEnumerable)CacheTable) + { + session.Evicted(); + } + CacheTable.Clear(); + } + } + + protected override void Free() + { + //Unsub from events + Client.ConnectionClosed -= Client_ConnectionClosed; + //Clear all cached sessions + CacheHardClear(); + } + } +} -- cgit