]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Unix version of sqlite3OsLock(). (CVS 1520)
authordanielk1977 <danielk1977@noemail.net>
Tue, 1 Jun 2004 14:09:28 +0000 (14:09 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 1 Jun 2004 14:09:28 +0000 (14:09 +0000)
FossilOrigin-Name: 023d1760c1a720632b25c98d14bf521ab91861e2

manifest
manifest.uuid
src/os.h
src/os_unix.c
src/test1.c

index 5edfd367650cdeab87333dad90d59ae9c112fac4..64a6a1c2504530c310744919bc6b95608cb169fe 100644 (file)
--- 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
index 64bd601bcf99952b487090efbe7b12bf5921e034..3441b6cd410b505ba338f037200c3118ff248529 100644 (file)
@@ -1 +1 @@
-a84ece250035d02e399ec208aded524c20c12737
\ No newline at end of file
+023d1760c1a720632b25c98d14bf521ab91861e2
\ No newline at end of file
index 93fa5352c89a9de12384258603222aef3ae0f4c6..c94a8f6eb8f3b9242f2e4a00ecf1e171fc2555aa 100644 (file)
--- a/src/os.h
+++ b/src/os.h
 # 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_ */
index c2a3679b7db4d33502a90eb4bb056a869f10331c..3ba8b5b3170d38fb68efc7a35dacd0506d5d6c3c 100644 (file)
@@ -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 ){
index 9a8efce670855f3065da64d138977f17599f5e68..1d793b262780b6e65a1a11873c3724475782994b 100644 (file)
@@ -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 <filename>
+*/
+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 <file handle>
+*/
+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 <file handle> <locktype>
+*/
+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 <file handle>
+*/
+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;