Browse Source

Merge pull request #24736 from abpframework/auto-merge/rel-10-1/4317

Merge branch dev with rel-10.1
pull/24740/head
Ma Liming 2 weeks ago
committed by GitHub
parent
commit
ba839446f1
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 64
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
  2. 69
      framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs

64
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs

@ -19,7 +19,7 @@ namespace Volo.Abp.Caching;
/// Represents a distributed cache of <typeparamref name="TCacheItem" /> type.
/// </summary>
/// <typeparam name="TCacheItem">The type of cache item being cached.</typeparam>
public class DistributedCache<TCacheItem> :
public class DistributedCache<TCacheItem> :
IDistributedCache<TCacheItem>
where TCacheItem : class
{
@ -683,35 +683,30 @@ public class DistributedCache<TCacheItem, TCacheKey> : IDistributedCache<TCacheI
result = cachedValues.Concat(ToCacheItems(cachedBytes, readKeys)).ToArray();
}
if (result.All(x => x.Value != null))
{
return result!;
}
var resultMap = result
.Where(x => x.Value != null)
.ToDictionary(x => x.Key, x => x.Value);
var missingKeys = new List<TCacheKey>();
var missingValuesIndex = new List<int>();
for (var i = 0; i < keyArray.Length; i++)
if (resultMap.Count == keyArray.Length)
{
if (result[i].Value != null)
{
continue;
}
missingKeys.Add(keyArray[i]);
missingValuesIndex.Add(i);
return keyArray
.Select(key => new KeyValuePair<TCacheKey, TCacheItem?>(key, resultMap[key]))
.ToArray();
}
var missingKeys = keyArray.Where(key => !resultMap.ContainsKey(key)).ToList();
var missingValues = factory.Invoke(missingKeys).ToArray();
var valueQueue = new Queue<KeyValuePair<TCacheKey, TCacheItem>>(missingValues);
SetMany(missingValues, optionsFactory?.Invoke(), hideErrors, considerUow);
foreach (var index in missingValuesIndex)
foreach (var pair in missingValues)
{
result[index] = valueQueue.Dequeue()!;
resultMap[pair.Key] = pair.Value;
}
return result;
return keyArray
.Select(key => new KeyValuePair<TCacheKey, TCacheItem?>(key, resultMap.GetOrDefault(key)))
.ToArray();
}
@ -779,35 +774,30 @@ public class DistributedCache<TCacheItem, TCacheKey> : IDistributedCache<TCacheI
result = cachedValues.Concat(ToCacheItems(cachedBytes, readKeys)).ToArray();
}
if (result.All(x => x.Value != null))
{
return result;
}
var resultMap = result
.Where(x => x.Value != null)
.ToDictionary(x => x.Key, x => x.Value);
var missingKeys = new List<TCacheKey>();
var missingValuesIndex = new List<int>();
for (var i = 0; i < keyArray.Length; i++)
if (resultMap.Count == keyArray.Length)
{
if (result[i].Value != null)
{
continue;
}
missingKeys.Add(keyArray[i]);
missingValuesIndex.Add(i);
return keyArray
.Select(key => new KeyValuePair<TCacheKey, TCacheItem?>(key, resultMap[key]))
.ToArray();
}
var missingKeys = keyArray.Where(key => !resultMap.ContainsKey(key)).ToList();
var missingValues = (await factory.Invoke(missingKeys)).ToArray();
var valueQueue = new Queue<KeyValuePair<TCacheKey, TCacheItem>>(missingValues);
await SetManyAsync(missingValues, optionsFactory?.Invoke(), hideErrors, considerUow, token);
foreach (var index in missingValuesIndex)
foreach (var pair in missingValues)
{
result[index] = valueQueue.Dequeue()!;
resultMap[pair.Key] = pair.Value;
}
return result;
return keyArray
.Select(key => new KeyValuePair<TCacheKey, TCacheItem?>(key, resultMap.GetOrDefault(key)))
.ToArray();
}
/// <summary>

69
framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Testing;
@ -751,6 +752,74 @@ public class DistributedCache_Tests : AbpIntegratedTest<AbpCachingTestModule>
cacheValue[1].Value.Name.ShouldBe("jack");
}
[Fact]
public async Task GetOrAddManyAsync_Should_Return_Values_By_Key_With_Uow()
{
var key1 = "testkey";
var key2 = "testkey2";
var keys = new[] { key1, key2 };
using (GetRequiredService<IUnitOfWorkManager>().Begin())
{
var personCache = GetRequiredService<IDistributedCache<PersonCacheItem>>();
await personCache.SetAsync(key2, new PersonCacheItem("cached"), considerUow: true);
var result = await personCache.GetOrAddManyAsync(keys, missingKeys =>
{
missingKeys.ToArray().ShouldBe(new[] { key1 });
return Task.FromResult(new List<KeyValuePair<string, PersonCacheItem>>
{
new(key1, new PersonCacheItem("factory"))
});
}, considerUow: true);
result.Length.ShouldBe(2);
result[0].Key.ShouldBe(key1);
result[0].Value.ShouldNotBeNull();
result[0].Value.Name.ShouldBe("factory");
result[1].Key.ShouldBe(key2);
result[1].Value.ShouldNotBeNull();
result[1].Value.Name.ShouldBe("cached");
}
}
[Fact]
public async Task GetOrAddManyAsync_Should_Map_By_Key_Under_Concurrency()
{
var key1 = "testkey";
var key2 = "testkey2";
var keys = new[] { key1, key2 };
var personCache = GetRequiredService<IDistributedCache<PersonCacheItem>>();
async Task<List<KeyValuePair<string, PersonCacheItem>>> Factory(IEnumerable<string> missingKeys)
{
await Task.Yield();
return missingKeys
.Reverse()
.Select(x => new KeyValuePair<string, PersonCacheItem>(x, new PersonCacheItem(x == key1 ? "v1" : "v2")))
.ToList();
}
var task1 = personCache.GetOrAddManyAsync(keys, Factory);
var task2 = personCache.GetOrAddManyAsync(keys, Factory);
var results = await Task.WhenAll(task1, task2);
foreach (var result in results)
{
result.Length.ShouldBe(2);
result[0].Key.ShouldBe(key1);
result[0].Value!.Name.ShouldBe("v1");
result[1].Key.ShouldBe(key2);
result[1].Value!.Name.ShouldBe("v2");
}
}
[Fact]
public async Task Cache_Should_Only_Available_In_Uow_For_GetOrAddManyAsync()
{

Loading…
Cancel
Save