Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8fa038c
Added Redis cache provider
maca88 Jun 15, 2018
fe9b9e0
Added cancellation tokens to the missing AbstractRegionStrategy members
maca88 Jun 19, 2018
a0f070b
Used IObjectsFactory for creating type instances.
maca88 Jun 19, 2018
97238c4
Fixed typos
maca88 Jun 19, 2018
e61468a
Added a retry policy used for locking
maca88 Jun 21, 2018
d8f8102
Moved lua scripts to embedded resources
maca88 Jun 21, 2018
c0cc960
Added serialization tests for NHibernate types
maca88 Jun 22, 2018
feeb44c
Updated Appveyor for running redis tests
maca88 Jun 23, 2018
c6642a4
Added a configuration option to control the appending of the hash cod…
maca88 Jun 23, 2018
20da5f8
Added test for concurrent locking
maca88 Jun 23, 2018
2350ae7
Added performance tests
maca88 Jun 23, 2018
e6653bb
Disabled using hash codes in cache keys by default
maca88 Jun 24, 2018
b05fba4
Renamed UseHashCode option to AppendHashcode to align with CoreDistri…
maca88 Jul 7, 2018
2c4cafa
Updated the IRedisSerializer methods to be easier replaced with Cache…
maca88 Jul 7, 2018
1fd0a3b
Added logging to region strategies
maca88 Jul 7, 2018
91669a9
Removed the dictionary of locked keys as it will not be needed with N…
maca88 Jul 7, 2018
54371f2
Added the ability to provide a custom IDatabase and IConnectionMultip…
maca88 Jul 7, 2018
a6b7851
Added the ability to set the default configuration options by a stati…
maca88 Jul 11, 2018
832b216
Update to NH5.2
fredericDelaporte Dec 5, 2018
094256d
Implemented TODOs
maca88 Dec 8, 2018
644dedd
Updated StackExchange.Redis package to version 2
maca88 Dec 8, 2018
4db42a5
Renamed project to NHibernate.Caches.StackExchangeRedis
maca88 Dec 8, 2018
2fb32ab
Replaced project name in missed files and added a build file
maca88 Dec 8, 2018
d361edf
Clean RemoveMany remnants
fredericDelaporte Dec 9, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions AsyncGenerator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,65 @@
registerPlugin:
- type: AsyncGenerator.Core.Plugins.EmptyRegionRemover
assemblyName: AsyncGenerator.Core
- filePath: StackExRedis\NHibernate.Caches.StackExRedis\NHibernate.Caches.StackExRedis.csproj
targetFramework: net461
concurrentRun: true
applyChanges: true
analyzation:
methodConversion:
- conversion: Ignore
hasAttributeName: ObsoleteAttribute
- conversion: Smart
containingTypeName: AbstractRegionStrategy
- conversion: Smart
containingTypeName: RedisKeyLocker
callForwarding: true
cancellationTokens:
guards: true
methodParameter:
- parameter: Required
requiresCancellationToken:
- containingType: NHibernate.Caches.StackExRedis.RedisCache
name: GetMany
- containingType: NHibernate.Caches.StackExRedis.RedisCache
name: PutMany
- containingType: NHibernate.Caches.StackExRedis.RedisCache
name: RemoveMany
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: Get
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: GetMany
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: Put
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: PutMany
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: Remove
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: RemoveMany
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: Unlock
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: UnlockMany
- containingType: NHibernate.Caches.StackExRedis.AbstractRegionStrategy
name: Clear
- containingType: NHibernate.Caches.StackExRedis.RedisKeyLocker
name: Unlock
- containingType: NHibernate.Caches.StackExRedis.RedisKeyLocker
name: UnlockMany
scanMethodBody: true
searchAsyncCounterpartsInInheritedTypes: true
scanForMissingAsyncMembers:
- all: true
transformation:
configureAwaitArgument: false
localFunctions: true
asyncLock:
type: NHibernate.Util.AsyncLock
methodName: LockAsync
registerPlugin:
- type: AsyncGenerator.Core.Plugins.EmptyRegionRemover
assemblyName: AsyncGenerator.Core
- filePath: NHibernate.Caches.Common.Tests\NHibernate.Caches.Common.Tests.csproj
targetFramework: net461
concurrentRun: true
Expand Down Expand Up @@ -356,6 +415,54 @@
registerPlugin:
- type: AsyncGenerator.Core.Plugins.NUnitAsyncCounterpartsFinder
assemblyName: AsyncGenerator.Core
- filePath: StackExRedis\NHibernate.Caches.StackExRedis.Tests\NHibernate.Caches.StackExRedis.Tests.csproj
targetFramework: net461
concurrentRun: true
applyChanges: true
analyzation:
methodConversion:
- conversion: Ignore
hasAttributeName: OneTimeSetUpAttribute
- conversion: Ignore
hasAttributeName: OneTimeTearDownAttribute
- conversion: Ignore
hasAttributeName: SetUpAttribute
- conversion: Ignore
hasAttributeName: TearDownAttribute
- conversion: Smart
hasAttributeName: TestAttribute
- conversion: Smart
hasAttributeName: TheoryAttribute
preserveReturnType:
- hasAttributeName: TestAttribute
- hasAttributeName: TheoryAttribute
typeConversion:
- conversion: Ignore
hasAttributeName: IgnoreAttribute
- conversion: Partial
hasAttributeName: TestFixtureAttribute
- conversion: Partial
anyBaseTypeRule: HasTestFixtureAttribute
ignoreSearchForMethodReferences:
- hasAttributeName: TheoryAttribute
- hasAttributeName: TestAttribute
cancellationTokens:
withoutCancellationToken:
- hasAttributeName: TestAttribute
- hasAttributeName: TheoryAttribute
exceptionHandling:
catchMethodBody:
- all: true
result: false
ignoreSearchForAsyncCounterparts:
- name: Disassemble
scanMethodBody: true
searchAsyncCounterpartsInInheritedTypes: true
scanForMissingAsyncMembers:
- all: true
registerPlugin:
- type: AsyncGenerator.Core.Plugins.NUnitAsyncCounterpartsFinder
assemblyName: AsyncGenerator.Core
- filePath: SysCache\NHibernate.Caches.SysCache.Tests\NHibernate.Caches.SysCache.Tests.csproj
targetFramework: net461
concurrentRun: true
Expand Down
189 changes: 189 additions & 0 deletions NHibernate.Caches.Common.Tests/Async/CacheFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using NHibernate.Cache;
using NUnit.Framework;
Expand Down Expand Up @@ -61,6 +62,63 @@ public async Task TestRemoveAsync()
Assert.That(item, Is.Null, "item still exists in cache after remove");
}

