]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add in-process file locking to test_async.c. The unix implementation of
authordrh <drh@noemail.net>
Mon, 13 Feb 2006 17:03:47 +0000 (17:03 +0000)
committerdrh <drh@noemail.net>
Mon, 13 Feb 2006 17:03:47 +0000 (17:03 +0000)
sqlite3OsFullPathname() now attempts to remove /./ and /../ elements from
the path. (CVS 3090)

FossilOrigin-Name: 42379c623073eb541d053c2dff9f49087fb290f8

manifest
manifest.uuid
src/os_unix.c
src/test_async.c

index ce77ca441e15b7693d712e9170ee2460ab27c651..bbb770d6d9c8eff47d1476c146eb72e9a6f74dd8 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sdeadlock\sproblem\son\sthe\ssqlite3async_wait\stest\sinterface.\s\sImprovements\nto\stracing\sin\stest_async.c.\s(CVS\s3089)
-D 2006-02-13T15:29:33
+C Add\sin-process\sfile\slocking\sto\stest_async.c.\s\sThe\sunix\simplementation\sof\nsqlite3OsFullPathname()\snow\sattempts\sto\sremove\s/./\sand\s/../\selements\sfrom\nthe\spath.\s(CVS\s3090)
+D 2006-02-13T17:03:48
 F Makefile.in 5d8dff443383918b700e495de42ec65bc1c8865b
 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -55,7 +55,7 @@ F src/os.h 93035a0e3b9dd05cdd0aaef32ea28ca28e02fe78
 F src/os_common.h 108cd719c96a2b714b64e02aeabbd40684274e6a
 F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c
 F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3
-F src/os_unix.c 378a89aaf15d83b901c1b73350e91ddecf743986
+F src/os_unix.c 7604ea2bdb447c1f87ca9f5103e452b9cd1cbd1d
 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
 F src/os_win.c c67a2c46d929cf54c8f80ec5e6079cf684a141a9
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
@@ -80,7 +80,7 @@ F src/test4.c ff4e9406b3d2809966d8f0e82468ac5508be9f56
 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
 F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de
 F src/test7.c d28d3e62f9594923648fc6a8fb030eba36564ba1
-F src/test_async.c b721c7cfcf40374a5e88d0ccd99d6354c7e5e258
+F src/test_async.c 2f43ce5293ca20bcd607d7fd261f8f2897cf9821
 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3
 F src/test_server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/tokenize.c 382b3bb0ca26eb9153b5d20b246ef512a114a24f
@@ -352,7 +352,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 4c6dfec54fc128644e066c04902433f8df30672e
-R 0f06f2bb71d391db7d343449491e5029
+P 58c6d501385c6f7656290e8451e28be3fc45843f
+R b777aa4c4acd9e845f59e4ffc4f5724f
 U drh
