diff --git a/app/Server/Database/Sqlite/SqliteDatabaseFile.cs b/app/Server/Database/Sqlite/SqliteDatabaseFile.cs index 9c11bcf..be8e742 100644 --- a/app/Server/Database/Sqlite/SqliteDatabaseFile.cs +++ b/app/Server/Database/Sqlite/SqliteDatabaseFile.cs @@ -36,10 +36,13 @@ namespace DHT.Server.Database.Sqlite { private readonly Log log; private readonly SqliteConnectionPool pool; + private readonly SqliteMessageStatisticsThread messageStatisticsThread; private SqliteDatabaseFile(string path, SqliteConnectionPool pool) { this.log = Log.ForType(typeof(SqliteDatabaseFile), System.IO.Path.GetFileName(path)); this.pool = pool; + this.messageStatisticsThread = new SqliteMessageStatisticsThread(pool, UpdateMessageStatistics); + this.Path = path; this.Statistics = new DatabaseStatistics(); @@ -51,6 +54,7 @@ namespace DHT.Server.Database.Sqlite { } public void Dispose() { + messageStatisticsThread.Dispose(); pool.Dispose(); } @@ -299,7 +303,7 @@ namespace DHT.Server.Database.Sqlite { } tx.Commit(); - UpdateMessageStatistics(conn); + messageStatisticsThread.RequestUpdate(); } public int CountMessages(MessageFilter? filter = null) { diff --git a/app/Server/Database/Sqlite/SqliteMessageStatisticsThread.cs b/app/Server/Database/Sqlite/SqliteMessageStatisticsThread.cs new file mode 100644 index 0000000..6ce1146 --- /dev/null +++ b/app/Server/Database/Sqlite/SqliteMessageStatisticsThread.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading; +using DHT.Server.Database.Sqlite.Utils; + +namespace DHT.Server.Database.Sqlite { + sealed class SqliteMessageStatisticsThread : IDisposable { + private readonly SqliteConnectionPool pool; + private readonly Action action; + + private readonly CancellationTokenSource cancellationTokenSource = new(); + private readonly CancellationToken cancellationToken; + + private readonly AutoResetEvent requestEvent = new (false); + + public SqliteMessageStatisticsThread(SqliteConnectionPool pool, Action action) { + this.pool = pool; + this.action = action; + + this.cancellationToken = cancellationTokenSource.Token; + + var thread = new Thread(RunThread) { + Name = "DHT message statistics thread", + IsBackground = true + }; + thread.Start(); + } + + public void Dispose() { + try { + cancellationTokenSource.Cancel(); + } catch (ObjectDisposedException) {} + } + + public void RequestUpdate() { + try { + requestEvent.Set(); + } catch (ObjectDisposedException) {} + } + + private void RunThread() { + try { + while (!cancellationToken.IsCancellationRequested) { + if (requestEvent.WaitOne(TimeSpan.FromMilliseconds(100))) { + using var conn = pool.Take(); + action(conn); + } + } + } finally { + cancellationTokenSource.Dispose(); + requestEvent.Dispose(); + } + } + } +}