aboutsummaryrefslogtreecommitdiff
path: root/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-03-09 01:48:38 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-03-09 01:48:38 -0500
commitcd1daadaeaa6ffbaaef3ed25452decd90d01fdfc (patch)
tree51252a42ccf3f6eb860e42d83f064a7247d7ebf7 /lib/VNLib.Plugins.Extensions.VNCache/src/DataModel
parent5edcd9b03532823c71fd337e39b7f03fe2ea174e (diff)
Omega cache, session, and account provider complete overhaul
Diffstat (limited to 'lib/VNLib.Plugins.Extensions.VNCache/src/DataModel')
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/EntityCacheExtensions.cs159
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheEntity.cs39
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs48
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheKeyGenerator.cs40
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs39
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ScopedCache.cs64
6 files changed, 389 insertions, 0 deletions
diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/EntityCacheExtensions.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/EntityCacheExtensions.cs
new file mode 100644
index 0000000..79bb4fc
--- /dev/null
+++ b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/EntityCacheExtensions.cs
@@ -0,0 +1,159 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Extensions.VNCache
+* File: EntityCacheExtensions.cs
+*
+* EntityCacheExtensions.cs is part of VNLib.Plugins.Extensions.VNCache
+* which is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Runtime.CompilerServices;
+
+using VNLib.Data.Caching;
+
+namespace VNLib.Plugins.Extensions.VNCache.DataModel
+{
+ /// <summary>
+ /// Provides cache extensions for entity caching
+ /// </summary>
+ public static class EntityCacheExtensions
+ {
+ /// <summary>
+ /// Gets a new <see cref="ScopedCache"/> that is backed by the current cache provider
+ /// and generates 1:1 keys from the <paramref name="cacheKeyGenerator"/>
+ /// </summary>
+ /// <param name="cache"></param>
+ /// <param name="cacheKeyGenerator">The instance that generates unique keys for a given entity id</param>
+ /// <returns>The new <see cref="ScopedCache"/> instance</returns>
+ public static ScopedCache GetScopedCache(this IGlobalCacheProvider cache, ICacheKeyGenerator cacheKeyGenerator) => new ScopedCacheImpl(cache, cacheKeyGenerator);
+
+ /// <summary>
+ /// Deletes an <see cref="ICacheEntity"/> from the cache from its id
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="cache"></param>
+ /// <param name="entity">The entity to delete from the store</param>
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>A task that completes when the delete operation has compelted</returns>
+ /// <exception cref="ArgumentNullException"></exception>
+ public static Task DeleteAsync<T>(this IGlobalCacheProvider cache, T entity, CancellationToken cancellation) where T: class, ICacheEntity
+ {
+ _ = entity ?? throw new ArgumentNullException(nameof(entity));
+ _ = cache ?? throw new ArgumentNullException(nameof(entity));
+ //Delete by its id
+ return cache.DeleteAsync(entity.Id, cancellation);
+ }
+
+ /// <summary>
+ /// Asynchronously sets (or updates) a cached value in the backing cache store
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="cache"></param>
+ /// <param name="cancellation">A token to cancel the async operation</param>
+ /// <param name="entity">The entity to set at the given key</param>
+ /// <returns>A task that completes when the add/update operation has compelted</returns>
+ /// <exception cref="ArgumentNullException"></exception>
+ public static Task AddOrUpdateAsync<T>(this IGlobalCacheProvider cache, T entity, CancellationToken cancellation) where T: class, ICacheEntity
+ {
+ _ = entity ?? throw new ArgumentNullException(nameof(entity));
+ _ = cache ?? throw new ArgumentNullException(nameof(cache));
+
+ //Add/update with its id
+ return cache.AddOrUpdateAsync(entity.Id, null, entity, cancellation);
+ }
+
+
+ private sealed class ScopedCacheImpl: ScopedCache
+ {
+ private readonly IGlobalCacheProvider cache;
+
+ public override bool IsConnected
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => cache.IsConnected;
+ }
+
+
+ protected override ICacheKeyGenerator KeyGen { get; }
+
+ public ScopedCacheImpl(IGlobalCacheProvider cache, ICacheKeyGenerator keyGen)
+ {
+ this.cache = cache;
+ KeyGen = keyGen;
+ }
+
+ public override Task AddOrUpdateAsync<T>(string key, string? newKey, T value, CancellationToken cancellation)
+ {
+ _ = key ?? throw new ArgumentNullException(nameof(key));
+
+ //Compute primary key from id
+ string primary = KeyGen.ComputedKey(key);
+
+ //If newkey exists, compute the secondary key
+ string? secondary = newKey != null ? KeyGen.ComputedKey(newKey) : null;
+
+ return cache.AddOrUpdateAsync(primary, secondary, value, cancellation);
+ }
+
+ public override Task DeleteAsync(string key, CancellationToken cancellation)
+ {
+ _ = key ?? throw new ArgumentNullException(nameof(key));
+ //Compute the key for the id
+ string scoped = KeyGen.ComputedKey(key);
+ return cache.DeleteAsync(scoped, cancellation);
+ }
+
+ public override Task<T> GetAsync<T>(string key, CancellationToken cancellation)
+ {
+ _ = key ?? throw new ArgumentNullException(nameof(key));
+
+ //Compute the key for the id
+ string scoped = KeyGen.ComputedKey(key);
+
+ return cache.GetAsync<T?>(scoped, cancellation);
+ }
+
+ public override Task<T> GetAsync<T>(string key, ICacheObjectDeserialzer deserializer, CancellationToken cancellation)
+ {
+ _ = key ?? throw new ArgumentNullException(nameof(key));
+
+ //Compute the key for the id
+ string scoped = KeyGen.ComputedKey(key);
+
+ return cache.GetAsync<T?>(scoped, deserializer, cancellation);
+ }
+
+ public override Task AddOrUpdateAsync<T>(string key, string? newKey, T value, ICacheObjectSerialzer serialzer, CancellationToken cancellation)
+ {
+ _ = key ?? throw new ArgumentNullException(nameof(key));
+
+ //Compute primary key from id
+ string primary = KeyGen.ComputedKey(key);
+
+ //If newkey exists, compute the secondary key
+ string? secondary = newKey != null ? KeyGen.ComputedKey(newKey) : null;
+
+ return cache.AddOrUpdateAsync(primary, secondary, value, serialzer, cancellation);
+ }
+ }
+ }
+
+}
diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheEntity.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheEntity.cs
new file mode 100644
index 0000000..77f0667
--- /dev/null
+++ b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheEntity.cs
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Extensions.VNCache
+* File: ICacheEntity.cs
+*
+* ICacheEntity.cs is part of VNLib.Plugins.Extensions.VNCache
+* which is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+namespace VNLib.Plugins.Extensions.VNCache.DataModel
+{
+
+ /// <summary>
+ /// Represents a uniquely cachable item
+ /// </summary>
+ public interface ICacheEntity
+ {
+ /// <summary>
+ /// The unique ID of the item within the store
+ /// </summary>
+ string Id { get; }
+ }
+
+}
diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs
new file mode 100644
index 0000000..f9ff54c
--- /dev/null
+++ b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Extensions.VNCache
+* File: ICacheExpirationStrategy.cs
+*
+* ICacheExpirationStrategy.cs is part of VNLib.Plugins.Extensions.VNCache
+* which is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+
+namespace VNLib.Plugins.Extensions.VNCache.DataModel
+{
+ /// <summary>
+ /// An interface that provides an object caching expiration
+ /// instructions
+ /// </summary>
+ public interface ICacheExpirationStrategy
+ {
+ /// <summary>
+ /// The maxium age of a given entity
+ /// </summary>
+ TimeSpan CacheMaxAge { get; }
+
+ /// <summary>
+ /// Invoked when a record is retrieved and determined to be expired
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="expired"></param>
+ void OnExpired<T>(T expired) where T : IExpirableCacheEntity;
+ }
+
+}
diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheKeyGenerator.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheKeyGenerator.cs
new file mode 100644
index 0000000..2e558b0
--- /dev/null
+++ b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheKeyGenerator.cs
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Extensions.VNCache
+* File: ICacheKeyGenerator.cs
+*
+* ICacheKeyGenerator.cs is part of VNLib.Plugins.Extensions.VNCache
+* which is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+namespace VNLib.Plugins.Extensions.VNCache.DataModel
+{
+ /// <summary>
+ /// An interface that provides 1:1 entity to cache key mapping
+ /// </summary>
+ public interface ICacheKeyGenerator
+ {
+ /// <summary>
+ /// Computes the unique key identifying the item within
+ /// the cache store, unique to the store.
+ /// </summary>
+ /// <param name="entityId">The id of the entity to get the key for</param>
+ /// <returns>The unique key identifying the item</returns>
+ string ComputedKey(string entityId);
+ }
+}
diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs
new file mode 100644
index 0000000..a47d3ca
--- /dev/null
+++ b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Extensions.VNCache
+* File: IExpirableCacheEntity.cs
+*
+* IExpirableCacheEntity.cs is part of VNLib.Plugins.Extensions.VNCache
+* which is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+namespace VNLib.Plugins.Extensions.VNCache.DataModel
+{
+ /// <summary>
+ /// A cache entity that has a controllable expiration
+ /// </summary>
+ public interface IExpirableCacheEntity : ICacheEntity
+ {
+ /// <summary>
+ /// A serializable value set by the cache subsystem to
+ /// handle stale cache entires
+ /// </summary>
+ long Expires { get; set; }
+ }
+
+}
diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ScopedCache.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ScopedCache.cs
new file mode 100644
index 0000000..da2f78a
--- /dev/null
+++ b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ScopedCache.cs
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Extensions.VNCache
+* File: ScopedCache.cs
+*
+* ScopedCache.cs is part of VNLib.Plugins.Extensions.VNCache
+* which is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System.Threading;
+using System.Threading.Tasks;
+
+using VNLib.Data.Caching;
+
+namespace VNLib.Plugins.Extensions.VNCache.DataModel
+{
+ /// <summary>
+ /// A cache that stores objects with 1:1 keys unique to this instance. That is, a unique entity
+ /// that is stored in this cache instance may only be retrieved, deleted, or updated, by the
+ /// same instance. This is an abstract class.
+ /// </summary>
+ public abstract class ScopedCache : IGlobalCacheProvider
+ {
+
+ /// <summary>
+ /// The <see cref="ICacheKeyGenerator"/> to provide unique
+ /// cache keys
+ /// </summary>
+ protected abstract ICacheKeyGenerator KeyGen { get; }
+
+ ///<inheritdoc/>
+ public abstract bool IsConnected { get; }
+
+ ///<inheritdoc/>
+ public abstract Task AddOrUpdateAsync<T>(string key, string? newKey, T value, CancellationToken cancellation);
+
+ ///<inheritdoc/>
+ public abstract Task DeleteAsync(string key, CancellationToken cancellation);
+
+ ///<inheritdoc/>
+ public abstract Task<T?> GetAsync<T>(string key, CancellationToken cancellation);
+
+ ///<inheritdoc/>
+ public abstract Task<T?> GetAsync<T>(string key, ICacheObjectDeserialzer deserializer, CancellationToken cancellation);
+
+ ///<inheritdoc/>
+ public abstract Task AddOrUpdateAsync<T>(string key, string? newKey, T value, ICacheObjectSerialzer serialzer, CancellationToken cancellation);
+ }
+}