libstore: use monotonic clock for SQLITE_BUSY warnings

Using time_t meant a warning could be printed arbitrarily soon depending
on when the second rolled over relative to when the SQLite transaction
was attempted.

Change-Id: I93401aea65f90e37cd450a293c4dd4d64fba7628
This commit is contained in:
Lily Ballard
2025-02-16 22:48:45 -08:00
parent d745b28500
commit ed03c3985d
2 changed files with 10 additions and 9 deletions
+5 -5
View File
@@ -278,11 +278,11 @@ void SQLiteTxn::Rollback::operator()(sqlite3 * db)
}
[[nodiscard]]
static std::chrono::milliseconds handleSQLiteBusyCommon(const SQLiteBusy & e, time_t & nextWarning)
static std::chrono::milliseconds handleSQLiteBusyCommon(const SQLiteBusy & e, std::chrono::time_point<std::chrono::steady_clock> & nextWarning)
{
time_t now = time(0);
auto now = std::chrono::steady_clock::now();
if (now > nextWarning) {
nextWarning = now + 10;
nextWarning = now + std::chrono::seconds(10);
logWarning({
.msg = HintFmt(e.what())
});
@@ -297,12 +297,12 @@ static std::chrono::milliseconds handleSQLiteBusyCommon(const SQLiteBusy & e, ti
return std::chrono::milliseconds { uniform_dist(generator) };
}
void handleSQLiteBusy(const SQLiteBusy & e, time_t & nextWarning)
void handleSQLiteBusy(const SQLiteBusy & e, std::chrono::time_point<std::chrono::steady_clock> & nextWarning)
{
std::this_thread::sleep_for(handleSQLiteBusyCommon(e, nextWarning));
}
kj::Promise<Result<void>> handleSQLiteBusyAsync(const SQLiteBusy & e, time_t & nextWarning)
kj::Promise<Result<void>> handleSQLiteBusyAsync(const SQLiteBusy & e, std::chrono::time_point<std::chrono::steady_clock> & nextWarning)
try {
std::chrono::milliseconds delay_ms = handleSQLiteBusyCommon(e, nextWarning);
co_await AIO().provider.getTimer().afterDelay(delay_ms.count() * kj::MILLISECONDS);
+5 -4
View File
@@ -1,6 +1,7 @@
#pragma once
///@file
#include <chrono>
#include <kj/async.h>
#include <string>
#include <type_traits>
@@ -190,8 +191,8 @@ protected:
MakeError(SQLiteBusy, SQLiteError);
void handleSQLiteBusy(const SQLiteBusy & e, time_t & nextWarning);
kj::Promise<Result<void>> handleSQLiteBusyAsync(const SQLiteBusy & e, time_t & nextWarning);
void handleSQLiteBusy(const SQLiteBusy & e, std::chrono::time_point<std::chrono::steady_clock> & nextWarning);
kj::Promise<Result<void>> handleSQLiteBusyAsync(const SQLiteBusy & e, std::chrono::time_point<std::chrono::steady_clock> & nextWarning);
/**
* Convenience function for retrying a SQLite transaction when the
@@ -200,10 +201,10 @@ kj::Promise<Result<void>> handleSQLiteBusyAsync(const SQLiteBusy & e, time_t & n
template<typename F>
auto retrySQLite(F fun)
{
time_t nextWarning = time(0) + 1;
auto nextWarning = std::chrono::steady_clock::now() + std::chrono::seconds(1);
if constexpr (requires (F f) { []<typename T>(kj::Promise<Result<T>>){}(f()); }) {
return [](time_t nextWarning, F fun) -> decltype(fun()) {
return [](std::chrono::time_point<std::chrono::steady_clock> nextWarning, F fun) -> decltype(fun()) {
while (true) {
kj::Promise<Result<void>> handleBusy{nullptr};
try {