Skip to content

Commit 585ce5e

Browse files
committed
- Added optional data cache to StorageService.
1 parent 944f7c6 commit 585ce5e

File tree

2 files changed

+72
-7
lines changed

2 files changed

+72
-7
lines changed

Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/StorageService.cs

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Immutable;
34
using System.IO;
45
using System.Reflection;
@@ -23,7 +24,8 @@ public StorageService(IStorageServiceConfig configData)
2324
{
2425
_configData = configData;
2526
}
26-
27+
28+
private readonly ConcurrentDictionary<string, OneOf.OneOf<byte[], string, XDocument>> _fsCache = new();
2729
private readonly IStorageServiceConfig _configData;
2830
private readonly string _runLocation = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location.CleanUpPath());
2931

@@ -34,6 +36,18 @@ public void Dispose()
3436
ModUtils.Threading.SetBool(ref _isDisposed, true);
3537
}
3638

39+
public void PurgeCache()
40+
{
41+
_fsCache.Clear();
42+
}
43+
44+
private int _useCaching;
45+
public bool UseCaching
46+
{
47+
get => ModUtils.Threading.GetBool(ref _useCaching);
48+
set => ModUtils.Threading.SetBool(ref _useCaching, value);
49+
}
50+
3751
public FluentResults.Result<XDocument> LoadLocalXml(ContentPackage package, string localFilePath) =>
3852
GetAbsFromLocal(package, localFilePath) is var r && r is { IsSuccess: true, Value: not null }
3953
? TryLoadXml(r.Value) : r.ToResult();
@@ -144,8 +158,11 @@ public FluentResults.Result<ImmutableArray<string>> FindFilesInPackage(ContentPa
144158
if (localFilePaths.IsDefaultOrEmpty)
145159
return ImmutableArray<(string, FluentResults.Result<XDocument>)>.Empty;
146160
var builder = ImmutableArray.CreateBuilder<(string, FluentResults.Result<XDocument>)>(localFilePaths.Length);
147-
foreach (var path in localFilePaths)
161+
162+
await localFilePaths.ParallelForEachAsync(async path =>
163+
{
148164
builder.Add((path, await LoadPackageXmlAsync(package, path)));
165+
}, maxDegreeOfParallelism: 2);
149166
return builder.MoveToImmutable();
150167
}
151168

@@ -155,8 +172,10 @@ public FluentResults.Result<ImmutableArray<string>> FindFilesInPackage(ContentPa
155172
if (localFilePaths.IsDefaultOrEmpty)
156173
return ImmutableArray<(string, FluentResults.Result<byte[]>)>.Empty;
157174
var builder = ImmutableArray.CreateBuilder<(string, FluentResults.Result<byte[]>)>(localFilePaths.Length);
158-
foreach (var path in localFilePaths)
175+
await localFilePaths.ParallelForEachAsync(async path =>
176+
{
159177
builder.Add((path, await LoadPackageBinaryAsync(package, path)));
178+
}, maxDegreeOfParallelism: 2);
160179
return builder.MoveToImmutable();
161180
}
162181

@@ -166,8 +185,10 @@ public FluentResults.Result<ImmutableArray<string>> FindFilesInPackage(ContentPa
166185
if (localFilePaths.IsDefaultOrEmpty)
167186
return ImmutableArray<(string, FluentResults.Result<string>)>.Empty;
168187
var builder = ImmutableArray.CreateBuilder<(string, FluentResults.Result<string>)>(localFilePaths.Length);
169-
foreach (var path in localFilePaths)
188+
await localFilePaths.ParallelForEachAsync(async path =>
189+
{
170190
builder.Add((path, await LoadPackageTextAsync(package, path)));
191+
}, maxDegreeOfParallelism: 2);
171192
return builder.MoveToImmutable();
172193
}
173194

@@ -188,23 +209,39 @@ public FluentResults.Result<XDocument> TryLoadXml(string filePath, Encoding enco
188209
public FluentResults.Result<string> TryLoadText(string filePath, Encoding encoding = null)
189210
{
190211
((IService)this).CheckDisposed();
212+
if (UseCaching && _fsCache.TryGetValue(filePath, out var result)
213+
&& result.TryPickT1(out var cachedVal, out _))
214+
{
215+
return FluentResults.Result.Ok(cachedVal);
216+
}
217+
191218
return IOExceptionsOperationRunner(nameof(TryLoadText), filePath, () =>
192219
{
193220
var fp = filePath.CleanUpPath();
194221
fp = System.IO.Path.IsPathRooted(fp) ? fp : System.IO.Path.GetFullPath(fp);
195222
var fileText = encoding is null ? System.IO.File.ReadAllText(fp) : System.IO.File.ReadAllText(fp, encoding);
223+
if (UseCaching)
224+
_fsCache[filePath] = fileText;
196225
return new FluentResults.Result<string>().WithSuccess($"Loaded file successfully").WithValue(fileText);
197226
});
198227
}
199228

200229
public FluentResults.Result<byte[]> TryLoadBinary(string filePath)
201230
{
202231
((IService)this).CheckDisposed();
232+
if (UseCaching && _fsCache.TryGetValue(filePath, out var result)
233+
&& result.TryPickT0(out var cachedVal, out _))
234+
{
235+
return FluentResults.Result.Ok(cachedVal);
236+
}
237+
203238
return IOExceptionsOperationRunner(nameof(TryLoadBinary), filePath, () =>
204239
{
205240
var fp = filePath.CleanUpPath();
206241
fp = System.IO.Path.IsPathRooted(fp) ? fp : System.IO.Path.GetFullPath(fp);
207242
var fileData = System.IO.File.ReadAllBytes(fp);
243+
if (UseCaching)
244+
_fsCache[filePath] = fileData;
208245
return new FluentResults.Result<byte[]>().WithSuccess($"Loaded file successfully").WithValue(fileData);
209246
});
210247
}
@@ -220,13 +257,14 @@ public FluentResults.Result TrySaveText(string filePath, in string text, Encodin
220257
.WithMetadata(MetadataType.ExceptionObject, this)
221258
.WithMetadata(MetadataType.Sources, filePath));
222259
}
223-
224260
string t = text; //copy
225261
return IOExceptionsOperationRunner(nameof(TrySaveText), filePath, () =>
226262
{
227263
var fp = filePath.CleanUpPath();
228264
fp = System.IO.Path.IsPathRooted(fp) ? fp : System.IO.Path.GetFullPath(fp);
229265
System.IO.File.WriteAllText(fp, t, encoding);
266+
if (UseCaching)
267+
_fsCache[filePath] = t;
230268
return new FluentResults.Result().WithSuccess($"Saved to file successfully");
231269
});
232270
}
@@ -248,6 +286,8 @@ public FluentResults.Result TrySaveBinary(string filePath, in byte[] bytes)
248286
var fp = filePath.CleanUpPath();
249287
fp = System.IO.Path.IsPathRooted(fp) ? fp : System.IO.Path.GetFullPath(fp);
250288
System.IO.File.WriteAllBytes(fp, b);
289+
if (UseCaching)
290+
_fsCache[filePath] = b;
251291
return new FluentResults.Result().WithSuccess($"Saved to file successfully");
252292
});
253293
}
@@ -279,10 +319,16 @@ public FluentResults.Result<bool> DirectoryExists(string directoryPath)
279319

