mirror of
https://github.com/MikuLeaks/MikuSB.git
synced 2026-06-04 09:23:57 +00:00
fix racing between AutoSave and process exit
This commit is contained in:
@@ -14,7 +14,10 @@ public class DatabaseHelper
|
|||||||
public static readonly ConcurrentDictionary<int, List<BaseDatabaseDataHelper>> UidInstanceMap = [];
|
public static readonly ConcurrentDictionary<int, List<BaseDatabaseDataHelper>> UidInstanceMap = [];
|
||||||
public static readonly List<int> ToSaveUidList = [];
|
public static readonly List<int> ToSaveUidList = [];
|
||||||
public static long LastSaveTick = DateTime.UtcNow.Ticks;
|
public static long LastSaveTick = DateTime.UtcNow.Ticks;
|
||||||
public static Thread? SaveThread;
|
|
||||||
|
private static int _saving = 0;
|
||||||
|
private static Task? _saveTask;
|
||||||
|
private static CancellationTokenSource? _cts;
|
||||||
public static bool LoadAccount;
|
public static bool LoadAccount;
|
||||||
public static bool LoadAllData;
|
public static bool LoadAllData;
|
||||||
|
|
||||||
@@ -80,16 +83,8 @@ public class DatabaseHelper
|
|||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
LastSaveTick = DateTime.UtcNow.Ticks;
|
_cts = new CancellationTokenSource();
|
||||||
|
_saveTask = RunAutoSave(_cts.Token);
|
||||||
SaveThread = new Thread(async () =>
|
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
CalcSaveDatabase();
|
|
||||||
await Task.Delay(100);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
SaveThread.Start();
|
|
||||||
|
|
||||||
LoadAllData = true;
|
LoadAllData = true;
|
||||||
}
|
}
|
||||||
@@ -252,6 +247,35 @@ public class DatabaseHelper
|
|||||||
ToSaveUidList.RemoveAll(x => x == key);
|
ToSaveUidList.RemoveAll(x => x == key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Stop()
|
||||||
|
{
|
||||||
|
_cts?.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task WaitAsync()
|
||||||
|
{
|
||||||
|
if (_saveTask != null)
|
||||||
|
await _saveTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task RunAutoSave(CancellationToken token)
|
||||||
|
{
|
||||||
|
LastSaveTick = DateTime.UtcNow.Ticks;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
CalcSaveDatabase();
|
||||||
|
await Task.Delay(100, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// exit normally
|
||||||
|
// Console.WriteLine($"RunAutoSave exit! - OperationCanceledException");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Auto save per 5 min
|
// Auto save per 5 min
|
||||||
public static void CalcSaveDatabase()
|
public static void CalcSaveDatabase()
|
||||||
{
|
{
|
||||||
@@ -261,6 +285,10 @@ public class DatabaseHelper
|
|||||||
|
|
||||||
public static void SaveDatabase()
|
public static void SaveDatabase()
|
||||||
{
|
{
|
||||||
|
// ensure only one SaveDatabase() runnig
|
||||||
|
if (Interlocked.Exchange(ref _saving, 1) == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var prev = DateTime.Now;
|
var prev = DateTime.Now;
|
||||||
@@ -285,11 +313,18 @@ public class DatabaseHelper
|
|||||||
Math.Round(t, 2).ToString(CultureInfo.InvariantCulture)));
|
Math.Round(t, 2).ToString(CultureInfo.InvariantCulture)));
|
||||||
|
|
||||||
ToSaveUidList.Clear();
|
ToSaveUidList.Clear();
|
||||||
|
|
||||||
|
// Thread.Sleep(5000); // for test if saving process taking too long
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.Error("An error occurred while saving the database", e);
|
logger.Error("An error occurred while saving the database", e);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// release lock
|
||||||
|
Volatile.Write(ref _saving, 0);
|
||||||
|
}
|
||||||
|
|
||||||
LastSaveTick = DateTime.UtcNow.Ticks;
|
LastSaveTick = DateTime.UtcNow.Ticks;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class MikuSB
|
|||||||
|
|
||||||
await consoleTask;
|
await consoleTask;
|
||||||
|
|
||||||
ProcessExit(Volatile.Read(ref _exitCode));
|
await ProcessExit(Volatile.Read(ref _exitCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Exit
|
#region Exit
|
||||||
@@ -96,11 +96,15 @@ public class MikuSB
|
|||||||
_cts.Cancel();
|
_cts.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ProcessExit(int exitCode)
|
private static async Task ProcessExit(int exitCode)
|
||||||
{
|
{
|
||||||
SocketListener.Connections.Values.ToList().ForEach(x => x.Stop(true));
|
SocketListener.Connections.Values.ToList().ForEach(x => x.Stop(true));
|
||||||
DatabaseHelper.SaveThread?.Interrupt();
|
|
||||||
DatabaseHelper.SaveDatabase();
|
DatabaseHelper.Stop(); // notify stop
|
||||||
|
await DatabaseHelper.WaitAsync(); // wait AutoSave thread exit
|
||||||
|
|
||||||
|
DatabaseHelper.SaveDatabase(); // final flush
|
||||||
|
|
||||||
Environment.Exit(exitCode);
|
Environment.Exit(exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user