Arch Linux

Please read this before reporting a bug:
https://wiki.archlinux.org/title/Bug_reporting_guidelines

Do NOT report bugs when a package is just outdated, or it is in the AUR. Use the 'flag out of date' link on the package page, or the Mailing List.

REPEAT: Do NOT report bugs for outdated packages!
Tasklist

FS#44471 - [sqlite] Please add HAVE_USLEEP

Attached to Project: Arch Linux
Opened by Tobias Tangemann (jakethedog) - Sunday, 05 April 2015, 11:14 GMT
Last edited by Andreas Radke (AndyRTR) - Wednesday, 08 April 2015, 19:55 GMT
Task Type Feature Request
Category Packages: Core
Status Closed
Assigned To Andreas Radke (AndyRTR)
Architecture All
Severity Low
Priority Normal
Reported Version
Due in Version Undecided
Due Date Undecided
Percent Complete 100%
Votes 0
Private No

Details

Description:

The default minimum sleep interval of sqlite is 1 whole seconds if the compile option "HAVE_USLEEP" is not defined.
I think usleep should be available on almost any system nowadys, so it should be save to use HAVE_USLEEP.
This would allow for shorter delays while waiting for sqlite locks.

https://www.sqlite.org/compile.html#usleep

Thanks
Tobias
This task depends upon

Closed by  Andreas Radke (AndyRTR)
Wednesday, 08 April 2015, 19:55 GMT
Reason for closing:  Won't implement
Comment by Andreas Radke (AndyRTR) - Tuesday, 07 April 2015, 14:03 GMT
So far I couldn't find any other distro using this variable. Any unwanted side effects we have to fear when using it? What do we gain?
Comment by Tobias Tangemann (jakethedog) - Wednesday, 08 April 2015, 19:10 GMT
NetBSD is using it, and also windows is using a minimum delay in milliseconds.
http://cvsweb.netbsd.org/bsdweb.cgi/src/external/public-domain/sqlite/Makefile.inc?only_with_tag=MAIN

This allows for shorter locks and faster multi process access to a single sqlite db:
http://beets.radbox.org/blog/sqlite-nightmare.html

Side effects, I'm assuming there shouldn't be any but that i can't promise ;)
Also if you download the code from their website and perform the "normal" ./configure && make
The -DHAVE_USLEEP=1 is the in addition to many other flags (which I'm personally not that interested in ;)

Some code from sqlite:
Without HAVE_USLEEP sqlite3OsSleep always waits 1 second before trying again to aquire a lock.

static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
u32 mxReadMark; /* Largest aReadMark[] value */
int mxI; /* Index of largest aReadMark[] value */
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */

assert( pWal->readLock<0 ); /* Not currently locked */

/* Take steps to avoid spinning forever if there is a protocol error.
**
** Circumstances that cause a RETRY should only last for the briefest
** instances of time. No I/O or other system calls are done while the
** locks are held, so the locks should not be held for very long. But
** if we are unlucky, another process that is holding a lock might get
** paged out or take a page-fault that is time-consuming to resolve,
** during the few nanoseconds that it is holding the lock. In that case,
** it might take longer than normal for the lock to free.
**
** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
** is more of a scheduler yield than an actual delay. But on the 10th
** an subsequent retries, the delays start becoming longer and longer,
** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
** The total delay time before giving up is less than 10 seconds.
*/
if( cnt>5 ){
int nDelay = 1; /* Pause time in microseconds */
if( cnt>100 ){
VVA_ONLY( pWal->lockError = 1; )
return SQLITE_PROTOCOL;
}
if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
sqlite3OsSleep(pWal->pVfs, nDelay);
}


The functions directly affected by this change will be only these two.

/*
** Sleep for a little while. Return the amount of time slept.
** The argument is the number of microseconds we want to sleep.
** The return value is the number of microseconds of sleep actually
** requested from the underlying operating system, a number which
** might be greater than or equal to the argument, but not less
** than the argument.
*/
static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
#if OS_VXWORKS
struct timespec sp;

sp.tv_sec = microseconds / 1000000;
sp.tv_nsec = (microseconds % 1000000) * 1000;
nanosleep(&sp, NULL);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
usleep(microseconds);
UNUSED_PARAMETER(NotUsed);
return microseconds;
#else
int seconds = (microseconds+999999)/1000000;
sleep(seconds);
UNUSED_PARAMETER(NotUsed);
return seconds*1000000;
#endif
}



/*
** This routine implements a busy callback that sleeps and tries
** again until a timeout value is reached. The timeout value is
** an integer number of milliseconds passed in as the first
** argument.
*/
static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
#if SQLITE_OS_WIN || HAVE_USLEEP
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
# define NDELAY ArraySize(delays)
sqlite3 *db = (sqlite3 *)ptr;
int timeout = db->busyTimeout;
int delay, prior;

assert( count>=0 );
if( count < NDELAY ){
delay = delays[count];
prior = totals[count];
}else{
delay = delays[NDELAY-1];
prior = totals[NDELAY-1] + delay*(count-(NDELAY-1));
}
if( prior + delay > timeout ){
delay = timeout - prior;
if( delay<=0 ) return 0;
}
sqlite3OsSleep(db->pVfs, delay*1000);
return 1;
#else
sqlite3 *db = (sqlite3 *)ptr;
int timeout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > timeout ){
return 0;
}
sqlite3OsSleep(db->pVfs, 1000000);
return 1;
#endif
}
Comment by Tobias Tangemann (jakethedog) - Wednesday, 08 April 2015, 19:30 GMT
Can be closed, was an error in my code, the current PKGBUILD (on my arm system) builds with HAVE_USLEEP=1

Loading...