Convert ReliableFileStorage to async

This commit is contained in:
goaaats 2025-11-17 23:55:55 +01:00
parent e65f441105
commit 20041be27c
6 changed files with 94 additions and 85 deletions

View file

@ -31,19 +31,19 @@ public class ReliableFileStorageTests
.Select(
i => Parallel.ForEachAsync(
Enumerable.Range(1, 100),
(j, _) =>
async (j, _) =>
{
if (i % 2 == 0)
{
// ReSharper disable once AccessToDisposedClosure
rfs.Instance.WriteAllText(tempFile, j.ToString());
await rfs.Instance.WriteAllTextAsync(tempFile, j.ToString());
}
else if (i % 3 == 0)
{
try
{
// ReSharper disable once AccessToDisposedClosure
rfs.Instance.ReadAllText(tempFile);
await rfs.Instance.ReadAllTextAsync(tempFile);
}
catch (FileNotFoundException)
{
@ -54,8 +54,6 @@ public class ReliableFileStorageTests
{
File.Delete(tempFile);
}
return ValueTask.CompletedTask;
})));
}
@ -112,41 +110,41 @@ public class ReliableFileStorageTests
}
[Fact]
public void Exists_WhenFileInBackup_ReturnsTrue()
public async Task Exists_WhenFileInBackup_ReturnsTrue()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
File.Delete(tempFile);
Assert.True(rfs.Instance.Exists(tempFile));
}
[Fact]
public void Exists_WhenFileInBackup_WithDifferentContainerId_ReturnsFalse()
public async Task Exists_WhenFileInBackup_WithDifferentContainerId_ReturnsFalse()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
File.Delete(tempFile);
Assert.False(rfs.Instance.Exists(tempFile, Guid.NewGuid()));
}
[Fact]
public void WriteAllText_ThrowsIfPathIsEmpty()
public async Task WriteAllText_ThrowsIfPathIsEmpty()
{
using var rfs = CreateRfs();
Assert.Throws<ArgumentException>(() => rfs.Instance.WriteAllText("", TestFileContent1));
await Assert.ThrowsAsync<ArgumentException>(async () => await rfs.Instance.WriteAllTextAsync("", TestFileContent1));
}
[Fact]
public void WriteAllText_ThrowsIfPathIsNull()
public async Task WriteAllText_ThrowsIfPathIsNull()
{
using var rfs = CreateRfs();
Assert.Throws<ArgumentNullException>(() => rfs.Instance.WriteAllText(null!, TestFileContent1));
await Assert.ThrowsAsync<ArgumentNullException>(async () => await rfs.Instance.WriteAllTextAsync(null!, TestFileContent1));
}
[Fact]
@ -155,26 +153,26 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
Assert.True(File.Exists(tempFile));
Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile, forceBackup: true));
Assert.Equal(TestFileContent1, await rfs.Instance.ReadAllTextAsync(tempFile, forceBackup: true));
Assert.Equal(TestFileContent1, await File.ReadAllTextAsync(tempFile));
}
[Fact]
public void WriteAllText_SeparatesContainers()
public async Task WriteAllText_SeparatesContainers()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
var containerId = Guid.NewGuid();
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
rfs.Instance.WriteAllText(tempFile, TestFileContent2, containerId);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent2, containerId);
File.Delete(tempFile);
Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile, forceBackup: true));
Assert.Equal(TestFileContent2, rfs.Instance.ReadAllText(tempFile, forceBackup: true, containerId));
Assert.Equal(TestFileContent1, await rfs.Instance.ReadAllTextAsync(tempFile, forceBackup: true));
Assert.Equal(TestFileContent2, await rfs.Instance.ReadAllTextAsync(tempFile, forceBackup: true, containerId));
}
[Fact]
@ -183,7 +181,7 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateFailedRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
Assert.True(File.Exists(tempFile));
Assert.Equal(TestFileContent1, await File.ReadAllTextAsync(tempFile));
@ -195,38 +193,38 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
rfs.Instance.WriteAllText(tempFile, TestFileContent2);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent2);
Assert.True(File.Exists(tempFile));
Assert.Equal(TestFileContent2, rfs.Instance.ReadAllText(tempFile, forceBackup: true));
Assert.Equal(TestFileContent2, await rfs.Instance.ReadAllTextAsync(tempFile, forceBackup: true));
Assert.Equal(TestFileContent2, await File.ReadAllTextAsync(tempFile));
}
[Fact]
public void WriteAllText_SupportsNullContent()
public async Task WriteAllText_SupportsNullContent()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, null);
await rfs.Instance.WriteAllTextAsync(tempFile, null);
Assert.True(File.Exists(tempFile));
Assert.Equal("", rfs.Instance.ReadAllText(tempFile));
Assert.Equal("", await rfs.Instance.ReadAllTextAsync(tempFile));
}
[Fact]
public void ReadAllText_ThrowsIfPathIsEmpty()
public async Task ReadAllText_ThrowsIfPathIsEmpty()
{
using var rfs = CreateRfs();
Assert.Throws<ArgumentException>(() => rfs.Instance.ReadAllText(""));
await Assert.ThrowsAsync<ArgumentException>(async () => await rfs.Instance.ReadAllTextAsync(""));
}
[Fact]
public void ReadAllText_ThrowsIfPathIsNull()
public async Task ReadAllText_ThrowsIfPathIsNull()
{
using var rfs = CreateRfs();
Assert.Throws<ArgumentNullException>(() => rfs.Instance.ReadAllText(null!));
await Assert.ThrowsAsync<ArgumentNullException>(async () => await rfs.Instance.ReadAllTextAsync(null!));
}
[Fact]
@ -236,40 +234,40 @@ public class ReliableFileStorageTests
await File.WriteAllTextAsync(tempFile, TestFileContent1);
using var rfs = CreateRfs();
Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile));
Assert.Equal(TestFileContent1, await rfs.Instance.ReadAllTextAsync(tempFile));
}
[Fact]
public void ReadAllText_WhenFileMissingWithBackup_ReturnsContent()
public async Task ReadAllText_WhenFileMissingWithBackup_ReturnsContent()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
File.Delete(tempFile);
Assert.Equal(TestFileContent1, rfs.Instance.ReadAllText(tempFile));
Assert.Equal(TestFileContent1, await rfs.Instance.ReadAllTextAsync(tempFile));
}
[Fact]
public void ReadAllText_WhenFileMissingWithBackup_ThrowsWithDifferentContainerId()
public async Task ReadAllText_WhenFileMissingWithBackup_ThrowsWithDifferentContainerId()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
var containerId = Guid.NewGuid();
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
File.Delete(tempFile);
Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile, containerId: containerId));
await Assert.ThrowsAsync<FileNotFoundException>(async () => await rfs.Instance.ReadAllTextAsync(tempFile, containerId: containerId));
}
[Fact]
public void ReadAllText_WhenFileMissing_ThrowsIfDbFailed()
public async Task ReadAllText_WhenFileMissing_ThrowsIfDbFailed()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateFailedRfs();
Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile));
await Assert.ThrowsAsync<FileNotFoundException>(async () => await rfs.Instance.ReadAllTextAsync(tempFile));
}
[Fact]
@ -278,7 +276,7 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
await File.WriteAllTextAsync(tempFile, TestFileContent1);
using var rfs = CreateRfs();
rfs.Instance.ReadAllText(tempFile, text => Assert.Equal(TestFileContent1, text));
await rfs.Instance.ReadAllTextAsync(tempFile, text => Assert.Equal(TestFileContent1, text));
}
[Fact]
@ -290,7 +288,7 @@ public class ReliableFileStorageTests
var readerCalledOnce = false;
using var rfs = CreateRfs();
Assert.Throws<FileReadException>(() => rfs.Instance.ReadAllText(tempFile, Reader));
await Assert.ThrowsAsync<FileReadException>(async () => await rfs.Instance.ReadAllTextAsync(tempFile, Reader));
return;
@ -303,7 +301,7 @@ public class ReliableFileStorageTests
}
[Fact]
public void ReadAllText_WithReader_WhenReaderThrows_ReadsContentFromBackup()
public async Task ReadAllText_WithReader_WhenReaderThrows_ReadsContentFromBackup()
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
@ -311,10 +309,10 @@ public class ReliableFileStorageTests
var assertionCalled = false;
using var rfs = CreateRfs();
rfs.Instance.WriteAllText(tempFile, TestFileContent1);
await rfs.Instance.WriteAllTextAsync(tempFile, TestFileContent1);
File.Delete(tempFile);
rfs.Instance.ReadAllText(tempFile, Reader);
await rfs.Instance.ReadAllTextAsync(tempFile, Reader);
Assert.True(assertionCalled);
return;
@ -335,17 +333,17 @@ public class ReliableFileStorageTests
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
await File.WriteAllTextAsync(tempFile, TestFileContent1);
using var rfs = CreateRfs();
Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile, _ => throw new FileNotFoundException()));
await Assert.ThrowsAsync<FileNotFoundException>(async () => await rfs.Instance.ReadAllTextAsync(tempFile, _ => throw new FileNotFoundException()));
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void ReadAllText_WhenFileDoesNotExist_Throws(bool forceBackup)
public async Task ReadAllText_WhenFileDoesNotExist_Throws(bool forceBackup)
{
var tempFile = Path.Combine(CreateTempDir(), TestFileName);
using var rfs = CreateRfs();
Assert.Throws<FileNotFoundException>(() => rfs.Instance.ReadAllText(tempFile, forceBackup));
await Assert.ThrowsAsync<FileNotFoundException>(async () => await rfs.Instance.ReadAllTextAsync(tempFile, forceBackup));
}
private static DisposableReliableFileStorage CreateRfs()

