From: danielk1977 Date: Tue, 1 Jun 2004 14:09:28 +0000 (+0000) Subject: Unix version of sqlite3OsLock(). (CVS 1520) X-Git-Tag: version-3.6.10~4554 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9a1d0abed448ba4deacabfac0fd7133e474b5321;p=thirdparty%2Fsqlite.git Unix version of sqlite3OsLock(). (CVS 1520) FossilOrigin-Name: 023d1760c1a720632b25c98d14bf521ab91861e2 --- diff --git a/manifest b/manifest index 5edfd36765..64a6a1c250 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypo\son\shomepage\s(CVS\s1519) -D 2004-06-01T12:59:50 +C Unix\sversion\sof\ssqlite3OsLock().\s(CVS\s1520) +D 2004-06-01T14:09:29 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -39,11 +39,11 @@ F src/insert.c 4268d9e3959cc845ea243fb4ec7507269404dad9 F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f F src/main.c 66c6c35e94f57a7505f7f44b5a9504fb60ca0730 F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481 -F src/os.h ab42f4a7c4c716f26b988e759b6e12085a3bfc67 +F src/os.h 833b9639720d1602d9bfa4ca69c615ec2bfe625a F src/os_common.h 744286a27de55c52f1b18921e8d17abbf7fafc0f F src/os_mac.c b823874690615ace0dd520d3ad1fe8bfd864b7e0 F src/os_mac.h 51d2445f47e182ed32d3bd6937f81070c6fd9bd4 -F src/os_unix.c 585665eccd31a9bb4dc090bc6b5e29d8d42899f0 +F src/os_unix.c 3dc2868d7ff477323f2eaedda0e05921afb6f124 F src/os_unix.h 426e1480f0847a7f8ba22aa9ac5115520875610b F src/os_win.c 92b51a38437b98d8aa3ac05b57c71e1d1092e5be F src/os_win.h 5d41af24caaef6c13a2d8e2399caa1c57d45c84d @@ -59,7 +59,7 @@ F src/sqlite.h.in d8222d4a1f76468560b60f2b7f5b592995ebd5cf F src/sqliteInt.h 8a3a6dc8ef5141563698a3b7a62fca7158cff1f5 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c ed8663e7703346ace72ca3899dba15dbfc0883d7 -F src/test1.c 42c494918ecfab5a86586a28a66a73968312aad1 +F src/test1.c 4a3cc1b628a29f24c0a43227a035d0f2a96eb634 F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872 F src/test3.c 86117b74ec7353d76f5cd85c144c7cda23a7e11b F src/test4.c caf675e443460ec76b04d78e1688986c17c82cec @@ -214,7 +214,7 @@ F www/support.tcl 67682848d6ddd283370451dc3da2e56cded9fc9a F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 915cba57123f859c7f128bd52580573877c502ba -R 869771be1ad6b0ff5d2cfdaa96e9bfc9 -U drh -Z b8d78d36bfca5048d38c8cf79e8d6789 +P a84ece250035d02e399ec208aded524c20c12737 +R 3b5d7842c2050c5f20aa6a72a163fd62 +U danielk1977 +Z e93eb17e32e32c7486f10dc44fff52c2 diff --git a/manifest.uuid b/manifest.uuid index 64bd601bcf..3441b6cd41 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a84ece250035d02e399ec208aded524c20c12737 \ No newline at end of file +023d1760c1a720632b25c98d14bf521ab91861e2 \ No newline at end of file diff --git a/src/os.h b/src/os.h index 93fa5352c8..c94a8f6eb8 100644 --- a/src/os.h +++ b/src/os.h @@ -80,6 +80,14 @@ # define TEMP_FILE_PREFIX "sqlite_" #endif +/* +** The following values may be passed as the second argument to +** sqlite3OsLock(). +*/ +#define SHARED_LOCK 1 +#define RESERVED_LOCK 2 +#define PENDING_LOCK 3 +#define EXCLUSIVE_LOCK 4 int sqlite3OsDelete(const char*); int sqlite3OsFileExists(const char*); @@ -105,5 +113,6 @@ int sqlite3OsCurrentTime(double*); void sqlite3OsEnterMutex(void); void sqlite3OsLeaveMutex(void); char *sqlite3OsFullPathname(const char*); +int sqlite3OsLock(OsFile*, int); #endif /* _SQLITE_OS_H_ */ diff --git a/src/os_unix.c b/src/os_unix.c index c2a3679b7d..3ba8b5b317 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -172,6 +172,7 @@ struct lockKey { struct lockInfo { struct lockKey key; /* The lookup key */ int cnt; /* 0: unlocked. -1: write lock. 1...: read lock. */ + int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ int nRef; /* Number of pointers to this structure */ }; @@ -265,6 +266,7 @@ int findLockInfo( pLock->key = key1; pLock->nRef = 1; pLock->cnt = 0; + pLock->locktype = 0; pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); if( pOld!=0 ){ assert( pOld==pLock ); @@ -648,36 +650,7 @@ int sqlite3OsFileSize(OsFile *id, off_t *pSize){ */ int sqlite3OsReadLock(OsFile *id){ int rc; - sqlite3OsEnterMutex(); - if( id->pLock->cnt>0 ){ - if( !id->locked ){ - id->pLock->cnt++; - id->locked = 1; - id->pOpen->nLock++; - } - rc = SQLITE_OK; - }else if( id->locked || id->pLock->cnt==0 ){ - struct flock lock; - int s; - lock.l_type = F_RDLCK; - lock.l_whence = SEEK_SET; - lock.l_start = lock.l_len = 0L; - s = fcntl(id->fd, F_SETLK, &lock); - if( s!=0 ){ - rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; - }else{ - rc = SQLITE_OK; - if( !id->locked ){ - id->pOpen->nLock++; - id->locked = 1; - } - id->pLock->cnt = 1; - } - }else{ - rc = SQLITE_BUSY; - } - sqlite3OsLeaveMutex(); - return rc; + return sqlite3OsLock(id, SHARED_LOCK); } /* @@ -688,27 +661,132 @@ int sqlite3OsReadLock(OsFile *id){ */ int sqlite3OsWriteLock(OsFile *id){ int rc; + return sqlite3OsLock(id, EXCLUSIVE_LOCK); +} + +/* +** Lock the file with the lock specified by parameter locktype - one +** of the following: +** +** SHARED_LOCK +** RESERVED_LOCK +** PENDING_LOCK +** EXCLUSIVE_LOCK +*/ +int sqlite3OsLock(OsFile *id, int locktype){ + int rc = SQLITE_OK; + struct lockInfo *pLock = id->pLock; + struct flock lock; + int s; + + /* It is an error to request any kind of lock before a shared lock */ + if( locktype>SHARED_LOCK && id->locked==0 ){ + rc = sqlite3OsLock(id, SHARED_LOCK); + if( rc!=SQLITE_OK ) return rc; + } + assert( locktype==SHARED_LOCK || id->locked!=0 ); + + /* If there is already a lock of this type or more restrictive on the + ** OsFile, do nothing. Don't use the end_lock: exit path, as + ** sqlite3OsEnterMutex() hasn't been called yet. + */ + if( id->locked>=locktype ){ + return SQLITE_OK; + } + sqlite3OsEnterMutex(); - if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){ - struct flock lock; - int s; - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = lock.l_len = 0L; + + /* If some thread using this PID has a lock via a different OsFile* + ** handle that precludes the requested lock, return BUSY. + */ + if( (id->locked!=pLock->locktype && + (pLock->locktype>RESERVED_LOCK || locktype!=SHARED_LOCK)) || + (locktype>RESERVED_LOCK && pLock->cnt>1) + ){ + rc = SQLITE_BUSY; + goto end_lock; + } + + /* 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( locktype==SHARED_LOCK && + (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){ + assert( locktype==SHARED_LOCK ); + assert( id->locked==0 ); + id->locked = SHARED_LOCK; + pLock->cnt++; + id->pOpen->nLock++; + goto end_lock; + } + + lock.l_len = 1L; + lock.l_whence = SEEK_SET; + + /* If control gets to this point, then actually go ahead and make + ** operating system calls for the specified lock. + */ + if( locktype==SHARED_LOCK ){ + assert( pLock->cnt==0 ); + assert( id->pOpen->nLock==0 ); + assert( pLock->locktype==0 ); + + /* Grab a read-lock on byte 2. This ensures that no other process + ** has a PENDING lock. + */ + lock.l_type = F_RDLCK; + lock.l_start = 2; s = fcntl(id->fd, F_SETLK, &lock); - if( s!=0 ){ + if( s ){ + rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; + goto end_lock; + } + + /* Now get a read-lock on byte 0 and renege on the byte 2 lock. */ + lock.l_start = 0; + s = fcntl(id->fd, F_SETLK, &lock); + lock.l_start = 2; + lock.l_type = F_UNLCK; + fcntl(id->fd, F_SETLK, &lock); + if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ - rc = SQLITE_OK; - if( !id->locked ){ - id->pOpen->nLock++; - id->locked = 1; - } - id->pLock->cnt = -1; + id->locked = SHARED_LOCK; + id->pOpen->nLock = 1; + pLock->cnt = 1; } }else{ - rc = SQLITE_BUSY; + /* The request was for a RESERVED, PENDING or EXCLUSIVE lock. It is + ** assumed that there is a SHARED or greater lock on the file + ** already. + */ + assert( 0!=id->locked ); + lock.l_type = F_WRLCK; + switch( locktype ){ + case RESERVED_LOCK: + lock.l_start = 1; + break; + case PENDING_LOCK: + lock.l_start = 2; + break; + case EXCLUSIVE_LOCK: + lock.l_start = 0; + break; + default: + assert(0); + } + s = fcntl(id->fd, F_SETLK, &lock); + if( s ){ + rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; + } } + + id->locked = locktype; + pLock->locktype = locktype; + assert(pLock->locktype==RESERVED_LOCK||(id->pOpen->nLock==1&&pLock->cnt==1)); + +end_lock: sqlite3OsLeaveMutex(); return rc; } @@ -725,6 +803,7 @@ int sqlite3OsUnlock(OsFile *id){ sqlite3OsEnterMutex(); assert( id->pLock->cnt!=0 ); if( id->pLock->cnt>1 ){ + id->locked = 0; id->pLock->cnt--; rc = SQLITE_OK; }else{ @@ -739,6 +818,8 @@ int sqlite3OsUnlock(OsFile *id){ }else{ rc = SQLITE_OK; id->pLock->cnt = 0; + id->pLock->locktype = 0; + id->locked = 0; } } if( rc==SQLITE_OK ){ diff --git a/src/test1.c b/src/test1.c index 9a8efce670..1d793b2627 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.68 2004/05/31 23:56:43 danielk1977 Exp $ +** $Id: test1.c,v 1.69 2004/06/01 14:09:29 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -117,6 +117,21 @@ static int getStmtPointer( return TCL_OK; } +/* +** Decode a pointer to an sqlite3_stmt object. +*/ +static int getFilePointer( + Tcl_Interp *interp, + const char *zArg, + OsFile **ppFile +){ + if( sscanf(zArg, PTR_FMT, (void**)ppFile)!=1 ){ + Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); + return TCL_ERROR; + } + return TCL_OK; +} + /* ** Generate a text representation of a pointer that can be understood ** by the getDbPointer and getVmPointer routines above. @@ -1677,7 +1692,144 @@ static int test_stmt_int( return TCL_OK; } +/* +** Usage: sqlite3OsOpenReadWrite +*/ +static int test_sqlite3OsOpenReadWrite( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + OsFile * pFile; + int rc; + int dummy; + char zBuf[100]; + + if( objc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetString(objv[0]), " filename", 0); + return TCL_ERROR; + } + + pFile = sqliteMalloc(sizeof(OsFile)); + rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy); + if( rc!=SQLITE_OK ){ + sqliteFree(pFile); + Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); + return TCL_ERROR; + } + makePointerStr(interp, zBuf, pFile); + Tcl_SetResult(interp, zBuf, 0); + return TCL_ERROR; +} + +/* +** Usage: sqlite3OsClose +*/ +static int test_sqlite3OsClose( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + OsFile * pFile; + int rc; + + if( objc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetString(objv[0]), " filehandle", 0); + return TCL_ERROR; + } + + if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){ + return TCL_ERROR; + } + rc = sqlite3OsClose(pFile); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); + return TCL_ERROR; + } + sqliteFree(pFile); + return TCL_OK; +} + +/* +** Usage: sqlite3OsLock +*/ +static int test_sqlite3OsLock( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + OsFile * pFile; + int rc; + if( objc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetString(objv[0]), + " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0); + return TCL_ERROR; + } + + if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){ + return TCL_ERROR; + } + + if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){ + rc = sqlite3OsLock(pFile, SHARED_LOCK); + } + else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){ + rc = sqlite3OsLock(pFile, RESERVED_LOCK); + } + else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){ + rc = sqlite3OsLock(pFile, PENDING_LOCK); + } + else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){ + rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK); + }else{ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetString(objv[0]), + " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0); + return TCL_ERROR; + } + + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: sqlite3OsUnlock +*/ +static int test_sqlite3OsUnlock( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + OsFile * pFile; + int rc; + + if( objc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetString(objv[0]), " filehandle", 0); + return TCL_ERROR; + } + + if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){ + return TCL_ERROR; + } + rc = sqlite3OsUnlock(pFile); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); + return TCL_ERROR; + } + return TCL_OK; +} /* ** Register commands with the TCL interpreter. @@ -1753,6 +1905,12 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_column_decltype16", test_stmt_utf16,sqlite3_column_decltype16}, { "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16}, + /* Functions from os.h */ + { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 }, + { "sqlite3OsClose", test_sqlite3OsClose, 0 }, + { "sqlite3OsLock", test_sqlite3OsLock, 0 }, + { "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 }, + }; int i;