GithubHelp home page GithubHelp logo

nhibernate / nhibernate-caches Goto Github PK

View Code? Open in Web Editor NEW
39.0 39.0 30.0 29.22 MB

NHibernate Cache Providers

Home Page: http://nhibernate.info/

License: GNU Lesser General Public License v2.1

C# 99.47% Batchfile 0.01% Lua 0.52%

nhibernate-caches's People

Contributors

ayende avatar dependabot[bot] avatar fabiomaulo avatar fredericdelaporte avatar hazzik avatar maca88 avatar oskarb avatar renovate[bot] avatar rjperes avatar suryapratap avatar tunatoksoz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nhibernate-caches's Issues

Error when using RedisFactory as second-level cache

We seem to have a compatibility problem in class NHibernate.Cfg.SettingsFactory.cs method CreateCacheProvider(IDictionary<string, string> properties).
In that method, the cache provider is instantiated with

Environment.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(cacheClassName));

Problem: The ICacheProvider implementation for Redis (NHibernate.Caches.CoreDistributedCache.Redis.RedisFactory) does not have a parameterless constructor. That causes an unhandled exception to be thrown.

The NHibernate documentation states:

27.1. How to use a cache?
Here are the steps to follow to enable the second-level cache in NHibernate:

Choose the cache provider you want to use and copy its assembly in your assemblies directory. (For example, NHibernate.Caches.Prevalence.dll or NHibernate.Caches.SysCache.dll.)

To tell NHibernate which cache provider to use, add in your NHibernate configuration file (can be YourAssembly.exe.config or web.config or a .cfg.xml file):

<property name="cache.provider_class">XXX</property>

"XXX" is the assembly-qualified class name of a class implementing ICacheProvider, eg. "NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache".

Also in the documentation:

27.8.2. Redis distributed cache factory
NHibernate.Caches.CoreDistributedCache.Redis provides a Redis distributed cache factory. This factory yields a Microsoft.Extensions.Caching.Redis.RedisCache. For using it, reference the cache factory package and set the factory-class attribute of the coredistributedcache configuration section to NHibernate.Caches.CoreDistributedCache.Redis.RedisFactory, NHibernate.Caches.CoreDistributedCache.Redis.

This might be related to nhibernate/nhibernate-core#774.

How to use NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy

According to the documentation

cache.strategy can take one of many values and one of them is NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy

When I try to configure it in the cache region configuration inside Web.config as following:
<cache region="community" strategy="NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy, NHibernate.Caches.StackExchangeRedis" />

Then I get the following exception:

NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy is not supported by NHibernate.Caches.StackExchangeRedis.DefaultCacheRegionStrategyFactory, register a custom NHibernate.Caches.StackExchangeRedis.ICacheRegionStrategyFactory or use a supported one.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: NHibernate.Cache.CacheException: NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy is not supported by NHibernate.Caches.StackExchangeRedis.DefaultCacheRegionStrategyFactory, register a custom NHibernate.Caches.StackExchangeRedis.ICacheRegionStrategyFactory or use a supported one.

[CacheException: NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy is not supported by NHibernate.Caches.StackExchangeRedis.DefaultCacheRegionStrategyFactory, register a custom NHibernate.Caches.StackExchangeRedis.ICacheRegionStrategyFactory or use a supported one.]
   NHibernate.Caches.StackExchangeRedis.DefaultCacheRegionStrategyFactory.Create(IConnectionMultiplexer connectionMultiplexer, RedisCacheRegionConfiguration configuration, IDictionary`2 properties) +305
   NHibernate.Caches.StackExchangeRedis.RedisCacheProvider.BuildCache(RedisCacheRegionConfiguration regionConfiguration, IDictionary`2 properties) +79
   NHibernate.Caches.StackExchangeRedis.RedisCacheProvider.BuildCache(String regionName, IDictionary`2 properties) +333
   NHibernate.Cache.CacheFactory.BuildCacheBase(String name, Settings settings, IDictionary`2 properties) +44

What am I doing wrong?

Configure programmatically

Hi, is it possible to configure that new
NHibernate.Caches.StackExchangeRedis provider programmatically?

`ConfigurationProvider.Current` shouldn't depend on `IConfigurationSectionHandler` from `System.Configuration.ConfigurationManager`

public static ConfigurationProviderBase<TConfig, TConfigHandler> Current
{
get => _current ?? (_current = new StaticConfigurationManagerProvider());
set => _current = value ?? new NullConfigurationProvider();
}

It's quite strange that user custom implementation not using xml still needs dependency on this xml related class from nuget package:

public class CoreDistributedCacheCustomConfigProvider : ConfigurationProviderBase<CacheConfig,CoreDistributedCacheSectionHandler>

Migrating from NHiberate 5.2.7 to 5.3.5 results in could not load assembly exception

We try to migrate the following dependencies of our project:

  • NHibernate: 5.2.7 --> 5.3.5
  • Nhibernate.Caches.SysCache: 5.6.0 --> 5.7.0

This results in the exception below:

NHibernate.HibernateException : could not instantiate CacheProvider: NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache
  ----> System.IO.FileLoadException : Could not load file or assembly 'NHibernate, Version=5.2.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
TearDown : System.NullReferenceException : Object reference not set to an instance of an object.
   at NHibernate.Cfg.SettingsFactory.CreateCacheProvider(IDictionary`2 properties)
   at NHibernate.Cfg.SettingsFactory.BuildSettings(IDictionary`2 properties)
   at NHibernate.Cfg.Configuration.BuildSettings()
   at NHibernate.Cfg.Configuration.BuildSessionFactory()

We have checked the output directory bin for the dependencies. The corresponding assemblies are included here.
It seems that NHibernate.Caches.SysCache does not recognize NHibernate version 5.3.5 as a version greater than 5.2.0.0.

Additional information:
Inside the hibernate-configuration we have specified the property cache.provider_class with the value NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache.

How can we solve this issue?

Thanks in advance!

Compatibility net core 3.1

Package 'NHibernate.Caches.SysCache2 5.7.0' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework '.NETCoreApp,Version=v3.1'. This package may not be fully compatible with your project.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • Update NUnit.Console to v3.18.1 (NUnit.Console, NUnit.ConsoleRunner)
  • Update dependency NUnit3TestAdapter to v4.6.0
  • Update dotnet monorepo to v8 (major) (Microsoft.Extensions.Caching.Abstractions, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Caching.SqlServer, Microsoft.Extensions.Caching.StackExchangeRedis, System.Runtime.Caching)
  • ๐Ÿ” Create all rate-limited PRs at once ๐Ÿ”

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/GenerateAsyncCode.yml
  • actions/checkout v4
  • actions/setup-dotnet v4
nuget
.config/dotnet-tools.json
  • csharpasyncgenerator.tool 0.22.0
CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.Memcached/NHibernate.Caches.CoreDistributedCache.Memcached.csproj
  • Microsoft.SourceLink.GitHub 1.1.1
  • EnyimMemcachedCore 2.1.0
CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.Memory/NHibernate.Caches.CoreDistributedCache.Memory.csproj
  • Microsoft.SourceLink.GitHub 1.1.1
  • Microsoft.Extensions.Caching.Memory 2.0.0
CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.Redis/NHibernate.Caches.CoreDistributedCache.Redis.csproj
  • Microsoft.SourceLink.GitHub 1.1.1
  • Microsoft.Extensions.Caching.StackExchangeRedis 2.2.0
CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.SqlServer/NHibernate.Caches.CoreDistributedCache.SqlServer.csproj
  • Microsoft.SourceLink.GitHub 1.1.1
  • Microsoft.Extensions.Caching.SqlServer 2.0.0
CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.Tests/NHibernate.Caches.CoreDistributedCache.Tests.csproj
  • NUnitLite 3.14.0
  • NUnit3TestAdapter 4.5.0
  • NSubstitute 5.1.0
  • Microsoft.NET.Test.Sdk 15.9.2
  • log4net 2.0.17
CoreDistributedCache/NHibernate.Caches.CoreDistributedCache/NHibernate.Caches.CoreDistributedCache.csproj
  • NHibernate 5.2.0
  • Microsoft.SourceLink.GitHub 1.1.1
  • Microsoft.Extensions.Caching.Abstractions 2.0.0
CoreMemoryCache/NHibernate.Caches.CoreMemoryCache.Tests/NHibernate.Caches.CoreMemoryCache.Tests.csproj
  • NUnitLite 3.14.0
  • NUnit3TestAdapter 4.5.0
  • Microsoft.NET.Test.Sdk 15.9.2
  • log4net 2.0.17
CoreMemoryCache/NHibernate.Caches.CoreMemoryCache/NHibernate.Caches.CoreMemoryCache.csproj
  • NHibernate 5.2.0
  • Microsoft.SourceLink.GitHub 1.1.1
  • Microsoft.Extensions.Caching.Memory 2.0.0
EnyimMemcached/NHibernate.Caches.EnyimMemcached.Tests/NHibernate.Caches.EnyimMemcached.Tests.csproj
  • log4net 2.0.17
EnyimMemcached/NHibernate.Caches.EnyimMemcached/NHibernate.Caches.EnyimMemcached.csproj
  • NHibernate 5.2.0
  • Microsoft.SourceLink.GitHub 1.1.1
  • EnyimMemcached 2.12.0
NHibernate.Caches.Common.Tests/NHibernate.Caches.Common.Tests.csproj
  • NUnit3TestAdapter 4.5.0
  • Microsoft.NET.Test.Sdk 15.9.2
  • log4net 2.0.17
  • NUnitLite 3.14.0
  • NSubstitute 5.1.0
  • NHibernate 5.2.0
  • NUnit 3.14.0
NHibernate.Caches.Common/NHibernate.Caches.Common.csproj
  • Microsoft.SourceLink.GitHub 1.1.1
  • NHibernate 5.2.0
RtMemoryCache/NHibernate.Caches.RtMemoryCache.Tests/NHibernate.Caches.RtMemoryCache.Tests.csproj
  • NUnitLite 3.14.0
  • NUnit3TestAdapter 4.5.0
  • Microsoft.NET.Test.Sdk 15.9.2
  • log4net 2.0.17
RtMemoryCache/NHibernate.Caches.RtMemoryCache/NHibernate.Caches.RtMemoryCache.csproj
  • System.Runtime.Caching 4.5.0
  • NHibernate 5.2.0
  • Microsoft.SourceLink.GitHub 1.1.1
StackExchangeRedis/NHibernate.Caches.StackExchangeRedis.Tests/NHibernate.Caches.StackExchangeRedis.Tests.csproj
  • System.Runtime.Caching 4.5.0
  • NUnitLite 3.14.0
  • NSubstitute 5.1.0
  • NUnit3TestAdapter 4.5.0
  • Microsoft.NET.Test.Sdk 15.9.2
  • log4net 2.0.17
StackExchangeRedis/NHibernate.Caches.StackExchangeRedis/NHibernate.Caches.StackExchangeRedis.csproj
  • StackExchange.Redis 2.0.495
  • NHibernate 5.2.0
  • Microsoft.SourceLink.GitHub 1.1.1
SysCache/NHibernate.Caches.SysCache.Tests/NHibernate.Caches.SysCache.Tests.csproj
  • log4net 2.0.17
SysCache/NHibernate.Caches.SysCache/NHibernate.Caches.SysCache.csproj
  • NHibernate 5.2.0
  • Microsoft.SourceLink.GitHub 1.1.1
SysCache2/NHibernate.Caches.SysCache2.Tests/NHibernate.Caches.SysCache2.Tests.csproj
  • log4net 2.0.17
SysCache2/NHibernate.Caches.SysCache2/NHibernate.Caches.SysCache2.csproj
  • NHibernate 5.2.0
  • Microsoft.SourceLink.GitHub 1.1.1
Tools/packages.csproj
  • NUnit.ConsoleRunner 3.17.0
  • NUnit.Console 3.17.0
Util/NHibernate.Caches.Util.JsonSerializer.Tests/NHibernate.Caches.Util.JsonSerializer.Tests.csproj
  • NUnitLite 3.14.0
  • NUnit3TestAdapter 4.5.0
  • log4net 2.0.17
Util/NHibernate.Caches.Util.JsonSerializer/NHibernate.Caches.Util.JsonSerializer.csproj
  • Newtonsoft.Json 13.0.1
  • Microsoft.SourceLink.GitHub 1.1.1
global.json
  • dotnet-sdk 8.0.100

  • Check this box to trigger a request for Renovate to run again on this repository

NHibernate Redis Caches goes into closed loop with multiple threads

I have multiple applications sharing the same backend code and after enabling SLC with Redis provider then application hangs in startup.
In the startup of each application it goes load thousands of data and tries to load/get from/into Redis. When I start 2 applications at the same moment then one manages to start while the second hangs and when I montiored Redis, I found that it keeps looping in getting a lot of keys over and over again.

This happens when Redis is empty and two applications would try to write the data into Redis. I have set cache.region_strategy.default.retry_times to 5 but no difference

Debug.log

Attached log file.

Unable to use DistributedCache with JsonCacheSerializer

Hi,
following up on #91:
I'm trying to use JsonCacheSerializer and the DistributedCache options (currently MemoryDistributedCache).

Looking at the code of CoreDistributedCache.Put I see, that it tries to cache a Tuple<object, object> of the key and the value. The key is a CacheKey.
The JsonCacheSerializer fails, because it does not know tuples nor CacheKeys (nor QueryKeys).

I wonder how this is supposed to work - am I missing something?

Here is an exception + stacktrace after I ran RegisterType(typeof(Tuple<object, object>), "tuoo") to register the tuple. I can also register the CacheKey, but it will fail when deserializing, obviously needing more work than just registering the type.

InvalidOperationException: Unknown type 'NHibernate.Cache.CacheKey, NHibernate, Version=5.2.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4', use JsonCacheSerializer.RegisterType method to register it.
NHibernate.Caches.Util.JsonSerializer.JsonCacheSerializer+ExplicitSerializationBinder.BindToName(Type serializedType, out string assemblyName, out string typeName)
Newtonsoft.Json.Utilities.ReflectionUtils.GetFullyQualifiedTypeName(Type t, ISerializationBinder binder)
Newtonsoft.Json.Utilities.ReflectionUtils.GetTypeName(Type t, TypeNameAssemblyFormatHandling assemblyFormat, ISerializationBinder binder)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.WriteTypeProperty(JsonWriter writer, Type type)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, object value, Type objectType)
Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, object value, Type objectType)
Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, object value, Type objectType)
NHibernate.Caches.Util.JsonSerializer.JsonCacheSerializer.Serialize(object value)
NHibernate.Caches.CoreDistributedCache.CoreDistributedCacheBase.Put(object key, object value)
NHibernate.Caches.CoreDistributedCache.CoreDistributedCache.Put(object key, object value)
NHibernate.Cache.ReadWriteCache.Put(CacheKey key, object value, long txTimestamp, object version, IComparer versionComparator, bool minimalPut)
NHibernate.Engine.TwoPhaseLoad.InitializeEntity(object entity, bool readOnly, ISessionImplementor session, PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent, Action<IEntityPersister, CachePutData> cacheBatchingHandler)
NHibernate.Loader.Loader.InitializeEntitiesAndCollections(IList hydratedObjects, DbDataReader reader, ISessionImplementor session, bool readOnly, CacheBatcher cacheBatcher)
NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies, IResultTransformer forcedResultTransformer)
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies, IResultTransformer forcedResultTransformer)
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies)
NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, object id, IType identifierType, object optionalObject, string optionalEntityName, object optionalIdentifier, IEntityPersister persister)

