Пример #1
0
        public void Set_Remove()
        {
            var key   = "key";
            var value = new byte[] { 0x20, 0x20, 0x20, };

            var prefixedKey = $"{RedisCacheOptions.InstanceName}{key}";

            L1L2Cache.Set(key, value);

            Assert.Equal(
                value,
                L1L2Cache.Get(key));
            Assert.Equal(
                value,
                L1Cache.Get(prefixedKey));
            Assert.Equal(
                value,
                L2Cache.Get(key));

            L1L2Cache.Remove(key);

            Assert.Null(
                L1L2Cache.Get(key));
            Assert.Null(
                L1Cache.Get(prefixedKey));
            Assert.Null(
                L2Cache.Get(key));
        }
Пример #2
0
    private async Task <SemaphoreSlim> GetOrCreateLockAsync(
        string key,
        DistributedCacheEntryOptions?distributedCacheEntryOptions,
        CancellationToken cancellationToken = default)
    {
        await KeySemaphore.WaitAsync(cancellationToken);

        try
        {
            return(await L1Cache.GetOrCreateAsync(
                       $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}",
                       cacheEntry =>
            {
                cacheEntry.AbsoluteExpiration =
                    distributedCacheEntryOptions?.AbsoluteExpiration;
                cacheEntry.AbsoluteExpirationRelativeToNow =
                    distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow;
                cacheEntry.SlidingExpiration =
                    distributedCacheEntryOptions?.SlidingExpiration;
                return Task.FromResult(new SemaphoreSlim(1, 1));
            }) ??
                   new SemaphoreSlim(1, 1));
        }
        finally
        {
            KeySemaphore.Release();
        }
    }
Пример #3
0
 private SemaphoreSlim GetOrCreateLock(
     string key,
     DistributedCacheEntryOptions?distributedCacheEntryOptions)
 {
     KeySemaphore.Wait();
     try
     {
         return(L1Cache.GetOrCreate(
                    $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}",
                    cacheEntry =>
         {
             cacheEntry.AbsoluteExpiration =
                 distributedCacheEntryOptions?.AbsoluteExpiration;
             cacheEntry.AbsoluteExpirationRelativeToNow =
                 distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow;
             cacheEntry.SlidingExpiration =
                 distributedCacheEntryOptions?.SlidingExpiration;
             return new SemaphoreSlim(1, 1);
         }) ??
                new SemaphoreSlim(1, 1));
     }
     finally
     {
         KeySemaphore.Release();
     }
 }