[Test]
public async Task TestLockUnlockAsync()
{
if (!SupportsLocking)
Assert.Ignore("Test not supported by provider");

const string key = "keyTestLock";
const string value = "valueLock";

var cache = GetDefaultCache();

// add the item
await (cache.PutAsync(key, value, CancellationToken.None));

await (cache.LockAsync(key, CancellationToken.None));
Assert.ThrowsAsync<CacheException>(() => cache.LockAsync(key, CancellationToken.None));

await (Task.Delay(cache.Timeout / Timestamper.OneMs));

for (var i = 0; i < 2; i++)
{
var lockValue = await (cache.LockAsync(key, CancellationToken.None));
await (cache.UnlockAsync(key, lockValue, CancellationToken.None));
}
}

[Test]
public async Task TestConcurrentLockUnlockAsync()
{
if (!SupportsLocking)
Assert.Ignore("Test not supported by provider");

const string value = "value";
const string key = "keyToLock";

var cache = GetDefaultCache();

await (cache.PutAsync(key, value, CancellationToken.None));
Assert.That(await (cache.GetAsync(key, CancellationToken.None)), Is.EqualTo(value), "Unable to retrieved cached object for key");

// Simulate NHibernate ReadWriteCache behavior with multiple concurrent threads
// Thread 1
var lockValue = await (cache.LockAsync(key, CancellationToken.None));
// Thread 2
Assert.ThrowsAsync<CacheException>(() => cache.LockAsync(key, CancellationToken.None), "The key should be locked");
// Thread 3
Assert.ThrowsAsync<CacheException>(() => cache.LockAsync(key, CancellationToken.None), "The key should still be locked");

// Thread 1
await (cache.UnlockAsync(key, lockValue, CancellationToken.None));

Assert.DoesNotThrowAsync(async () => lockValue = await (cache.LockAsync(key, CancellationToken.None)), "The key should be unlocked");
await (cache.UnlockAsync(key, lockValue, CancellationToken.None));

await (cache.RemoveAsync(key, CancellationToken.None));
}

[Test]
public async Task TestClearAsync()
{
Expand Down Expand Up @@ -134,6 +192,137 @@ public async Task TestRegionsAsync()
Assert.That(get2, Is.EqualTo(s2), "Unexpected value in cache2");
}

