From: drh Date: Sat, 12 Mar 2011 17:02:57 +0000 (+0000) Subject: Add the new optional "unix-excl" VFS. This VFS grabs an exclusive lock on X-Git-Tag: version-3.7.6~103^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a7e61d8b247ded7b5b2283e6b598fb4cc1b7895a;p=thirdparty%2Fsqlite.git Add the new optional "unix-excl" VFS. This VFS grabs an exclusive lock on the database preventing other processes from accessing it, but continues to allow other database connections from the same process. FossilOrigin-Name: 00051c3296e11211b2bb5ae28f016b17dca857d7 --- diff --git a/manifest b/manifest index f956375794..014dfe961b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,8 @@ -C More\stests\sfor\sSQLITE_OMIT_UNIQUE_ENFORCEMENT\sand\sminor\schange\sto\simplementation. -D 2011-03-12T04:58:55.547 +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +C Add\sthe\snew\soptional\s"unix-excl"\sVFS.\s\sThis\sVFS\sgrabs\san\sexclusive\slock\son\nthe\sdatabase\spreventing\sother\sprocesses\sfrom\saccessing\sit,\sbut\scontinues\sto\nallow\sother\sdatabase\sconnections\sfrom\sthe\ssame\sprocess. +D 2011-03-12T17:02:57.101 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -162,7 +165,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 2596fd2d5d0976c6c0c628d0c3c7c4e7a724f4cf -F src/os_unix.c c4d50608133e16185dd2e120d2713c096f390260 +F src/os_unix.c 557837beff775c448bb072ae21edeff912d1f0df F src/os_win.c 24d72407a90551969744cf9bcbb1b4c72c5fa845 F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 @@ -177,7 +180,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c d24406c45dd2442eb2eeaac413439066b149c944 -F src/shell.c 649c51979812f77f97507024a4cea480c6862b8b +F src/shell.c 54f8fe0afab6839444882c4d18a0032668392c9a F src/sqlite.h.in 369c767e6b9f101d63d8e4c5e40279f975ccec08 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqliteInt.h 2cea3e47997e3f4d9b4f1ce62f99c35be1b5a586 @@ -913,7 +916,18 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P f957f23a8a392bb1720720960bda2c7b24de9663 -R 9809ca6e3f2473669b6771844893033b -U shaneh -Z 165de3d9f760ec4796ef397e07022985 +P b86999436ec2414c990ba720441fe316f647eef6 +R b4018b4a3ca8304164ff6618b813c5a9 +T *bgcolor * #aaa8d3 +T *branch * unix-excl +T *sym-unix-excl * +T -sym-trunk * +U drh +Z ca346ade739e93ef182345e803581a80 +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQFNe6dEoxKgR168RlERAkgMAJ47rTo3YzDvLp8S+pIflXBmm5FOSwCggCkn +s82X2XcH9cqBqUU6lQenClw= +=LUbU +-----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 1dab3e6dc1..e7ce79f84b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b86999436ec2414c990ba720441fe316f647eef6 \ No newline at end of file +00051c3296e11211b2bb5ae28f016b17dca857d7 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 0d72802bdf..c373ebee6b 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -206,6 +206,7 @@ struct unixFile { int h; /* The file descriptor */ int dirfd; /* File descriptor for the directory */ unsigned char eFileLock; /* The type of lock held on this fd */ + unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ @@ -242,6 +243,11 @@ struct unixFile { #endif }; +/* +** Allowed values for the unixFile.ctrlFlags bitmask: +*/ +#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ + /* ** Include code that is common to all os_*.c files */ @@ -887,7 +893,8 @@ struct unixFileId { struct unixInodeInfo { struct unixFileId fileId; /* The lookup key */ int nShared; /* Number of SHARED locks held */ - int eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ + unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ + unsigned char bProcessLock; /* An exclusive process lock is held */ int nRef; /* Number of pointers to this structure */ unixShmNode *pShmNode; /* Shared memory associated with this inode */ int nLock; /* Number of outstanding file locks */ @@ -1158,7 +1165,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ /* Otherwise see if some other process holds it. */ #ifndef __DJGPP__ - if( !reserved ){ + if( !reserved && !pFile->pInode->bProcessLock ){ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; @@ -1181,6 +1188,40 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ return rc; } +/* +** Attempt to set a system-lock on the file pFile. The lock is +** described by pLock. +** +** If the pFile was opened from unix-excl, then the only lock ever +** obtained is an exclusive lock, and it is obtained exactly once +** the first time any lock is attempted. All subsequent system locking +** operations become no-ops. Locking operations still happen internally, +** in order to coordinate access between separate database connections +** within this process, but all of that is handled in memory and the +** operating system does not participate. +*/ +static int unixFileLock(unixFile *pFile, struct flock *pLock){ + int rc; + assert( unixMutexHeld() ); + if( (pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pFile->pInode->bProcessLock ){ + if( pFile->pInode->bProcessLock==0 ){ + struct flock lock; + lock.l_whence = SEEK_SET; + lock.l_start = SHARED_FIRST; + lock.l_len = SHARED_SIZE; + lock.l_type = F_WRLCK; + rc = osFcntl(pFile->h, F_SETLK, &lock); + if( rc<0 ) return rc; + pFile->pInode->bProcessLock = 1; + }else{ + rc = 0; + } + }else{ + rc = osFcntl(pFile->h, F_SETLK, pLock); + } + return rc; +} + /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: @@ -1317,7 +1358,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ){ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; - s = osFcntl(pFile->h, F_SETLK, &lock); + s = unixFileLock(pFile, &lock); if( s==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); @@ -1339,14 +1380,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* Now get the read-lock */ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( (s = osFcntl(pFile->h, F_SETLK, &lock))==(-1) ){ + if( (s = unixFileLock(pFile, &lock))==(-1) ){ tErrno = errno; } /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; - if( osFcntl(pFile->h, F_SETLK, &lock)!=0 ){ + if( unixFileLock(pFile, &lock)!=0 ){ if( s != -1 ){ /* This could happen with a network mount */ tErrno = errno; @@ -1389,7 +1430,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ default: assert(0); } - s = osFcntl(pFile->h, F_SETLK, &lock); + s = unixFileLock(pFile, &lock); if( s==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); @@ -1458,7 +1499,7 @@ static void setPendingFd(unixFile *pFile){ ** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to ** remove the write lock on a region when a read lock is set. */ -static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ +static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; struct flock lock; @@ -1525,7 +1566,7 @@ static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; - if( osFcntl(h, F_SETLK, &lock)==(-1) ){ + if( unixFileLock(pFile,, &lock)==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ @@ -1537,7 +1578,7 @@ static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; - if( osFcntl(h, F_SETLK, &lock)==(-1) ){ + if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); if( IS_LOCK_ERROR(rc) ){ @@ -1549,7 +1590,7 @@ static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST+divSize; lock.l_len = SHARED_SIZE-divSize; - if( osFcntl(h, F_SETLK, &lock)==(-1) ){ + if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ @@ -1564,7 +1605,7 @@ static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( osFcntl(h, F_SETLK, &lock)==(-1) ){ + if( unixFileLock(pFile, &lock)==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); if( IS_LOCK_ERROR(rc) ){ @@ -1578,7 +1619,7 @@ static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); - if( osFcntl(h, F_SETLK, &lock)!=(-1) ){ + if( unixFileLock(pFile, &lock)!=(-1) ){ pInode->eFileLock = SHARED_LOCK; }else{ tErrno = errno; @@ -1602,7 +1643,7 @@ static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ SimulateIOErrorBenign(1); SimulateIOError( h=(-1) ) SimulateIOErrorBenign(0); - if( osFcntl(h, F_SETLK, &lock)!=(-1) ){ + if( unixFileLock(pFile, &lock)!=(-1) ){ pInode->eFileLock = NO_LOCK; }else{ tErrno = errno; @@ -1640,7 +1681,7 @@ end_unlock: ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int eFileLock){ - return _posixUnlock(id, eFileLock, 0); + return posixUnlock(id, eFileLock, 0); } /* @@ -2821,7 +2862,7 @@ static int afpClose(sqlite3_file *id) { ** the requested locking level, this routine is a no-op. */ static int nfsUnlock(sqlite3_file *id, int eFileLock){ - return _posixUnlock(id, eFileLock, 1); + return posixUnlock(id, eFileLock, 1); } #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ @@ -4351,6 +4392,11 @@ static int fillInUnixFile( pNew->h = h; pNew->dirfd = dirfd; pNew->zPath = zFilename; + if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ + pNew->ctrlFlags = UNIXFILE_EXCL; + }else{ + pNew->ctrlFlags = 0; + } #if OS_VXWORKS pNew->pId = vxworksFindFileId(zFilename); @@ -6550,6 +6596,7 @@ int sqlite3_os_init(void){ #endif UNIXVFS("unix-none", nolockIoFinder ), UNIXVFS("unix-dotfile", dotlockIoFinder ), + UNIXVFS("unix-excl", posixIoFinder ), #if OS_VXWORKS UNIXVFS("unix-namedsem", semIoFinder ), #endif diff --git a/src/shell.c b/src/shell.c index 82bb20f5e0..a617c06795 100644 --- a/src/shell.c +++ b/src/shell.c @@ -419,6 +419,7 @@ struct callback_data { ** .explain ON */ char outfile[FILENAME_MAX]; /* Filename for *out */ const char *zDbFilename; /* name of the database file */ + const char *zVfs; /* Name of VFS to use */ sqlite3_stmt *pStmt; /* Current statement if any. */ FILE *pLog; /* Write log output here */ }; @@ -2600,6 +2601,7 @@ static const char zOptions[] = " -stats print memory stats before each finalize\n" " -nullvalue 'text' set text string for NULL values\n" " -version show SQLite version\n" + " -vfs NAME use NAME as the default VFS\n" ; static void usage(int showDetail){ fprintf(stderr, @@ -2684,6 +2686,15 @@ int main(int argc, char **argv){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #endif + }else if( strcmp(argv[i],"-vfs")==0 ){ + i++; + sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[i]); + if( pVfs ){ + sqlite3_vfs_register(pVfs, 1); + }else{ + fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]); + exit(1); + } } } if( i