aboutsummaryrefslogtreecommitdiff
path: root/Libs/VNLib.Plugins.Essentials.Sessions
diff options
context:
space:
mode:
Diffstat (limited to 'Libs/VNLib.Plugins.Essentials.Sessions')
-rw-r--r--Libs/VNLib.Plugins.Essentials.Sessions/MemorySession.cs30
-rw-r--r--Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionEntrypoint.cs3
-rw-r--r--Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs34
-rw-r--r--Libs/VNLib.Plugins.Essentials.Sessions/VNLib.Plugins.Essentials.Sessions.Memory.csproj4
4 files changed, 56 insertions, 15 deletions
diff --git a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySession.cs b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySession.cs
index a806438..d365cd2 100644
--- a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySession.cs
+++ b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySession.cs
@@ -28,23 +28,27 @@ using System.Threading.Tasks;
using System.Collections.Generic;
using VNLib.Plugins.Essentials.Extensions;
+using VNLib.Utils.Async;
using VNLib.Net.Http;
+using VNLib.Utils.Memory.Caching;
using static VNLib.Plugins.Essentials.Sessions.ISessionExtensions;
#nullable enable
namespace VNLib.Plugins.Essentials.Sessions.Memory
{
- internal class MemorySession : SessionBase
+ internal class MemorySession : SessionBase, ICacheable
{
private readonly Dictionary<string, string> DataStorage;
private readonly Func<IHttpEvent, string, string> OnSessionUpdate;
+ private readonly AsyncQueue<MemorySession> ExpiredTable;
- public MemorySession(string sessionId, IPAddress ipAddress, Func<IHttpEvent, string, string> onSessionUpdate)
+ public MemorySession(string sessionId, IPAddress ipAddress, Func<IHttpEvent, string, string> onSessionUpdate, AsyncQueue<MemorySession> expired)
{
//Set the initial is-new flag
DataStorage = new Dictionary<string, string>(10);
+ ExpiredTable = expired;
OnSessionUpdate = onSessionUpdate;
//Get new session id
@@ -90,14 +94,7 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory
//Memory session always completes
return ValueTask.FromResult<Task?>(null);
}
-
- protected override Task OnEvictedAsync()
- {
- //Clear all session data
- DataStorage.Clear();
- return Task.CompletedTask;
- }
-
+
protected override string IndexerGet(string key)
{
return DataStorage.GetValueOrDefault(key, string.Empty);
@@ -116,5 +113,18 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory
}
DataStorage[key] = value;
}
+
+
+ DateTime ICacheable.Expires { get; set; }
+
+ void ICacheable.Evicted()
+ {
+ DataStorage.Clear();
+ //Enque cleanup
+ _ = ExpiredTable.TryEnque(this);
+ }
+
+ bool IEquatable<ICacheable>.Equals(ICacheable? other) => other is ISession ses && SessionID.Equals(ses.SessionID, StringComparison.Ordinal);
+
}
}
diff --git a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionEntrypoint.cs b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionEntrypoint.cs
index 91a3a0e..f58129a 100644
--- a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionEntrypoint.cs
+++ b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionEntrypoint.cs
@@ -73,6 +73,9 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory
_sessions = new(config);
+ //Begin listening for expired records
+ _ = plugin.DeferTask(() => _sessions.CleanupExiredAsync(localized, plugin.UnloadToken));
+
//Schedule garbage collector
_ = plugin.ScheduleInterval(this, TimeSpan.FromMinutes(1));
diff --git a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs
index e76d7a4..1af885e 100644
--- a/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs
+++ b/Libs/VNLib.Plugins.Essentials.Sessions/MemorySessionStore.cs
@@ -28,11 +28,12 @@ using System.Threading.Tasks;
using System.Collections.Generic;
using VNLib.Net.Http;
+using VNLib.Net.Http.Core;
using VNLib.Utils;
using VNLib.Utils.Async;
+using VNLib.Utils.Logging;
using VNLib.Utils.Extensions;
using VNLib.Plugins.Essentials.Extensions;
-using VNLib.Net.Http.Core;
#nullable enable
@@ -47,12 +48,14 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory
internal readonly MemorySessionConfig Config;
internal readonly SessionIdFactory IdFactory;
+ internal readonly AsyncQueue<MemorySession> ExpiredSessions;
public MemorySessionStore(MemorySessionConfig config)
{
Config = config;
SessionsStore = new(config.MaxAllowedSessions, StringComparer.Ordinal);
IdFactory = new(config.SessionIdSizeBytes, config.SessionCookieID, config.SessionTimeout);
+ ExpiredSessions = new(false, true);
}
///<inheritdoc/>
@@ -68,7 +71,7 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory
if (IdFactory.TryGetSessionId(entity, out string? sessionId))
{
//Try to get the old record or evict it
- ERRNO result = SessionsStore.TryGetOrEvictRecord(sessionId, out MemorySession session);
+ ERRNO result = SessionsStore.TryGetOrEvictRecord(sessionId, out MemorySession? session);
if(result > 0)
{
//Valid, now wait for exclusive access
@@ -89,7 +92,7 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory
return new(null, FileProcessArgs.VirtualSkip, null);
}
//Initialze a new session
- session = new(sessionId, entity.Server.GetTrustedIp(), UpdateSessionId);
+ session = new(sessionId, entity.Server.GetTrustedIp(), UpdateSessionId, ExpiredSessions);
//Increment the semaphore
(session as IWaitHandle).WaitOne();
//store the session in cache while holding semaphore, and set its expiration
@@ -104,6 +107,31 @@ namespace VNLib.Plugins.Essentials.Sessions.Memory
}
}
+ public async Task CleanupExiredAsync(ILogProvider log, CancellationToken token)
+ {
+ while (true)
+ {
+ try
+ {
+ //Wait for expired session and dispose it
+ using MemorySession session = await ExpiredSessions.DequeueAsync(token);
+
+ //Obtain lock on session
+ await session.WaitOneAsync(CancellationToken.None);
+
+ log.Verbose("Removed expired session {id}", session.SessionID);
+ }
+ catch (OperationCanceledException)
+ {
+ break;
+ }
+ catch (Exception ex)
+ {
+ log.Error(ex);
+ }
+ }
+ }
+
private string UpdateSessionId(IHttpEvent entity, string oldId)
{
//Generate and set a new sessionid
diff --git a/Libs/VNLib.Plugins.Essentials.Sessions/VNLib.Plugins.Essentials.Sessions.Memory.csproj b/Libs/VNLib.Plugins.Essentials.Sessions/VNLib.Plugins.Essentials.Sessions.Memory.csproj
index 0d3cb40..c4a65f5 100644
--- a/Libs/VNLib.Plugins.Essentials.Sessions/VNLib.Plugins.Essentials.Sessions.Memory.csproj
+++ b/Libs/VNLib.Plugins.Essentials.Sessions/VNLib.Plugins.Essentials.Sessions.Memory.csproj
@@ -36,8 +36,8 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\..\..\..\VNLib\Essentials\VNLib.Plugins.Essentials.csproj" />
- <ProjectReference Include="..\..\..\..\VNLib\Http\VNLib.Net.Http.csproj" />
+ <ProjectReference Include="..\..\..\..\VNLib\Essentials\src\VNLib.Plugins.Essentials.csproj" />
+ <ProjectReference Include="..\..\..\..\VNLib\Http\src\VNLib.Net.Http.csproj" />
<ProjectReference Include="..\..\..\Extensions\VNLib.Plugins.Extensions.Loading\VNLib.Plugins.Extensions.Loading.csproj" />
<ProjectReference Include="..\..\..\PluginBase\VNLib.Plugins.PluginBase.csproj" />
<ProjectReference Include="..\VNLib.Plugins.Essentials.Sessions.Runtime\VNLib.Plugins.Essentials.Sessions.Runtime.csproj" />