[Test]
public async Task TestPutManyAsync()
{
var keys = new object[10];
var values = new object[10];
for (var i = 0; i < keys.Length; i++)
{
keys[i] = $"keyTestPut{i}";
values[i] = $"valuePut{i}";
}

var cache = GetDefaultCache();
// Due to async version, it may already be there.
foreach (var key in keys)
await (cache.RemoveAsync(key, CancellationToken.None));

Assert.That(await (cache.GetManyAsync(keys, CancellationToken.None)), Is.EquivalentTo(new object[10]), "cache returned items we didn't add !?!");

await (cache.PutManyAsync(keys, values, CancellationToken.None));
var items = await (cache.GetManyAsync(keys, CancellationToken.None));

for (var i = 0; i < items.Length; i++)
{
var item = items[i];
Assert.That(item, Is.Not.Null, "unable to retrieve cached item");
Assert.That(item, Is.EqualTo(values[i]), "didn't return the item we added");
}
}

[Test]
public async Task TestRemoveManyAsync()
{
var keys = new object[10];
var values = new object[10];
for (var i = 0; i < keys.Length; i++)
{
keys[i] = $"keyTestRemove{i}";
values[i] = $"valueRemove{i}";
}

var cache = GetDefaultCache();

// add the item
await (cache.PutManyAsync(keys, values, CancellationToken.None));

// make sure it's there
var items = await (cache.GetManyAsync(keys, CancellationToken.None));
Assert.That(items, Is.EquivalentTo(values), "items just added are not there");

// remove it
foreach (var key in keys)
await (cache.RemoveAsync(key, CancellationToken.None));

// make sure it's not there
items = await (cache.GetManyAsync(keys, CancellationToken.None));
Assert.That(items, Is.EquivalentTo(new object[10]), "items still exists in cache after remove");
}

[Test]
public async Task TestLockUnlockManyAsync()
{
if (!SupportsLocking)
Assert.Ignore("Test not supported by provider");

var keys = new object[10];
var values = new object[10];
for (var i = 0; i < keys.Length; i++)
{
keys[i] = $"keyTestLock{i}";
values[i] = $"valueLock{i}";
}

var cache = GetDefaultCache();

// add the item
await (cache.PutManyAsync(keys, values, CancellationToken.None));
await (cache.LockManyAsync(keys, CancellationToken.None));
Assert.ThrowsAsync<CacheException>(() => cache.LockManyAsync(keys, CancellationToken.None), "all items should be locked");

await (Task.Delay(cache.Timeout / Timestamper.OneMs));

for (var i = 0; i < 2; i++)
{
Assert.DoesNotThrowAsync(async () =>
{
await (cache.UnlockManyAsync(keys, await (cache.LockManyAsync(keys, CancellationToken.None)), CancellationToken.None));
}, "the items should be unlocked");
}

// Test partial locks by locking the first 5 keys and afterwards try to lock last 6 keys.
var lockValue = await (cache.LockManyAsync(keys.Take(5).ToArray(), CancellationToken.None));

Assert.ThrowsAsync<CacheException>(() => cache.LockManyAsync(keys.Skip(4).ToArray(), CancellationToken.None), "the fifth key should be locked");

Assert.DoesNotThrowAsync(async () =>
{
await (cache.UnlockManyAsync(keys, await (cache.LockManyAsync(keys.Skip(5).ToArray(), CancellationToken.None)), CancellationToken.None));
}, "the last 5 keys should not be locked.");

// Unlock the first 5 keys
await (cache.UnlockManyAsync(keys, lockValue, CancellationToken.None));

Assert.DoesNotThrowAsync(async () =>
{
lockValue = await (cache.LockManyAsync(keys, CancellationToken.None));
await (cache.UnlockManyAsync(keys, lockValue, CancellationToken.None));
}, "the first 5 keys should not be locked.");
}

[Test]
public void TestNullKeyPutManyAsync()
{
var cache = GetDefaultCache();
Assert.ThrowsAsync<ArgumentNullException>(() => cache.PutManyAsync(null, null, CancellationToken.None));
}

[Test]
public void TestNullValuePutManyAsync()
{
var cache = GetDefaultCache();
Assert.ThrowsAsync<ArgumentNullException>(() => cache.PutManyAsync(new object[] { "keyTestNullValuePut" }, null, CancellationToken.None));
}

[Test]
public async Task TestNullKeyGetManyAsync()
{
var cache = GetDefaultCache();
await (cache.PutAsync("keyTestNullKeyGet", "value", CancellationToken.None));
Assert.ThrowsAsync<ArgumentNullException>(() => cache.GetManyAsync(null, CancellationToken.None));
}

[Test]
public async Task TestNonEqualObjectsWithEqualHashCodeAndToStringAsync()
{
Expand Down
Loading