NHibernate.Caches.StackExchangeRedis.DistributedLocalCacheRegionStrategy UpdateTimestampsCache concurrency issue

Hi,
When we use NHibernate.Caches.StackExchangeRedis NH Second Level Cache "DistributedLocalCacheRegionStrategy" with one entity, performance is great.
In our scenario: 300 tables are mostly readonly, using Cache .NonStrictReadWriteCache(). System has also 100 more online tables that perform insert/update/delete every 1-2ms. So system always takes insert/update/delete operation in every 3-4 ms.

Here lies a bottleneck with UpdateTimestampsCache: when second level cache is enabled read operations is great only if there is no write operation at the same time. This happens even for entities/spaces which have no need to interact with the "UpdateTimestampsCache".

Am I missing something? This issue is also raised here: nhibernate/nhibernate-core#2735.

Third Level Cache Performance Notes by @maca88 also shows the idea of sync time increases on concurrent requests(our case 300-400 tps), so other clients waits to read/write while executing operation completes. Any cached query read with StandardQueryCache waits because only one writer can access AsyncReaderWriterLock -> UpdateTimeStampsCache at the same time. Any other dml operation waits because there is only one UpdateTimestampsCache.

Java Implementation have no lock.

Simple possible solution: do not interact with UpdateTimestampsCache if it is a non cached entity?

NHibernate:5.3.8
NHibernate.Caches.StackExchangeRedis 5.7.0

NH-2574 - Dialect and Driver for Intersystems Cachรฉ

Werner Kolov created an issue โ€” 14th March 2011, 4:55:28:

In the attachment you can find all necessary classes to add support for Intersystems Cachรฉ to NHibernate 3.0. Classes were ported from Hibernate 3.6.1 for Java.
NHibernate can be configured either to use ODBC or the client driver from InterSystems.Data.CacheClient.dll. The driver can be downloaded from www.intersystems.com


Zeeshan Waheed added a comment โ€” 7th January 2013, 21:37:27:

have anyone updated the CacheDialect for Nhibernate 3.2?

Copied from original issue: nhibernate/nhibernate-core#936

StackExchangeRedis fails with "too many results to unpack" with 8000 items

StackExchangeRedis fails with "too many results to unpack" when querying with SetCacheable() under certain circumstances.

This happens (only) when the following occur at same time:

  • using FastRegionStrategy
  • with Sliding expiration
  • the collection is big >8000 items I assume.

The call we make is something like:

session.Query<MyClass>().
  WithOptions(o => o.SetCacheable(true)).
  Where(x => x.Zz.Id == theId).ToListAsync();

Exception looks like:

DefaultSocketManager:Completion:2|NHibernate.Util.ADOExceptionReporter|ERR Error running script (call to f_f9ee676fc28fa27545ce0818084....):
 @user_script:2: user_script:2: too many results to unpack 

Using NHibernate.Caches.StackExchangeRedis v 5.5.1. Pinpointed the issue to

Quoting from random web resource, many referring to the same 8000 default limit for unpack: "That said, unpack() actually has a limit on the size of the table which is defined by LUAI_MAXCSTACK in luaconf.h forcing a maximum number of Lua stack slots that a C function can use. This limit is set to 8000 by default"

The question is:

  1. how it could batch it so that the unpack() wouldn't fail to hitting >8000 items
  2. could it be easily worked around somehow else with the current issue existing

NullReferenceException in SysCache2's SysCacheProvider

In commit d7e1dc9#diff-fdf851d99f0719e7ffb772921c9f01ef, a line was removed (CacheRegions = new Dictionary<string, SysCacheRegion>(0);) which now causes a NullReferenceException with our configuration.

We mark each entity as cacheable, in our mappings, but we do not define any region manually in our web.config file.

As such, because our configSection.CacheRegions.Count is always 0, CacheRegionSettings ends up being never initialized, and we get a NullReferenceException.

You should not attempt to reference an uninitialized property, to avoid such exceptions being thrown at runtime.

If it is intended for this use case not to work, you should manually throw an exception describing the problem, instead of relying on a nondescriptive NullReferenceException.

I will provide a pull request to avoid the exception soon.

Issues with custom Regions with RedisCacheProvider

Hi @maca88 ,
Because of "RedisCacheProvider.ConfiguredCacheRegions" is private readonly I cannot specify region based expiration with hibernate config file, give us a way to implement custom configuration.
If we want to write our RedisCacheProvider we are nearly copying this project.

Below config option is not enough with .net core add support for region configuration like "ConfigureRegions(RegionConfig[] regions)"

NHibernate.Caches.StackExchangeRedis

        static RedisCacheProvider()
        {
            Log = NHibernateLogger.For(typeof(RedisCacheProvider));
            ConfiguredCacheRegions = new Dictionary<string, RegionConfig>();

            if (!(ConfigurationManager.GetSection("redis") is CacheConfig config))
                return;

            ConfiguredCache = config;
	    foreach (var cache in config.Regions)
	    {
			ConfiguredCacheRegions.Add(cache.Region, cache);
	    }
        }

Also if we specify "cache.region_prefix" in hibernate configuration file it is added twice to key.
One is added in Nhibernate code the other one is NHibernate.Caches.StackExchangeRedis;

NHibernate

                internal string GetFullCacheRegionName(string name)
		{
			var prefix = CacheRegionPrefix;
			if (!string.IsNullOrEmpty(prefix))
				return prefix + '.' + name;
			return name;
		}

NHibernate.Caches.StackExchangeRedis

        private void BuildDefaultConfiguration(IDictionary<string, string> properties)
        {
            var config = CacheConfiguration;

            config.CacheKeyPrefix = GetString(RedisEnvironment.KeyPrefix, properties, config.CacheKeyPrefix);
            Log.Debug("Cache key prefix: {0}", config.CacheKeyPrefix);

            config.EnvironmentName = GetString(RedisEnvironment.EnvironmentName, properties, config.EnvironmentName);
            Log.Debug("Cache environment name: {0}", config.EnvironmentName);

            config.RegionPrefix = GetString(Cfg.Environment.CacheRegionPrefix, properties, config.RegionPrefix);
            // if region name contains region prefix so do not add to RegionPrefix, because it's triggered from Nhibernate code base?
        .
        .
        .
        }

CoreDistributedCache: BinaryFormatter key Value cannot be null

The Put method is serializing the key object. When this is a QueryCacheKey object it cannot be deserialized when starting a new instance (ie different session factory) and fails in the Get method.

This can be fixed by serializing the cacheKey instead.

byte[] cachedData;
var serializer = new BinaryFormatter();
var cacheKey = GetCacheKey(key);

using (var stream = new MemoryStream())
{
	var entry = new Tuple<object, object>(cacheKey, value); // use cacheKey instead
	serializer.Serialize(stream, entry);
	cachedData = stream.ToArray();
}

Partially configured regions do not fallback on defaults

When a region is defined in configuration, it does not take into account configured global defaults such as timeout. It only considers its own settings in configuration, fallback-ing to their hard-coded default value if they are not set.

This affects RtMemoryCache & SysCache.

StackExchangeRedis: Connection resilience

