]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add simple io error tests for test_async.c. (CVS 3094)
authordanielk1977 <danielk1977@noemail.net>
Tue, 14 Feb 2006 13:25:43 +0000 (13:25 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 14 Feb 2006 13:25:43 +0000 (13:25 +0000)
FossilOrigin-Name: 528dfb71801bb7b8a66944db6f32cc3dc0054118

manifest
manifest.uuid
src/test_async.c
test/async2.test [new file with mode: 0644]

index 44bd32e914ab538f65f835b087f4a2fe61c3f67f..fc163d00704fc8d7757b32ff72d5c03f8ab2766b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Changes\sso\sthat\stest_async.c\sworks\swith\smemory\smanagement\sturned\son.\s(CVS\s3093)
-D 2006-02-14T10:48:39
+C Add\ssimple\sio\serror\stests\sfor\stest_async.c.\s(CVS\s3094)
+D 2006-02-14T13:25:44
 F Makefile.in 5d8dff443383918b700e495de42ec65bc1c8865b
 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -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 02531d8b049ae0d8bf1a709ac691dac1d9b147bb
+F src/test_async.c 326fc8dcced899473fca2d877a05e446c1c92fef
 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3
 F src/test_server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/tokenize.c 382b3bb0ca26eb9153b5d20b246ef512a114a24f
@@ -106,6 +106,7 @@ F test/alter3.test a6eec8f454be9b6ce73d8d7dc711453675a10ce7
 F test/altermalloc.test 6e1f404ec021eb2ba6582e3c77b0a35cf206b7af
 F test/analyze.test 2f55535aa335785db1a2f97d3f3831c16c09f8b0
 F test/async.test ae59f861f17f3e9076cd557cd93677b7c77e57b5
+F test/async2.test 941fe5e7f44c3ab85fd62cfd615a20980d2ab717
 F test/attach.test 036315207c477211470168bf121b1c493f781515
 F test/attach2.test 0e6a7c54343c85dd877a1e86073a05176043ed40
 F test/attach3.test 63013383adc4380af69779f34f4af19bd49f7cbe
@@ -352,7 +353,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 111a426b3e2fae77c9e6c3cd903fd80652b23720
-R 9e1ed54ea3d446f32aefb065fced0a43
+P f4150c29df2774b4422d4296d913cdbcee62c859
+R aae805bd9f65608fc6774fd635877e1c
 U danielk1977
-Z fdf8411d6a6b39c9d4eae52b0ecfc18b
+Z 364385439507478c54b1444a42b19b2e
index 9ef0ef60fa360ffe80b846e57a6afb911b33b296..fbe63b5790808802328d04c745697b39ce3b2d67 100644 (file)
@@ -1 +1 @@
-f4150c29df2774b4422d4296d913cdbcee62c859
\ No newline at end of file
+528dfb71801bb7b8a66944db6f32cc3dc0054118
\ No newline at end of file
index 3760583561145a9e4deb8ca461a8f00a5d8ca085..422a0007bde87b1c9b00e5c3c9fd2cf5e78d6c77 100644 (file)
@@ -244,6 +244,8 @@ static struct TestAsyncStaticData {
   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 */
+  int ioError;                 /* True if an IO error has occured */
+  int nFile;                   /* Number of open files (from sqlite pov) */
 } async = {
   PTHREAD_MUTEX_INITIALIZER,
   PTHREAD_MUTEX_INITIALIZER,
@@ -332,7 +334,6 @@ struct AsyncWrite {
 */
 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 */
@@ -366,6 +367,13 @@ static void addAsyncWrite(AsyncWrite *pWrite){
   TRACE(("PUSH %p (%s %s)\n", pWrite, azOpcodeName[pWrite->op],
          pWrite->pFile ? pWrite->pFile->zName : "-"));
 
+  if( pWrite->op==ASYNC_CLOSE ){
+    async.nFile--;
+    if( async.nFile==0 ){
+      async.ioError = SQLITE_OK;
+    }
+  }
+
   /* Drop the queue mutex */
   pthread_mutex_unlock(&async.queueMutex);
 
@@ -374,6 +382,19 @@ static void addAsyncWrite(AsyncWrite *pWrite){
   pthread_cond_signal(&async.queueSignal);
 }
 
+/*
+** Increment async.nFile in a thread-safe manner.
+*/
+static void incrOpenFileCount(){
+  /* We must hold the queue mutex in order to modify async.nFile */
+  pthread_mutex_lock(&async.queueMutex);
+  if( async.nFile==0 ){
+    async.ioError = SQLITE_OK;
+  }
+  async.nFile++;
+  pthread_mutex_unlock(&async.queueMutex);
+}
+
 /*
 ** This is a utility function to allocate and populate a new AsyncWrite
 ** structure and insert it (via addAsyncWrite() ) into the global list.
@@ -386,8 +407,8 @@ static int addNewAsyncWrite(
   const char *zByte
 ){
   AsyncWrite *p;
-  if( pFile && pFile->ioError!=SQLITE_OK ){
-    return pFile->ioError;
+  if( op!=ASYNC_CLOSE && async.ioError ){
+    return async.ioError;
   }
   p = sqlite3OsMalloc(sizeof(AsyncWrite) + (zByte?nByte:0));
   if( !p ){
@@ -484,8 +505,8 @@ static int asyncRead(OsFile *id, void *obuf, int amt){
   /* If an I/O error has previously occurred on this file, then all
   ** subsequent operations fail.
   */
-  if( pFile->ioError!=SQLITE_OK ){
-    return pFile->ioError;
+  if( async.ioError!=SQLITE_OK ){
+    return async.ioError;
   }
 
   /* Grab the write queue mutex for the duration of the call */
@@ -708,7 +729,6 @@ static int asyncOpenFile(
   p->pMethod = &iomethod;
   p->pBaseRead = pBaseRead;
   p->pBaseWrite = pBaseWrite;
-  p->ioError = SQLITE_OK;
   
   *pFile = (OsFile *)p;
   return SQLITE_OK;
@@ -738,6 +758,9 @@ static int asyncOpenExclusive(const char *z, OsFile **ppFile, int delFlag){
       *ppFile = 0;
     }
   }
+  if( rc==SQLITE_OK ){
+    incrOpenFileCount();
+  }
   return rc;
 }
 static int asyncOpenReadOnly(const char *z, OsFile **ppFile){
@@ -746,6 +769,9 @@ static int asyncOpenReadOnly(const char *z, OsFile **ppFile){
   if( rc==SQLITE_OK ){
     rc = asyncOpenFile(z, ppFile, pBase, 0);
   }
+  if( rc==SQLITE_OK ){
+    incrOpenFileCount();
+  }
   return rc;
 }
 static int asyncOpenReadWrite(const char *z, OsFile **ppFile, int *pReadOnly){
@@ -754,6 +780,9 @@ static int asyncOpenReadWrite(const char *z, OsFile **ppFile, int *pReadOnly){
   if( rc==SQLITE_OK ){
     rc = asyncOpenFile(z, ppFile, pBase, (*pReadOnly ? 0 : 1));
   }
+  if( rc==SQLITE_OK ){
+    incrOpenFileCount();
+  }
   return rc;
 }
 
@@ -869,16 +898,17 @@ static void asyncEnable(int enable){
 static void *asyncWriterThread(void *NotUsed){
   AsyncWrite *p = 0;
   int rc = SQLITE_OK;
+  int holdingMutex = 0;
 
   if( pthread_mutex_trylock(&async.writerMutex) ){
     return 0;
   }
   while( async.writerHaltNow==0 ){
-    int holdingMutex;
     OsFile *pBase = 0;
 
-    pthread_mutex_lock(&async.queueMutex);
-    holdingMutex = 1;
+    if( !holdingMutex ){
+      pthread_mutex_lock(&async.queueMutex);
+    }
     while( (p = async.pQueueFirst)==0 ){
       pthread_cond_broadcast(&async.emptySignal);
       if( async.writerHaltWhenIdle ){
@@ -891,6 +921,7 @@ static void *asyncWriterThread(void *NotUsed){
       }
     }
     if( p==0 ) break;
+    holdingMutex = 1;
 
     /* 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
@@ -911,11 +942,11 @@ static void *asyncWriterThread(void *NotUsed){
     **       SQLITE_ASYNC_TWO_FILEHANDLES was set at compile time and two
     **       file-handles are open for the particular file being "synced".
     */
+    if( async.ioError!=SQLITE_OK && p->op!=ASYNC_CLOSE ){
+      p->op = ASYNC_NOOP;
+    }
     if( p->pFile ){
       pBase = p->pFile->pBaseWrite;
-      if( p->pFile->ioError!=SQLITE_OK && p->op!=ASYNC_CLOSE ){
-        p->op = ASYNC_NOOP;
-      }
       if( 
         p->op==ASYNC_CLOSE || 
         p->op==ASYNC_OPENEXCLUSIVE ||
@@ -1003,19 +1034,6 @@ static void *asyncWriterThread(void *NotUsed){
       default: assert(!"Illegal value for AsyncWrite.op");
     }
 
-    /* If an error happens, store the error code in the pFile.ioError
-    ** field.  This will prevent any future operations on that file,
-    ** other than closing it.
-    **
-    ** We cannot report the error back to the connection that requested
-    ** the I/O since the error happened asynchronously.  The connection has
-    ** already moved on.  There really is nobody to report the error to.
-    */
-    if( rc!=SQLITE_OK ){
-      p->pFile->ioError = rc;
-      rc = SQLITE_OK;
-    }
-
     /* If we didn't hang on to the mutex during the IO op, obtain it now
     ** so that the AsyncWrite structure can be safely removed from the 
     ** global write-op queue.
@@ -1032,16 +1050,42 @@ static void *asyncWriterThread(void *NotUsed){
     sqlite3OsFree(p);
     assert( holdingMutex );
 
+    /* An IO error has occured. We cannot report the error back to the
+    ** connection that requested the I/O since the error happened 
+    ** asynchronously.  The connection has already moved on.  There 
+    ** really is nobody to report the error to.
+    **
+    ** The file for which the error occured may have been a database or
+    ** journal file. Regardless, none of the currently queued operations
+    ** associated with the same database should now be performed. Nor should
+    ** any subsequently requested IO on either a database or journal file 
+    ** handle for the same database be accepted until the main database
+    ** file handle has been closed and reopened.
+    **
+    ** Furthermore, no further IO should be queued or performed on any file
+    ** handle associated with a database that may have been part of a 
+    ** multi-file transaction that included the database associated with 
+    ** the IO error (i.e. a database ATTACHed to the same handle at some 
+    ** point in time).
+    */
+    if( rc!=SQLITE_OK ){
+      async.ioError = rc;
+    }
+
     /* 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.
     */
-    pthread_mutex_unlock(&async.queueMutex);
-    if( async.ioDelay>0 ){
-      sqlite3OsSleep(async.ioDelay);
-    }else{
-      sched_yield();
+    if( !async.pQueueFirst || !async.ioError ){
+      pthread_mutex_unlock(&async.queueMutex);
+      holdingMutex = 0;
+      if( async.ioDelay>0 ){
+        sqlite3OsSleep(async.ioDelay);
+      }else{
+        sched_yield();
+      }
     }
   }
+  
   pthread_mutex_unlock(&async.writerMutex);
   return 0;
 }
diff --git a/test/async2.test b/test/async2.test
new file mode 100644 (file)
index 0000000..d08fb66
--- /dev/null
@@ -0,0 +1,111 @@
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# $Id: async2.test,v 1.1 2006/02/14 13:25:45 danielk1977 Exp $
+
+
+if {[info commands sqlite3async_enable]==""} {
+  # The async logic is not built into this system
+  return
+}
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Enable asynchronous IO.
+
+set setup_script {
+  CREATE TABLE counter(c);
+  INSERT INTO counter(c) VALUES (1);
+} 
+
+set sql_script {
+  BEGIN;
+    UPDATE counter SET c = 2;
+    CREATE TABLE t1(a PRIMARY KEY, b, c);
+    CREATE TABLE t2(a PRIMARY KEY, b, c);
+  COMMIT;
+
+  BEGIN;
+    UPDATE counter SET c = 3;
+    INSERT INTO t1 VALUES('abcdefghij', 'four', 'score');
+    INSERT INTO t2 VALUES('klmnopqrst', 'and', 'seven');
+  COMMIT;
+
+  UPDATE counter SET c = 'FIN';
+}
+
+db close
+
+set ::go 1
+for {set n 3} {$::go} {incr n} {
+  set ::sqlite_io_error_pending 0
+  file delete -force test.db test.db-journal
+  sqlite3 db test.db
+  execsql $::setup_script
+  db close
+
+  sqlite3async_enable 1
+  sqlite3 db test.db
+  execsql $::sql_script
+  db close
+
+  set ::sqlite_io_error_pending $n
+  sqlite3async_halt idle
+  sqlite3async_start
+  sqlite3async_wait
+
+  sqlite3async_enable 0
+  set ::sqlite_io_error_pending 0
+  sqlite3 db test.db
+  set c [db eval {SELECT c FROM counter LIMIT 1}]
+  switch -- $c {
+    1 {
+      do_test async-ioerr-1.1.$n {
+        execsql {
+          SELECT name FROM sqlite_master;
+        }
+      } {counter}
+    }
+    2 {
+      do_test async-ioerr-1.2.$n.1 {
+        execsql {
+          SELECT * FROM t1;
+        }
+      } {}
+      do_test async-ioerr-1.2.$n.2 {
+        execsql {
+          SELECT * FROM t2;
+        }
+      } {}
+    }
+    3 {
+      do_test async-ioerr-1.3.$n.1 {
+        execsql {
+          SELECT * FROM t1;
+        }
+      } {abcdefghij four score}
+      do_test async-ioerr-1.3.$n.2 {
+        execsql {
+          SELECT * FROM t2;
+        }
+      } {klmnopqrst and seven}
+    }
+    FIN {
+      set ::go 0
+    }
+  }
+
+  sqlite3async_enable 0
+}
+
+catch {db close}
+sqlite3async_halt idle
+sqlite3async_start
+sqlite3async_wait
+
+finish_test