1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Add infrastructure to support for using F_SETLKW with a timeout on system

that support that functionality.  Requires SQLITE_ENABLE_SETLK_TIMEOUT.

FossilOrigin-Name: 2e54a7433ece4eb27e71bda6f2d121d5aa46ddd5a481357d8543d1432aaad689
This commit is contained in:
drh
2018-03-26 17:40:53 +00:00
parent 80262896d6
commit f0119b2e1b
7 changed files with 122 additions and 27 deletions

View File

@@ -1476,21 +1476,38 @@ const char *sqlite3ErrStr(int rc){
** again until a timeout value is reached. The timeout value is
** an integer number of milliseconds passed in as the first
** argument.
**
** Return non-zero to retry the lock. Return zero to stop trying
** and cause SQLite to return SQLITE_BUSY.
*/
static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
void *ptr, /* Database connection */
int count, /* Number of times table has been busy */
sqlite3_file *pFile /* The file on which the lock occurred */
){
#if SQLITE_OS_WIN || HAVE_USLEEP
/* This case is for systems that have support for sleeping for fractions of
** a second. Examples: All windows systems, unix systems with 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 tmout = db->busyTimeout;
int delay, prior;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
if( count ){
tmout = 0;
sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
return 0;
}else{
return 1;
}
}
#endif
assert( count>=0 );
if( count < NDELAY ){
delay = delays[count];
@@ -1499,16 +1516,18 @@ static int sqliteDefaultBusyCallback(
delay = delays[NDELAY-1];
prior = totals[NDELAY-1] + delay*(count-(NDELAY-1));
}
if( prior + delay > timeout ){
delay = timeout - prior;
if( prior + delay > tmout ){
delay = tmout - prior;
if( delay<=0 ) return 0;
}
sqlite3OsSleep(db->pVfs, delay*1000);
return 1;
#else
/* This case for unix systems that lack usleep() support. Sleeping
** must be done in increments of whole seconds */
sqlite3 *db = (sqlite3 *)ptr;
int timeout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > timeout ){
int tmout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > tmout ){
return 0;
}
sqlite3OsSleep(db->pVfs, 1000000);
@@ -1519,14 +1538,25 @@ static int sqliteDefaultBusyCallback(
/*
** Invoke the given busy handler.
**
** This routine is called when an operation failed with a lock.
** This routine is called when an operation failed to acquire a
** lock on VFS file pFile.
**
** If this routine returns non-zero, the lock is retried. If it
** returns 0, the operation aborts with an SQLITE_BUSY error.
*/
int sqlite3InvokeBusyHandler(BusyHandler *p){
int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
int rc;
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
if( p->bExtraFileArg ){
/* Add an extra parameter with the pFile pointer to the end of the
** callback argument list */
int (*xTra)(void*,int,sqlite3_file*);
xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
rc = xTra(p->pBusyArg, p->nBusy, pFile);
}else{
/* Legacy style busy handler callback */
rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
}
if( rc==0 ){
p->nBusy = -1;
}else{
@@ -1551,6 +1581,7 @@ int sqlite3_busy_handler(
db->busyHandler.xBusyHandler = xBusy;
db->busyHandler.pBusyArg = pArg;
db->busyHandler.nBusy = 0;
db->busyHandler.bExtraFileArg = 0;
db->busyTimeout = 0;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -1598,8 +1629,10 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms>0 ){
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
(void*)db);
db->busyTimeout = ms;
db->busyHandler.bExtraFileArg = 1;
}else{
sqlite3_busy_handler(db, 0, 0);
}