280320
public async Task<FluentResults.Result<XDocument>> TryLoadXmlAsync(string filePath, Encoding encoding = null)
281321
{
322+
if (UseCaching && _fsCache.TryGetValue(filePath, out var cachedVal)
323+
&& cachedVal.TryPickT2(out var cachedDoc, out _))
324+
return FluentResults.Result.Ok(cachedDoc);
282325
try
283326
{
284327
await using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
285-
return await XDocument.LoadAsync(fs, LoadOptions.PreserveWhitespace, CancellationToken.None);
328+
var doc = await XDocument.LoadAsync(fs, LoadOptions.PreserveWhitespace, CancellationToken.None);
329+
if (UseCaching)
330+
_fsCache[filePath] = doc;
331+
return FluentResults.Result.Ok(doc);
286332
}
287333
catch (Exception e)
288334
{
@@ -293,17 +339,30 @@ public FluentResults.Result<bool> DirectoryExists(string directoryPath)
293339
public async Task<FluentResults.Result<string>> TryLoadTextAsync(string filePath, Encoding encoding = null)
294340
{
295341
((IService)this).CheckDisposed();
342+
if (UseCaching && _fsCache.TryGetValue(filePath, out var cachedVal)
343+
&& cachedVal.TryPickT1(out var cachedTxt, out _))
344+
return FluentResults.Result.Ok(cachedTxt);
345+
296346
return await IOExceptionsOperationRunnerAsync<string>(nameof(TryLoadTextAsync), filePath, async () =>
297347
{
298348
var fp = filePath.CleanUpPath();
299349
fp = System.IO.Path.IsPathRooted(fp) ? fp : System.IO.Path.GetFullPath(fp);
300-
return await System.IO.File.ReadAllTextAsync(fp);
350+
var txt = await System.IO.File.ReadAllTextAsync(fp);
351+
if (UseCaching)
352+
_fsCache[filePath] = txt;
353+
return FluentResults.Result.Ok(txt);
301354
});
302355
}
303356

304357
public async Task<FluentResults.Result<byte[]>> TryLoadBinaryAsync(string filePath)
305358
{
306359
((IService)this).CheckDisposed();
360+
if (UseCaching && _fsCache.TryGetValue(filePath, out var cachedVal)
361+
&& cachedVal.TryPickT0(out var cachedBin, out _))
362+
{
363+
return cachedBin;
364+
}
365+
307366
return await IOExceptionsOperationRunnerAsync<byte[]>(nameof(TryLoadTextAsync), filePath, async () =>
308367
{
309368
var fp = filePath.CleanUpPath();
@@ -330,6 +389,8 @@ public FluentResults.Result<bool> DirectoryExists(string directoryPath)
330389
var fp = filePath.CleanUpPath();
331390
fp = System.IO.Path.IsPathRooted(fp) ? fp : System.IO.Path.GetFullPath(fp);
332391
await System.IO.File.WriteAllTextAsync(fp, t, encoding);
392+
if (UseCaching)
393+
_fsCache[filePath] = t;
333394
return new FluentResults.Result().WithSuccess($"Saved to file successfully");
334395
});
335396
}
@@ -351,6 +412,8 @@ public FluentResults.Result<bool> DirectoryExists(string directoryPath)
351412
var fp = filePath.CleanUpPath();
352413
fp = System.IO.Path.IsPathRooted(fp) ? fp : System.IO.Path.GetFullPath(fp);
353414
await System.IO.File.WriteAllBytesAsync(fp, b);
415+
if (UseCaching)
416+
_fsCache[filePath] = b;
354417
return new FluentResults.Result().WithSuccess($"Saved to file successfully");
355418
});
356419
}

Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IStorageService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace Barotrauma.LuaCs.Services;
77

88
public interface IStorageService : IService
99
{
10+
void PurgeCache();
11+
bool UseCaching { get; set; }
1012
// -- local game folder storage
1113
FluentResults.Result<XDocument> LoadLocalXml(ContentPackage package, string localFilePath);
1214
FluentResults.Result<byte[]> LoadLocalBinary(ContentPackage package, string localFilePath);

0 commit comments

Comments
 (0)