-Z 257635654268c39c1b6895d7785df9c1
+Z bfa3cfee6b6173ed141a70e906af7ee7
index ff9801566c6df72ea9019f1bedfb2c8f34c5c576..86cd9f67b86a87de4cd90f3e84f64ca5896f6ab7 100644 (file)
@@ -1 +1 @@
-58c6d501385c6f7656290e8451e28be3fc45843f
\ No newline at end of file
+42379c623073eb541d053c2dff9f49087fb290f8
\ No newline at end of file
index f7adab2b2c30527fef7466b80ecfeafb9b2d2df7..6621625ac220641218dab06eaf5dd7ff0dedf2da 100644 (file)
@@ -1539,6 +1539,7 @@ static int unixClose(OsFile **pId){
 */
 char *sqlite3UnixFullPathname(const char *zRelative){
   char *zFull = 0;
+  int i, j;
   if( zRelative[0]=='/' ){
     sqlite3SetString(&zFull, zRelative, (char*)0);
   }else{
@@ -1551,6 +1552,28 @@ char *sqlite3UnixFullPathname(const char *zRelative){
                     (char*)0);
     sqliteFree(zBuf);
   }
+  /*
+  ** Remove "/./" path elements and convert "/A/./" path elements
+  ** to just "/".
+  */
+  if( zFull ){
+    for(i=j=0; zFull[i]; i++){
+      if( zFull[i]=='/' ){
+        if( zFull[i+1]=='/' ) continue;
+        if( zFull[i+1]=='.' && zFull[i+2]=='/' ){
+          i += 1;
+          continue;
+        }
+        if( zFull[i+1]=='.' && zFull[i+2]=='.' && zFull[i+3]=='/' ){
+          while( j>0 && zFull[j-1]!='/' ){ j--; }
+          i += 3;
+          continue;
+        }
+      }
+      zFull[j++] = zFull[i];
+    }
+    zFull[j] = 0;
+  }
   return zFull;
 }
 
index 989ab27c192d63d63604a6035b5be06dc5e4db74..fa8787ed56d342b992d1be03ed3a853db09dade9 100644 (file)
@@ -161,8 +161,10 @@ static void asyncTrace(const char *zFormat, ...){
 **
 **         asyncLock, asyncUnlock, asyncLockState, asyncCheckReservedLock
 **    
-**     These locking primitives become no-ops. Files are always opened for 
-**     exclusive access when using this IO backend.  
+**     These primitives implement in-process locking using a hash table
+**     on the file name.  Files are locked correctly for connections coming
+**     from the same process.  But other processes cannot see these locks
+**     and will therefore not honor them.
 **
 **
 **         asyncFileHandle.
@@ -233,14 +235,17 @@ static void asyncTrace(const char *zFormat, ...){
 static struct TestAsyncStaticData {
   pthread_mutex_t queueMutex;  /* Mutex for access to write operation queue */
   pthread_mutex_t writerMutex; /* Prevents multiple writer threads */
+  pthread_mutex_t lockMutex;   /* For access to aLock hash table */
   pthread_cond_t queueSignal;  /* For waking up sleeping writer thread */
   pthread_cond_t emptySignal;  /* Notify when the write queue is empty */
   AsyncWrite *pQueueFirst;     /* Next write operation to be processed */
   AsyncWrite *pQueueLast;      /* Last write operation on the list */
+  Hash aLock;                  /* Files locked */
   volatile int ioDelay;             /* Extra delay between write operations */
   volatile int writerHaltWhenIdle;  /* Writer thread halts when queue empty */
   volatile int writerHaltNow;       /* Writer thread halts after next op */
 } async = {
+  PTHREAD_MUTEX_INITIALIZER,
   PTHREAD_MUTEX_INITIALIZER,
   PTHREAD_MUTEX_INITIALIZER,
   PTHREAD_COND_INITIALIZER,
@@ -255,7 +260,6 @@ static struct TestAsyncStaticData {
 #define ASYNC_CLOSE         4
 #define ASYNC_OPENDIRECTORY 5
 #define ASYNC_SETFULLSYNC   6
-
 #define ASYNC_DELETE        7
 #define ASYNC_OPENEXCLUSIVE 8
 #define ASYNC_SYNCDIRECTORY 9
@@ -265,7 +269,7 @@ static struct TestAsyncStaticData {
 */
 static const char *azOpcodeName[] = {
   "NOOP", "WRITE", "SYNC", "TRUNCATE", "CLOSE",
-  "OPENDIR", "SETFULLSYNC", "DELETE", "OPENEX", "SYNCDIR"
+  "OPENDIR", "SETFULLSYNC", "DELETE", "OPENEX", "SYNCDIR",
 };
 
 /*
@@ -308,6 +312,7 @@ static const char *azOpcodeName[] = {
 **     iOffset -> Value of "delflag".
 **     nByte   -> Number of bytes of zBuf points to (file name).
 **
+**
 ** For an ASYNC_WRITE operation, zBuf points to the data to write to the file. 
 ** This space is sqliteMalloc()d along with the AsyncWrite structure in a
 ** single blob, so is deleted when sqliteFree() is called on the parent 
@@ -329,6 +334,8 @@ struct AsyncFile {
   IoMethod *pMethod;   /* Must be first */
   int ioError;         /* Value of any asychronous error we have seen */
   i64 iOffset;         /* Current seek() offset in file */
+  char *zName;         /* Underlying OS filename - used for debugging */
+  int nName;           /* Number of characters in zName */
   OsFile *pBaseRead;   /* Read handle to the underlying Os file */
   OsFile *pBaseWrite;  /* Write handle to the underlying Os file */
 };
@@ -356,7 +363,8 @@ static void addAsyncWrite(AsyncWrite *pWrite){
     async.pQueueFirst = pWrite;
   }
   async.pQueueLast = pWrite;
-  TRACE(("PUSH %p (%s)\n", pWrite, azOpcodeName[pWrite->op]));
+  TRACE(("PUSH %p (%s %s)\n", pWrite, azOpcodeName[pWrite->op],
+         pWrite->pFile ? pWrite->pFile->zName : "-"));
 
   /* Drop the queue mutex */
   pthread_mutex_unlock(&async.queueMutex);
@@ -585,14 +593,23 @@ static int asyncFileHandle(OsFile *id){
 }
 
 /*
-** No file locking occurs with this version of the asynchronous backend.
-** So the locking routines are no-ops.
+** No disk locking is performed.  We keep track of locks locally in
+** the async.aLock hash table.  Locking should appear to work the same
+** as with standard (unmodified) SQLite as long as all connections 
+** come from this one process.  Connections from external processes
+** cannot see our internal hash table (obviously) and will thus not
+** honor our locks.
 */
 static int asyncLock(OsFile *id, int lockType){
+  AsyncFile *pFile = (AsyncFile*)id;
+  TRACE(("LOCK %d (%s)\n", lockType, pFile->zName));
+  pthread_mutex_lock(&async.lockMutex);
+  sqlite3HashInsert(&async.aLock, pFile->zName, pFile->nName, (void*)lockType);
+  pthread_mutex_unlock(&async.lockMutex);
   return SQLITE_OK;
 }
 static int asyncUnlock(OsFile *id, int lockType){
-  return SQLITE_OK;
+  return asyncLock(id, lockType);
 }
 
 /*
@@ -600,7 +617,13 @@ static int asyncUnlock(OsFile *id, int lockType){
 ** and is checking for a hot-journal.
 */
 static int asyncCheckReservedLock(OsFile *id){
-  return SQLITE_OK;
+  AsyncFile *pFile = (AsyncFile*)id;
+  int rc;
+  pthread_mutex_lock(&async.lockMutex);
+  rc = (int)sqlite3HashFind(&async.aLock, pFile->zName, pFile->nName);
+  pthread_mutex_unlock(&async.lockMutex);
+  TRACE(("CHECK-LOCK %d (%s)\n", rc, pFile->zName));
+  return rc;
 }
 
 /* 
@@ -632,7 +655,7 @@ static int asyncOpenFile(
   OsFile *pBaseRead,     /* The real OsFile from the real I/O routine */
   int openForWriting     /* Open a second file handle for writing if true */
 ){
-  int rc;
+  int rc, i, n;
   AsyncFile *p;
   OsFile *pBaseWrite = 0;
 
@@ -661,13 +684,17 @@ static int asyncOpenFile(
     }
   }
 
-  p = (AsyncFile *)sqlite3OsMalloc(sizeof(AsyncFile));
+  n = strlen(zName);
+  for(i=n-1; i>=0 && zName[i]!='/'; i--){}
+  p = (AsyncFile *)sqlite3OsMalloc(sizeof(AsyncFile) + n - i);
   if( !p ){
     rc = SQLITE_NOMEM;
     goto error_out;
   }
   memset(p, 0, sizeof(AsyncFile));
-  
+  p->zName = (char*)&p[1];
+  strcpy(p->zName, &zName[i+1]);
+  p->nName = n - i;
   p->pMethod = &iomethod;
   p->pBaseRead = pBaseRead;
   p->pBaseWrite = pBaseWrite;
@@ -759,6 +786,7 @@ static int asyncFileExists(const char *z){
     }
   }
 
+  TRACE(("EXISTS: %s = %d\n", z, ret));
   pthread_mutex_unlock(&async.queueMutex);
   return ret;
 }
@@ -772,6 +800,8 @@ static int asyncFileExists(const char *z){
 */
 static void asyncEnable(int enable){
   if( enable && xOrigOpenReadWrite==0 ){
+    sqlite3HashInit(&async.aLock, SQLITE_HASH_BINARY, 1);
+    
     xOrigOpenReadWrite = sqlite3Os.xOpenReadWrite;
     xOrigOpenReadOnly = sqlite3Os.xOpenReadOnly;
     xOrigOpenExclusive = sqlite3Os.xOpenExclusive;
@@ -787,6 +817,8 @@ static void asyncEnable(int enable){
     sqlite3Os.xSyncDirectory = asyncSyncDirectory;
   }
   if( !enable && xOrigOpenReadWrite!=0 ){
+    sqlite3HashClear(&async.aLock);
+
     sqlite3Os.xOpenReadWrite = xOrigOpenReadWrite;
     sqlite3Os.xOpenReadOnly = xOrigOpenReadOnly;
     sqlite3Os.xOpenExclusive = xOrigOpenExclusive;
@@ -847,7 +879,8 @@ static void *asyncWriterThread(void *NotUsed){
       }
     }
     if( p==0 ) break;
-    TRACE(("PROCESSING %p (%s)\n", p, azOpcodeName[p->op]));
+    TRACE(("PROCESSING %p (%s %s)\n", p, azOpcodeName[p->op],
+            p->pFile ? p->pFile->zName : "-"));
 
     /* Right now this thread is holding the mutex on the write-op queue.
     ** Variable 'p' points to the first entry in the write-op queue. In
@@ -1125,16 +1158,25 @@ static int testAsyncWait(
   int objc,
   Tcl_Obj *CONST objv[]
 ){
+  int cnt = 10;
   if( async.writerHaltNow==0 && async.writerHaltWhenIdle==0 ){
     Tcl_AppendResult(interp, "would block forever", (char*)0);
     return TCL_ERROR;
   }
-  TRACE(("WAIT\n"));
-  pthread_mutex_lock(&async.queueMutex);
-  pthread_cond_broadcast(&async.queueSignal);
-  pthread_mutex_unlock(&async.queueMutex);
-  pthread_mutex_lock(&async.writerMutex);
-  pthread_mutex_unlock(&async.writerMutex);
+  while( cnt-- && !pthread_mutex_trylock(&async.writerMutex) ){
+    pthread_mutex_unlock(&async.writerMutex);
+    sched_yield();
+  }
+  if( cnt>=0 ){
+    TRACE(("WAIT\n"));
+    pthread_mutex_lock(&async.queueMutex);
+    pthread_cond_broadcast(&async.queueSignal);
+    pthread_mutex_unlock(&async.queueMutex);
+    pthread_mutex_lock(&async.writerMutex);
+    pthread_mutex_unlock(&async.writerMutex);
+  }else{
+    TRACE(("NOTHING TO WAIT ON\n"));
+  }
   return TCL_OK;
 }