Skip to content

Commit 478ca95

Browse files
authored
Merge pull request #56 from solidify-project/feature/lazy-cache-mutex
Feature/lazy cache mutex
2 parents d79272f + 67d8b04 commit 478ca95

8 files changed

Lines changed: 84 additions & 12 deletions

File tree

src/SolidifyProject.Engine.Services/ContentReaderService/FileSystemBinaryContentReaderService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public FileSystemBinaryContentReaderService(string root)
1111
{
1212
}
1313

14-
public override async Task<T> LoadContentByIdAsync(string id)
14+
protected override async Task<T> LoadContentByIdAsyncInternal(string id)
1515
{
1616
var path = Path.Combine(_root, id);
1717

src/SolidifyProject.Engine.Services/ContentReaderService/FileSystemTextContentReaderService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public FileSystemTextContentReaderService(string root)
1111
{
1212
}
1313

14-
public override async Task<T> LoadContentByIdAsync(string id)
14+
protected override async Task<T> LoadContentByIdAsyncInternal(string id)
1515
{
1616
var path = Path.Combine(_root, id);
1717

src/SolidifyProject.Engine.Services/ContentReaderService/_FileSystemContentReaderServiceBase.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace SolidifyProject.Engine.Services.ContentReaderService
99
{
10-
public abstract class _FileSystemContentReaderServiceBase<T> : IContentReaderService<T> where T : class
10+
public abstract class _FileSystemContentReaderServiceBase<T> : _FileSystemContentServiceBase, IContentReaderService<T> where T : class
1111
{
1212
public readonly string[] IGNORED_FILES = {"README.md", ".DS_Store"};
1313
protected readonly string _root;
@@ -53,6 +53,20 @@ public async Task<IEnumerable<string>> LoadContentsIdsAsync(bool includeIgnored
5353
/// </summary>
5454
/// <param name="id"></param>
5555
/// <returns>File content or null, if file wasn't found.</returns>
56-
public abstract Task<T> LoadContentByIdAsync(string id);
56+
public async Task<T> LoadContentByIdAsync(string id)
57+
{
58+
LockFileByKey(id);
59+
60+
try
61+
{
62+
return await LoadContentByIdAsyncInternal(id);
63+
}
64+
finally
65+
{
66+
ReleaseFileByKey(id);
67+
}
68+
}
69+
70+
protected abstract Task<T> LoadContentByIdAsyncInternal(string id);
5771
}
5872
}

src/SolidifyProject.Engine.Services/ContentWriterService/FileSystemBinaryContentWriterService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public FileSystemBinaryContentWriterService(string root)
1111
{
1212
}
1313

14-
public override async Task SaveContentAsync(string id, T content)
14+
protected override async Task SaveContentAsyncInternal(string id, T content)
1515
{
1616
var path = Path.Combine(_root, id);
1717
EnsureDirectoryExists(path);

src/SolidifyProject.Engine.Services/ContentWriterService/FileSystemTextContentWriterService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public FileSystemTextContentWriterService(string root)
1111
{
1212
}
1313

14-
public override async Task SaveContentAsync(string id, T content)
14+
protected override async Task SaveContentAsyncInternal(string id, T content)
1515
{
1616
var path = Path.Combine(_root, id);
1717
EnsureDirectoryExists(path);

src/SolidifyProject.Engine.Services/ContentWriterService/_FileSystemContentWriterServiceBase.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
using System.IO;
1+
using System;
2+
using System.IO;
23
using System.Threading.Tasks;
34
using SolidifyProject.Engine.Infrastructure.Interfaces;
45

56
namespace SolidifyProject.Engine.Services.ContentWriterService
67
{
7-
public abstract class _FileSystemContentWriterServiceBase<T> : IContentWriterService<T> where T : class
8+
public abstract class _FileSystemContentWriterServiceBase<T> : _FileSystemContentServiceBase, IContentWriterService<T> where T : class
89
{
910
protected readonly string _root;
1011

@@ -43,6 +44,20 @@ public Task CleanFolderAsync(string path)
4344
return Task.CompletedTask;
4445
}
4546

46-
public abstract Task SaveContentAsync(string id, T content);
47+
public async Task SaveContentAsync(string id, T content)
48+
{
49+
LockFileByKey(id);
50+
51+
try
52+
{
53+
await SaveContentAsyncInternal(id, content);
54+
}
55+
finally
56+
{
57+
ReleaseFileByKey(id);
58+
}
59+
}
60+
61+
protected abstract Task SaveContentAsyncInternal(string id, T content);
4762
}
4863
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Collections.Concurrent;
2+
using System.Threading;
3+
4+
namespace SolidifyProject.Engine.Services
5+
{
6+
public abstract class _FileSystemContentServiceBase
7+
{
8+
private static readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new ConcurrentDictionary<string, SemaphoreSlim>();
9+
10+
protected _FileSystemContentServiceBase(string root = null)
11+
{
12+
}
13+
14+
protected void LockFileByKey(string key)
15+
{
16+
var fileLock = _getLockByKey(key);
17+
fileLock.Wait();
18+
}
19+
20+
protected void ReleaseFileByKey(string key)
21+
{
22+
var fileLock = _getLockByKey(key);
23+
fileLock.Release();
24+
}
25+
26+
private static SemaphoreSlim _getLockByKey(string key)
27+
{
28+
SemaphoreSlim result;
29+
if (_semaphores.TryGetValue(key, out result))
30+
{
31+
return result;
32+
}
33+
34+
result = new SemaphoreSlim(1, 1);
35+
if (_semaphores.TryAdd(key, result))
36+
{
37+
return result;
38+
}
39+
40+
return _getLockByKey(key);
41+
}
42+
}
43+
}

src/SolidifyProject.Engine.Utils/Cache/LazyCache.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public sealed class LazyCache<T> where T : class
1111
private readonly LoadToCacheAsyncDelegate _loadToCache;
1212

1313
private readonly ConcurrentDictionary<string, Lazy<Task<T>>> _cache= new ConcurrentDictionary<string, Lazy<Task<T>>>();
14-
14+
1515
public LazyCache(LoadToCacheAsyncDelegate loadToCache)
1616
{
1717
_loadToCache = loadToCache;
@@ -23,9 +23,9 @@ public async Task<T> GetFromCacheAsync(string key)
2323
{
2424
return await result.Value.ConfigureAwait(false);
2525
}
26-
27-
result = new Lazy<Task<T>>(() => _loadToCache(key));
2826

27+
result = new Lazy<Task<T>>(() => _loadToCache(key));
28+
2929
_cache.AddOrUpdate(key, result, (k, r) => result);
3030

3131
return await GetFromCacheAsync(key).ConfigureAwait(false);

0 commit comments

Comments
 (0)