When using cloud managed Redis like Azure Cache, you can get network blips when, for example, they patch servers or the like. This can cause connection failures, as described in: https://gist.github.com/JonCole/925630df72be1351b21440625ff2671f#file-redis-bestpractices-stackexchange-redis-md (see 'Reconnecting with Lazy pattern').

With NHibernate.Caches.StackExchangeRedis, the only way to recover from this situation seems to be to restart the servers but as per the example code in the above link, it is possible to recreate the connection multiplexer in these situations to force a re-connection.

It would be great to add this connection resilience to NHibernate.Caches.StackExchangeRedis. I was thinking perhaps adding additional functionality (e.g. a reconnect method) to the IConnectionMultiplexerProvider and passing this down into AbstractRegionStrategy instead of the IConnectionMultiplexer itself. We could then add retries in the various methods (get, put etc) if the connection exceptions occur and recreate the IConnectionMultiplexer and associated properties when the issue occurs.

Is there any way to set and use custom regions for StackExchangeRedis?

I have been unable to figure out how to set up and use custom regions with NHibernate.Caches.StackExchangeRedis. Looking through the code, it's unclear to me how to do it through Fluent NHibernate, or just using a config file.

Is this a supported feature? If so, what's the best way to employ it?

Also, with this configuration here, I never get cache hits. I can see the entries getting written to Redis, but every single read results in the TTL on the cache entry getting reset to the default value.

Any suggestions as to what I'm doing wrong would be appreciated.

Here's my code that sets up NHibernate; this obviously doesn't work, since when RedisCacheProvider is constructed, it builds a new array of regions . . . but how to pass my own array of regions in?


            SetUpCacheRegion("foo", 600, true);

            /*
			const string xmlSimple =
				"<redis configuration=\"127.0.0.1\"><cache region=\"foo\" expiration=\"500\" sliding=\"true\" /></redis>";

			var handler = new RedisSectionHandler();
			var section = GetConfigurationSection(xmlSimple);
			var result = (CacheConfig)handler.Create(null, null, section);
            */

            var redisConnectionString = AppConfig.GetRedisConnectionString(appConfig, redisConfigOverrides);
            var commandTimeout = "100";

            var config = new NHibernate.Cfg.Configuration().Configure();
            var configuration = Fluently.Configure(config)
                .Database(
                    MsSqlConfiguration.MsSql2012
                        .ConnectionString(connectionString)
                        .DefaultSchema("ms")
                        .FormatSql()
                        .Dialect<NHibernate.Dialect.MsSql2012Dialect>()
                        .AdoNetBatchSize(100)
                        .IsolationLevel(IsolationLevel.ReadCommitted)
                )
                .Mappings((m =>
                {
                    m.FluentMappings
                        .AddFromAssembly(mapAssembly)
                        .Conventions.Add(Table.Is(x => x.EntityType.Name.Replace("ModelSource", "") + "s"))
                    ;
                }))
                .Cache(c => c
                    .UseQueryCache()
                    .UseSecondLevelCache()
                    .ProviderClass(typeof(RedisCacheProvider).AssemblyQualifiedName)
                    .RegionPrefix("region")
                )
                .ExposeConfiguration(c =>
                {
                    // Use this to build tables and DB objects
                    // new SchemaExport(c).Execute(true, true, false);

                    // Cache
                    c.SessionFactory().Caching.WithDefaultExpiration(90);
                    c.SetProperty("cache.configuration", redisConnectionString);
                    c.SetProperty("cache.environment_name", GetEnvironmentName(environment));
                    c.SetProperty("cache.key_prefix", $"microMedStudy-{apiName}-");


                    // Try to set command timeout for this connection
                    c.SetProperty("command_timeout", commandTimeout);

                    // This will set the command_timeout property on factory-level
                    c.SetProperty(NHibernate.Cfg.Environment.CommandTimeout, commandTimeout);

                    // This will set the command_timeout property on system-level
                    NHibernate.Cfg.Environment.Properties.Add(NHibernate.Cfg.Environment.CommandTimeout, commandTimeout);
                })
                .CurrentSessionContext("thread_static")
                .BuildConfiguration()
            ;

            if (environment != "Production" && environment != "Offline")
                configuration.SetInterceptor(new SQLInterceptor());

            return configuration;
        }

        private static void SetUpCacheRegion(string cacheRegion, int expireSeconds, bool slidingExpiration)
        {
            RedisCacheProvider.SetRegionConfiguration(
                cacheRegion.ToString(),
                new RegionConfig(
                    cacheRegion.ToString()
                    , TimeSpan.FromSeconds(expireSeconds)
                    , slidingExpiration
                    , 1
                    , typeof(RedisCacheRegionConfiguration)
                    , false
                )
            );
        }

And here's my hibernate.cfg.xml:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
      <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
      <section name="redis" type="NHibernate.Caches.StackExchangeRedis.RedisSectionHandler, NHibernate.Caches.StackExchangeRedis"/>
    </configSections>
    <redis>
      <cache region="foo" expiration="500" sliding="true" />
      <cache region="noExplicitExpiration" sliding="true" />
    </redis>
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
            <property name="show_sql">true</property>
        </session-factory>
    </hibernate-configuration>
</configuration>

And here's a sample mapping:

public class ProductMap : ClassMap<Product>
    {
        public ProductMap()
        {
            Id(x => x.Id);  // Read-only

            Cache
                .NonStrictReadWrite()
                .Region("foo")
                ;

Key computing for Memcached leaks hashers

Both NHibernate-Caches MemCache and EnyimMemcached use a hash algorithm for computing keys when they exceed the maximal length supported by Memcached, 250.

They use a thread-static instance of HashAlgorithm, which is disposable. There is no way to properly dispose of them. They should be local variables instead.

Initially reported as:

Both NHibernate-Caches MemCache and EnyimMemcached use a non-thread safe algorithm for computing keys when they exceed the maximal length supported by Memcached, 250.

They use a static instance of HashAlgorithm, which is not thread safe. This may cause caching or retrieving values with unexpected keys. The HashAlgorithm instance must be a local variable of the function computing the key. (It cannot either be a non static field, since caches need to be thread safe.) No thread safety issue, they are stored as ThreadStatic variables.

Cache expiration tests are flacky

I suspect that one second gap might be not enough.

So far these are the tests that often fail:

  • NHibernate.Caches.Common.Tests.CacheFixture.TestDistributedClear
  • NHibernate.Caches.Common.Tests.CacheFixture.TestObjectExpirationAfterUpdate
  • NHibernate.Caches.Common.Tests.CacheFixture.TestSlidingExpiration
  • NHibernate.Caches.StackExchangeRedis.Tests.DistributedLocalCacheStrategyFixture.TestLockUnlockManyAsync
  • NHibernate.Caches.StackExchangeRedis.Tests.DistributedLocalCacheStrategyFixture.TestObjectExpiration("cache.default_expiration")
  • NHibernate.Caches.StackExchangeRedis.Tests.DistributedLocalCacheStrategyFixture.TestDistributedClear
  • NHibernate.Caches.StackExchangeRedis.Tests.DistributedLocalCacheStrategyFixture.TestObjectExpiration("expiration")

NHCH-31 - NHibernate.Caches.Velocity - update to AppFabric Caching Services 1.0

Migrated from Jira.
Paul Duran created an issue โ€” 26th November 2010, 19:14:00:

Velocity has been renamed to AppFabric Caching Services. I've taken the suggested updates from this stackoverflow article: http://stackoverflow.com/questions/3233792/appfabric-could-not-contact-the-cache-service and improved them.

Namely:

Known limitation:

  • if cache cluster is restarted, we will receive an error "ErrorCode:SubStatus:Region referred to does not exist. Use CreateRegion API to fix the error". Open to options on how to resolve that.

Please note: as part of applying this patch, the following files may be removed from lib\net\3.5:

  • CacheBaseLibrary.dll
  • CacheBaseLibrary.XML
  • CASBase.dll
  • CASClient.dll
  • ClientLibrary.dll
  • ClientLibrary.XML
  • FabricCommon.dll

Paul Duran added a comment - 28/Nov/10 6:46 PM

Attaching new version of patch. This version wraps the DataCache operations so that if the cache cluster is restarted, it will trap the RegionDoesNotExist error and recreate the region.

Frantisek Jandos added a comment - 08/Jun/11 4:20 AM

I appreciate there is cache provider for AppFavric Cache, but I think that the usage of locks dictionary in VelocityClient is problematic due to following reasons:

  • The client class is not thread safe (according to ICache comments should be) as distinct Add, Remove, Count may be performed concurrenctly. This could lead to race condions and unexpected dictionary exceptions.
  • If we are in cluster, each node would have its own locks dictionary, which could again lead to potential unlock by put.

Frรฉdรฉric Delaporte added a comment - 22/Oct/17 3:52 PM

If someone is interested by this, please issue a PR.

Obsolete some cache providers?

Some of the cache providers are long dead:

  • SharedCache - Last release was in March 2009 (15 years ago as for now). The website stopped functioning in 2015/2016. CodePlex was shut down in July 2021. Luckily Internet Archive has the archive of the codeplex site and source code. Here suppose to be a copy of the source code, but the repo is empty.
  • Prevalence - even older. Last release in March 2005 (19 years ago). Copy of the source code is here.
  • Velocity - seems like research project by Microsoft that never made it to a release. It was later merged into AppFabric (using different assemblies/namespaces). Support for AppFabric has ended in Apr 12, 2022.

NHibernate.Caches.StackExchangeRedis can not deserialize data from cache

I faced following exception today when i tried to use NHibernate.Caches.StackExchangeRedis

Application startup exception: NHibernate.Exceptions.GenericADOException: Unable to perform find[SQL: SQL not available] ---> System.ArgumentException: The value "NHibernate.Util.DynamicComponent" is not of type "System.Collections.Hashtable" and cannot be used in this generic collection.

I found that data was serialize and save to redis like this

"\x00\x01\x00\x00\x00\xff\xff\xff\xff\x01\x00\x00\x00\x00\x00\x00\x00\x0c\x02\x00\x00\x00MNHibernate, Version=5.2.0.0, Culture=neutral, 
PublicKeyToken=aa95f207798dfdb4\x05\x01\x00\x00\x00\x1bNHibernate.Cache.CachedItem\x03\x00\x00\x00\x0efreshTimestamp\x05value\aversion\x00\x02\x02\t\x02\x00\x00\x00\x00 
$\xc1*\x97\x16\x00\t\x03\x00\x00\x00\n\x05\x03\x00\x00\x00!NHibernate.Cache.Entry.CacheEntry\x04\x00\x00\x00\x11disassembledState\bsubclass\x1alazyPropertiesAreUnfetched\aversion\x05\x01\x00\x02\
x01\x02\x00\x00\x00\t\x04\x00\x00\x00\x06\x05\x00\x00\x00\x02SR\x01\n\x10\x04\x00\x00\x00\x01\x0
0\x00\x00\x06\x06\x00\x00\x00\x85\x04PROJCS[\"NAD_1983_StatePlane_Arizona_West_FIPS_0203_Feet\,
GEOGCS[\"GCS_North_American_1983\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS_1980\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],
PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",699998.5999999999],PARAMETER[\"
False_Northing\",0],PARAMETER[\"Central_Meridian\",-113.75],PARAMETER[\"Scale_Factor\",0.9999333333333333],PARAMETER[\"Latitude_Of_Origin\",31],UNIT[\"Foot_US\",0.30480060960121924],AUTHORITY[\"EPSG\",\"102650\"]]\x0b"

So that they could not be deserialized to Hashtable.
Why i am going to this exception? Please give me a solution!
Regards,

Cache issue-.net core 3.0-Could not load type 'System.Web.Caching.CacheItemPriority'

I was using nhibernate for Cache in old .net framework.

Now we are rewriting to .net core 3.0.

We are having runtime issue for nhibernate cache.

Inner Exception
Could not load type 'System.Web.Caching.CacheItemPriority' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.":"System.Web.Caching.CacheItemPriority

Exception:
{"An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.\r\n\r\n
nhibernate cache issue

Add a Core RtMemoryCache

System.Runtime.Caching is ported to .Net Core 2.1, to be released in Q2 of 2008. dotnet/corefx#14529.

So once released, RtMemoryCache could gain an netcoreapp2.1 target. (Unfortunately not a netstandard2.1, no plan for inclusion seems scheduled, dotnet/standard#682.)

Redis Cache Max Connection is limited to 5

Hi,
I am using CoreDistributedCache Redis, with below configuration, I manually implement Redis Cache Factory because I don't want to use app.config nor web.config.

I am trying load test .net core web api with soap ui, When I did with thread strategy simultaneously more than 5 thread it goes slow and slow till timeout. At tcp view I just 5 connection opened to Redis why?
When I looked at below Redis config I see maxclient 10K.

I try 50 thread, 100thread but tcp view shows just 5 connection established to Redis Server.

redis-cli -benchmark command line shows good results but with library best is around 16ms mostly timeout, just 1 row record with 2 columns in it with Linq2Sql query cache for the same query.

NHibernate-Cache:NHibernate.Cache.StandardQueryCache:sql: select distinct apidef1_.API_ROUTE as col_0_0_, userrol0_.AUTH_LEVEL as col_1_0_ from ABC.USER_ROLE userrol0_ left outer join ABC.API_DEF apidef1_ on userrol0_.API_GUID=apidef1_.GUID where (userrol0_.ROLE_GUID in (? , ?)) and (? like (lower(apidef1_.API_ROUTE)||'%')); parameters: []; named parameters: {'p2'='/api/customer/cstcustomergroupdef', 'p1_0_'='2', 'p1_1_'='1'}

Return result is not an entity identifier its just a result and string[1][2] array, so I assume it will not refreshed when the entity changed?

Redis is running on local machine as windows service.

appsettings.cs

"CoreDistributedCache": {
    "FactoryClass": "NHibernate.Caches.CoreDistributedCache.Redis.RedisFactory,NHibernate.Caches.CoreDistributedCache.Redis",
    "Properties": {
      "regionPrefix": "",
      "configuration": "localhost,syncTimeout=1000,connectTimeout=5000,connectRetry=3",
      "instance-name": null,
      "cache.default_expiration": "300",
      "cache.use_sliding_expiration": "false",
      "append-hashcode": "false"
    }

Redis Cache config before SessionFactory Build

        static CoreDistributedCacheCastleWindsorExtensions()
        {
            var config = IocFacility.Container.AppSettings.GetSection("CoreDistributedCache").Get<CoreDistributedCacheConfig>();

            var factoryClass = ReflectHelper.ClassForName(config.FactoryClass);
            var ctorWithProperties = factoryClass.GetConstructor(CacheFactoryCtorWithPropertiesSignature);

            CoreDistributedCacheProvider.CacheFactory = (IDistributedCacheFactory)(ctorWithProperties != null ?
                ctorWithProperties.Invoke(new object[] { config.Properties }) :
                NHibernate.Cfg.Environment.BytecodeProvider.ObjectsFactory.CreateInstance(factoryClass));
        }

Redis Server config files
redis.windows.txt
redis.windows-service.txt

StackTrace:

2018-11-01 16:01:50,858 [28  ] WARN  [653600911462458f850951adc795858c] ADOExceptionReporter - Timeout performing EVAL, inst: 5, queue: 5, qu: 0, qs: 5, qc: 0, wr: 0, wq: 0, in: 8192, ar: 0, clientName: CARDTEK0044, serverEndpoint: Unspecified/localhost:6379, keyHashSlot: 10634 (Please take a look at this article for some common client-side issues that can cause timeouts: http://stackexchange.github.io/StackExchange.Redis/Timeouts)
StackExchange.Redis.RedisTimeoutException: Timeout performing EVAL, inst: 5, queue: 5, qu: 0, qs: 5, qc: 0, wr: 0, wq: 0, in: 8192, ar: 0, clientName: CARDTEK0044, serverEndpoint: Unspecified/localhost:6379, keyHashSlot: 10634 (Please take a look at this article for some common client-side issues that can cause timeouts: http://stackexchange.github.io/StackExchange.Redis/Timeouts)
   at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor`1 processor, ServerEndPoint server) in c:\code\StackExchange.Redis\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs:line 2120
   at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor`1 processor, ServerEndPoint server) in c:\code\StackExchange.Redis\StackExchange.Redis\StackExchange\Redis\RedisBase.cs:line 81
   at StackExchange.Redis.RedisDatabase.ScriptEvaluate(String script, RedisKey[] keys, RedisValue[] values, CommandFlags flags) in c:\code\StackExchange.Redis\StackExchange.Redis\StackExchange\Redis\RedisDatabase.cs:line 1052
   at Microsoft.Extensions.Caching.Redis.RedisExtensions.HashMemberGet(IDatabase cache, String key, String[] members)
   at Microsoft.Extensions.Caching.Redis.RedisCache.GetAndRefresh(String key, Boolean getData)
   at NHibernate.Caches.CoreDistributedCache.CoreDistributedCache.Get(Object key)
   at NHibernate.Cache.StandardQueryCache.Get(QueryKey key, ICacheAssembler[] returnTypes, Boolean isNaturalKeyLookup, ISet`1 spaces, ISessionImplementor session) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Cache\StandardQueryCache.cs:line 128
   at NHibernate.Cache.StandardQueryCache.Get(QueryKey key, QueryParameters queryParameters, ICacheAssembler[] returnTypes, ISet`1 spaces, ISessionImplementor session) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Cache\StandardQueryCache.cs:line 112
   at NHibernate.Cache.QueryCacheExtensions.Get(IQueryCache queryCache, QueryKey key, QueryParameters queryParameters, ICacheAssembler[] returnTypes, ISet`1 spaces, ISessionImplementor session) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Cache\IQueryCache.cs:line 141
   at NHibernate.Loader.Loader.GetResultFromQueryCache(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IQueryCache queryCache, QueryKey key) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Loader\Loader.cs:line 1733
   at NHibernate.Loader.Loader.ListUsingQueryCache(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Loader\Loader.cs:line 1683
   at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Loader\Loader.cs:line 1662
   at NHibernate.Loader.Hql.QueryLoader.List(ISessionImplementor session, QueryParameters queryParameters) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Loader\Hql\QueryLoader.cs:line 287
   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Hql\Ast\ANTLR\QueryTranslatorImpl.cs:line 110
   at NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Engine\Query\HQLQueryPlan.cs:line 115
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results, Object filterConnection) in C:\Users\gokhan.abatay\Desktop\nhibernate-core-SerializedHashcode\src\NHibernate\Impl\SessionImpl.cs:line 541

C:\windows\system32>redis-benchmark
====== PING_INLINE ======
100000 requests completed in 1.56 seconds
50 parallel clients
3 bytes payload
keep alive: 1

88.24% <= 1 milliseconds
99.06% <= 2 milliseconds
99.80% <= 3 milliseconds
99.90% <= 4 milliseconds
99.96% <= 5 milliseconds
99.99% <= 6 milliseconds
100.00% <= 6 milliseconds
64061.50 requests per second

====== PING_BULK ======
100000 requests completed in 1.41 seconds
50 parallel clients
3 bytes payload
keep alive: 1

91.91% <= 1 milliseconds
99.25% <= 2 milliseconds
99.82% <= 3 milliseconds
99.97% <= 4 milliseconds
100.00% <= 5 milliseconds
70671.38 requests per second

====== SET ======
100000 requests completed in 1.67 seconds
50 parallel clients
3 bytes payload
keep alive: 1

83.78% <= 1 milliseconds
98.08% <= 2 milliseconds
99.66% <= 3 milliseconds
99.84% <= 4 milliseconds
99.88% <= 5 milliseconds
99.92% <= 6 milliseconds
99.95% <= 8 milliseconds
99.97% <= 9 milliseconds
100.00% <= 9 milliseconds
59844.41 requests per second

====== GET ======
100000 requests completed in 1.47 seconds
50 parallel clients
3 bytes payload
keep alive: 1

89.96% <= 1 milliseconds
99.11% <= 2 milliseconds
99.89% <= 3 milliseconds
99.96% <= 4 milliseconds
100.00% <= 4 milliseconds
68212.83 requests per second

====== INCR ======
100000 requests completed in 1.55 seconds
50 parallel clients
3 bytes payload
keep alive: 1

88.22% <= 1 milliseconds
99.13% <= 2 milliseconds
99.92% <= 3 milliseconds
99.99% <= 4 milliseconds
100.00% <= 4 milliseconds
64308.68 requests per second

====== LPUSH ======
100000 requests completed in 1.64 seconds
50 parallel clients
3 bytes payload
keep alive: 1

84.37% <= 1 milliseconds
98.91% <= 2 milliseconds
99.86% <= 3 milliseconds
99.93% <= 4 milliseconds
99.95% <= 5 milliseconds
99.98% <= 6 milliseconds
100.00% <= 6 milliseconds
61012.81 requests per second

====== RPUSH ======
100000 requests completed in 1.86 seconds
50 parallel clients
3 bytes payload
keep alive: 1

78.14% <= 1 milliseconds
96.81% <= 2 milliseconds
99.30% <= 3 milliseconds
99.80% <= 4 milliseconds
99.99% <= 5 milliseconds
100.00% <= 5 milliseconds
53648.07 requests per second

====== LPOP ======
100000 requests completed in 1.66 seconds
50 parallel clients
3 bytes payload
keep alive: 1

84.33% <= 1 milliseconds
98.68% <= 2 milliseconds
99.81% <= 3 milliseconds
99.94% <= 4 milliseconds
100.00% <= 4 milliseconds
60168.47 requests per second

====== RPOP ======
100000 requests completed in 1.63 seconds
50 parallel clients
3 bytes payload
keep alive: 1

85.95% <= 1 milliseconds
98.67% <= 2 milliseconds
99.94% <= 3 milliseconds
100.00% <= 4 milliseconds
100.00% <= 4 milliseconds
61312.08 requests per second

====== SADD ======
100000 requests completed in 1.51 seconds
50 parallel clients
3 bytes payload
keep alive: 1

89.27% <= 1 milliseconds
99.38% <= 2 milliseconds
99.96% <= 3 milliseconds
100.00% <= 3 milliseconds
66269.05 requests per second

====== SPOP ======
100000 requests completed in 1.51 seconds
50 parallel clients
3 bytes payload
keep alive: 1

88.74% <= 1 milliseconds
98.88% <= 2 milliseconds
99.94% <= 3 milliseconds
99.99% <= 4 milliseconds
100.00% <= 4 milliseconds
66181.34 requests per second

====== LPUSH (needed to benchmark LRANGE) ======
100000 requests completed in 1.73 seconds
50 parallel clients
3 bytes payload
keep alive: 1

82.01% <= 1 milliseconds
98.85% <= 2 milliseconds
99.86% <= 3 milliseconds
99.99% <= 4 milliseconds
100.00% <= 4 milliseconds
57670.13 requests per second

====== LRANGE_100 (first 100 elements) ======
100000 requests completed in 7.29 seconds
50 parallel clients
3 bytes payload
keep alive: 1

0.22% <= 1 milliseconds
77.24% <= 2 milliseconds
95.23% <= 3 milliseconds
98.68% <= 4 milliseconds
99.44% <= 5 milliseconds
99.78% <= 6 milliseconds
99.89% <= 7 milliseconds
99.96% <= 8 milliseconds
99.97% <= 12 milliseconds
99.98% <= 13 milliseconds
100.00% <= 14 milliseconds
100.00% <= 14 milliseconds
13717.42 requests per second

====== LRANGE_300 (first 300 elements) ======
100000 requests completed in 16.18 seconds
50 parallel clients
3 bytes payload
keep alive: 1

0.02% <= 1 milliseconds
0.42% <= 2 milliseconds
13.05% <= 3 milliseconds
57.46% <= 4 milliseconds
86.03% <= 5 milliseconds
94.10% <= 6 milliseconds
97.45% <= 7 milliseconds
98.60% <= 8 milliseconds
99.10% <= 9 milliseconds
99.38% <= 10 milliseconds
99.55% <= 11 milliseconds
99.65% <= 12 milliseconds
99.73% <= 13 milliseconds
99.81% <= 14 milliseconds
99.86% <= 15 milliseconds
99.88% <= 16 milliseconds
99.91% <= 17 milliseconds
99.93% <= 18 milliseconds
99.93% <= 19 milliseconds
99.95% <= 20 milliseconds
99.97% <= 21 milliseconds
99.97% <= 22 milliseconds
99.98% <= 23 milliseconds
99.98% <= 24 milliseconds
99.98% <= 27 milliseconds
99.99% <= 28 milliseconds
99.99% <= 29 milliseconds
100.00% <= 30 milliseconds
100.00% <= 31 milliseconds
100.00% <= 33 milliseconds
6180.47 requests per second

How to clear distributed cache?

It appears that using one of the CoreDistributedCache providers means that you cannot use things like sessionFactory.EvictQueries() to clear the cache as you just get a warning of 'Clear is not supported by IDistributedCache'. Any thoughts on how to clear the cache when using one of these providers?

Add support for custom serializer in CoreDistributedCache

CoreDistributesCache is using BinaryFormatter for serializing the cache data:

var serializer = new BinaryFormatter();
using (var stream = new MemoryStream())
{
var entry = new Tuple<object, object>(key, value);
serializer.Serialize(stream, entry);
cachedData = stream.ToArray();

In .NET Core some types are not serializable anymore, for example System.Net.IPAddress, so it makes impossible to cache those entities which has this property type.

If I see it right there is some (or at least one) providers which already support the custom serializer:

public CacheSerializerBase Serializer
{
get => _serializer ?? DefaultSerializer;
set => _serializer = value;
}

So I think it is relatively easy to put the same functionality to the CoreDistributedCache provider.

Another reason is to make the serialization faster and making smaller serialized data (for example with ProtoBuf).

DistributedLocalCacheRegionStrategy - failed to lazily initialize a collection of role

Hi @maca88 ,
When we store objects in memory cache it's a issue if it has a lazy load property on entity.
When we finally get cached entity from cache it retrieves from cache but lazy property is not initialized because when it's has been cached it is not accessed lazy property so proxy class private variable session is closed.

Then another thread try to retrieve cache item but this time it tries to get Country lazy property as well, then NHibernate.LazyInitializationException
Initializing[Domain.Entities.City#4]-failed to lazily initialize a collection of role: Domain.Entities.Country, no session or session was closed

City has Country referance with lazy load enabled.

What can we do for this issue?

Cache issue-.net core 3.0-Could not load type 'System.Web.Caching.CacheItemPriority'

I was using nhibernate for Cache in old .net framework.

Now we are rewriting to .net core 3.0.

We are having runtime issue for nhibernate cache.

Inner Exception
Could not load type 'System.Web.Caching.CacheItemPriority' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.":"System.Web.Caching.CacheItemPriority

Exception:
{"An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.\r\n\r\n

nhibernate cache issue

"Third Level Cache" for Redis

Hi @maca88,
I have been doing lots of performance test I find out some issues and report with second level cache usage, we are good point now against starting point but i have an idea thinking about third level cache?

Let me tell you i wan't to put in app memory cache on front of redis cache think about that.
Pre request;

  1. StandartQueryCache always sync with in memory and redis
  2. UpdateTimestampsCache sync with just redis
  3. Object cache always sync with in memory and redis
  4. UpdateTimestampsCache never expires

Query().WithOptions(x=>x.SetCacheable(true)).ToList()
Get StandartQueryCache from local cache if exists if not get from redis
Get UpdateTimestamsCache from redis
Compare objects is outdated?
a.if outdated it will get result from database and put updated cache to inmemory and redis
b.if its not outdated it will gets the cache item from in memory cache

So we can minimize redis network cost serialize/deserialize costs

image

public class RedisCacheImpl : RedisCache
{
    public override bool PreferMultipleGet => true;

    public RedisCacheImpl(string regionName, AbstractRegionStrategy regionStrategy) : base(regionName, regionStrategy)
    {

    }
}

public partial class RedisInMemoryCache : RedisCacheImpl
{
    protected CacheBase InMemoryCache { get; private set; }

    public RedisInMemoryCache(string regionName, AbstractRegionStrategy regionStrategy, CacheBase inMemoryCache) 
        : base(regionName, regionStrategy)
    {
        InMemoryCache = inMemoryCache;
    }

    public override object Get(object key)
    {
        var result = InMemoryCache.Get(key);
        if(result == null)
        {
            result = base.Get(key);
            if (result != null)
            {
                InMemoryCache.Put(key, result);
            }
        }
        return result;
    }

    public override object[] GetMany(object[] keys)
    {
        var objects = new object[keys.Length];
        var nullValues = new List<(int index, object key)>();
        for (var i = 0; i < keys.Length; i++)
        {
            var result = InMemoryCache.Get(keys[i]);
            objects[i] = result;
            if(result == null)
            {
                nullValues.Add((i, keys[i]));
            }
        }

        if (nullValues.Count > 0)
        {
            var remoteObjects = base.GetMany(nullValues.Select(x=>x.key).ToArray());
            if(remoteObjects.Length > 0)
            {
                for (int i = 0; i < remoteObjects.Length; i++)
                {
                    var nullValue = nullValues[i];
                    var remoteObject = remoteObjects[i];
                    if (remoteObject != null)
                    {
                        objects[nullValue.index] = remoteObject;
                        InMemoryCache.Put(nullValue.key, remoteObject);
                    }
                }
            }
        }

        return objects;
    }

    public override void Put(object key, object value)
    {
        InMemoryCache.Put(key, value);
        base.Put(key, value);
    }

    public override void PutMany(object[] keys, object[] values)
    {
        for (int i = 0; i < keys.Length; i++)
        {
            InMemoryCache.Put(keys[i], values[i]);
        }
        base.PutMany(keys, values);
    }

    public override void Remove(object key)
    {
        InMemoryCache.Remove(key);
        base.Remove(key);
    }

    public override void Clear()
    {
        InMemoryCache.Clear();
        base.Clear();
    }

    public override void Destroy()
    {
        InMemoryCache.Destroy();
        // No resources to clean-up for redis
    }
}

public partial class RedisInMemoryCache : RedisCacheImpl
{
    public override Task<object> GetAsync(object key, CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled<object>(cancellationToken);
        }
        return InternalGetAsync();

        async Task<object> InternalGetAsync()
        {
            var result = await InMemoryCache.GetAsync(key,cancellationToken).ConfigureAwait(false);
            if (result == null)
            {
                result = await base.GetAsync(key,cancellationToken).ConfigureAwait(false);
                if (result != null)
                {
                    await InMemoryCache.PutAsync(key, result,cancellationToken).ConfigureAwait(false);
                }
            }
            return result;
        }
    }

    public override Task<object[]> GetManyAsync(object[] keys, CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled<object[]>(cancellationToken);
        }

        return InternalGetManyAsync();

        async Task<object[]> InternalGetManyAsync()
        {
            var objects = new object[keys.Length];

            var nullValues = new List<(int index, object key)>();
            for (var i = 0; i < keys.Length; i++)
            {
                var result = await InMemoryCache.GetAsync(keys[i], cancellationToken).ConfigureAwait(false);
                objects[i] = result;
                if (result == null)
                {
                    nullValues.Add((i, keys[i]));
                }
            }

            if (nullValues.Count > 0)
            {
                var remoteObjects = await base.GetManyAsync(nullValues.Select(x => x.key).ToArray(), cancellationToken).ConfigureAwait(false);
                if (remoteObjects.Length > 0)
                {
                    for (int i = 0; i < remoteObjects.Length; i++)
                    {
                        var nullValue = nullValues[i];
                        var remoteObject = remoteObjects[i];
                        if (remoteObject != null)
                        {
                            objects[nullValue.index] = remoteObject;
                            await InMemoryCache.PutAsync(nullValue.key, remoteObject, cancellationToken).ConfigureAwait(false);
                        }
                    }
                }
            }

            return objects;
        }
    }

    public override Task PutAsync(object key, object value, CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled(cancellationToken);
        }
        return InternalPutAsync();

        async Task InternalPutAsync()
        {
            await InMemoryCache.PutAsync(key, value,cancellationToken).ConfigureAwait(false);
            await base.PutAsync(key, value, cancellationToken).ConfigureAwait(false);
        }
    }

    public override Task PutManyAsync(object[] keys, object[] values, CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled(cancellationToken);
        }
        return InternalPutManyAsync();

        async Task InternalPutManyAsync()
        {
            for (int i = 0; i < keys.Length; i++)
            {
                await InMemoryCache.PutAsync(keys[i], values[i], cancellationToken).ConfigureAwait(false);
            }
            await base.PutManyAsync(keys, values, cancellationToken).ConfigureAwait(false);
        }
    }

    public override Task RemoveAsync(object key, CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled(cancellationToken);
        }
        return InternalRemoveAsync();

        async Task InternalRemoveAsync()
        {
            await InMemoryCache.RemoveAsync(key, cancellationToken).ConfigureAwait(false);
            await base.RemoveAsync(key, cancellationToken).ConfigureAwait(false);
        }
    }

    public override Task ClearAsync(CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled(cancellationToken);
        }
        return InternalClearAsync();

        async Task InternalClearAsync()
        {
            await InMemoryCache.ClearAsync(cancellationToken).ConfigureAwait(false);
            await base.ClearAsync(cancellationToken).ConfigureAwait(false);
        }
    }
}

public class RedisInMemoryCacheProvider : RedisCacheProvider
{
    private static readonly CoreMemoryCacheProvider memoryCacheProvider = new CoreMemoryCacheProvider();

    private static readonly FieldInfo connectionMultiplexer = typeof(RedisCacheProvider)
        .GetField("_connectionMultiplexer", BindingFlags.NonPublic | BindingFlags.Instance);

    private const string UpdateTimestampsCache = "UpdateTimestampsCache";
    private const string InMemoryUsage = "cache.inmemory_usage";
    private const string InMemoryExpiration = "cache.inmemory_expiration";
    private const string InMemoryExpirationScanFrequency = "cache.inmemory_expiration_scan_frequency";

    protected override CacheBase BuildCache(RedisCacheRegionConfiguration regionConfiguration, IDictionary<string, string> properties)
    {
        var regionStrategy =
            CacheConfiguration.RegionStrategyFactory.Create(connectionMultiplexer.GetValue(this) as IConnectionMultiplexer,
            regionConfiguration, properties);

        var inMemoryUsage = PropertiesHelper.GetBoolean(InMemoryUsage, properties, false);

        if (!inMemoryUsage || 
            regionConfiguration.RegionName.EndsWith(UpdateTimestampsCache))
        {
            return new RedisCacheImpl(regionConfiguration.RegionName, regionStrategy);
        }
        else
        {
            var clonedProperties = properties.ToDictionary(x => x.Key, x => x.Value);
            SetConfiguration(clonedProperties);
            var inMemoryCache = memoryCacheProvider.BuildCache(regionConfiguration.RegionName, clonedProperties) as CacheBase;
            return new RedisInMemoryCache(regionConfiguration.RegionName, regionStrategy, inMemoryCache);
        }
    }

    protected void SetConfiguration(IDictionary<string, string> properties)
    {
        if (CoreMemoryCacheProvider.ExpirationScanFrequency == null)
        {
            var seconds = PropertiesHelper.GetInt32(InMemoryExpirationScanFrequency, properties, 60);
            CoreMemoryCacheProvider.ExpirationScanFrequency = TimeSpan.FromSeconds(seconds);
        }

        const string expiration = "expiration";
        if (!properties.ContainsKey(expiration))
        {
            properties[expiration] = PropertiesHelper.GetInt32(InMemoryExpiration, properties, 60).ToString();
        }
    }
}

Collection Cache is not removed from Redis when the child entity record is deleted or new one added

I have Contact Entity and MailingAddress Entity. Contact has a bag of MailingAddresses which is cached inside Redis but when a MailingAddress is deleted, the association bag of MailingAddress inside Redis is not updated so when we try to load the contact again we are getting an exception

NHibernate.ObjectNotFoundException: No row with the given identifier exists[Entity.MailingAddress#14448]

Here is the definition of entities:

  <class name="MailingAddress" table="MailingAddress">
    <cache include="all" usage="read-write" region="community" />
    <id name="ID" type="System.Int64" column="ID">
      <generator class="identity" />
    </id>
    <property name="Address1" column="Address1" />
    <property name="StreetName" column="StreetName" />
    <property name="Obsolete" column="Obsolete" />
    <many-to-one name="Contact" cascade="none" lazy="proxy" fetch="select" class="Entity.Contact" column="ContactID" />
  </class>

  <class name="Contact" table="Contacts" discriminator-value="0">
    <cache include="all" usage="read-write" region="community" />
    <id name="ID" type="System.Int64" column="ID">
      <generator class="identity" />
    </id>
    <discriminator column="ContactType" type="int" insert="false"/>
    <property name="ContactType" column="ContactType" />
    <property name="DisplayName" column="DisplayName" />
    <property name="GID" column="GID" />
    <property name="Obsolete" column="Obsolete" />
    <bag name="Addresses" inverse="true" cascade="all-delete-orphan" fetch="select" lazy="true">
      <cache include="all" usage="read-write" region="community" />
      <key column="ContactID" />
      <one-to-many class="Entity.MailingAddress" />
    </bag>    
  </class>

If I update MailingAddress record then if I refresh Contact view then I get the updated value and I also see the key value updated. The issue happens if I delete MailingAddress then Contact.Addresses key inside Redis is not removing the deleted MailingAddress and then I am getting.

Everything is done inside transactions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.