Пример #4
0
    public void Subscribe()
    {
        if (!ConfigurationVerifier
            .TryVerifyConfiguration(
                "notify-keyspace-events",
                out var keyeventNotificationsException,
                "g",
                "h",
                "E"))
        {
            Logger?.LogWarning(
                keyeventNotificationsException,
                "Failed to verify keyevent notifications config.");
        }

        Subscriber.Value.Subscribe(
            "__keyevent@*__:del",
            (channel, message) =>
        {
            if (message.StartsWith(
                    L1L2RedisCacheOptions.KeyPrefix))
            {
                var key = message
                          .ToString()[L1L2RedisCacheOptions.KeyPrefix.Length..];
                L1Cache.Remove(
                    $"{L1L2RedisCacheOptions.KeyPrefix}{key}");
                L1Cache.Remove(
                    $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}");
            }
Пример #5
0
        /// <inheritdoc />
        /// <summary>
        /// Sets an item into cache
        /// </summary>
        /// <typeparam name="T">The type of item</typeparam>
        /// <param name="key">Name of the item in cache</param>
        /// <param name="item">The item being set into cache</param>
        public virtual void Set <T>(string key, T item)
        {
            var expiration = DateTimeOffset.Now.AddSeconds(Options.Seconds);

            // Optionally place in L1 Cache
            if (Options.UseLocalCache)
            {
                var l1Options = new MemoryCacheEntryOptions
                {
                    AbsoluteExpiration = expiration,
                    Priority           = Options.Priority
                };
                L1Cache.Set(key, item, l1Options);
            }

            // Optionally place in L2 Cache
            if (Options.UseDistributedCache)
            {
                // If these calls fail, do nothing
                try
                {
                    var obj       = new L2CacheItem <T>(Options.Seconds, Options.Priority, item);
                    var l2Options = new DistributedCacheEntryOptions {
                        AbsoluteExpiration = expiration
                    };
                    L2Cache.Set(key, obj.ToByteArray(), l2Options);
                }
                catch { }
            }
        }
Пример #6
0
        public async Task SetAsync_RemoveAsync()
        {
            var key   = "key";
            var value = new byte[] { 0x20, 0x20, 0x20, };

            var prefixedKey = $"{RedisCacheOptions.InstanceName}{key}";

            await L1L2Cache.SetAsync(key, value);

            Assert.Equal(
                value,
                await L1L2Cache.GetAsync(key));
            Assert.Equal(
                value,
                L1Cache.Get(prefixedKey));
            Assert.Equal(
                value,
                await L2Cache.GetAsync(key));

            await L1L2Cache.RemoveAsync(key);

            Assert.Null(
                await L1L2Cache.GetAsync(key));
            Assert.Null(
                L1Cache.Get(prefixedKey));
            Assert.Null(
                await L2Cache.GetAsync(key));
        }
Пример #7
0
        ///-------------------------------------------------------------------------------------------------
        /// <summary>
        ///  Gets a relationship.
        /// </summary>
        /// <param name="id">
        ///  The identifier.
        /// </param>
        /// <param name="schemaRelationship">
        ///  (Optional) the schema relationship.
        /// </param>
        /// <returns>
        ///  The relationship.
        /// </returns>
        ///-------------------------------------------------------------------------------------------------
        public virtual IModelRelationship GetRelationship(Identity id, ISchemaRelationship schemaRelationship = null)
        {
            Contract.Requires(id, "id");

            CheckInitialized();
            return(L1Cache.GetElement(id, schemaRelationship) as IModelRelationship);
        }
Пример #8
0
    public void Subscribe()
    {
        if (!ConfigurationVerifier
            .TryVerifyConfiguration(
                "notify-keyspace-events",
                out var keyeventNotificationsException,
                "g",
                "h",
                "K"))
        {
            Logger?.LogWarning(
                keyeventNotificationsException,
                "Failed to verify keyspace notifications config.");
        }

        Subscriber.Value.Subscribe(
            "__keyspace@*__:*",
            (channel, message) =>
        {
            if (message == "del" ||
                message == "hset")
            {
                var keyPrefixIndex = channel.ToString().IndexOf(
                    L1L2RedisCacheOptions.KeyPrefix);
                if (keyPrefixIndex != -1)
                {
                    var key = channel.ToString()[
                        (keyPrefixIndex + L1L2RedisCacheOptions.KeyPrefix.Length)..];
                    L1Cache.Remove(
                        $"{L1L2RedisCacheOptions.KeyPrefix}{key}");
                    L1Cache.Remove(
                        $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}");
                }
Пример #9
0
        public virtual async Task Set(string key, object value, CachePolicyItem cachePolicy)
        {
            //清除一级缓存,写入二级缓存
            await L1Cache.Remove(key);

            await L2Cache.Set(key, value, cachePolicy);

            //后台写入一级缓存。
            Background(L1Cache.Set(key, value, cachePolicy));
        }
Пример #10
0
 public void Dispose()
 {
     try
     {
         L1Cache.Dispose();
     }
     finally
     {
         L2Cache.Dispose();
     }
 }
Пример #11
0
        ///-------------------------------------------------------------------------------------------------
        /// <summary>
        ///  Releases the unmanaged resources used by the Hyperstore.Modeling.Domain.DomainModel and
        ///  optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">
        ///  true to release both managed and unmanaged resources; false to release only unmanaged
        ///  resources.
        /// </param>
        ///-------------------------------------------------------------------------------------------------
        protected virtual void Dispose(bool disposing)
        {
            var tmp = DomainUnloaded;

            if (tmp != null)
            {
                tmp(this, new EventArgs());
            }

            if (L1Cache != null)
            {
                L1Cache.Dispose();
            }

            var disposable = InnerGraph as IDisposable;

            if (disposable != null)
            {
                disposable.Dispose();
            }
            InnerGraph = null;

            disposable = _commandManager as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
            _commandManager = null;

            disposable = _eventManager as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
            _eventManager = null;

            disposable = IdGenerator as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
            IdGenerator = null;

            disposable = _modelElementFactory as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
            _modelElementFactory = null;

            Services.Dispose();
            _disposed = true;
        }
Пример #12
0
        ///-------------------------------------------------------------------------------------------------
        /// <summary>
        ///  Gets an element.
        /// </summary>
        /// <param name="id">
        ///  The identifier.
        /// </param>
        /// <param name="schemaElement">
        ///  (Optional) the schema element.
        /// </param>
        /// <returns>
        ///  The element.
        /// </returns>
        ///-------------------------------------------------------------------------------------------------
        public virtual IModelElement GetElement(Identity id, ISchemaElement schemaElement = null)
        {
            CheckInitialized();

            if (id == null)
            {
                return(null);
            }

            IModelElement elem = L1Cache.GetElement(id, schemaElement);

            return(elem);
        }
Пример #13
0
        /// <inheritdoc />
        /// <summary>
        /// Retrieves an item from the Cache
        /// </summary>
        /// <typeparam name="T">The type of item</typeparam>
        /// <param name="key">Name of the item in cache</param>
        /// <param name="item">If the object is not found in the Cache, this will be populated</param>
        /// <returns>True if the object was found, False if not found</returns>
        public virtual bool Get <T>(string key, out T item)
        {
            // If in L1 cache, just return it
            if (Options.UseLocalCache && L1Cache.TryGetValue(key, out item))
            {
                return(true);
            }

            // Check L2 cache
            if (Options.UseDistributedCache)
            {
                byte[] bytes = null;
                try
                {
                    bytes = L2Cache.Get(key);
                }
                catch { }

                // Was not found
                if (bytes == null)
                {
                    item = default;
                    return(false);
                }

                // Object was found
                var obj = bytes.FromByteArray <L2CacheItem <T> >();
                item = obj.Item;

                // Store the object back into L1 cache
                // ReSharper disable once InvertIf
                if (Options.UseLocalCache)
                {
                    var options = new MemoryCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = obj.RemainingCacheTime(),
                        Priority = obj.Priority
                    };
                    L1Cache.Set(key, item, options);
                }

                // Return it now
                return(true);
            }

            item = default;
            return(false);
        }
Пример #14
0
    /// <summary>
    /// Gets a value with the given key.
    /// </summary>
    /// <param name="key">A string identifying the requested value.</param>
    /// <param name="cancellationToken">Optional. The System.Threading.CancellationToken used to propagate notifications that the operation should be canceled.</param>
    /// <returns>The System.Threading.Tasks.Task that represents the asynchronous operation, containing the located value or null.</returns>
    public async Task <byte[]?> GetAsync(
        string key,
        CancellationToken cancellationToken = default)
    {
        var value = L1Cache.Get(
            $"{L1L2RedisCacheOptions.KeyPrefix}{key}") as byte[];

        if (value == null)
        {
            if (await Database.Value.KeyExistsAsync(
                    $"{L1L2RedisCacheOptions.KeyPrefix}{key}"))
            {
                var semaphore = await GetOrCreateLockAsync(
                    key,
                    null,
                    cancellationToken);

                await semaphore.WaitAsync(cancellationToken);

                try
                {
                    var hashEntries = await GetHashEntriesAsync(key);

                    var distributedCacheEntryOptions = hashEntries
                                                       .GetDistributedCacheEntryOptions();
                    value = hashEntries.GetRedisValue();

                    SetMemoryCache(
                        key,
                        value,
                        distributedCacheEntryOptions);
                    SetLock(
                        key,
                        semaphore,
                        distributedCacheEntryOptions);
                }
                finally
                {
                    semaphore.Release();
                }
            }
        }

        return(value);
    }
Пример #15
0
        ///-------------------------------------------------------------------------------------------------
        /// <summary>
        ///  Creates entity core.
        /// </summary>
        /// <param name="id">
        ///  The identifier.
        /// </param>
        /// <param name="metaClass">
        ///  the meta class.
        /// </param>
        /// <param name="instance">
        ///  The instance.
        /// </param>
        /// <returns>
        ///  The new entity core.
        /// </returns>
        ///-------------------------------------------------------------------------------------------------
        protected virtual IModelElement CreateEntityCore(Identity id, ISchemaEntity metaClass, IModelEntity instance)
        {
            Contract.Requires(id, "id");
            Contract.Requires(metaClass, "metaClass");
            IModelElement result = instance;

            CheckInitialized();

            using (var session = EnsuresRunInSession())
            {
                result = L1Cache.CreateEntity(id, metaClass, instance);
                if (session != null)
                {
                    session.AcceptChanges();
                }
                return(result);
            }
        }
Пример #16
0
    /// <summary>
    /// Removes the value with the given key.
    /// </summary>
    /// <param name="key">A string identifying the requested value.</param>
    public void Remove(string key)
    {
        var semaphore = GetOrCreateLock(key, null);

        semaphore.Wait();
        try
        {
            L2Cache.Remove(key);
            L1Cache.Remove(
                $"{L1L2RedisCacheOptions.KeyPrefix}{key}");
            MessagePublisher.Publish(key);
            L1Cache.Remove(
                $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}");
        }
        finally
        {
            semaphore.Release();
        }
    }
Пример #17
0
        ///-------------------------------------------------------------------------------------------------
        /// <summary>
        ///  Creates relationship core.
        /// </summary>
        /// <param name="id">
        ///  The identifier.
        /// </param>
        /// <param name="relationshipSchema">
        ///  The relationship schema.
        /// </param>
        /// <param name="start">
        ///  the start.
        /// </param>
        /// <param name="endId">
        ///  The end identifier.
        /// </param>
        /// <param name="relationship">
        ///  The relationship.
        /// </param>
        /// <returns>
        ///  The new relationship core.
        /// </returns>
        ///-------------------------------------------------------------------------------------------------
        protected virtual IModelRelationship CreateRelationshipCore(Identity id, ISchemaRelationship relationshipSchema, IModelElement start, Identity endId, IModelRelationship relationship)
        {
            Contract.Requires(id, "id");
            Contract.Requires(relationshipSchema, "relationshipSchema");
            Contract.Requires(start, "start");
            Contract.Requires(endId, "endId");

            CheckInitialized();
            using (var session = EnsuresRunInSession())
            {
                relationship = L1Cache.CreateRelationship(id, relationshipSchema, start, endId, relationship);

                if (session != null)
                {
                    session.AcceptChanges();
                }
                return(relationship);
            }
        }
Пример #18
0
 public void Subscribe()
 {
     Subscriber.Value.Subscribe(
         L1L2RedisCacheOptions.Channel,
         (channel, message) =>
     {
         var cacheMessage = JsonSerializer
                            .Deserialize <CacheMessage>(
             message.ToString(),
             JsonSerializerOptions);
         if (cacheMessage?.PublisherId !=
             L1L2RedisCacheOptions.Id)
         {
             L1Cache.Remove(
                 $"{L1L2RedisCacheOptions.KeyPrefix}{cacheMessage?.Key}");
             L1Cache.Remove(
                 $"{L1L2RedisCacheOptions.LockKeyPrefix}{cacheMessage?.Key}");
         }
     });
 }
Пример #19
0
    private SemaphoreSlim SetLock(
        string key,
        SemaphoreSlim semaphore,
        DistributedCacheEntryOptions distributedCacheEntryOptions)
    {
        var memoryCacheEntryOptions = new MemoryCacheEntryOptions
        {
            AbsoluteExpiration =
                distributedCacheEntryOptions?.AbsoluteExpiration,
            AbsoluteExpirationRelativeToNow =
                distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow,
            SlidingExpiration =
                distributedCacheEntryOptions?.SlidingExpiration,
        };

        return(L1Cache.Set(
                   $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}",
                   semaphore,
                   memoryCacheEntryOptions));
    }
Пример #20
0
    /// <summary>
    /// Gets a value with the given key.
    /// </summary>
    /// <param name="key">A string identifying the requested value.</param>
    /// <returns>The located value or null.</returns>
    public byte[]? Get(string key)
    {
        var value = L1Cache.Get(
            $"{L1L2RedisCacheOptions.KeyPrefix}{key}") as byte[];

        if (value == null)
        {
            if (Database.Value.KeyExists(
                    $"{L1L2RedisCacheOptions.KeyPrefix}{key}"))
            {
                var semaphore = GetOrCreateLock(
                    key,
                    null);
                semaphore.Wait();
                try
                {
                    var hashEntries = GetHashEntries(key);
                    var distributedCacheEntryOptions = hashEntries
                                                       .GetDistributedCacheEntryOptions();
                    value = hashEntries.GetRedisValue();

                    SetMemoryCache(
                        key,
                        value,
                        distributedCacheEntryOptions);
                    SetLock(
                        key,
                        semaphore,
                        distributedCacheEntryOptions);
                }
                finally
                {
                    semaphore.Release();
                }
            }
        }

        return(value);
    }
Пример #21
0
    /// <summary>
    /// Removes the value with the given key.
    /// </summary>
    /// <param name="key">A string identifying the requested value.</param>
    /// <param name="cancellationToken">Optional. The System.Threading.CancellationToken used to propagate notifications that the operation should be canceled.</param>
    /// <returns>The System.Threading.Tasks.Task that represents the asynchronous operation.</returns>
    public async Task RemoveAsync(
        string key,
        CancellationToken cancellationToken = default)
    {
        var semaphore = await GetOrCreateLockAsync(
            key, null, cancellationToken);

        await semaphore.WaitAsync(cancellationToken);

        try
        {
            L2Cache.Remove(key);
            L1Cache.Remove(
                $"{L1L2RedisCacheOptions.KeyPrefix}{key}");
            MessagePublisher.Publish(key);
            L1Cache.Remove(
                $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}");
        }
        finally
        {
            semaphore.Release();
        }
    }
Пример #22
0
    private void SetMemoryCache(
        string key,
        byte[] value,
        DistributedCacheEntryOptions distributedCacheEntryOptions)
    {
        var memoryCacheEntryOptions = new MemoryCacheEntryOptions
        {
            AbsoluteExpiration =
                distributedCacheEntryOptions?.AbsoluteExpiration,
            AbsoluteExpirationRelativeToNow =
                distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow,
            SlidingExpiration =
                distributedCacheEntryOptions?.SlidingExpiration,
        };

        if (!memoryCacheEntryOptions.SlidingExpiration.HasValue)
        {
            L1Cache.Set(
                $"{L1L2RedisCacheOptions.KeyPrefix}{key}",
                value,
                memoryCacheEntryOptions);
        }
    }
Пример #23
0
        public virtual async Task <object> Get(string key)
        {
            var value = await L1Cache.Get(key);

            if (value != null)
            {
                return(value);
            }


            CachePolicyItem cachePolicy;

            value = await L2Cache.Get(key, out cachePolicy);

            if (value == null)
            {
                return(null);
            }


            //后台写入一级缓存
            Background(L1Cache.Set(key, value, cachePolicy));
            return(value);
        }
Пример #24
0
        ///-------------------------------------------------------------------------------------------------
        /// <summary>
        ///  Gets the relationships in this collection.
        /// </summary>
        /// <param name="metadata">
        ///  (Optional) the metadata.
        /// </param>
        /// <param name="start">
        ///  (Optional) the start.
        /// </param>
        /// <param name="end">
        ///  (Optional) the end.
        /// </param>
        /// <param name="skip">
        ///  (Optional) the skip.
        /// </param>
        /// <returns>
        ///  An enumerator that allows foreach to be used to process the relationships in this collection.
        /// </returns>
        ///-------------------------------------------------------------------------------------------------
        public virtual IEnumerable <IModelRelationship> GetRelationships(ISchemaRelationship metadata = null, IModelElement start = null, IModelElement end = null, int skip = 0)
        {
            CheckInitialized();

            return(L1Cache.GetRelationships(metadata, start, end, skip));
        }
Пример #25
0
 public virtual Task Clear()
 {
     return(Task.WhenAll(L1Cache.Clear(), L2Cache.Clear()));
 }
Пример #26
0
 IModelElement ICacheAccessor.TryGetFromCache(Identity id)
 {
     return(L1Cache.TryGetFromCache(id));
 }
Пример #27
0
 ///-------------------------------------------------------------------------------------------------
 /// <summary>
 ///  Gets the entities in this collection.
 /// </summary>
 /// <param name="metaClass">
 ///  (Optional) the meta class.
 /// </param>
 /// <param name="skip">
 ///  (Optional) the skip.
 /// </param>
 /// <returns>
 ///  An enumerator that allows foreach to be used to process the entities in this collection.
 /// </returns>
 ///-------------------------------------------------------------------------------------------------
 public virtual IEnumerable <IModelEntity> GetEntities(ISchemaEntity metaClass = null, int skip = 0)
 {
     CheckInitialized();
     return(L1Cache.GetEntities(metaClass, skip));
 }
Пример #28
0
 public virtual Task Remove(string cacheKey)
 {
     return(Task.WhenAll(L1Cache.Remove(cacheKey), L2Cache.Remove(cacheKey)));
 }