]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix error handling (malloc and io errors) in the asynchronous backend. (CVS 4404)
authordanielk1977 <danielk1977@noemail.net>
Wed, 5 Sep 2007 16:54:41 +0000 (16:54 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Wed, 5 Sep 2007 16:54:41 +0000 (16:54 +0000)
FossilOrigin-Name: 80a44382d149b9d53212c15368565ede31aa2dc4

manifest
manifest.uuid
src/test_async.c
test/async2.test
test/async3.test

index bd30bbaa7dc717717641bb7954bb76edae69ae0b..7dbe6bed5376911d95bbe3833b87e3ecabb73bde 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Test\sthat\sthe\sasynchronous\sbackend\sworks\swith\scomponents\slike\s"."\sor\s".."\sin\sthe\spath\sto\sthe\sdatabase\sfile.\s(CVS\s4403)
-D 2007-09-05T14:32:25
+C Fix\serror\shandling\s(malloc\sand\sio\serrors)\sin\sthe\sasynchronous\sbackend.\s(CVS\s4404)
+D 2007-09-05T16:54:41
 F Makefile.in cbfb898945536a8f9ea8b897e1586dd1fdbcc5db
 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -145,7 +145,7 @@ F src/test6.c 0513982dfef4da2a4154b538d2bf538b84ca21d3
 F src/test7.c a9d509d0e9ad214b4772696f49f6e61be26213d1
 F src/test8.c f113aa3723a52113d0fa7c28155ecd37e7e04077
 F src/test9.c b46c8fe02ac7cca1a7316436d8d38d50c66f4b2f
-F src/test_async.c 6e30875ed6227a28f61ce5fce6cd6b3571c06133
+F src/test_async.c 9bf363454cc1d5e0695c2ae51dd626f1f115fbe3
 F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436
 F src/test_btree.c c1308ba0b88ab577fa56c9e493a09829dfcded9c
 F src/test_config.c 6fb459214b27952b143f45e35200d94096d54cc6
@@ -181,8 +181,8 @@ F test/alter3.test a6eec8f454be9b6ce73d8d7dc711453675a10ce7
 F test/altermalloc.test 1f4d2d66750bea1a78cd9f0b7dba5bfb155dd6cf
 F test/analyze.test 2f55535aa335785db1a2f97d3f3831c16c09f8b0
 F test/async.test eca5ea2646ea4adfbfa276fa710238e79eb1d477
-F test/async2.test 75f2d15f4c27189ec3296cf2565ec91834bbed76
-F test/async3.test 60a6e5a8e739a418d3f95f16d3061e54583997ee
+F test/async2.test e56affa75ed822424a6f9b12b22db8031433bb7c
+F test/async3.test 08ea0217083e4866eb1b0147158298f2a2cd1346
 F test/attach.test b849e1baae863c3a6132ff8b9b1baf356ab6c178
 F test/attach2.test 78bc1a25ea8785c7571b44f5947ada2bd5d78127
 F test/attach3.test eafcafb107585aecc2ed1569a77914138eef46a9
@@ -570,7 +570,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 3aace2fa91e96038f7a32366828ac7520470fa67
-R 4773df5025bfb3384ab08322753dc6d8
+P 0a87a854226ccea920484613dd7f7873e673c96e
+R f4e7b2c15b1baf3a171de58fa18366fc
 U danielk1977
-Z f1ee4a8ff07588869cdd656e05c5eaeb
+Z 99f53f4bf25aa26163bc39c798fb3945
index 3b6c7842d074e752252eebb36ca3d087d22fde55..4d1cadd3d7327f5494df24a74531c7355188e761 100644 (file)
@@ -1 +1 @@
-0a87a854226ccea920484613dd7f7873e673c96e
\ No newline at end of file
+80a44382d149b9d53212c15368565ede31aa2dc4
\ No newline at end of file
index f4f564c848caae9117befc0d20dcb7243b6f9acd..de09edcda73ded4a76d3375c3e91f988b60d67c0 100644 (file)
@@ -360,6 +360,7 @@ struct AsyncFileData {
   sqlite3_file *pBaseRead;   /* Read handle to the underlying Os file */
   sqlite3_file *pBaseWrite;  /* Write handle to the underlying Os file */
   AsyncFileLock lock;
+  AsyncWrite close;
 };
 
 /*
@@ -390,9 +391,6 @@ static void addAsyncWrite(AsyncWrite *pWrite){
 
   if( pWrite->op==ASYNC_CLOSE ){
     async.nFile--;
-    if( async.nFile==0 ){
-      async.ioError = SQLITE_OK;
-    }
   }
 
   /* Drop the queue mutex */
@@ -433,7 +431,13 @@ static int addNewAsyncWrite(
   }
   p = sqlite3_malloc(sizeof(AsyncWrite) + (zByte?nByte:0));
   if( !p ){
-    return SQLITE_NOMEM;
+    /* The upper layer does not expect operations like OsWrite() to
+    ** return SQLITE_NOMEM. This is partly because under normal conditions
+    ** SQLite is required to do rollback without calling malloc(). So
+    ** if malloc() fails here, treat it as an I/O error. The above
+    ** layer knows how to handle that.
+    */
+    return SQLITE_IOERR;
   }
   p->op = op;
   p->iOffset = iOffset;
@@ -462,7 +466,8 @@ static int asyncClose(sqlite3_file *pFile){
   p->lock.eLock = 0;
   pthread_mutex_unlock(&async.lockMutex);
 
-  return addNewAsyncWrite(p, ASYNC_CLOSE, 0, 0, 0);
+  addAsyncWrite(&p->close);
+  return SQLITE_OK;
 }
 
 /*
@@ -737,6 +742,34 @@ static int asyncDeviceCharacteristics(sqlite3_file *pFile){
   return 0;
 }
 
+static int unlinkAsyncFile(AsyncFileData *pData){
+  AsyncLock *pLock;
+  AsyncFileLock **ppIter;
+  int rc = SQLITE_OK;
+
+  pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName);
+  for(ppIter=&pLock->pList; *ppIter; ppIter=&((*ppIter)->pNext)){
+    if( (*ppIter)==&pData->lock ){
+      *ppIter = pData->lock.pNext;
+      break;
+    }
+  }
+  if( !pLock->pList ){
+    if( pLock->pFile ){
+      sqlite3OsClose(pLock->pFile);
+    }
+    sqlite3_free(pLock);
+    sqlite3HashInsert(&async.aLock, pData->zName, pData->nName, 0);
+    if( !sqliteHashFirst(&async.aLock) ){
+      sqlite3HashClear(&async.aLock);
+    }
+  }else{
+    rc = getFileLock(pLock);
+  }
+
+  return rc;
+}
+
 /*
 ** Open a file.
 */
@@ -766,11 +799,11 @@ static int asyncOpen(
   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
   AsyncFile *p = (AsyncFile *)pFile;
   int nName = strlen(zName)+1;
-  int rc;
+  int rc = SQLITE_OK;
   int nByte;
   AsyncFileData *pData;
-
   AsyncLock *pLock = 0;
+  int isExclusive = (flags&SQLITE_OPEN_EXCLUSIVE);
 
   nByte = (
     sizeof(AsyncFileData) +        /* AsyncFileData structure */
@@ -786,12 +819,11 @@ static int asyncOpen(
   pData->nName = nName;
   pData->pBaseRead = (sqlite3_file *)&pData->zName[nName];
   pData->pBaseWrite = (sqlite3_file *)&pData->zName[nName+pVfs->szOsFile];
+  pData->close.pFileData = pData;
+  pData->close.op = ASYNC_CLOSE;
   memcpy(pData->zName, zName, nName);
 
-  if( flags&SQLITE_OPEN_EXCLUSIVE ){
-    rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (i64)flags, 0, 0);
-    if( pOutFlags ) *pOutFlags = flags;
-  }else{
+  if( !isExclusive ){
     rc = sqlite3OsOpen(pVfs, zName, pData->pBaseRead, flags, pOutFlags);
     if( rc==SQLITE_OK && ((*pOutFlags)&SQLITE_OPEN_READWRITE) ){
       rc = sqlite3OsOpen(pVfs, zName, pData->pBaseWrite, flags, 0);
@@ -805,6 +837,7 @@ static int asyncOpen(
     if( !pLock ){
       pLock = sqlite3MallocZero(pVfs->szOsFile + sizeof(AsyncLock));
       if( pLock ){
+        AsyncLock *pDelete;
 #ifdef ENABLE_FILE_LOCKING
         if( flags&SQLITE_OPEN_MAIN_DB ){
           pLock->pFile = (sqlite3_file *)&pLock[1];
@@ -815,9 +848,13 @@ static int asyncOpen(
           }
         }
 #endif
-        sqlite3HashInsert(
+        pDelete = sqlite3HashInsert(
           &async.aLock, pData->zName, pData->nName, (void *)pLock
         );
+        if( pDelete ){
+          rc = SQLITE_NOMEM;
+          sqlite3_free(pLock);
+        }
       }else{
         rc = SQLITE_NOMEM;
       }
@@ -845,6 +882,18 @@ static int asyncOpen(
   }
 
   pthread_mutex_unlock(&async.lockMutex);
+
+  if( rc==SQLITE_OK && isExclusive ){
+    rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (i64)flags, 0, 0);
+    if( rc==SQLITE_OK ){
+      if( pOutFlags ) *pOutFlags = flags;
+    }else{
+      pthread_mutex_lock(&async.lockMutex);
+      unlinkAsyncFile(pData);
+      pthread_mutex_unlock(&async.lockMutex);
+      sqlite3_free(pData);
+    }
+  }
   return rc;
 }
 
@@ -1062,6 +1111,7 @@ static void *asyncWriterThread(void *NotUsed){
     return 0;
   }
   while( async.writerHaltNow==0 ){
+    int doNotFree = 0;
     sqlite3_file *pBase = 0;
 
     if( !holdingMutex ){
@@ -1143,8 +1193,6 @@ static void *asyncWriterThread(void *NotUsed){
         break;
 
       case ASYNC_CLOSE: {
-        AsyncLock *pLock;
-        AsyncFileLock **ppIter;
         AsyncFileData *pData = p->pFileData;
         ASYNC_TRACE(("CLOSE %s\n", p->pFileData->zName));
         sqlite3OsClose(pData->pBaseWrite);
@@ -1155,28 +1203,12 @@ static void *asyncWriterThread(void *NotUsed){
         ** before doing so.
         */
         pthread_mutex_lock(&async.lockMutex);
-        pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName);
-        for(ppIter=&pLock->pList; *ppIter; ppIter=&((*ppIter)->pNext)){
-          if( (*ppIter)==&pData->lock ){
-            *ppIter = pData->lock.pNext;
-            break;
-          }
-        }
-        if( !pLock->pList ){
-          if( pLock->pFile ){
-            sqlite3OsClose(pLock->pFile);
-          }
-          sqlite3_free(pLock);
-          sqlite3HashInsert(&async.aLock, pData->zName, pData->nName, 0);
-          if( !sqliteHashFirst(&async.aLock) ){
-            sqlite3HashClear(&async.aLock);
-          }
-        }else{
-          rc = getFileLock(pLock);
-        }
+        rc = unlinkAsyncFile(pData);
         pthread_mutex_unlock(&async.lockMutex);
 
+        async.pQueueFirst = p->pNext;
         sqlite3_free(pData);
+        doNotFree = 1;
         break;
       }
 
@@ -1227,8 +1259,10 @@ static void *asyncWriterThread(void *NotUsed){
     if( p==async.pQueueLast ){
       async.pQueueLast = 0;
     }
-    async.pQueueFirst = p->pNext;
-    sqlite3_free(p);
+    if( !doNotFree ){
+      async.pQueueFirst = p->pNext;
+      sqlite3_free(p);
+    }
     assert( holdingMutex );
 
     /* An IO error has occured. We cannot report the error back to the
@@ -1253,11 +1287,18 @@ static void *asyncWriterThread(void *NotUsed){
       async.ioError = rc;
     }
 
+    if( async.ioError && !async.pQueueFirst ){
+      pthread_mutex_lock(&async.lockMutex);
+      if( 0==sqliteHashFirst(&async.aLock) ){
+        async.ioError = SQLITE_OK;
+      }
+      pthread_mutex_unlock(&async.lockMutex);
+    }
+
     /* Drop the queue mutex before continuing to the next write operation
     ** in order to give other threads a chance to work with the write queue.
     */
     if( !async.pQueueFirst || !async.ioError ){
-      sqlite3ApiExit(0, 0);
       pthread_mutex_unlock(&async.queueMutex);
       holdingMutex = 0;
       if( async.ioDelay>0 ){
index 3403ea44c03f114a41bf78f21a78fb0fac8fcf44..cfbe06a55ff68db5108a2b5350df5bde8af06043 100644 (file)
@@ -5,7 +5,7 @@
 #
 #***********************************************************************
 #
-# $Id: async2.test,v 1.7 2007/09/05 11:34:54 danielk1977 Exp $
+# $Id: async2.test,v 1.8 2007/09/05 16:54:41 danielk1977 Exp $
 
 
 set testdir [file dirname $argv0]
@@ -46,7 +46,6 @@ set sql_script {
 
 db close
 
-
 foreach err [list ioerr malloc-transient malloc-persistent] {
   set ::go 1
   for {set n 1} {$::go} {incr n} {
@@ -59,14 +58,16 @@ foreach err [list ioerr malloc-transient malloc-persistent] {
   
     sqlite3async_enable 1
     sqlite3 db test.db
-    execsql $::sql_script
-    db close
   
     switch -- $err {
       ioerr             { set ::sqlite_io_error_pending $n }
       malloc-persistent { sqlite3_memdebug_fail $n -repeat 1 }
       malloc-transient  { sqlite3_memdebug_fail $n -repeat 0 }
     }
+
+    catchsql $::sql_script
+    db close
+
     sqlite3async_halt idle
     sqlite3async_start
     sqlite3async_wait
index d45f0a83786c95a333baa30b0ff53fea3c2aab1a..0434a285300fa7c0904fc1b7ef7c263b8517d4ee 100644 (file)
@@ -13,7 +13,7 @@
 # Specifically, it tests that the xFullPathname() method of
 # of the asynchronous vfs works correctly.
 #
-# $Id: async3.test,v 1.1 2007/09/05 14:32:25 danielk1977 Exp $
+# $Id: async3.test,v 1.2 2007/09/05 16:54:41 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -43,6 +43,7 @@ do_test async3-1.0 {
   file delete -force chocolate/banana/vanilla/file.db
   file delete -force chocolate/banana/vanilla/file.db-journal
 } {}
+
 do_test async3-1.1 {
   sqlite3 db chocolate/banana/vanilla/file.db
   execsql {