From 950ead9b47a25702d03716d643f954f47fbc03a5 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 4 Mar 2022 23:55:35 +0100 Subject: [PATCH] Introduce artificial delay into SQLite on DEBUG. This makes SQLite DB ops properly asynchronous (instead of synchronously completing tasks). This makes them more consistent with postgres and means that any deadlock bugs introduced the next time somebody does .Result will be caught on SQLite too. --- Content.Server/Database/ServerDbSqlite.cs | 10 +++++++++- Content.Shared/CCVar/CCVars.cs | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Content.Server/Database/ServerDbSqlite.cs b/Content.Server/Database/ServerDbSqlite.cs index 4ad42baeed..0b26e91f01 100644 --- a/Content.Server/Database/ServerDbSqlite.cs +++ b/Content.Server/Database/ServerDbSqlite.cs @@ -31,11 +31,14 @@ namespace Content.Server.Database private readonly Task _dbReadyTask; private readonly SqliteServerDbContext _prefsCtx; + private int _msDelay; + public ServerDbSqlite(DbContextOptions options) { _prefsCtx = new SqliteServerDbContext(options); - if (IoCManager.Resolve().GetCVar(CCVars.DatabaseSynchronous)) + var cfg = IoCManager.Resolve(); + if (cfg.GetCVar(CCVars.DatabaseSynchronous)) { _prefsCtx.Database.Migrate(); _dbReadyTask = Task.CompletedTask; @@ -44,6 +47,8 @@ namespace Content.Server.Database { _dbReadyTask = Task.Run(() => _prefsCtx.Database.Migrate()); } + + cfg.OnValueChanged(CCVars.DatabaseSqliteDelay, v => _msDelay = v, true); } #region Ban @@ -488,6 +493,9 @@ namespace Content.Server.Database private async Task GetDbImpl() { await _dbReadyTask; + if (_msDelay > 0) + await Task.Delay(_msDelay); + await _prefsSemaphore.WaitAsync(); return new DbGuardImpl(this); diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index d9b3f549a3..06d783fc55 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -242,6 +242,24 @@ namespace Content.Shared.CCVar public static readonly CVarDef DatabaseSqliteDbPath = CVarDef.Create("database.sqlite_dbpath", "preferences.db", CVar.SERVERONLY); + /// + /// Milliseconds to asynchronously delay all SQLite database acquisitions with. + /// + /// + /// Defaults to 1 on DEBUG, 0 on RELEASE. + /// This is intended to help catch .Result deadlock bugs that only happen on postgres + /// (because SQLite is not actually asynchronous normally) + /// + public static readonly CVarDef DatabaseSqliteDelay = + CVarDef.Create("database.sqlite_delay", DefaultSqliteDelay, CVar.SERVERONLY); + +#if DEBUG + private const int DefaultSqliteDelay = 1; +#else + private const int DefaultSqliteDelay = 0; +#endif + + public static readonly CVarDef DatabasePgHost = CVarDef.Create("database.pg_host", "localhost", CVar.SERVERONLY); @@ -380,7 +398,7 @@ namespace Content.Shared.CCVar /// /// Large nukes tend to generate a lot of shrapnel that flies through space. This can functionally cripple /// the server TPS for a while after an explosion (or even during, if the explosion is processed - /// incrementally. + /// incrementally. /// public static readonly CVarDef ExplosionThrowLimit = CVarDef.Create("explosion.throwlimit", 400, CVar.SERVERONLY);