[PATCH] sqlite3 abuses usleep for >=1sec sleeps
(1) By anonymous on 2020-09-15 07:04:57 [source]
In src/os_unix.c, unixSleep
is defined in terms of usleep
on platforms that support it, by passing the number of microseconds through verbatim. This is used to implement sqlite3_sleep
on Unix, via the VFS xSleep
method.
There is no limit on duration in the sqlite3_sleep
documentation, other than the limit of INT_MAX/1000
milliseconds implied by the argument type and the 1000*ms
logic in sqlite3_sleep
. In practice, fossil backoffice
sometimes uses sqlite3_sleep
in an attempt to sleep for up to a minute.
But in the specification of usleep
, POSIX says that the number of microseconds shall be less than one million, and that usleep
may fail with EINVAL
otherwise. If this happens, fossil backoffice
spins in a busy-wait rather than actually sleeping, with the side effect that the Fossil sqlite3 database is constantly locked, touched, fsynced, and unlocked by the backoffice process, starving out other writers.
The attached patch fixes unixSleep
by dividing the number of microseconds into a number of seconds, passed to sleep
, and a remainder of microseconds, passed to usleep
. The patch also fixes the one other call to usleep
with more than one million microseconds by using sleep
instead.
Index: src/os_unix.c
==================================================================
--- src/os_unix.c
+++ src/os_unix.c
@@ -6574,11 +6574,14 @@
sp.tv_nsec = (microseconds % 1000000) * 1000;
nanosleep(&sp, NULL);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
- usleep(microseconds);
+ if( microseconds >= 1000000 ){
+ sleep(microseconds / 1000000);
+ }
+ usleep(microseconds % 1000000);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#else
int seconds = (microseconds+999999)/1000000;
sleep(seconds);
@@ -7173,11 +7176,11 @@
}
}else{
/* don't break the lock on short read or a version mismatch */
return SQLITE_BUSY;
}
- usleep(10000000); /* wait 10 sec and try the lock again */
+ sleep(10); /* wait 10 sec and try the lock again */
continue;
}
assert( nTries==3 );
if( 0==proxyBreakConchLock(pFile, myHostID) ){