Skip to content

Commit

Permalink
Merge pull request #3629 from rockfordlhotka/3395-tests
Browse files Browse the repository at this point in the history
Enhancements to data portal cache
  • Loading branch information
rockfordlhotka authored Dec 21, 2023
2 parents 328cd90 + 7b13493 commit eb5cdfa
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 18 deletions.
32 changes: 24 additions & 8 deletions Source/Csla/DataPortalClient/DataPortalCacheDefault.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// <summary>Null implementation of a client-side cache service</summary>
//-----------------------------------------------------------------------
using System;
using System.Threading;
using System.Threading.Tasks;
using Csla.Server;

Expand All @@ -16,6 +17,15 @@ namespace Csla.DataPortalClient
/// </summary>
public class DataPortalCacheDefault : IDataPortalCache
{
/// <summary>
/// Gets a semaphore used by the data portal to only allow a single
/// consumer/thread to get/add an item to the cache at a time.
/// </summary>
/// <remarks>
/// This semaphore must be a `new SemaphoreSlim(1)`
/// </remarks>
public SemaphoreSlim Semaphore => throw new NotImplementedException();

/// <summary>
/// Always returns success, does not cache values.
/// </summary>
Expand All @@ -24,10 +34,19 @@ public class DataPortalCacheDefault : IDataPortalCache
/// <param name="operation">Data portal operation</param>
/// <param name="result">Data portal result to cache</param>
/// <returns></returns>
public Task AddObject(Type objectType, object criteria, DataPortalOperations operation, DataPortalResult result)
{
return Task.CompletedTask;
}
public Task AddObject(Type objectType, object criteria, DataPortalOperations operation, DataPortalResult result)
=> throw new NotImplementedException();

/// <summary>
/// Gets a value indicating whether the domain type
/// can be cached.
/// </summary>
/// <param name="objectType">Type of domain object to add</param>
/// <param name="criteria">Criteria for domain type being added</param>
/// <param name="operation">Data portal operation</param>
/// <returns></returns>
public bool IsCacheable(Type objectType, object criteria, DataPortalOperations operation)
=> false;

/// <summary>
/// Always returns false, does not retrieve values from cache.
Expand All @@ -38,9 +57,6 @@ public Task AddObject(Type objectType, object criteria, DataPortalOperations ope
/// <param name="result">Cached data portal result</param>
/// <returns>true if success, false if object isn't returned</returns>
public Task<bool> TryGetObject(Type objectType, object criteria, DataPortalOperations operation, out DataPortalResult result)
{
result = null;
return Task.FromResult(false);
}
=> throw new NotImplementedException();
}
}
18 changes: 18 additions & 0 deletions Source/Csla/DataPortalClient/IDataPortalCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// <summary>Defines interface for a client-side cache service</summary>
//-----------------------------------------------------------------------
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Csla.DataPortalClient
Expand Down Expand Up @@ -35,5 +36,22 @@ public interface IDataPortalCache
/// <param name="result">Data portal result to cache</param>
/// <returns></returns>
Task AddObject(Type objectType, object criteria, DataPortalOperations operation, Server.DataPortalResult result);
/// <summary>
/// Gets a value indicating whether the domain type
/// can be cached.
/// </summary>
/// <param name="objectType">Type of domain object to add</param>
/// <param name="criteria">Criteria for domain type being added</param>
/// <param name="operation">Data portal operation</param>
/// <returns></returns>
bool IsCacheable(Type objectType, object criteria, DataPortalOperations operation);
/// <summary>
/// Gets a semaphore used by the data portal to only allow a single
/// consumer/thread to get/add an item to the cache at a time.
/// </summary>
/// <remarks>
/// This semaphore must be a `new SemaphoreSlim(1)`
/// </remarks>
SemaphoreSlim Semaphore { get; }
}
}
98 changes: 88 additions & 10 deletions Source/Csla/DataPortalT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Csla.DataPortalClient;
using Csla.Properties;
Expand Down Expand Up @@ -41,8 +42,10 @@ public DataPortal(ApplicationContext applicationContext, IDataPortalProxy proxy,
/// </summary>
private ApplicationContext ApplicationContext { get; set; }
private DataPortalClient.IDataPortalProxy DataPortalProxy { get; set; }

private IDataPortalCache Cache { get; set; }


private class DataPortalAsyncRequest
{
private ApplicationContext ApplicationContext { get; set; }
Expand Down Expand Up @@ -115,10 +118,25 @@ private async Task<object> DoCreateAsync(Type objectType, object criteria, bool

try
{
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Create, out result))
if (Cache.IsCacheable(objectType, criteria, DataPortalOperations.Create))
{
try
{
await Cache.Semaphore.WaitAsync();
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Create, out result))
{
result = await proxy.Create(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Create, result);
}
}
finally
{
Cache.Semaphore.Release();
}
}
else
{
result = await proxy.Create(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Create, result);
}
}
catch (AggregateException ex)
Expand Down Expand Up @@ -220,10 +238,25 @@ private async Task<object> DoFetchAsync(Type objectType, object criteria, bool i

try
{
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Fetch, out result))
if (Cache.IsCacheable(objectType, criteria, DataPortalOperations.Fetch))
{
try
{
await Cache.Semaphore.WaitAsync();
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Fetch, out result))
{
result = await proxy.Fetch(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Fetch, result);
}
}
finally
{
Cache.Semaphore.Release();
}
}
else
{
result = await proxy.Fetch(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Fetch, result);
}
}
catch (AggregateException ex)
Expand Down Expand Up @@ -269,10 +302,25 @@ private async Task<object> DoExecuteAsync(Type objectType, object criteria, bool

try
{
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Execute, out result))
if (Cache.IsCacheable(objectType, criteria, DataPortalOperations.Execute))
{
try
{
await Cache.Semaphore.WaitAsync();
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Execute, out result))
{
result = await proxy.Fetch(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Execute, result);
}
}
finally
{
Cache.Semaphore.Release();
}
}
else
{
result = await proxy.Fetch(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Execute, result);
}
}
catch (AggregateException ex)
Expand Down Expand Up @@ -487,10 +535,25 @@ internal async Task<T> DoUpdateAsync(T obj, bool isSync)
if (obj is ICloneable cloneable)
obj = (T)cloneable.Clone();
}
if (!await Cache.TryGetObject(objectType, obj, operation, out result))
if (Cache.IsCacheable(objectType, obj, operation))
{
try
{
await Cache.Semaphore.WaitAsync();
if (!await Cache.TryGetObject(objectType, obj, operation, out result))
{
result = await proxy.Update(obj, dpContext, isSync);
await Cache.AddObject(objectType, obj, operation, result);
}
}
finally
{
Cache.Semaphore.Release();
}
}
else
{
result = await proxy.Update(obj, dpContext, isSync);
await Cache.AddObject(objectType, obj, operation, result);
}
}
catch (AggregateException ex)
Expand Down Expand Up @@ -580,10 +643,25 @@ internal async Task DoDeleteAsync(Type objectType, object criteria, bool isSync)

try
{
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Delete, out result))
if (Cache.IsCacheable(objectType, criteria, DataPortalOperations.Delete))
{
try
{
await Cache.Semaphore.WaitAsync();
if (!await Cache.TryGetObject(objectType, criteria, DataPortalOperations.Delete, out result))
{
result = await proxy.Delete(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Delete, result);
}
}
finally
{
Cache.Semaphore.Release();
}
}
else
{
result = await proxy.Delete(objectType, criteria, dpContext, isSync);
await Cache.AddObject(objectType, criteria, DataPortalOperations.Delete, result);
}
}
catch (AggregateException ex)
Expand Down

0 comments on commit eb5cdfa

Please sign in to comment.