View file

@ -503,13 +503,13 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
/// <param name="path">Path to read from.</param>
/// <param name="fs">File storage.</param>
/// <returns>The deserialized configuration file.</returns>
public static DalamudConfiguration Load(string path, ReliableFileStorage fs)
public static async Task<DalamudConfiguration> Load(string path, ReliableFileStorage fs)
{
DalamudConfiguration deserialized = null;
try
{
fs.ReadAllText(path, text =>
await fs.ReadAllTextAsync(path, text =>
{
deserialized =
JsonConvert.DeserializeObject<DalamudConfiguration>(text, SerializerSettings);
@ -580,8 +580,6 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
{
this.Save();
this.isSaveQueued = false;
Log.Verbose("Config saved");
}
}
@ -630,16 +628,20 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
// Wait for previous write to finish
this.writeTask?.Wait();
this.writeTask = Task.Run(() =>
this.writeTask = Task.Run(async () =>
{
Service<ReliableFileStorage>.Get().WriteAllText(
await Service<ReliableFileStorage>.Get().WriteAllTextAsync(
this.configPath,
JsonConvert.SerializeObject(this, SerializerSettings));
Log.Verbose("DalamudConfiguration saved");
}).ContinueWith(t =>
{
if (t.IsFaulted)
{
Log.Error(t.Exception, "Failed to save DalamudConfiguration to {Path}", this.configPath);
Log.Error(
t.Exception,
"Failed to save DalamudConfiguration to {Path}",
this.configPath);
}
});

View file

@ -2,6 +2,8 @@ using System.IO;
using System.Reflection;
using Dalamud.Storage;
using Dalamud.Utility;
using Newtonsoft.Json;
namespace Dalamud.Configuration;
@ -9,6 +11,7 @@ namespace Dalamud.Configuration;
/// <summary>
/// Configuration to store settings for a dalamud plugin.
/// </summary>
[Api13ToDo("Make this a service. We need to be able to dispose it reliably to write configs asynchronously. Maybe also let people write files with vfs.")]
public sealed class PluginConfigurations
{
private readonly DirectoryInfo configDirectory;
@ -36,7 +39,7 @@ public sealed class PluginConfigurations
public void Save(IPluginConfiguration config, string pluginName, Guid workingPluginId)
{
Service<ReliableFileStorage>.Get()
.WriteAllText(this.GetConfigFile(pluginName).FullName, SerializeConfig(config), workingPluginId);
.WriteAllTextAsync(this.GetConfigFile(pluginName).FullName, SerializeConfig(config), workingPluginId).GetAwaiter().GetResult();
}
/// <summary>
@ -52,12 +55,12 @@ public sealed class PluginConfigurations
IPluginConfiguration? config = null;
try
{
Service<ReliableFileStorage>.Get().ReadAllText(path.FullName, text =>
Service<ReliableFileStorage>.Get().ReadAllTextAsync(path.FullName, text =>
{
config = DeserializeConfig(text);
if (config == null)
throw new Exception("Read config was null.");
}, workingPluginId);
}, workingPluginId).GetAwaiter().GetResult();
}
catch (FileNotFoundException)
{

View file

@ -144,7 +144,8 @@ public sealed class EntryPoint
// Load configuration first to get some early persistent state, like log level
var fs = new ReliableFileStorage(Path.GetDirectoryName(info.ConfigurationPath)!);
var configuration = DalamudConfiguration.Load(info.ConfigurationPath!, fs);
var configuration = DalamudConfiguration.Load(info.ConfigurationPath!, fs)
.GetAwaiter().GetResult();
// Set the appropriate logging level from the configuration
if (!configuration.LogSynchronously)

View file

@ -52,7 +52,7 @@ internal class VfsWidget : IDataWindowWidget
for (var i = 0; i < this.reps; i++)
{
stopwatch.Restart();
service.WriteAllBytes(path, data);
service.WriteAllBytesAsync(path, data).GetAwaiter().GetResult();
stopwatch.Stop();
acc += stopwatch.ElapsedMilliseconds;
Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds);
@ -70,7 +70,7 @@ internal class VfsWidget : IDataWindowWidget
for (var i = 0; i < this.reps; i++)
{
stopwatch.Restart();
service.ReadAllBytes(path);
service.ReadAllBytesAsync(path).GetAwaiter().GetResult();
stopwatch.Stop();
acc += stopwatch.ElapsedMilliseconds;
Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds);

View file

@ -1,5 +1,6 @@
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Dalamud.Logging.Internal;
using Dalamud.Utility;
@ -92,8 +93,9 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="path">Path to write to.</param>
/// <param name="contents">The contents of the file.</param>
/// <param name="containerId">Container to write to.</param>
public void WriteAllText(string path, string? contents, Guid containerId = default)
=> this.WriteAllText(path, contents, Encoding.UTF8, containerId);
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task WriteAllTextAsync(string path, string? contents, Guid containerId = default)
=> await this.WriteAllTextAsync(path, contents, Encoding.UTF8, containerId);
/// <summary>
/// Write all text to a file.
@ -102,10 +104,11 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="contents">The contents of the file.</param>
/// <param name="encoding">The encoding to write with.</param>
/// <param name="containerId">Container to write to.</param>
public void WriteAllText(string path, string? contents, Encoding encoding, Guid containerId = default)
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task WriteAllTextAsync(string path, string? contents, Encoding encoding, Guid containerId = default)
{
var bytes = encoding.GetBytes(contents ?? string.Empty);
this.WriteAllBytes(path, bytes, containerId);
await this.WriteAllBytesAsync(path, bytes, containerId);
}
/// <summary>
@ -114,7 +117,8 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="path">Path to write to.</param>
/// <param name="bytes">The contents of the file.</param>
/// <param name="containerId">Container to write to.</param>
public void WriteAllBytes(string path, byte[] bytes, Guid containerId = default)
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public Task WriteAllBytesAsync(string path, byte[] bytes, Guid containerId = default)
{
ArgumentException.ThrowIfNullOrEmpty(path);
@ -123,7 +127,7 @@ internal class ReliableFileStorage : IInternalDisposableService
if (this.db == null)
{
FilesystemUtil.WriteAllBytesSafe(path, bytes);
return;
return Task.CompletedTask;
}
this.db.RunInTransaction(() =>
@ -149,6 +153,8 @@ internal class ReliableFileStorage : IInternalDisposableService
FilesystemUtil.WriteAllBytesSafe(path, bytes);
});
}
return Task.CompletedTask;
}
/// <summary>
@ -161,8 +167,8 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="containerId">The container to read from.</param>
/// <returns>All text stored in this file.</returns>
/// <exception cref="FileNotFoundException">Thrown if the file does not exist on the filesystem or in the backup.</exception>
public string ReadAllText(string path, bool forceBackup = false, Guid containerId = default)
=> this.ReadAllText(path, Encoding.UTF8, forceBackup, containerId);
public Task<string> ReadAllTextAsync(string path, bool forceBackup = false, Guid containerId = default)
=> this.ReadAllTextAsync(path, Encoding.UTF8, forceBackup, containerId);
/// <summary>
/// Read all text from a file.
@ -175,9 +181,9 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="containerId">The container to read from.</param>
/// <returns>All text stored in this file.</returns>
/// <exception cref="FileNotFoundException">Thrown if the file does not exist on the filesystem or in the backup.</exception>
public string ReadAllText(string path, Encoding encoding, bool forceBackup = false, Guid containerId = default)
public async Task<string> ReadAllTextAsync(string path, Encoding encoding, bool forceBackup = false, Guid containerId = default)
{
var bytes = this.ReadAllBytes(path, forceBackup, containerId);
var bytes = await this.ReadAllBytesAsync(path, forceBackup, containerId);
return encoding.GetString(bytes);
}
@ -191,8 +197,9 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="containerId">The container to read from.</param>
/// <exception cref="FileNotFoundException">Thrown if the file does not exist on the filesystem or in the backup.</exception>
/// <exception cref="FileReadException">Thrown here if the file and the backup fail their read.</exception>
public void ReadAllText(string path, Action<string> reader, Guid containerId = default)
=> this.ReadAllText(path, Encoding.UTF8, reader, containerId);
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task ReadAllTextAsync(string path, Action<string> reader, Guid containerId = default)
=> await this.ReadAllTextAsync(path, Encoding.UTF8, reader, containerId);
/// <summary>
/// Read all text from a file, and automatically try again with the backup if the file does not exist or
@ -205,7 +212,8 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="containerId">The container to read from.</param>
/// <exception cref="FileNotFoundException">Thrown if the file does not exist on the filesystem or in the backup.</exception>
/// <exception cref="FileReadException">Thrown here if the file and the backup fail their read.</exception>
public void ReadAllText(string path, Encoding encoding, Action<string> reader, Guid containerId = default)
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task ReadAllTextAsync(string path, Encoding encoding, Action<string> reader, Guid containerId = default)
{
ArgumentException.ThrowIfNullOrEmpty(path);
@ -216,7 +224,7 @@ internal class ReliableFileStorage : IInternalDisposableService
// 1.) Try without using the backup
try
{
var text = this.ReadAllText(path, encoding, false, containerId);
var text = await this.ReadAllTextAsync(path, encoding, false, containerId);
reader(text);
return;
}
@ -233,7 +241,7 @@ internal class ReliableFileStorage : IInternalDisposableService
// 2.) Try using the backup
try
{
var text = this.ReadAllText(path, encoding, true, containerId);
var text = await this.ReadAllTextAsync(path, encoding, true, containerId);
reader(text);
}
catch (Exception ex)
@ -253,7 +261,7 @@ internal class ReliableFileStorage : IInternalDisposableService
/// <param name="containerId">The container to read from.</param>
/// <returns>All bytes stored in this file.</returns>
/// <exception cref="FileNotFoundException">Thrown if the file does not exist on the filesystem or in the backup.</exception>
public byte[] ReadAllBytes(string path, bool forceBackup = false, Guid containerId = default)
public async Task<byte[]> ReadAllBytesAsync(string path, bool forceBackup = false, Guid containerId = default)
{
ArgumentException.ThrowIfNullOrEmpty(path);
@ -265,15 +273,12 @@ internal class ReliableFileStorage : IInternalDisposableService
var normalizedPath = NormalizePath(path);
var file = this.db.Table<DbFile>().FirstOrDefault(f => f.Path == normalizedPath && f.ContainerId == containerId);
if (file == null)
throw new FileNotFoundException();
return file.Data;
return file == null ? throw new FileNotFoundException() : file.Data;
}
// If the file doesn't exist, immediately check the backup db
if (!File.Exists(path))
return this.ReadAllBytes(path, true, containerId);
return await this.ReadAllBytesAsync(path, true, containerId);
try
{
@ -282,7 +287,7 @@ internal class ReliableFileStorage : IInternalDisposableService
catch (Exception e)
{
Log.Error(e, "Failed to read file from disk, falling back to database");
return this.ReadAllBytes(path, true, containerId);
return await this.ReadAllBytesAsync(path, true, containerId);
}
}