]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modify test_async.c to avoid using internal SQLite APIs. There are still some comment...
authordanielk1977 <danielk1977@noemail.net>
Mon, 15 Sep 2008 14:08:04 +0000 (14:08 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Mon, 15 Sep 2008 14:08:04 +0000 (14:08 +0000)
FossilOrigin-Name: 1d4fcaafd058bf1b726378e9ec308ecd8130fe1b

manifest
manifest.uuid
src/test_async.c

index fb4aba917901a3a3111aff32c9d5abb98b1b11b2..ad8693a7d6aca13fe73035dee180479547b9edb2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Check\sif\serror\scode\sENOTSUP\sis\ssupported\sbefore\susing\sit.\sTicket\s#3375.\s(CVS\s5697)
-D 2008-09-15T04:20:32
+C Modify\stest_async.c\sto\savoid\susing\sinternal\sSQLite\sAPIs.\sThere\sare\sstill\ssome\scomments\sthat\sneed\supdating.\s(CVS\s5698)
+D 2008-09-15T14:08:04
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -165,7 +165,7 @@ F src/test6.c 0a0304a69cfa4962a429d084c6d451ff9e4fb572
 F src/test7.c 475b1fa7e3275408b40a3cbdc9508cbdc41ffa02
 F src/test8.c 3637439424d0d21ff2dcf9b015c30fcc1e7bcb24
 F src/test9.c 904ebe0ed1472d6bad17a81e2ecbfc20017dc237
-F src/test_async.c da9f58f49faccd3a26ba89f58de125862351b6e2
+F src/test_async.c 2f644e5c4ee4ecc568234a22b98d992deda6006e
 F src/test_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad
 F src/test_btree.c 8d5b835054f1dd15992e09864a8bc04386bab701
 F src/test_config.c b2681a8e1b570f0c3686c934d6ef6112921af05d
@@ -635,7 +635,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P ced6bbd228b4a324ddb9c5ff15fd027811c8806a
-R 4d23aa13f9709d8ea8e494bd8ecff601
+P c32cb106c5d68e98f51f1eaf9ae0e2a3c36d00d6
+R 81c8df88182aeac4375b62d10daf76ae
 U danielk1977
-Z 15f69e2058d6662c1b75f3319378d24f
+Z 598fdfba976b3753bad5428908262014
index 220e8fcf465e03f1c36873fcb9958776922c24fb..c1fb60e88db61d0a8aa853a250419de078680e2b 100644 (file)
@@ -1 +1 @@
-c32cb106c5d68e98f51f1eaf9ae0e2a3c36d00d6
\ No newline at end of file
+1d4fcaafd058bf1b726378e9ec308ecd8130fe1b
\ No newline at end of file
index 7b48afe0ae6a39603c7b86c6e92a291e65a525a4..d255d0dcd9b43e03233ddb5b3f94c0132e357615 100644 (file)
@@ -10,7 +10,7 @@
 **
 *************************************************************************
 **
-** $Id: test_async.c,v 1.45 2008/06/26 10:41:19 danielk1977 Exp $
+** $Id: test_async.c,v 1.46 2008/09/15 14:08:04 danielk1977 Exp $
 **
 ** This file contains an example implementation of an asynchronous IO 
 ** backend for SQLite.
 #define ENABLE_FILE_LOCKING
 
 #ifndef SQLITE_AMALGAMATION
-# include "sqliteInt.h"
+# include "sqlite3.h"
+# include <assert.h>
+# include <string.h>
 #endif
 #include <tcl.h>
 
@@ -274,7 +276,7 @@ static struct TestAsyncStaticData {
   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 */
+  AsyncLock *pLock;            /* Linked list of all AsyncLock structures */
   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 */
@@ -350,7 +352,7 @@ static const char *azOpcodeName[] = {
 struct AsyncWrite {
   AsyncFileData *pFileData;    /* File to write data to or sync */
   int op;                      /* One of ASYNC_xxx etc. */
-  i64 iOffset;        /* See above */
+  sqlite_int64 iOffset;        /* See above */
   int nByte;          /* See above */
   char *zBuf;         /* Data to write to file (or NULL if op!=ASYNC_WRITE) */
   AsyncWrite *pNext;  /* Next write operation (to any file) */
@@ -376,9 +378,12 @@ struct AsyncWrite {
 ** the implementation of database locking used by this backend.
 */
 struct AsyncLock {
+  char *zFile;
+  int nFile;
   sqlite3_file *pFile;
   int eLock;
   AsyncFileLock *pList;
+  AsyncLock *pNext;           /* Next in linked list headed by async.pLock */
 };
 
 /*
@@ -412,7 +417,8 @@ struct AsyncFileData {
   int nName;                 /* Number of characters in zName */
   sqlite3_file *pBaseRead;   /* Read handle to the underlying Os file */
   sqlite3_file *pBaseWrite;  /* Write handle to the underlying Os file */
-  AsyncFileLock lock;
+  AsyncFileLock lock;        /* Lock state for this handle */
+  AsyncLock *pLock;          /* AsyncLock object for this file system entry */
   AsyncWrite close;
 };
 
@@ -631,7 +637,7 @@ static void incrOpenFileCount(){
 static int addNewAsyncWrite(
   AsyncFileData *pFileData, 
   int op, 
-  i64 iOffset, 
+  sqlite3_int64 iOffset, 
   int nByte,
   const char *zByte
 ){
@@ -686,7 +692,12 @@ static int asyncClose(sqlite3_file *pFile){
 ** the global AsyncWrite list. Either SQLITE_OK or SQLITE_NOMEM may be
 ** returned.
 */
-static int asyncWrite(sqlite3_file *pFile, const void *pBuf, int amt, i64 iOff){
+static int asyncWrite(
+  sqlite3_file *pFile, 
+  const void *pBuf, 
+  int amt, 
+  sqlite3_int64 iOff
+){
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
   return addNewAsyncWrite(p, ASYNC_WRITE, iOff, amt, pBuf);
 }
@@ -698,10 +709,15 @@ static int asyncWrite(sqlite3_file *pFile, const void *pBuf, int amt, i64 iOff){
 **
 ** This method holds the mutex from start to finish.
 */
-static int asyncRead(sqlite3_file *pFile, void *zOut, int iAmt, i64 iOffset){
+static int asyncRead(
+  sqlite3_file *pFile, 
+  void *zOut, 
+  int iAmt, 
+  sqlite3_int64 iOffset
+){
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
   int rc = SQLITE_OK;
-  i64 filesize;
+  sqlite3_int64 filesize;
   int nRead;
   sqlite3_file *pBase = p->pBaseRead;
 
@@ -717,13 +733,13 @@ static int asyncRead(sqlite3_file *pFile, void *zOut, int iAmt, i64 iOffset){
   }
 
   if( pBase->pMethods ){
-    rc = sqlite3OsFileSize(pBase, &filesize);
+    rc = pBase->pMethods->xFileSize(pBase, &filesize);
     if( rc!=SQLITE_OK ){
       goto asyncread_out;
     }
     nRead = MIN(filesize - iOffset, iAmt);
     if( nRead>0 ){
-      rc = sqlite3OsRead(pBase, zOut, nRead, iOffset);
+      rc = pBase->pMethods->xRead(pBase, zOut, nRead, iOffset);
       ASYNC_TRACE(("READ %s %d bytes at %d\n", p->zName, nRead, iOffset));
     }
   }
@@ -733,7 +749,10 @@ static int asyncRead(sqlite3_file *pFile, void *zOut, int iAmt, i64 iOffset){
     char *zName = p->zName;
 
     for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
-      if( pWrite->op==ASYNC_WRITE && pWrite->pFileData->zName==zName ){
+      if( pWrite->op==ASYNC_WRITE && (
+        (pWrite->pFileData==p) ||
+        (zName && pWrite->pFileData->zName==zName)
+      )){
         int iBeginOut = (pWrite->iOffset-iOffset);
         int iBeginIn = -iBeginOut;
         int nCopy;
@@ -759,7 +778,7 @@ asyncread_out:
 ** Truncate the file to nByte bytes in length. This just adds an entry to 
 ** the write-op list, no IO actually takes place.
 */
-static int asyncTruncate(sqlite3_file *pFile, i64 nByte){
+static int asyncTruncate(sqlite3_file *pFile, sqlite3_int64 nByte){
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
   return addNewAsyncWrite(p, ASYNC_TRUNCATE, nByte, 0, 0);
 }
@@ -780,10 +799,10 @@ static int asyncSync(sqlite3_file *pFile, int flags){
 **
 ** This method holds the mutex from start to finish.
 */
-int asyncFileSize(sqlite3_file *pFile, i64 *piSize){
+int asyncFileSize(sqlite3_file *pFile, sqlite3_int64 *piSize){
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
   int rc = SQLITE_OK;
-  i64 s = 0;
+  sqlite3_int64 s = 0;
   sqlite3_file *pBase;
 
   pthread_mutex_lock(&async.queueMutex);
@@ -795,18 +814,24 @@ int asyncFileSize(sqlite3_file *pFile, i64 *piSize){
   */
   pBase = p->pBaseRead;
   if( pBase->pMethods ){
-    rc = sqlite3OsFileSize(pBase, &s);
+    rc = pBase->pMethods->xFileSize(pBase, &s);
   }
 
   if( rc==SQLITE_OK ){
     AsyncWrite *pWrite;
     for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
-      if( pWrite->op==ASYNC_DELETE && strcmp(p->zName, pWrite->zBuf)==0 ){
+      if( pWrite->op==ASYNC_DELETE 
+       && p->zName 
+       && strcmp(p->zName, pWrite->zBuf)==0 
+      ){
         s = 0;
-      }else if( pWrite->pFileData && pWrite->pFileData->zName==p->zName){
+      }else if( pWrite->pFileData && (
+          (pWrite->pFileData==p) 
+       || (p->zName && pWrite->pFileData->zName==p->zName) 
+      )){
         switch( pWrite->op ){
           case ASYNC_WRITE:
-            s = MAX(pWrite->iOffset + (i64)(pWrite->nByte), s);
+            s = MAX(pWrite->iOffset + (sqlite3_int64)(pWrite->nByte), s);
             break;
           case ASYNC_TRUNCATE:
             s = MIN(s, pWrite->iOffset);
@@ -838,13 +863,13 @@ static int getFileLock(AsyncLock *pLock){
     }
 
     if( eRequired>pLock->eLock ){
-      rc = sqlite3OsLock(pLock->pFile, eRequired);
+      rc = pLock->pFile->pMethods->xLock(pLock->pFile, eRequired);
       if( rc==SQLITE_OK ){
         pLock->eLock = eRequired;
       }
     }
     else if( eRequired<pLock->eLock && eRequired<=SQLITE_LOCK_SHARED ){
-      rc = sqlite3OsUnlock(pLock->pFile, eRequired);
+      rc = pLock->pFile->pMethods->xUnlock(pLock->pFile, eRequired);
       if( rc==SQLITE_OK ){
         pLock->eLock = eRequired;
       }
@@ -854,6 +879,19 @@ static int getFileLock(AsyncLock *pLock){
   return rc;
 }
 
+/*
+** Return the AsyncLock structure from the global async.pLock list 
+** associated with the file-system entry identified by path zName 
+** (a string of nName bytes). If no such structure exists, return 0.
+*/
+static AsyncLock *findLock(const char *zName, int nName){
+  AsyncLock *p = async.pLock;
+  while( p && (p->nFile!=nName || memcmp(p->zFile, zName, nName)) ){
+    p = p->pNext;
+  }
+  return p;
+}
+
 /*
 ** The following two methods - asyncLock() and asyncUnlock() - are used
 ** to obtain and release locks on database files opened with the
@@ -863,43 +901,48 @@ static int asyncLock(sqlite3_file *pFile, int eLock){
   int rc = SQLITE_OK;
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
 
-  pthread_mutex_lock(&async.lockMutex);
-  if( p->lock.eLock<eLock ){
-    AsyncLock *pLock;
-    AsyncFileLock *pIter;
-    pLock = (AsyncLock *)sqlite3HashFind(&async.aLock, p->zName, p->nName);
-    assert(pLock && pLock->pList);
-    for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
-      if( pIter!=&p->lock && (
-        (eLock==SQLITE_LOCK_EXCLUSIVE && pIter->eLock>=SQLITE_LOCK_SHARED) ||
-        (eLock==SQLITE_LOCK_PENDING && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
-        (eLock==SQLITE_LOCK_RESERVED && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
-        (eLock==SQLITE_LOCK_SHARED && pIter->eLock>=SQLITE_LOCK_PENDING)
-      )){
-        rc = SQLITE_BUSY;
+  if( p->zName ){
+    pthread_mutex_lock(&async.lockMutex);
+    if( p->lock.eLock<eLock ){
+      AsyncLock *pLock = p->pLock;
+      AsyncFileLock *pIter;
+      assert(pLock && pLock->pList);
+      for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
+        if( pIter!=&p->lock && (
+          (eLock==SQLITE_LOCK_EXCLUSIVE && pIter->eLock>=SQLITE_LOCK_SHARED) ||
+          (eLock==SQLITE_LOCK_PENDING && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
+          (eLock==SQLITE_LOCK_RESERVED && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
+          (eLock==SQLITE_LOCK_SHARED && pIter->eLock>=SQLITE_LOCK_PENDING)
+        )){
+          rc = SQLITE_BUSY;
+        }
+      }
+      if( rc==SQLITE_OK ){
+        p->lock.eLock = eLock;
+        p->lock.eAsyncLock = MAX(p->lock.eAsyncLock, eLock);
+      }
+      assert(p->lock.eAsyncLock>=p->lock.eLock);
+      if( rc==SQLITE_OK ){
+        rc = getFileLock(pLock);
       }
     }
-    if( rc==SQLITE_OK ){
-      p->lock.eLock = eLock;
-      p->lock.eAsyncLock = MAX(p->lock.eAsyncLock, eLock);
-    }
-    assert(p->lock.eAsyncLock>=p->lock.eLock);
-    if( rc==SQLITE_OK ){
-      rc = getFileLock(pLock);
-    }
+    pthread_mutex_unlock(&async.lockMutex);
   }
-  pthread_mutex_unlock(&async.lockMutex);
 
   ASYNC_TRACE(("LOCK %d (%s) rc=%d\n", eLock, p->zName, rc));
   return rc;
 }
 static int asyncUnlock(sqlite3_file *pFile, int eLock){
+  int rc = SQLITE_OK;
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
-  AsyncFileLock *pLock = &p->lock;
-  pthread_mutex_lock(&async.lockMutex);
-  pLock->eLock = MIN(pLock->eLock, eLock);
-  pthread_mutex_unlock(&async.lockMutex);
-  return addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0);
+  if( p->zName ){
+    AsyncFileLock *pLock = &p->lock;
+    pthread_mutex_lock(&async.lockMutex);
+    pLock->eLock = MIN(pLock->eLock, eLock);
+    pthread_mutex_unlock(&async.lockMutex);
+    rc = addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0);
+  }
+  return rc;
 }
 
 /*
@@ -909,12 +952,10 @@ static int asyncUnlock(sqlite3_file *pFile, int eLock){
 static int asyncCheckReservedLock(sqlite3_file *pFile, int *pResOut){
   int ret = 0;
   AsyncFileLock *pIter;
-  AsyncLock *pLock;
   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
 
   pthread_mutex_lock(&async.lockMutex);
-  pLock = (AsyncLock *)sqlite3HashFind(&async.aLock, p->zName, p->nName);
-  for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
+  for(pIter=p->pLock->pList; pIter; pIter=pIter->pNext){
     if( pIter->eLock>=SQLITE_LOCK_RESERVED ){
       ret = 1;
     }
@@ -927,7 +968,7 @@ static int asyncCheckReservedLock(sqlite3_file *pFile, int *pResOut){
 }
 
 /* 
-** This is a no-op, as the asynchronous backend does not support locking.
+** sqlite3_file_control() implementation.
 */
 static int asyncFileControl(sqlite3_file *id, int op, void *pArg){
   switch( op ){
@@ -954,28 +995,28 @@ static int asyncDeviceCharacteristics(sqlite3_file *pFile){
 }
 
 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);
+  if( pData->zName ){
+    AsyncLock *pLock = pData->pLock;
+    for(ppIter=&pLock->pList; *ppIter; ppIter=&((*ppIter)->pNext)){
+      if( (*ppIter)==&pData->lock ){
+        *ppIter = pData->lock.pNext;
+        break;
+      }
     }
-    sqlite3_free(pLock);
-    sqlite3HashInsert(&async.aLock, pData->zName, pData->nName, 0);
-    if( !sqliteHashFirst(&async.aLock) ){
-      sqlite3HashClear(&async.aLock);
+    if( !pLock->pList ){
+      AsyncLock **pp;
+      if( pLock->pFile ){
+        pLock->pFile->pMethods->xClose(pLock->pFile);
+      }
+      for(pp=&async.pLock; *pp!=pLock; pp=&((*pp)->pNext));
+      *pp = pLock->pNext;
+      sqlite3_free(pLock);
+    }else{
+      rc = getFileLock(pLock);
     }
-  }else{
-    rc = getFileLock(pLock);
   }
 
   return rc;
@@ -1009,7 +1050,7 @@ static int asyncOpen(
 
   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
   AsyncFile *p = (AsyncFile *)pFile;
-  int nName = strlen(zName)+1;
+  int nName = 0;
   int rc = SQLITE_OK;
   int nByte;
   AsyncFileData *pData;
@@ -1017,6 +1058,11 @@ static int asyncOpen(
   char *z;
   int isExclusive = (flags&SQLITE_OPEN_EXCLUSIVE);
 
+  /* If zName is NULL, then the upper layer is requesting an anonymous file */
+  if( zName ){
+    nName = strlen(zName)+1;
+  }
+
   nByte = (
     sizeof(AsyncFileData) +        /* AsyncFileData structure */
     2 * pVfs->szOsFile +           /* AsyncFileData.pBaseRead and pBaseWrite */
@@ -1032,44 +1078,48 @@ static int asyncOpen(
   pData->pBaseRead = (sqlite3_file*)z;
   z += pVfs->szOsFile;
   pData->pBaseWrite = (sqlite3_file*)z;
-  z += pVfs->szOsFile;
-  pData->zName = z;
-  pData->nName = nName;
   pData->close.pFileData = pData;
   pData->close.op = ASYNC_CLOSE;
-  memcpy(pData->zName, zName, nName);
+
+  if( zName ){
+    z += pVfs->szOsFile;
+    pData->zName = z;
+    pData->nName = nName;
+    memcpy(pData->zName, zName, nName);
+  }
 
   if( !isExclusive ){
-    rc = sqlite3OsOpen(pVfs, zName, pData->pBaseRead, flags, pOutFlags);
+    rc = pVfs->xOpen(pVfs, zName, pData->pBaseRead, flags, pOutFlags);
     if( rc==SQLITE_OK && ((*pOutFlags)&SQLITE_OPEN_READWRITE) ){
-      rc = sqlite3OsOpen(pVfs, zName, pData->pBaseWrite, flags, 0);
+      rc = pVfs->xOpen(pVfs, zName, pData->pBaseWrite, flags, 0);
     }
   }
 
   pthread_mutex_lock(&async.lockMutex);
 
-  if( rc==SQLITE_OK ){
-    pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName);
+  if( zName && rc==SQLITE_OK ){
+    pLock = findLock(pData->zName, pData->nName);
     if( !pLock ){
-      pLock = sqlite3MallocZero(pVfs->szOsFile + sizeof(AsyncLock));
+      int nByte = pVfs->szOsFile + sizeof(AsyncLock) + pData->nName + 1; 
+      pLock = (AsyncLock *)sqlite3_malloc(nByte);
       if( pLock ){
-        AsyncLock *pDelete;
+        memset(pLock, 0, nByte);
 #ifdef ENABLE_FILE_LOCKING
         if( flags&SQLITE_OPEN_MAIN_DB ){
           pLock->pFile = (sqlite3_file *)&pLock[1];
-          rc = sqlite3OsOpen(pVfs, zName, pLock->pFile, flags, 0);
+          rc = pVfs->xOpen(pVfs, zName, pLock->pFile, flags, 0);
           if( rc!=SQLITE_OK ){
             sqlite3_free(pLock);
             pLock = 0;
           }
         }
 #endif
-        pDelete = sqlite3HashInsert(
-          &async.aLock, pData->zName, pData->nName, (void *)pLock
-        );
-        if( pDelete ){
-          rc = SQLITE_NOMEM;
-          sqlite3_free(pLock);
+        if( pLock ){
+          pLock->nFile = pData->nName;
+          pLock->zFile = &((char *)(&pLock[1]))[pVfs->szOsFile];
+          memcpy(pLock->zFile, pData->zName, pLock->nFile);
+          pLock->pNext = async.pLock;
+          async.pLock = pLock;
         }
       }else{
         rc = SQLITE_NOMEM;
@@ -1078,21 +1128,24 @@ static int asyncOpen(
   }
 
   if( rc==SQLITE_OK ){
-    HashElem *pElem;
     p->pMethod = &async_methods;
     p->pData = pData;
 
     /* Link AsyncFileData.lock into the linked list of 
     ** AsyncFileLock structures for this file.
     */
-    pData->lock.pNext = pLock->pList;
-    pLock->pList = &pData->lock;
-
-    pElem = sqlite3HashFindElem(&async.aLock, pData->zName, pData->nName);
-    pData->zName = (char *)sqliteHashKey(pElem);
+    if( zName ){
+      pData->lock.pNext = pLock->pList;
+      pLock->pList = &pData->lock;
+      pData->zName = pLock->zFile;
+    }
   }else{
-    sqlite3OsClose(pData->pBaseRead);
-    sqlite3OsClose(pData->pBaseWrite);
+    if( pData->pBaseRead->pMethods ){
+      pData->pBaseRead->pMethods->xClose(pData->pBaseRead);
+    }
+    if( pData->pBaseWrite->pMethods ){
+      pData->pBaseWrite->pMethods->xClose(pData->pBaseWrite);
+    }
     sqlite3_free(pData);
   }
 
@@ -1100,10 +1153,11 @@ static int asyncOpen(
 
   if( rc==SQLITE_OK ){
     incrOpenFileCount();
+    pData->pLock = pLock;
   }
 
   if( rc==SQLITE_OK && isExclusive ){
-    rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (i64)flags, 0, 0);
+    rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (sqlite3_int64)flags,0,0);
     if( rc==SQLITE_OK ){
       if( pOutFlags ) *pOutFlags = flags;
     }else{
@@ -1145,12 +1199,13 @@ static int asyncAccess(
   );
 
   pthread_mutex_lock(&async.queueMutex);
-  rc = sqlite3OsAccess(pVfs, zName, flags, &ret);
+  rc = pVfs->xAccess(pVfs, zName, flags, &ret);
   if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
     for(p=async.pQueueFirst; p; p = p->pNext){
       if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, zName) ){
         ret = 0;
       }else if( p->op==ASYNC_OPENEXCLUSIVE 
+             && p->pFileData->zName
              && 0==strcmp(p->pFileData->zName, zName) 
       ){
         ret = 1;
@@ -1178,7 +1233,7 @@ static int asyncFullPathname(
 ){
   int rc;
   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
-  rc = sqlite3OsFullPathname(pVfs, zPath, nPathOut, zPathOut);
+  rc = pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
 
   /* Because of the way intra-process file locking works, this backend
   ** needs to return a canonical path. The following block assumes the
@@ -1286,14 +1341,9 @@ static sqlite3_vfs async_vfs = {
 static void asyncEnable(int enable){
   if( enable ){
     if( !async_vfs.pAppData ){
-      static int hashTableInit = 0;
       async_vfs.pAppData = (void *)sqlite3_vfs_find(0);
       async_vfs.mxPathname = ((sqlite3_vfs *)async_vfs.pAppData)->mxPathname;
       sqlite3_vfs_register(&async_vfs, 1);
-      if( !hashTableInit ){
-        sqlite3HashInit(&async.aLock, SQLITE_HASH_BINARY, 1);
-        hashTableInit = 1;
-      }
     }
   }else{
     if( async_vfs.pAppData ){
@@ -1398,27 +1448,31 @@ static void *asyncWriterThread(void *pIsStarted){
         assert( pBase );
         ASYNC_TRACE(("WRITE %s %d bytes at %d\n",
                 p->pFileData->zName, p->nByte, p->iOffset));
-        rc = sqlite3OsWrite(pBase, (void *)(p->zBuf), p->nByte, p->iOffset);
+        rc = pBase->pMethods->xWrite(pBase, (void *)(p->zBuf), p->nByte, p->iOffset);
         break;
 
       case ASYNC_SYNC:
         assert( pBase );
         ASYNC_TRACE(("SYNC %s\n", p->pFileData->zName));
-        rc = sqlite3OsSync(pBase, p->nByte);
+        rc = pBase->pMethods->xSync(pBase, p->nByte);
         break;
 
       case ASYNC_TRUNCATE:
         assert( pBase );
         ASYNC_TRACE(("TRUNCATE %s to %d bytes\n", 
                 p->pFileData->zName, p->iOffset));
-        rc = sqlite3OsTruncate(pBase, p->iOffset);
+        rc = pBase->pMethods->xTruncate(pBase, p->iOffset);
         break;
 
       case ASYNC_CLOSE: {
         AsyncFileData *pData = p->pFileData;
         ASYNC_TRACE(("CLOSE %s\n", p->pFileData->zName));
-        sqlite3OsClose(pData->pBaseWrite);
-        sqlite3OsClose(pData->pBaseRead);
+        if( pData->pBaseWrite->pMethods ){
+          pData->pBaseWrite->pMethods->xClose(pData->pBaseWrite);
+        }
+        if( pData->pBaseRead->pMethods ){
+          pData->pBaseRead->pMethods->xClose(pData->pBaseRead);
+        }
 
         /* Unlink AsyncFileData.lock from the linked list of AsyncFileLock 
         ** structures for this file. Obtain the async.lockMutex mutex 
@@ -1435,7 +1489,6 @@ static void *asyncWriterThread(void *pIsStarted){
       }
 
       case ASYNC_UNLOCK: {
-        AsyncLock *pLock;
         AsyncFileData *pData = p->pFileData;
         int eLock = p->nByte;
         pthread_mutex_lock(&async.lockMutex);
@@ -1443,15 +1496,14 @@ static void *asyncWriterThread(void *pIsStarted){
             pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
         );
         assert(pData->lock.eAsyncLock>=pData->lock.eLock);
-        pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName);
-        rc = getFileLock(pLock);
+        rc = getFileLock(pData->pLock);
         pthread_mutex_unlock(&async.lockMutex);
         break;
       }
 
       case ASYNC_DELETE:
         ASYNC_TRACE(("DELETE %s\n", p->zBuf));
-        rc = sqlite3OsDelete(pVfs, p->zBuf, (int)p->iOffset);
+        rc = pVfs->xDelete(pVfs, p->zBuf, (int)p->iOffset);
         break;
 
       case ASYNC_OPENEXCLUSIVE: {
@@ -1459,7 +1511,7 @@ static void *asyncWriterThread(void *pIsStarted){
         AsyncFileData *pData = p->pFileData;
         ASYNC_TRACE(("OPEN %s flags=%d\n", p->zBuf, (int)p->iOffset));
         assert(pData->pBaseRead->pMethods==0 && pData->pBaseWrite->pMethods==0);
-        rc = sqlite3OsOpen(pVfs, pData->zName, pData->pBaseRead, flags, 0);
+        rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, 0);
         assert( holdingMutex==0 );
         pthread_mutex_lock(&async.queueMutex);
         holdingMutex = 1;
@@ -1511,7 +1563,7 @@ static void *asyncWriterThread(void *pIsStarted){
 
     if( async.ioError && !async.pQueueFirst ){
       pthread_mutex_lock(&async.lockMutex);
-      if( 0==sqliteHashFirst(&async.aLock) ){
+      if( 0==async.pLock ){
         async.ioError = SQLITE_OK;
       }
       pthread_mutex_unlock(&async.lockMutex);
@@ -1524,7 +1576,7 @@ static void *asyncWriterThread(void *pIsStarted){
       pthread_mutex_unlock(&async.queueMutex);
       holdingMutex = 0;
       if( async.ioDelay>0 ){
-        sqlite3OsSleep(pVfs, async.ioDelay);
+        pVfs->xSleep(pVfs, async.ioDelay);
       }else{
         sched_yield();
       }