Index: src/global.c ================================================================== --- src/global.c +++ src/global.c @@ -238,10 +238,11 @@ #endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ + 1, /* bOfdLocks */ 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE /* szSorterRef */ }; /* Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -650,10 +650,15 @@ } sqlite3GlobalConfig.szSorterRef = (u32)iVal; break; } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ + + case SQLITE_CONFIG_OFD_LOCKS: { + sqlite3GlobalConfig.bOfdLocks = va_arg(ap, int); + break; + } default: { rc = SQLITE_ERROR; break; } Index: src/os_unix.c ================================================================== --- src/os_unix.c +++ src/os_unix.c @@ -176,10 +176,25 @@ ** Only set the lastErrno if the error code is a real error and not ** a normal expected return code of SQLITE_BUSY or SQLITE_OK */ #define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY)) +/* +** Are OFD locks supported? +*/ +#if defined(F_OFD_SETLK) && defined(F_OFD_GETLK) +# define HAVE_OFD_LOCKS 1 +# define UsesOfd(F) ((F)->eGetLk==F_OFD_GETLK) +# define UsesOldStylePosixLocks(F) ((F)->eGetLk==F_GETLK) +#else +# define HAVE_OFD_LOCKS 0 +# define UsesOfd(F) 0 +# define UsesOldStylePosixLocks(F) 1 +# define F_OFD_SETLK 0 /* Fake value so we can use the identifier */ +# define F_OFD_GETLK 0 /* Fake value so we can use the identifier */ +#endif + /* Forward references */ typedef struct unixShm unixShm; /* Connection shared memory */ typedef struct unixShmNode unixShmNode; /* Shared memory instance */ typedef struct unixInodeInfo unixInodeInfo; /* An i-node */ typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */ @@ -212,10 +227,11 @@ void *lockingContext; /* Locking style specific state */ UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ + int eGetLk, eSetLk; #if SQLITE_MAX_MMAP_SIZE>0 int nFetchOut; /* Number of outstanding xFetch refs */ sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */ sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ @@ -746,14 +762,20 @@ */ static int lockTrace(int fd, int op, struct flock *p){ char *zOpName, *zType; int s; int savedErrno; - if( op==F_GETLK ){ + if( op==F_GETLK || op==F_OFD_GETLK ){ zOpName = "GETLK"; - }else if( op==F_SETLK ){ + }else if( op==F_SETLK || op==F_OFD_SETLK ){ zOpName = "SETLK"; +#if HAVE_OFD_LOCKS + }else if( op==F_OFD_GETLK ){ + zOpName = "OFD_GETLK"; + }else if( op==F_OFD_SETLK ){ + zOpName = "OFD_SETLK"; +#endif }else{ s = osFcntl(fd, op, p); sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); return s; } @@ -770,14 +792,17 @@ s = osFcntl(fd, op, p); savedErrno = errno; sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, (int)p->l_pid, s); - if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ + if( s==(-1) + && (op==F_SETLK || op==F_OFD_SETLK) + && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) + ){ struct flock l2; l2 = *p; - osFcntl(fd, F_GETLK, &l2); + osFcntl(fd, op==F_SETLK ? F_GETLK : F_OFD_GETLK, &l2); if( l2.l_type==F_RDLCK ){ zType = "RDLCK"; }else if( l2.l_type==F_WRLCK ){ zType = "WRLCK"; }else if( l2.l_type==F_UNLCK ){ @@ -992,27 +1017,29 @@ /****************************************************************************** *************************** Posix Advisory Locking **************************** ** ** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996) -** section 6.5.2.2 lines 483 through 490 specify that when a process +** section 6.5.2.2 lines 483 through 490 says that when a process ** sets or clears a lock, that operation overrides any prior locks set -** by the same process. It does not explicitly say so, but this implies -** that it overrides locks set by the same process using a different -** file descriptor. Consider this test case: +** by the *same process*. That means that if two different threads +** open the same file using different file descriptors, then POSIX +** advisory locking will not work to coordinate access between those two +** threads. Consider this test case: ** ** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); ** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); ** ** Suppose ./file1 and ./file2 are really the same file (because ** one is a hard or symbolic link to the other) then if you set ** an exclusive lock on fd1, then try to get an exclusive lock -** on fd2, it works. I would have expected the second lock to +** on fd2, it works. In a reasonable system, the second lock would ** fail since there was already a lock on the file due to fd1. -** But not so. Since both locks came from the same process, the -** second overrides the first, even though they were on different -** file descriptors opened on different file names. +** But this is not the case in POSIX advisory locking. Since both +** locks came from the same process, the second overrides the first, +** even though they were on different file descriptors opened on +** different file names. ** ** This means that we cannot use POSIX locks to synchronize file access ** among competing threads of the same process. POSIX locks will work fine ** to synchronize access for threads in separate processes, but not ** threads within the same process. @@ -1028,40 +1055,36 @@ ** ** (Aside: The use of inode numbers as unique IDs does not work on VxWorks. ** For VxWorks, we have to use the alternative unique ID system based on ** canonical filename and implemented in the previous division.) ** -** The sqlite3_file structure for POSIX is no longer just an integer file -** descriptor. It is now a structure that holds the integer file -** descriptor and a pointer to a structure that describes the internal -** locks on the corresponding inode. There is one locking structure -** per inode, so if the same inode is opened twice, both unixFile structures -** point to the same locking structure. The locking structure keeps -** a reference count (so we will know when to delete it) and a "cnt" -** field that tells us its internal lock status. cnt==0 means the -** file is unlocked. cnt==-1 means the file has an exclusive lock. -** cnt>0 means there are cnt shared locks on the file. +** The sqlite3_file object for POSIX (a.k.a. the unixFile object) is more +** than just an integer file descriptor. It also holds a pointer +** a pointer to another object (unixInodeInfo) that describes the +** internal locks on the corresponding inode. There is one +** unixInodeInfo object per inode, so if the same inode is opened twice, +** both unixFile objects point to the same lunixInodeInfo. The unixInodeInfo +** keeps a reference count (nRef) so we will know when to delete it. ** -** Any attempt to lock or unlock a file first checks the locking -** structure. The fcntl() system call is only invoked to set a -** POSIX lock if the internal lock structure transitions between -** a locked and an unlocked state. +** Any attempt to lock or unlock a unixFile first checks the unixInodeInfo. +** The fcntl() system call is only invoked to set a POSIX lock if the +** unixInodeInfo transitions between a locked and an unlocked state. ** ** But wait: there are yet more problems with POSIX advisory locks. ** ** If you close a file descriptor that points to a file that has locks, ** all locks on that file that are owned by the current process are ** released. To work around this problem, each unixInodeInfo object ** maintains a count of the number of pending locks on tha inode. -** When an attempt is made to close an unixFile, if there are -** other unixFile open on the same inode that are holding locks, the call +** When an attempt is made to close an unixFile, if there are other +** unixFile objcts open on the same inode that are holding locks, the call ** to close() the file descriptor is deferred until all of the locks clear. ** The unixInodeInfo structure keeps a list of file descriptors that need to ** be closed and that list is walked (and cleared) when the last lock ** clears. ** -** Yet another problem: LinuxThreads do not play well with posix locks. +** LinuxThreads: ** ** Many older versions of linux use the LinuxThreads library which is ** not posix compliant. Under LinuxThreads, a lock created by thread ** A cannot be modified or overridden by a different thread B. ** Only thread A can modify the lock. Locking behavior is correct @@ -1076,17 +1099,38 @@ ** SQLite used to support LinuxThreads. But support for LinuxThreads ** was dropped beginning with version 3.7.0. SQLite will still work with ** LinuxThreads provided that (1) there is no more than one connection ** per database file in the same process and (2) database connections ** do not move across threads. +** +** OFD Locks: +** +** Recent unix-like OSes have added support for Open File Description or "OFD" +** locks. (This is not a typo: the name is "Open File Description" not +** "Open File Descriptor". "-ion" not "-or". There is a subtle difference +** between "Discription" and "Descriptor" which is described on the Linux +** fcntl manpage and will not be repeated here.) The main difference +** between OFD locks and POSIX locks is that OFD locks are associated +** with a single open() system call and do not interfere with with file +** descriptors obtained from different open() system calls in the same +** process. In other words, OFD locks fix the brokenness of POSIX locks. +** +** As of 2018-06-19, SQLite will use OFD locks if they are available. +** But the older work-arounds for POSIX locks are still here in the code +** since SQLite also needs to work on systems that do not support +** OFD locks. Someday, perhaps, all unix systems will have reliable +** support for OFD locks, and at that time we can omit the unixInodeInfo +** object and all of its associated complication. But for now we still +** have to support the older POSIX lock work-around hack. */ /* ** An instance of the following structure serves as the key used ** to locate a particular unixInodeInfo object. */ struct unixFileId { + void *pExtra; dev_t dev; /* Device number */ #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID for vxworks. */ #else /* We are told that some versions of Android contain a bug that @@ -1339,10 +1383,11 @@ } #endif memset(&fileId, 0, sizeof(fileId)); fileId.dev = statbuf.st_dev; + if( UsesOfd(pFile) ) fileId.pExtra = pFile; #if OS_VXWORKS fileId.pId = pFile->pId; #else fileId.ino = (u64)statbuf.st_ino; #endif @@ -1450,11 +1495,12 @@ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; lock.l_len = 1; lock.l_type = F_WRLCK; - if( osFcntl(pFile->h, F_GETLK, &lock) ){ + lock.l_pid = 0; + if( osFcntl(pFile->h, pFile->eGetLk, &lock) ){ rc = SQLITE_IOERR_CHECKRESERVEDLOCK; storeLastErrno(pFile, errno); } else if( lock.l_type!=F_UNLCK ){ reserved = 1; } @@ -1480,26 +1526,27 @@ ** ** If SQLITE_ENABLE_SETLK_TIMEOUT is not defined, then do a non-blocking ** attempt to set the lock. */ #ifndef SQLITE_ENABLE_SETLK_TIMEOUT -# define osSetPosixAdvisoryLock(h,x,t) osFcntl(h,F_SETLK,x) +# define osSetAdvisoryLock(h,e,x,t) osFcntl(h,e,x) #else -static int osSetPosixAdvisoryLock( +static int osSetAdvisoryLock( int h, /* The file descriptor on which to take the lock */ + int eSetLk, /* ioctl verb for setting the lock */ struct flock *pLock, /* The description of the lock */ unixFile *pFile /* Structure holding timeout value */ ){ - int rc = osFcntl(h,F_SETLK,pLock); + int rc = osFcntl(h,eSetLk,pLock); while( rc<0 && pFile->iBusyTimeout>0 ){ /* On systems that support some kind of blocking file lock with a timeout, ** make appropriate changes here to invoke that blocking file lock. On ** generic posix, however, there is no such API. So we simply try the ** lock once every millisecond until either the timeout expires, or until ** the lock is obtained. */ usleep(1000); - rc = osFcntl(h,F_SETLK,pLock); + rc = osFcntl(h,eSetLk,pLock); pFile->iBusyTimeout--; } return rc; } #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ @@ -1535,19 +1582,21 @@ assert( pInode->nLock==0 ); lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; lock.l_type = F_WRLCK; - rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile); + lock.l_pid = 0; + rc = osSetAdvisoryLock(pFile->h, pFile->eSetLk, &lock, pFile); if( rc<0 ) return rc; pInode->bProcessLock = 1; pInode->nLock++; }else{ rc = 0; } }else{ - rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile); + pLock->l_pid = 0; + rc = osSetAdvisoryLock(pFile->h, pFile->eSetLk, pLock, pFile); } return rc; } /* @@ -1662,21 +1711,22 @@ /* If a SHARED lock is requested, and some thread using this PID already ** has a SHARED or RESERVED lock, then increment reference counts and ** return SQLITE_OK. */ - if( eFileLock==SHARED_LOCK && - (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ + if( eFileLock==SHARED_LOCK + && UsesOldStylePosixLocks(pFile) + && (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) + ){ assert( eFileLock==SHARED_LOCK ); assert( pFile->eFileLock==0 ); assert( pInode->nShared>0 ); pFile->eFileLock = SHARED_LOCK; pInode->nShared++; pInode->nLock++; goto end_lock; } - /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ @@ -3908,10 +3958,16 @@ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { pFile->iBusyTimeout = *(int*)pArg; return SQLITE_OK; } +#endif +#if HAVE_OFD_LOCKS + case SQLITE_FCNTL_OFD_LOCKS: { + *(int*)pArg = UsesOfd(pFile); + return SQLITE_OK; + } #endif #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; int rc = SQLITE_OK; @@ -4228,11 +4284,12 @@ /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; - rc = osSetPosixAdvisoryLock(pShmNode->h, &f, pFile); + f.l_pid = 0; + rc = osSetAdvisoryLock(pShmNode->h, pFile->eSetLk, &f, pFile); rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; } /* Update the global lock state and do debug tracing */ #ifdef SQLITE_DEBUG @@ -4353,11 +4410,12 @@ ** system crash, the database itself may also become corrupt. */ lock.l_whence = SEEK_SET; lock.l_start = UNIX_SHM_DMS; lock.l_len = 1; lock.l_type = F_WRLCK; - if( osFcntl(pShmNode->h, F_GETLK, &lock)!=0 ) { + lock.l_pid = 0; + if( osFcntl(pShmNode->h, pDbFd->eGetLk, &lock)!=0 ) { rc = SQLITE_IOERR_LOCK; }else if( lock.l_type==F_UNLCK ){ if( pShmNode->isReadonly ){ pShmNode->isUnlocked = 1; rc = SQLITE_READONLY_CANTINIT; @@ -5423,10 +5481,26 @@ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } + pNew->eSetLk = F_SETLK; + pNew->eGetLk = F_GETLK; +#if HAVE_OFD_LOCKS + if( sqlite3GlobalConfig.bOfdLocks && (pNew->ctrlFlags & UNIXFILE_EXCL)==0 ){ + struct flock lock; + lock.l_whence = SEEK_SET; + lock.l_start = RESERVED_BYTE; + lock.l_len = 1; + lock.l_type = F_WRLCK; + lock.l_pid = 0; + if( osFcntl(h, F_OFD_GETLK, &lock)==0 ){ + pNew->eSetLk = F_OFD_SETLK; + pNew->eGetLk = F_OFD_GETLK; + } + } +#endif #if OS_VXWORKS pNew->pId = vxworksFindFileId(zFilename); if( pNew->pId==0 ){ ctrlFlags |= UNIXFILE_NOLOCK; Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -1071,10 +1071,16 @@ **
  • [[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain ** a file lock using the xLock or xShmLock methods of the VFS to wait ** for up to M milliseconds before failing, where M is the single ** unsigned integer parameter. +** +**
  • [[SQLITE_FCNTL_OFD_LOCKS]] +** The [SQLITE_FCNTL_OFD_LOCKS] opcode will query whether or not OFD +** locking is currently being used for an open file. The argument is +** a pointer to an integer into which is written a value of 1 if OFD +** locks are being used for the file and 0 if OFD locks are not used. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 @@ -1106,10 +1112,11 @@ #define SQLITE_FCNTL_PDB 30 #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 +#define SQLITE_FCNTL_OFD_LOCKS 35 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO @@ -1947,10 +1954,17 @@ ** from the database as records are returned in sorted order. The default ** value for this option is to never use this optimization. Specifying a ** negative value for this option restores the default behaviour. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. +** +** [[SQLITE_CONFIG_OFD_LOCKS]] +**
    SQLITE_CONFIG_OFD_LOCKS +**
    The SQLITE_CONFIG_OFD_LOCKS option accepts a single parameter +** of type (int). If the value is true then OFD Locks are used on systems +** that support that feature. If the vlaue is false, then OFD locks are +** never used. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ @@ -1977,10 +1991,11 @@ #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ +#define SQLITE_CONFIG_OFD_LOCKS 29 /* int */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3368,10 +3368,11 @@ #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ + int bOfdLocks; /* Use OFD locks on supported systems */ int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ }; /* Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -5960,10 +5960,51 @@ rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist); sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist); Tcl_AppendResult(interp, z, (char*)0); return TCL_OK; } + +/* +** tclcmd: file_control_ofd_locks DB +** +** Run sqlite3_file_control() to query the OFD lock capability. Return: +** +** 2 OFD locks are available and are used on DB +** 1 OFD locks are available but DB is not using them +** 0 OFD locks are not available +*/ +static int SQLITE_TCLAPI file_control_ofd_locks( + ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + int rc; + int b = 0; + const char *z; + + if( objc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetStringFromObj(objv[0], 0), " DB", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ + return TCL_ERROR; + } + b = 0; + rc = sqlite3_file_control(db,NULL,SQLITE_FCNTL_OFD_LOCKS,(void*)&b); + if( rc!=SQLITE_OK ){ + z = "0"; + }else if( b ){ + z = "2"; + }else{ + z = "1"; + } + Tcl_AppendResult(interp, z, (char*)0); + return TCL_OK; +} /* ** tclcmd: file_control_powersafe_overwrite DB PSOW-FLAG ** ** This TCL command runs the sqlite3_file_control interface with @@ -5992,11 +6033,10 @@ rc = sqlite3_file_control(db,NULL,SQLITE_FCNTL_POWERSAFE_OVERWRITE,(void*)&b); sqlite3_snprintf(sizeof(z), z, "%d %d", rc, b); Tcl_AppendResult(interp, z, (char*)0); return TCL_OK; } - /* ** tclcmd: file_control_vfsname DB ?AUXDB? ** ** Return a string that describes the stack of VFSes. @@ -7703,10 +7743,11 @@ { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, { "file_control_win32_get_handle", file_control_win32_get_handle, 0 }, { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, #endif { "file_control_persist_wal", file_control_persist_wal, 0 }, + { "file_control_ofd_locks", file_control_ofd_locks, 0 }, { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, { "file_control_vfsname", file_control_vfsname, 0 }, { "file_control_tempfilename", file_control_tempfilename, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, Index: src/test_malloc.c ================================================================== --- src/test_malloc.c +++ src/test_malloc.c @@ -1272,10 +1272,35 @@ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } +/* +** Usage: sqlite3_config_ofd_locks INTEGER +** +** Enable or disable the use of OFD locks. +*/ +static int SQLITE_TCLAPI test_config_ofd_locks( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int eOk; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[1], &eOk) ){ + return TCL_ERROR; + } + + sqlite3_config(SQLITE_CONFIG_OFD_LOCKS, eOk); + + return TCL_OK; +} /* ** Usage: sqlite3_dump_memsys3 FILENAME ** sqlite3_dump_memsys5 FILENAME ** @@ -1528,10 +1553,11 @@ { "sqlite3_config_lookaside", test_config_lookaside ,0 }, { "sqlite3_config_error", test_config_error ,0 }, { "sqlite3_config_uri", test_config_uri ,0 }, { "sqlite3_config_cis", test_config_cis ,0 }, { "sqlite3_config_pmasz", test_config_pmasz ,0 }, + { "sqlite3_config_ofd_locks", test_config_ofd_locks ,0 }, { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }, { "sqlite3_install_memsys3", test_install_memsys3 ,0 }, { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 }, Index: test/unixexcl.test ================================================================== --- test/unixexcl.test +++ test/unixexcl.test @@ -22,10 +22,13 @@ finish_test return } set testprefix unixexcl +catch {db close} +sqlite3_shutdown +sqlite3_config_ofd_locks 0 # Test that when using VFS "unix-excl", the first time the database is read # a process-wide exclusive lock is taken on it. This means other connections # within the process may still access the db normally, but connections from @@ -124,6 +127,10 @@ sql1 { PRAGMA wal_checkpoint; } } {0 7 7} } } +catch {db close} +sqlite3_shutdown +sqlite3_config_ofd_locks 1 + finish_test