Improve mutexes
MODIFY
WalletWasabi/Helpers/IoHelpers.cs
WalletWasabi/Helpers/IoHelpers.cs
@@ -78,51 +78,113 @@ namespace System.IO
public static void SafeWriteAllText(string path, string content)
{
var newPath = path + NewExtension;
+ var mutexName = Path.GetFileNameWithoutExtension(path);
+ using (var mutex = new Mutex(false, mutexName))
+ {
+ var mutexAcquired = false;
+ try
+ {
+ // acquire the mutex (or timeout after 60 seconds)
+ // will return false if it timed out
+ mutexAcquired = mutex.WaitOne(60000);
+ }
+ catch (AbandonedMutexException)
+ {
+ // abandoned mutexes are still acquired, we just need
+ // to handle the exception and treat it as acquisition
+ mutexAcquired = true;
+ }
+
+ if (mutexAcquired == false)
+ {
+ throw new IOException("Couldn't acquire Mutex on the file.");
+ }
+
+ try
+ {
File.WriteAllText(newPath, content);
SafeMove(newPath, path);
}
+ finally
+ {
+ mutex.ReleaseMutex();
+ }
+ }
+ }
public static void SafeWriteAllText(string path, string content, Encoding encoding)
{
var newPath = path + NewExtension;
- File.WriteAllText(newPath, content, encoding);
- SafeMove(newPath, path);
+ var mutexName = Path.GetFileNameWithoutExtension(path);
+ using (var mutex = new Mutex(false, mutexName))
+ {
+ var mutexAcquired = false;
+ try
+ {
+ // acquire the mutex (or timeout after 60 seconds)
+ // will return false if it timed out
+ mutexAcquired = mutex.WaitOne(60000);
+ }
+ catch (AbandonedMutexException)
+ {
+ // abandoned mutexes are still acquired, we just need
+ // to handle the exception and treat it as acquisition
+ mutexAcquired = true;
}
- public static async Task SafeWriteAllTextAsync(string path, string content)
+ if (mutexAcquired == false)
{
- var newPath = path + NewExtension;
- await File.WriteAllTextAsync(newPath, content);
- SafeMove(newPath, path);
+ throw new IOException("Couldn't acquire Mutex on the file.");
}
- public static async Task SafeWriteAllTextAsync(string path, string content, Encoding encoding)
+ try
{
- var newPath = path + NewExtension;
- await File.WriteAllTextAsync(newPath, content, encoding);
+ File.WriteAllText(newPath, content, encoding);
SafeMove(newPath, path);
}
+ finally
+ {
+ mutex.ReleaseMutex();
+ }
+ }
+ }
public static void SafeWriteAllLines(string path, IEnumerable<string> content)
{
var newPath = path + NewExtension;
- File.WriteAllLines(newPath, content);
- SafeMove(newPath, path);
+ var mutexName = Path.GetFileNameWithoutExtension(path);
+ using (var mutex = new Mutex(false, mutexName))
+ {
+ var mutexAcquired = false;
+ try
+ {
+ // acquire the mutex (or timeout after 60 seconds)
+ // will return false if it timed out
+ mutexAcquired = mutex.WaitOne(60000);
+ }
+ catch (AbandonedMutexException)
+ {
+ // abandoned mutexes are still acquired, we just need
+ // to handle the exception and treat it as acquisition
+ mutexAcquired = true;
}
- public static async Task SafeWriteAllLinesAsync(string path, IEnumerable<string> content)
+ if (mutexAcquired == false)
{
- var newPath = path + NewExtension;
- await File.WriteAllLinesAsync(newPath, content);
- SafeMove(newPath, path);
+ throw new IOException("Couldn't acquire Mutex on the file.");
}
- public static async Task SafeWriteAllBytesAsync(string path, byte[] content)
+ try
{
- var newPath = path + NewExtension;
- await File.WriteAllBytesAsync(newPath, content);
+ File.WriteAllLines(newPath, content);
SafeMove(newPath, path);
}
+ finally
+ {
+ mutex.ReleaseMutex();
+ }
+ }
+ }
public static async Task BetterExtractZipToDirectoryAsync(string src, string dest)
{

MODIFY
WalletWasabi/Services/IndexDownloader.cs
WalletWasabi/Services/IndexDownloader.cs
@@ -92,7 +92,6 @@ namespace WalletWasabi.Services
public WasabiClient WasabiClient { get; }
public string IndexFilePath { get; }
- public string IndexFilePathMutexName { get; }
private List<FilterModel> Index { get; }
private AsyncLock IndexLock { get; }
@@ -138,7 +137,6 @@ namespace WalletWasabi.Services
Network = Guard.NotNull(nameof(network), network);
WasabiClient = new WasabiClient(indexHostUri, torSocks5EndPoint);
IndexFilePath = Guard.NotNullOrEmptyOrWhitespace(nameof(indexFilePath), indexFilePath);
- IndexFilePathMutexName = "55BE9271-85C6-4B3D-AAA8-642B9CFE0F2C";
Index = new List<FilterModel>();
IndexLock = new AsyncLock();
@@ -146,24 +144,6 @@ namespace WalletWasabi.Services
_running = 0;
Cancel = new CancellationTokenSource();
- using (var mutex = new Mutex(false, IndexFilePathMutexName))
- {
- var mutexAcquired = false;
- try
- {
- // acquire the mutex (or timeout after 7 seconds)
- // will return false if it timed out
- mutexAcquired = mutex.WaitOne(7000);
- }
- catch (AbandonedMutexException)
- {
- // abandoned mutexes are still acquired, we just need
- // to handle the exception and treat it as acquisition
- mutexAcquired = true;
- }
-
- try
- {
IoHelpers.EnsureContainingDirectoryExists(indexFilePath);
if (File.Exists(IndexFilePath))
{
@@ -201,15 +181,6 @@ namespace WalletWasabi.Services
Index.Add(StartingFilter);
IoHelpers.SafeWriteAllLines(IndexFilePath, Index.Select(x => x.ToLine()));
}
- }
- finally
- {
- if (mutexAcquired)
- {
- mutex.ReleaseMutex();
- }
- }
- }
BestKnownFilter = Index.Last();
BestHeight = Height.Unknown; // At this point we don't know it.
@@ -288,34 +259,7 @@ namespace WalletWasabi.Services
NewFilter?.Invoke(this, filterModel);
}
- using (var mutex = new Mutex(false, IndexFilePathMutexName))
- {
- var mutexAcquired = false;
- try
- {
- // acquire the mutex (or timeout after 7 seconds)
- // will return false if it timed out
- mutexAcquired = mutex.WaitOne(7000);
- }
- catch (AbandonedMutexException)
- {
- // abandoned mutexes are still acquired, we just need
- // to handle the exception and treat it as acquisition
- mutexAcquired = true;
- }
-
- try
- {
- IoHelpers.SafeWriteAllLines(IndexFilePath, Index.Select(x => x.ToLine())); // Don't async inside mutex.
- }
- finally
- {
- if (mutexAcquired)
- {
- mutex.ReleaseMutex();
- }
- }
- }
+ IoHelpers.SafeWriteAllLines(IndexFilePath, Index.Select(x => x.ToLine()));
Logger.LogInfo<IndexDownloader>($"Downloaded filters for blocks from {startingFilter.BlockHeight + 1} to {BestKnownFilter.BlockHeight}.");
}
@@ -348,24 +292,6 @@ namespace WalletWasabi.Services
Reorged?.Invoke(this, reorgedHash);
- using (var mutex = new Mutex(false, IndexFilePathMutexName))
- {
- var mutexAcquired = false;
- try
- {
- // acquire the mutex (or timeout after 7 seconds)
- // will return false if it timed out
- mutexAcquired = mutex.WaitOne(7000);
- }
- catch (AbandonedMutexException)
- {
- // abandoned mutexes are still acquired, we just need
- // to handle the exception and treat it as acquisition
- mutexAcquired = true;
- }
-
- try
- {
// 2. Serialize Index. (Remove last line.)
string[] lines = null;
if (IoHelpers.TryGetSafestFileVersion(IndexFilePath, out var safestFileVerion))
@@ -373,15 +299,6 @@ namespace WalletWasabi.Services
lines = File.ReadAllLines(safestFileVerion);
}
IoHelpers.SafeWriteAllLines(IndexFilePath, lines.Take(lines.Length - 1).ToArray()); // It's not async for a reason, I think.
- }
- finally
- {
- if (mutexAcquired)
- {
- mutex.ReleaseMutex();
- }
- }
- }
// 3. Skip the last valid block.
continue;

Improve mutexes