diff --git a/src/NHibernate/Async/Cache/NonstrictReadWriteCache.cs b/src/NHibernate/Async/Cache/NonstrictReadWriteCache.cs index da86e36832a..bd8fe846c02 100644 --- a/src/NHibernate/Async/Cache/NonstrictReadWriteCache.cs +++ b/src/NHibernate/Async/Cache/NonstrictReadWriteCache.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -31,7 +32,7 @@ public async Task GetAsync(CacheKey key, long txTimestamp, CancellationT log.Debug("Cache lookup: {0}", key); } - var result = await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + var result = await (InternalCache.GetAsync(key, cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug(result != null ? "Cache hit: {0}" : "Cache miss: {0}", key); @@ -48,7 +49,7 @@ public async Task GetManyAsync(CacheKey[] keys, long timestamp, Cancel log.Debug("Cache lookup: {0}", string.Join(",", keys.AsEnumerable())); } - var results = await (_cache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); + var results = await (InternalCache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Cache hit: {0}", string.Join(",", keys.Where((k, i) => results != null))); @@ -83,10 +84,12 @@ public async Task PutManyAsync( checkKeyIndexes.Add(i); } } + + var cache = InternalCache; var skipKeyIndexes = new HashSet(); if (checkKeys.Any()) { - var objects = await (_cache.GetManyAsync(checkKeys.ToArray(), cancellationToken)).ConfigureAwait(false); + var objects = await (cache.GetManyAsync(checkKeys.ToArray(), cancellationToken)).ConfigureAwait(false); for (var i = 0; i < objects.Length; i++) { if (objects[i] != null) @@ -118,7 +121,7 @@ public async Task PutManyAsync( putValues[j++] = values[i]; result[i] = true; } - await (_cache.PutManyAsync(putKeys, putValues, cancellationToken)).ConfigureAwait(false); + await (cache.PutManyAsync(putKeys, putValues, cancellationToken)).ConfigureAwait(false); return result; } @@ -135,7 +138,8 @@ public async Task PutAsync(CacheKey key, object value, long txTimestamp, o return false; } - if (minimalPut && await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false) != null) + var cache = InternalCache; + if (minimalPut && await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false) != null) { if (log.IsDebugEnabled()) { @@ -147,7 +151,7 @@ public async Task PutAsync(CacheKey key, object value, long txTimestamp, o { log.Debug("Caching: {0}", key); } - await (Cache.PutAsync(key, value, cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, value, cancellationToken)).ConfigureAwait(false); return true; } @@ -164,7 +168,7 @@ public Task LockAsync(CacheKey key, object version, CancellationToken { return Task.FromResult(Lock(key, version)); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -182,9 +186,9 @@ public Task RemoveAsync(CacheKey key, CancellationToken cancellationToken) { log.Debug("Removing: {0}", key); } - return Cache.RemoveAsync(key, cancellationToken); + return InternalCache.RemoveAsync(key, cancellationToken); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -202,9 +206,9 @@ public Task ClearAsync(CancellationToken cancellationToken) { log.Debug("Clearing"); } - return Cache.ClearAsync(cancellationToken); + return InternalCache.ClearAsync(cancellationToken); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -225,9 +229,9 @@ public Task EvictAsync(CacheKey key, CancellationToken cancellationToken) { log.Debug("Invalidating: {0}", key); } - return Cache.RemoveAsync(key, cancellationToken); + return InternalCache.RemoveAsync(key, cancellationToken); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -259,9 +263,9 @@ public Task ReleaseAsync(CacheKey key, ISoftLock @lock, CancellationToken cancel log.Debug("Invalidating (again): {0}", key); } - return Cache.RemoveAsync(key, cancellationToken); + return InternalCache.RemoveAsync(key, cancellationToken); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -290,7 +294,7 @@ public Task AfterInsertAsync(CacheKey key, object value, object version, C { return Task.FromResult(AfterInsert(key, value, version)); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } diff --git a/src/NHibernate/Async/Cache/ReadOnlyCache.cs b/src/NHibernate/Async/Cache/ReadOnlyCache.cs index b87852ed39b..65610093cea 100644 --- a/src/NHibernate/Async/Cache/ReadOnlyCache.cs +++ b/src/NHibernate/Async/Cache/ReadOnlyCache.cs @@ -24,7 +24,7 @@ public partial class ReadOnlyCache : IBatchableCacheConcurrencyStrategy public async Task GetAsync(CacheKey key, long timestamp, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var result = await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + var result = await (InternalCache.GetAsync(key, cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug(result != null ? "Cache hit: {0}" : "Cache miss: {0}", key); @@ -41,7 +41,7 @@ public async Task GetManyAsync(CacheKey[] keys, long timestamp, Cancel log.Debug("Cache lookup: {0}", string.Join(",", keys.AsEnumerable())); } - var results = await (_cache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); + var results = await (InternalCache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Cache hit: {0}", string.Join(",", keys.Where((k, i) => results[i] != null))); @@ -92,10 +92,12 @@ public async Task PutManyAsync( checkKeyIndexes.Add(i); } } + + var cache = InternalCache; var skipKeyIndexes = new HashSet(); if (checkKeys.Any()) { - var objects = await (_cache.GetManyAsync(checkKeys.ToArray(), cancellationToken)).ConfigureAwait(false); + var objects = await (cache.GetManyAsync(checkKeys.ToArray(), cancellationToken)).ConfigureAwait(false); for (var i = 0; i < objects.Length; i++) { if (objects[i] != null) @@ -127,7 +129,7 @@ public async Task PutManyAsync( putValues[j++] = values[i]; result[i] = true; } - await (_cache.PutManyAsync(putKeys, putValues, cancellationToken)).ConfigureAwait(false); + await (cache.PutManyAsync(putKeys, putValues, cancellationToken)).ConfigureAwait(false); return result; } @@ -141,7 +143,8 @@ public async Task PutAsync(CacheKey key, object value, long timestamp, obj return false; } - if (minimalPut && await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false) != null) + var cache = InternalCache; + if (minimalPut && await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false) != null) { if (log.IsDebugEnabled()) { @@ -153,7 +156,7 @@ public async Task PutAsync(CacheKey key, object value, long timestamp, obj { log.Debug("Caching: {0}", key); } - await (Cache.PutAsync(key, value, cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, value, cancellationToken)).ConfigureAwait(false); return true; } @@ -183,7 +186,7 @@ public Task ClearAsync(CancellationToken cancellationToken) { return Task.FromCanceled(cancellationToken); } - return Cache.ClearAsync(cancellationToken); + return InternalCache.ClearAsync(cancellationToken); } public Task RemoveAsync(CacheKey key, CancellationToken cancellationToken) @@ -192,7 +195,7 @@ public Task RemoveAsync(CacheKey key, CancellationToken cancellationToken) { return Task.FromCanceled(cancellationToken); } - return Cache.RemoveAsync(key, cancellationToken); + return InternalCache.RemoveAsync(key, cancellationToken); } /// diff --git a/src/NHibernate/Async/Cache/ReadWriteCache.cs b/src/NHibernate/Async/Cache/ReadWriteCache.cs index eac3b2bc339..ce8ac6a7031 100644 --- a/src/NHibernate/Async/Cache/ReadWriteCache.cs +++ b/src/NHibernate/Async/Cache/ReadWriteCache.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -40,6 +41,8 @@ public partial class ReadWriteCache : IBatchableCacheConcurrencyStrategy /// public async Task GetAsync(CacheKey key, long txTimestamp, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + var cache = InternalCache; cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.ReadLockAsync()).ConfigureAwait(false)) { @@ -52,7 +55,7 @@ public async Task GetAsync(CacheKey key, long txTimestamp, CancellationT /*try { cache.Lock( key );*/ - var lockable = (ILockable) await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + var lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); return GetValue(txTimestamp, key, lockable); /*} finally @@ -69,11 +72,12 @@ public async Task GetManyAsync(CacheKey[] keys, long timestamp, Cancel { log.Debug("Cache lookup: {0}", string.Join(",", keys.AsEnumerable())); } + var cache = InternalCache; var result = new object[keys.Length]; cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.ReadLockAsync()).ConfigureAwait(false)) { - var lockables = await (_cache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); + var lockables = await (cache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); for (var i = 0; i < lockables.Length; i++) { var o = (ILockable) lockables[i]; @@ -92,6 +96,8 @@ public async Task GetManyAsync(CacheKey[] keys, long timestamp, Cancel /// public async Task LockAsync(CacheKey key, object version, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + var cache = InternalCache; cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.WriteLockAsync()).ConfigureAwait(false)) { @@ -100,20 +106,20 @@ public async Task LockAsync(CacheKey key, object version, Cancellatio log.Debug("Invalidating: {0}", key); } - var lockValue = await (_cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); + var lockValue = await (cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); try { - ILockable lockable = (ILockable) await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); - long timeout = Cache.NextTimestamp() + Cache.Timeout; + ILockable lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + long timeout = cache.NextTimestamp() + cache.Timeout; CacheLock @lock = lockable == null ? CacheLock.Create(timeout, NextLockId(), version) : lockable.Lock(timeout, NextLockId()); - await (Cache.PutAsync(key, @lock, cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, @lock, cancellationToken)).ConfigureAwait(false); return @lock; } finally { - await (_cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); + await (cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); } } } @@ -136,8 +142,9 @@ public async Task PutManyAsync( // MinValue means cache is disabled return result; } - cancellationToken.ThrowIfCancellationRequested(); + var cache = InternalCache; + cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.WriteLockAsync()).ConfigureAwait(false)) { if (log.IsDebugEnabled()) @@ -145,11 +152,11 @@ public async Task PutManyAsync( log.Debug("Caching: {0}", string.Join(",", keys.AsEnumerable())); } - var lockValue = await (_cache.LockManyAsync(keys, cancellationToken)).ConfigureAwait(false); + var lockValue = await (cache.LockManyAsync(keys, cancellationToken)).ConfigureAwait(false); try { var putBatch = new Dictionary(); - var lockables = await (_cache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); + var lockables = await (cache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false); for (var i = 0; i < keys.Length; i++) { var key = keys[i]; @@ -159,7 +166,7 @@ public async Task PutManyAsync( lockable.IsPuttable(timestamp, version, versionComparers[i]); if (puttable) { - putBatch.Add(key, CachedItem.Create(values[i], Cache.NextTimestamp(), version)); + putBatch.Add(key, CachedItem.Create(values[i], cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); @@ -180,12 +187,12 @@ public async Task PutManyAsync( if (putBatch.Count > 0) { - await (_cache.PutManyAsync(putBatch.Keys.ToArray(), putBatch.Values.ToArray(), cancellationToken)).ConfigureAwait(false); + await (cache.PutManyAsync(putBatch.Keys.ToArray(), putBatch.Values.ToArray(), cancellationToken)).ConfigureAwait(false); } } finally { - await (_cache.UnlockManyAsync(keys, lockValue, cancellationToken)).ConfigureAwait(false); + await (cache.UnlockManyAsync(keys, lockValue, cancellationToken)).ConfigureAwait(false); } } return result; @@ -207,8 +214,9 @@ public async Task PutAsync(CacheKey key, object value, long txTimestamp, o // MinValue means cache is disabled return false; } - cancellationToken.ThrowIfCancellationRequested(); + var cache = InternalCache; + cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.WriteLockAsync()).ConfigureAwait(false)) { if (log.IsDebugEnabled()) @@ -216,17 +224,17 @@ public async Task PutAsync(CacheKey key, object value, long txTimestamp, o log.Debug("Caching: {0}", key); } - var lockValue = await (_cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); + var lockValue = await (cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); try { - ILockable lockable = (ILockable) await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + ILockable lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); bool puttable = lockable == null || lockable.IsPuttable(txTimestamp, version, versionComparator); if (puttable) { - await (Cache.PutAsync(key, CachedItem.Create(value, Cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, CachedItem.Create(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); @@ -244,7 +252,7 @@ public async Task PutAsync(CacheKey key, object value, long txTimestamp, o } finally { - await (_cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); + await (cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); } } } @@ -261,10 +269,11 @@ private Task DecrementLockAsync(object key, CacheLock @lock, CancellationToken c try { //decrement the lock - @lock.Unlock(Cache.NextTimestamp()); - return Cache.PutAsync(key, @lock, cancellationToken); + var cache = InternalCache; + @lock.Unlock(cache.NextTimestamp()); + return cache.PutAsync(key, @lock, cancellationToken); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -272,6 +281,8 @@ private Task DecrementLockAsync(object key, CacheLock @lock, CancellationToken c public async Task ReleaseAsync(CacheKey key, ISoftLock clientLock, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + var cache = InternalCache; cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.WriteLockAsync()).ConfigureAwait(false)) { @@ -280,10 +291,10 @@ public async Task ReleaseAsync(CacheKey key, ISoftLock clientLock, CancellationT log.Debug("Releasing: {0}", key); } - var lockValue = await (_cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); + var lockValue = await (cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); try { - ILockable lockable = (ILockable) await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + ILockable lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); if (IsUnlockable(clientLock, lockable)) { await (DecrementLockAsync(key, (CacheLock) lockable, cancellationToken)).ConfigureAwait(false); @@ -295,7 +306,7 @@ public async Task ReleaseAsync(CacheKey key, ISoftLock clientLock, CancellationT } finally { - await (_cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); + await (cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); } } } @@ -309,13 +320,14 @@ internal Task HandleLockExpiryAsync(object key, CancellationToken cancellationTo try { log.Warn("An item was expired by the cache while it was locked (increase your cache timeout): {0}", key); - long ts = Cache.NextTimestamp() + Cache.Timeout; + var cache = InternalCache; + long ts = cache.NextTimestamp() + cache.Timeout; // create new lock that times out immediately CacheLock @lock = CacheLock.Create(ts, NextLockId(), null); @lock.Unlock(ts); - return Cache.PutAsync(key, @lock, cancellationToken); + return cache.PutAsync(key, @lock, cancellationToken); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -327,7 +339,7 @@ public Task ClearAsync(CancellationToken cancellationToken) { return Task.FromCanceled(cancellationToken); } - return Cache.ClearAsync(cancellationToken); + return InternalCache.ClearAsync(cancellationToken); } public Task RemoveAsync(CacheKey key, CancellationToken cancellationToken) @@ -336,7 +348,7 @@ public Task RemoveAsync(CacheKey key, CancellationToken cancellationToken) { return Task.FromCanceled(cancellationToken); } - return Cache.RemoveAsync(key, cancellationToken); + return InternalCache.RemoveAsync(key, cancellationToken); } /// @@ -345,6 +357,8 @@ public Task RemoveAsync(CacheKey key, CancellationToken cancellationToken) /// public async Task AfterUpdateAsync(CacheKey key, object value, object version, ISoftLock clientLock, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + var cache = InternalCache; cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.WriteLockAsync()).ConfigureAwait(false)) { @@ -353,10 +367,10 @@ public async Task AfterUpdateAsync(CacheKey key, object value, object vers log.Debug("Updating: {0}", key); } - var lockValue = await (_cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); + var lockValue = await (cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); try { - ILockable lockable = (ILockable) await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + ILockable lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); if (IsUnlockable(clientLock, lockable)) { CacheLock @lock = (CacheLock) lockable; @@ -369,7 +383,7 @@ public async Task AfterUpdateAsync(CacheKey key, object value, object vers else { //recache the updated state - await (Cache.PutAsync(key, CachedItem.Create(value, Cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, CachedItem.Create(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Updated: {0}", key); @@ -385,13 +399,15 @@ public async Task AfterUpdateAsync(CacheKey key, object value, object vers } finally { - await (_cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); + await (cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); } } } public async Task AfterInsertAsync(CacheKey key, object value, object version, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + var cache = InternalCache; cancellationToken.ThrowIfCancellationRequested(); using (await (_asyncReaderWriterLock.WriteLockAsync()).ConfigureAwait(false)) { @@ -400,13 +416,13 @@ public async Task AfterInsertAsync(CacheKey key, object value, object vers log.Debug("Inserting: {0}", key); } - var lockValue = await (_cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); + var lockValue = await (cache.LockAsync(key, cancellationToken)).ConfigureAwait(false); try { - ILockable lockable = (ILockable) await (Cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); + ILockable lockable = (ILockable) await (cache.GetAsync(key, cancellationToken)).ConfigureAwait(false); if (lockable == null) { - await (Cache.PutAsync(key, CachedItem.Create(value, Cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); + await (cache.PutAsync(key, CachedItem.Create(value, cache.NextTimestamp(), version), cancellationToken)).ConfigureAwait(false); if (log.IsDebugEnabled()) { log.Debug("Inserted: {0}", key); @@ -420,7 +436,7 @@ public async Task AfterInsertAsync(CacheKey key, object value, object vers } finally { - await (_cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); + await (cache.UnlockAsync(key, lockValue, cancellationToken)).ConfigureAwait(false); } } } @@ -436,7 +452,7 @@ public Task EvictAsync(CacheKey key, CancellationToken cancellationToken) Evict(key); return Task.CompletedTask; } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } @@ -452,7 +468,7 @@ public Task UpdateAsync(CacheKey key, object value, object currentVersion, { return Task.FromResult(Update(key, value, currentVersion, previousVersion)); } - catch (System.Exception ex) + catch (Exception ex) { return Task.FromException(ex); } diff --git a/src/NHibernate/Cache/CacheFactory.cs b/src/NHibernate/Cache/CacheFactory.cs index b6c5df8549d..27c1150bbad 100644 --- a/src/NHibernate/Cache/CacheFactory.cs +++ b/src/NHibernate/Cache/CacheFactory.cs @@ -60,7 +60,7 @@ public static ICacheConcurrencyStrategy CreateCache( public static ICacheConcurrencyStrategy CreateCache(string usage, CacheBase cache) { if (log.IsDebugEnabled()) - log.Debug("cache for: {0} usage strategy: {1}", cache.RegionName, usage); + log.Debug("cache for: {0} usage strategy: {1}", cache?.RegionName, usage); ICacheConcurrencyStrategy ccs; switch (usage) diff --git a/src/NHibernate/Cache/NonstrictReadWriteCache.cs b/src/NHibernate/Cache/NonstrictReadWriteCache.cs index 011a2c9b7be..e67b35dfe24 100644 --- a/src/NHibernate/Cache/NonstrictReadWriteCache.cs +++ b/src/NHibernate/Cache/NonstrictReadWriteCache.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -18,13 +19,14 @@ public partial class NonstrictReadWriteCache : IBatchableCacheConcurrencyStrateg private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(NonstrictReadWriteCache)); private CacheBase _cache; + private bool _isDestroyed; /// /// Gets the cache region name. /// public string RegionName { - get { return Cache.RegionName; } + get { return Cache?.RegionName; } } // 6.0 TODO: remove @@ -36,7 +38,18 @@ public ICache Cache set { _cache = value?.AsCacheBase(); } } - // 6.0 TODO: make implicit and switch to auto-property + // 6.0 TODO: Rename to Cache and make public (possible breaking change for reader when null). + private CacheBase InternalCache + { + get + { + if (_cache == null || _isDestroyed) + throw new InvalidOperationException(_isDestroyed ? "The cache has already been destroyed" : "The concrete cache is not defined"); + return _cache; + } + } + + // 6.0 TODO: remove CacheBase IBatchableCacheConcurrencyStrategy.Cache { get => _cache; @@ -53,7 +66,7 @@ public object Get(CacheKey key, long txTimestamp) log.Debug("Cache lookup: {0}", key); } - var result = Cache.Get(key); + var result = InternalCache.Get(key); if (log.IsDebugEnabled()) { log.Debug(result != null ? "Cache hit: {0}" : "Cache miss: {0}", key); @@ -69,7 +82,7 @@ public object[] GetMany(CacheKey[] keys, long timestamp) log.Debug("Cache lookup: {0}", string.Join(",", keys.AsEnumerable())); } - var results = _cache.GetMany(keys); + var results = InternalCache.GetMany(keys); if (log.IsDebugEnabled()) { log.Debug("Cache hit: {0}", string.Join(",", keys.Where((k, i) => results != null))); @@ -103,10 +116,12 @@ public bool[] PutMany( checkKeyIndexes.Add(i); } } + + var cache = InternalCache; var skipKeyIndexes = new HashSet(); if (checkKeys.Any()) { - var objects = _cache.GetMany(checkKeys.ToArray()); + var objects = cache.GetMany(checkKeys.ToArray()); for (var i = 0; i < objects.Length; i++) { if (objects[i] != null) @@ -138,7 +153,7 @@ public bool[] PutMany( putValues[j++] = values[i]; result[i] = true; } - _cache.PutMany(putKeys, putValues); + cache.PutMany(putKeys, putValues); return result; } @@ -154,7 +169,8 @@ public bool Put(CacheKey key, object value, long txTimestamp, object version, IC return false; } - if (minimalPut && Cache.Get(key) != null) + var cache = InternalCache; + if (minimalPut && cache.Get(key) != null) { if (log.IsDebugEnabled()) { @@ -166,7 +182,7 @@ public bool Put(CacheKey key, object value, long txTimestamp, object version, IC { log.Debug("Caching: {0}", key); } - Cache.Put(key, value); + cache.Put(key, value); return true; } @@ -184,7 +200,7 @@ public void Remove(CacheKey key) { log.Debug("Removing: {0}", key); } - Cache.Remove(key); + InternalCache.Remove(key); } public void Clear() @@ -193,14 +209,15 @@ public void Clear() { log.Debug("Clearing"); } - Cache.Clear(); + InternalCache.Clear(); } public void Destroy() { + _isDestroyed = true; // The cache is externally provided and may be shared. Destroying the cache is // not the responsibility of this class. - Cache = null; + _cache = null; } /// @@ -212,7 +229,7 @@ public void Evict(CacheKey key) { log.Debug("Invalidating: {0}", key); } - Cache.Remove(key); + InternalCache.Remove(key); } /// @@ -242,7 +259,7 @@ public void Release(CacheKey key, ISoftLock @lock) log.Debug("Invalidating (again): {0}", key); } - Cache.Remove(key); + InternalCache.Remove(key); } /// diff --git a/src/NHibernate/Cache/ReadOnlyCache.cs b/src/NHibernate/Cache/ReadOnlyCache.cs index e95ec9c3475..ceba37dccee 100644 --- a/src/NHibernate/Cache/ReadOnlyCache.cs +++ b/src/NHibernate/Cache/ReadOnlyCache.cs @@ -14,13 +14,14 @@ public partial class ReadOnlyCache : IBatchableCacheConcurrencyStrategy private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(ReadOnlyCache)); private CacheBase _cache; + private bool _isDestroyed; /// /// Gets the cache region name. /// public string RegionName { - get { return Cache.RegionName; } + get { return Cache?.RegionName; } } // 6.0 TODO: remove @@ -32,7 +33,18 @@ public ICache Cache set { _cache = value?.AsCacheBase(); } } - // 6.0 TODO: make implicit and switch to auto-property + // 6.0 TODO: Rename to Cache and make public (possible breaking change for reader when null). + private CacheBase InternalCache + { + get + { + if (_cache == null || _isDestroyed) + throw new InvalidOperationException(_isDestroyed ? "The cache has already been destroyed" : "The concrete cache is not defined"); + return _cache; + } + } + + // 6.0 TODO: remove CacheBase IBatchableCacheConcurrencyStrategy.Cache { get => _cache; @@ -41,7 +53,7 @@ CacheBase IBatchableCacheConcurrencyStrategy.Cache public object Get(CacheKey key, long timestamp) { - var result = Cache.Get(key); + var result = InternalCache.Get(key); if (log.IsDebugEnabled()) { log.Debug(result != null ? "Cache hit: {0}" : "Cache miss: {0}", key); @@ -57,7 +69,7 @@ public object[] GetMany(CacheKey[] keys, long timestamp) log.Debug("Cache lookup: {0}", string.Join(",", keys.AsEnumerable())); } - var results = _cache.GetMany(keys); + var results = InternalCache.GetMany(keys); if (log.IsDebugEnabled()) { log.Debug("Cache hit: {0}", string.Join(",", keys.Where((k, i) => results[i] != null))); @@ -97,10 +109,12 @@ public bool[] PutMany( checkKeyIndexes.Add(i); } } + + var cache = InternalCache; var skipKeyIndexes = new HashSet(); if (checkKeys.Any()) { - var objects = _cache.GetMany(checkKeys.ToArray()); + var objects = cache.GetMany(checkKeys.ToArray()); for (var i = 0; i < objects.Length; i++) { if (objects[i] != null) @@ -132,7 +146,7 @@ public bool[] PutMany( putValues[j++] = values[i]; result[i] = true; } - _cache.PutMany(putKeys, putValues); + cache.PutMany(putKeys, putValues); return result; } @@ -145,7 +159,8 @@ public bool Put(CacheKey key, object value, long timestamp, object version, ICom return false; } - if (minimalPut && Cache.Get(key) != null) + var cache = InternalCache; + if (minimalPut && cache.Get(key) != null) { if (log.IsDebugEnabled()) { @@ -157,7 +172,7 @@ public bool Put(CacheKey key, object value, long timestamp, object version, ICom { log.Debug("Caching: {0}", key); } - Cache.Put(key, value); + cache.Put(key, value); return true; } @@ -171,19 +186,22 @@ public void Release(CacheKey key, ISoftLock @lock) public void Clear() { - Cache.Clear(); + InternalCache.Clear(); } public void Remove(CacheKey key) { - Cache.Remove(key); + InternalCache.Remove(key); } public void Destroy() { + if (_isDestroyed) + return; + _isDestroyed = true; // The cache is externally provided and may be shared. Destroying the cache is // not the responsibility of this class. - Cache = null; + _cache = null; } /// diff --git a/src/NHibernate/Cache/ReadWriteCache.cs b/src/NHibernate/Cache/ReadWriteCache.cs index 9bb25e51048..aa6fc8e290e 100644 --- a/src/NHibernate/Cache/ReadWriteCache.cs +++ b/src/NHibernate/Cache/ReadWriteCache.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -35,6 +36,7 @@ public interface ILockable private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(ReadWriteCache)); private CacheBase _cache; + private bool _isDestroyed; private int _nextLockId; private readonly AsyncReaderWriterLock _asyncReaderWriterLock = new AsyncReaderWriterLock(); @@ -43,7 +45,7 @@ public interface ILockable /// public string RegionName { - get { return Cache.RegionName; } + get { return Cache?.RegionName; } } // 6.0 TODO: remove @@ -55,7 +57,18 @@ public ICache Cache set { _cache = value?.AsCacheBase(); } } - // 6.0 TODO: make implicit and switch to auto-property + // 6.0 TODO: Rename to Cache and make public (possible breaking change for reader when null). + private CacheBase InternalCache + { + get + { + if (_cache == null || _isDestroyed) + throw new InvalidOperationException(_isDestroyed ? "The cache has already been destroyed" : "The concrete cache is not defined"); + return _cache; + } + } + + // 6.0 TODO: remove CacheBase IBatchableCacheConcurrencyStrategy.Cache { get => _cache; @@ -96,6 +109,7 @@ private int NextLockId() /// public object Get(CacheKey key, long txTimestamp) { + var cache = InternalCache; using (_asyncReaderWriterLock.ReadLock()) { if (log.IsDebugEnabled()) @@ -107,7 +121,7 @@ public object Get(CacheKey key, long txTimestamp) /*try { cache.Lock( key );*/ - var lockable = (ILockable) Cache.Get(key); + var lockable = (ILockable) cache.Get(key); return GetValue(txTimestamp, key, lockable); /*} finally @@ -123,10 +137,11 @@ public object[] GetMany(CacheKey[] keys, long timestamp) { log.Debug("Cache lookup: {0}", string.Join(",", keys.AsEnumerable())); } + var cache = InternalCache; var result = new object[keys.Length]; using (_asyncReaderWriterLock.ReadLock()) { - var lockables = _cache.GetMany(keys); + var lockables = cache.GetMany(keys); for (var i = 0; i < lockables.Length; i++) { var o = (ILockable) lockables[i]; @@ -167,6 +182,7 @@ private static object GetValue(long timestamp, CacheKey key, ILockable lockable) /// public ISoftLock Lock(CacheKey key, object version) { + var cache = InternalCache; using (_asyncReaderWriterLock.WriteLock()) { if (log.IsDebugEnabled()) @@ -174,20 +190,20 @@ public ISoftLock Lock(CacheKey key, object version) log.Debug("Invalidating: {0}", key); } - var lockValue = _cache.Lock(key); + var lockValue = cache.Lock(key); try { - ILockable lockable = (ILockable) Cache.Get(key); - long timeout = Cache.NextTimestamp() + Cache.Timeout; + ILockable lockable = (ILockable) cache.Get(key); + long timeout = cache.NextTimestamp() + cache.Timeout; CacheLock @lock = lockable == null ? CacheLock.Create(timeout, NextLockId(), version) : lockable.Lock(timeout, NextLockId()); - Cache.Put(key, @lock); + cache.Put(key, @lock); return @lock; } finally { - _cache.Unlock(key, lockValue); + cache.Unlock(key, lockValue); } } } @@ -210,6 +226,7 @@ public bool[] PutMany( return result; } + var cache = InternalCache; using (_asyncReaderWriterLock.WriteLock()) { if (log.IsDebugEnabled()) @@ -217,11 +234,11 @@ public bool[] PutMany( log.Debug("Caching: {0}", string.Join(",", keys.AsEnumerable())); } - var lockValue = _cache.LockMany(keys); + var lockValue = cache.LockMany(keys); try { var putBatch = new Dictionary(); - var lockables = _cache.GetMany(keys); + var lockables = cache.GetMany(keys); for (var i = 0; i < keys.Length; i++) { var key = keys[i]; @@ -231,7 +248,7 @@ public bool[] PutMany( lockable.IsPuttable(timestamp, version, versionComparers[i]); if (puttable) { - putBatch.Add(key, CachedItem.Create(values[i], Cache.NextTimestamp(), version)); + putBatch.Add(key, CachedItem.Create(values[i], cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); @@ -252,12 +269,12 @@ public bool[] PutMany( if (putBatch.Count > 0) { - _cache.PutMany(putBatch.Keys.ToArray(), putBatch.Values.ToArray()); + cache.PutMany(putBatch.Keys.ToArray(), putBatch.Values.ToArray()); } } finally { - _cache.UnlockMany(keys, lockValue); + cache.UnlockMany(keys, lockValue); } } return result; @@ -279,6 +296,7 @@ public bool Put(CacheKey key, object value, long txTimestamp, object version, IC return false; } + var cache = InternalCache; using (_asyncReaderWriterLock.WriteLock()) { if (log.IsDebugEnabled()) @@ -286,17 +304,17 @@ public bool Put(CacheKey key, object value, long txTimestamp, object version, IC log.Debug("Caching: {0}", key); } - var lockValue = _cache.Lock(key); + var lockValue = cache.Lock(key); try { - ILockable lockable = (ILockable) Cache.Get(key); + ILockable lockable = (ILockable) cache.Get(key); bool puttable = lockable == null || lockable.IsPuttable(txTimestamp, version, versionComparator); if (puttable) { - Cache.Put(key, CachedItem.Create(value, Cache.NextTimestamp(), version)); + cache.Put(key, CachedItem.Create(value, cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Cached: {0}", key); @@ -314,7 +332,7 @@ public bool Put(CacheKey key, object value, long txTimestamp, object version, IC } finally { - _cache.Unlock(key, lockValue); + cache.Unlock(key, lockValue); } } } @@ -325,12 +343,14 @@ public bool Put(CacheKey key, object value, long txTimestamp, object version, IC private void DecrementLock(object key, CacheLock @lock) { //decrement the lock - @lock.Unlock(Cache.NextTimestamp()); - Cache.Put(key, @lock); + var cache = InternalCache; + @lock.Unlock(cache.NextTimestamp()); + cache.Put(key, @lock); } public void Release(CacheKey key, ISoftLock clientLock) { + var cache = InternalCache; using (_asyncReaderWriterLock.WriteLock()) { if (log.IsDebugEnabled()) @@ -338,10 +358,10 @@ public void Release(CacheKey key, ISoftLock clientLock) log.Debug("Releasing: {0}", key); } - var lockValue = _cache.Lock(key); + var lockValue = cache.Lock(key); try { - ILockable lockable = (ILockable) Cache.Get(key); + ILockable lockable = (ILockable) cache.Get(key); if (IsUnlockable(clientLock, lockable)) { DecrementLock(key, (CacheLock) lockable); @@ -353,7 +373,7 @@ public void Release(CacheKey key, ISoftLock clientLock) } finally { - _cache.Unlock(key, lockValue); + cache.Unlock(key, lockValue); } } } @@ -361,28 +381,32 @@ public void Release(CacheKey key, ISoftLock clientLock) internal void HandleLockExpiry(object key) { log.Warn("An item was expired by the cache while it was locked (increase your cache timeout): {0}", key); - long ts = Cache.NextTimestamp() + Cache.Timeout; + var cache = InternalCache; + long ts = cache.NextTimestamp() + cache.Timeout; // create new lock that times out immediately CacheLock @lock = CacheLock.Create(ts, NextLockId(), null); @lock.Unlock(ts); - Cache.Put(key, @lock); + cache.Put(key, @lock); } public void Clear() { - Cache.Clear(); + InternalCache.Clear(); } public void Remove(CacheKey key) { - Cache.Remove(key); + InternalCache.Remove(key); } public void Destroy() { + if (_isDestroyed) + return; + _isDestroyed = true; // The cache is externally provided and may be shared. Destroying the cache is // not the responsibility of this class. - Cache = null; + _cache = null; _asyncReaderWriterLock.Dispose(); } @@ -392,6 +416,7 @@ public void Destroy() /// public bool AfterUpdate(CacheKey key, object value, object version, ISoftLock clientLock) { + var cache = InternalCache; using (_asyncReaderWriterLock.WriteLock()) { if (log.IsDebugEnabled()) @@ -399,10 +424,10 @@ public bool AfterUpdate(CacheKey key, object value, object version, ISoftLock cl log.Debug("Updating: {0}", key); } - var lockValue = _cache.Lock(key); + var lockValue = cache.Lock(key); try { - ILockable lockable = (ILockable) Cache.Get(key); + ILockable lockable = (ILockable) cache.Get(key); if (IsUnlockable(clientLock, lockable)) { CacheLock @lock = (CacheLock) lockable; @@ -415,7 +440,7 @@ public bool AfterUpdate(CacheKey key, object value, object version, ISoftLock cl else { //recache the updated state - Cache.Put(key, CachedItem.Create(value, Cache.NextTimestamp(), version)); + cache.Put(key, CachedItem.Create(value, cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Updated: {0}", key); @@ -431,13 +456,14 @@ public bool AfterUpdate(CacheKey key, object value, object version, ISoftLock cl } finally { - _cache.Unlock(key, lockValue); + cache.Unlock(key, lockValue); } } } public bool AfterInsert(CacheKey key, object value, object version) { + var cache = InternalCache; using (_asyncReaderWriterLock.WriteLock()) { if (log.IsDebugEnabled()) @@ -445,13 +471,13 @@ public bool AfterInsert(CacheKey key, object value, object version) log.Debug("Inserting: {0}", key); } - var lockValue = _cache.Lock(key); + var lockValue = cache.Lock(key); try { - ILockable lockable = (ILockable) Cache.Get(key); + ILockable lockable = (ILockable) cache.Get(key); if (lockable == null) { - Cache.Put(key, CachedItem.Create(value, Cache.NextTimestamp(), version)); + cache.Put(key, CachedItem.Create(value, cache.NextTimestamp(), version)); if (log.IsDebugEnabled()) { log.Debug("Inserted: {0}", key); @@ -465,7 +491,7 @@ public bool AfterInsert(CacheKey key, object value, object version) } finally { - _cache.Unlock(key, lockValue); + cache.Unlock(key, lockValue); } } }