1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

Modify test_async.c to avoid using internal SQLite APIs. There are still some comments that need updating. (CVS 5698)

FossilOrigin-Name: 1d4fcaafd058bf1b726378e9ec308ecd8130fe1b
This commit is contained in:
danielk1977
2008-09-15 14:08:04 +00:00
parent 5ad6a88f59
commit 92c4b8a2ca
3 changed files with 175 additions and 123 deletions

View File

@@ -1,5 +1,5 @@
C Check\sif\serror\scode\sENOTSUP\sis\ssupported\sbefore\susing\sit.\sTicket\s#3375.\s(CVS\s5697) 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-15T04:20:32 D 2008-09-15T14:08:04
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329 F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -165,7 +165,7 @@ F src/test6.c 0a0304a69cfa4962a429d084c6d451ff9e4fb572
F src/test7.c 475b1fa7e3275408b40a3cbdc9508cbdc41ffa02 F src/test7.c 475b1fa7e3275408b40a3cbdc9508cbdc41ffa02
F src/test8.c 3637439424d0d21ff2dcf9b015c30fcc1e7bcb24 F src/test8.c 3637439424d0d21ff2dcf9b015c30fcc1e7bcb24
F src/test9.c 904ebe0ed1472d6bad17a81e2ecbfc20017dc237 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_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad
F src/test_btree.c 8d5b835054f1dd15992e09864a8bc04386bab701 F src/test_btree.c 8d5b835054f1dd15992e09864a8bc04386bab701
F src/test_config.c b2681a8e1b570f0c3686c934d6ef6112921af05d F src/test_config.c b2681a8e1b570f0c3686c934d6ef6112921af05d
@@ -635,7 +635,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P ced6bbd228b4a324ddb9c5ff15fd027811c8806a P c32cb106c5d68e98f51f1eaf9ae0e2a3c36d00d6
R 4d23aa13f9709d8ea8e494bd8ecff601 R 81c8df88182aeac4375b62d10daf76ae
U danielk1977 U danielk1977
Z 15f69e2058d6662c1b75f3319378d24f Z 598fdfba976b3753bad5428908262014

View File

@@ -1 +1 @@
c32cb106c5d68e98f51f1eaf9ae0e2a3c36d00d6 1d4fcaafd058bf1b726378e9ec308ecd8130fe1b

View 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 ** This file contains an example implementation of an asynchronous IO
** backend for SQLite. ** backend for SQLite.
@@ -109,7 +109,9 @@
#define ENABLE_FILE_LOCKING #define ENABLE_FILE_LOCKING
#ifndef SQLITE_AMALGAMATION #ifndef SQLITE_AMALGAMATION
# include "sqliteInt.h" # include "sqlite3.h"
# include <assert.h>
# include <string.h>
#endif #endif
#include <tcl.h> #include <tcl.h>
@@ -274,7 +276,7 @@ static struct TestAsyncStaticData {
pthread_cond_t emptySignal; /* Notify when the write queue is empty */ pthread_cond_t emptySignal; /* Notify when the write queue is empty */
AsyncWrite *pQueueFirst; /* Next write operation to be processed */ AsyncWrite *pQueueFirst; /* Next write operation to be processed */
AsyncWrite *pQueueLast; /* Last write operation on the list */ 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 ioDelay; /* Extra delay between write operations */
volatile int writerHaltWhenIdle; /* Writer thread halts when queue empty */ volatile int writerHaltWhenIdle; /* Writer thread halts when queue empty */
volatile int writerHaltNow; /* Writer thread halts after next op */ volatile int writerHaltNow; /* Writer thread halts after next op */
@@ -350,7 +352,7 @@ static const char *azOpcodeName[] = {
struct AsyncWrite { struct AsyncWrite {
AsyncFileData *pFileData; /* File to write data to or sync */ AsyncFileData *pFileData; /* File to write data to or sync */
int op; /* One of ASYNC_xxx etc. */ int op; /* One of ASYNC_xxx etc. */
i64 iOffset; /* See above */ sqlite_int64 iOffset; /* See above */
int nByte; /* See above */ int nByte; /* See above */
char *zBuf; /* Data to write to file (or NULL if op!=ASYNC_WRITE) */ char *zBuf; /* Data to write to file (or NULL if op!=ASYNC_WRITE) */
AsyncWrite *pNext; /* Next write operation (to any file) */ AsyncWrite *pNext; /* Next write operation (to any file) */
@@ -376,9 +378,12 @@ struct AsyncWrite {
** the implementation of database locking used by this backend. ** the implementation of database locking used by this backend.
*/ */
struct AsyncLock { struct AsyncLock {
char *zFile;
int nFile;
sqlite3_file *pFile; sqlite3_file *pFile;
int eLock; int eLock;
AsyncFileLock *pList; 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 */ int nName; /* Number of characters in zName */
sqlite3_file *pBaseRead; /* Read handle to the underlying Os file */ sqlite3_file *pBaseRead; /* Read handle to the underlying Os file */
sqlite3_file *pBaseWrite; /* Write 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; AsyncWrite close;
}; };
@@ -631,7 +637,7 @@ static void incrOpenFileCount(){
static int addNewAsyncWrite( static int addNewAsyncWrite(
AsyncFileData *pFileData, AsyncFileData *pFileData,
int op, int op,
i64 iOffset, sqlite3_int64 iOffset,
int nByte, int nByte,
const char *zByte 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 ** the global AsyncWrite list. Either SQLITE_OK or SQLITE_NOMEM may be
** returned. ** 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; AsyncFileData *p = ((AsyncFile *)pFile)->pData;
return addNewAsyncWrite(p, ASYNC_WRITE, iOff, amt, pBuf); 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. ** 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; AsyncFileData *p = ((AsyncFile *)pFile)->pData;
int rc = SQLITE_OK; int rc = SQLITE_OK;
i64 filesize; sqlite3_int64 filesize;
int nRead; int nRead;
sqlite3_file *pBase = p->pBaseRead; sqlite3_file *pBase = p->pBaseRead;
@@ -717,13 +733,13 @@ static int asyncRead(sqlite3_file *pFile, void *zOut, int iAmt, i64 iOffset){
} }
if( pBase->pMethods ){ if( pBase->pMethods ){
rc = sqlite3OsFileSize(pBase, &filesize); rc = pBase->pMethods->xFileSize(pBase, &filesize);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto asyncread_out; goto asyncread_out;
} }
nRead = MIN(filesize - iOffset, iAmt); nRead = MIN(filesize - iOffset, iAmt);
if( nRead>0 ){ 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)); 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; char *zName = p->zName;
for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){ 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 iBeginOut = (pWrite->iOffset-iOffset);
int iBeginIn = -iBeginOut; int iBeginIn = -iBeginOut;
int nCopy; int nCopy;
@@ -759,7 +778,7 @@ asyncread_out:
** Truncate the file to nByte bytes in length. This just adds an entry to ** Truncate the file to nByte bytes in length. This just adds an entry to
** the write-op list, no IO actually takes place. ** 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; AsyncFileData *p = ((AsyncFile *)pFile)->pData;
return addNewAsyncWrite(p, ASYNC_TRUNCATE, nByte, 0, 0); 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. ** 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; AsyncFileData *p = ((AsyncFile *)pFile)->pData;
int rc = SQLITE_OK; int rc = SQLITE_OK;
i64 s = 0; sqlite3_int64 s = 0;
sqlite3_file *pBase; sqlite3_file *pBase;
pthread_mutex_lock(&async.queueMutex); pthread_mutex_lock(&async.queueMutex);
@@ -795,18 +814,24 @@ int asyncFileSize(sqlite3_file *pFile, i64 *piSize){
*/ */
pBase = p->pBaseRead; pBase = p->pBaseRead;
if( pBase->pMethods ){ if( pBase->pMethods ){
rc = sqlite3OsFileSize(pBase, &s); rc = pBase->pMethods->xFileSize(pBase, &s);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
AsyncWrite *pWrite; AsyncWrite *pWrite;
for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){ 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; 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 ){ switch( pWrite->op ){
case ASYNC_WRITE: case ASYNC_WRITE:
s = MAX(pWrite->iOffset + (i64)(pWrite->nByte), s); s = MAX(pWrite->iOffset + (sqlite3_int64)(pWrite->nByte), s);
break; break;
case ASYNC_TRUNCATE: case ASYNC_TRUNCATE:
s = MIN(s, pWrite->iOffset); s = MIN(s, pWrite->iOffset);
@@ -838,13 +863,13 @@ static int getFileLock(AsyncLock *pLock){
} }
if( eRequired>pLock->eLock ){ if( eRequired>pLock->eLock ){
rc = sqlite3OsLock(pLock->pFile, eRequired); rc = pLock->pFile->pMethods->xLock(pLock->pFile, eRequired);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pLock->eLock = eRequired; pLock->eLock = eRequired;
} }
} }
else if( eRequired<pLock->eLock && eRequired<=SQLITE_LOCK_SHARED ){ 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 ){ if( rc==SQLITE_OK ){
pLock->eLock = eRequired; pLock->eLock = eRequired;
} }
@@ -854,6 +879,19 @@ static int getFileLock(AsyncLock *pLock){
return rc; 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 ** The following two methods - asyncLock() and asyncUnlock() - are used
** to obtain and release locks on database files opened with the ** to obtain and release locks on database files opened with the
@@ -863,11 +901,11 @@ static int asyncLock(sqlite3_file *pFile, int eLock){
int rc = SQLITE_OK; int rc = SQLITE_OK;
AsyncFileData *p = ((AsyncFile *)pFile)->pData; AsyncFileData *p = ((AsyncFile *)pFile)->pData;
if( p->zName ){
pthread_mutex_lock(&async.lockMutex); pthread_mutex_lock(&async.lockMutex);
if( p->lock.eLock<eLock ){ if( p->lock.eLock<eLock ){
AsyncLock *pLock; AsyncLock *pLock = p->pLock;
AsyncFileLock *pIter; AsyncFileLock *pIter;
pLock = (AsyncLock *)sqlite3HashFind(&async.aLock, p->zName, p->nName);
assert(pLock && pLock->pList); assert(pLock && pLock->pList);
for(pIter=pLock->pList; pIter; pIter=pIter->pNext){ for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
if( pIter!=&p->lock && ( if( pIter!=&p->lock && (
@@ -889,17 +927,22 @@ static int asyncLock(sqlite3_file *pFile, int eLock){
} }
} }
pthread_mutex_unlock(&async.lockMutex); pthread_mutex_unlock(&async.lockMutex);
}
ASYNC_TRACE(("LOCK %d (%s) rc=%d\n", eLock, p->zName, rc)); ASYNC_TRACE(("LOCK %d (%s) rc=%d\n", eLock, p->zName, rc));
return rc; return rc;
} }
static int asyncUnlock(sqlite3_file *pFile, int eLock){ static int asyncUnlock(sqlite3_file *pFile, int eLock){
int rc = SQLITE_OK;
AsyncFileData *p = ((AsyncFile *)pFile)->pData; AsyncFileData *p = ((AsyncFile *)pFile)->pData;
if( p->zName ){
AsyncFileLock *pLock = &p->lock; AsyncFileLock *pLock = &p->lock;
pthread_mutex_lock(&async.lockMutex); pthread_mutex_lock(&async.lockMutex);
pLock->eLock = MIN(pLock->eLock, eLock); pLock->eLock = MIN(pLock->eLock, eLock);
pthread_mutex_unlock(&async.lockMutex); pthread_mutex_unlock(&async.lockMutex);
return addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0); 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){ static int asyncCheckReservedLock(sqlite3_file *pFile, int *pResOut){
int ret = 0; int ret = 0;
AsyncFileLock *pIter; AsyncFileLock *pIter;
AsyncLock *pLock;
AsyncFileData *p = ((AsyncFile *)pFile)->pData; AsyncFileData *p = ((AsyncFile *)pFile)->pData;
pthread_mutex_lock(&async.lockMutex); pthread_mutex_lock(&async.lockMutex);
pLock = (AsyncLock *)sqlite3HashFind(&async.aLock, p->zName, p->nName); for(pIter=p->pLock->pList; pIter; pIter=pIter->pNext){
for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
if( pIter->eLock>=SQLITE_LOCK_RESERVED ){ if( pIter->eLock>=SQLITE_LOCK_RESERVED ){
ret = 1; 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){ static int asyncFileControl(sqlite3_file *id, int op, void *pArg){
switch( op ){ switch( op ){
@@ -954,11 +995,11 @@ static int asyncDeviceCharacteristics(sqlite3_file *pFile){
} }
static int unlinkAsyncFile(AsyncFileData *pData){ static int unlinkAsyncFile(AsyncFileData *pData){
AsyncLock *pLock;
AsyncFileLock **ppIter; AsyncFileLock **ppIter;
int rc = SQLITE_OK; int rc = SQLITE_OK;
pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName); if( pData->zName ){
AsyncLock *pLock = pData->pLock;
for(ppIter=&pLock->pList; *ppIter; ppIter=&((*ppIter)->pNext)){ for(ppIter=&pLock->pList; *ppIter; ppIter=&((*ppIter)->pNext)){
if( (*ppIter)==&pData->lock ){ if( (*ppIter)==&pData->lock ){
*ppIter = pData->lock.pNext; *ppIter = pData->lock.pNext;
@@ -966,17 +1007,17 @@ static int unlinkAsyncFile(AsyncFileData *pData){
} }
} }
if( !pLock->pList ){ if( !pLock->pList ){
AsyncLock **pp;
if( pLock->pFile ){ if( pLock->pFile ){
sqlite3OsClose(pLock->pFile); pLock->pFile->pMethods->xClose(pLock->pFile);
} }
for(pp=&async.pLock; *pp!=pLock; pp=&((*pp)->pNext));
*pp = pLock->pNext;
sqlite3_free(pLock); sqlite3_free(pLock);
sqlite3HashInsert(&async.aLock, pData->zName, pData->nName, 0);
if( !sqliteHashFirst(&async.aLock) ){
sqlite3HashClear(&async.aLock);
}
}else{ }else{
rc = getFileLock(pLock); rc = getFileLock(pLock);
} }
}
return rc; return rc;
} }
@@ -1009,7 +1050,7 @@ static int asyncOpen(
sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
AsyncFile *p = (AsyncFile *)pFile; AsyncFile *p = (AsyncFile *)pFile;
int nName = strlen(zName)+1; int nName = 0;
int rc = SQLITE_OK; int rc = SQLITE_OK;
int nByte; int nByte;
AsyncFileData *pData; AsyncFileData *pData;
@@ -1017,6 +1058,11 @@ static int asyncOpen(
char *z; char *z;
int isExclusive = (flags&SQLITE_OPEN_EXCLUSIVE); 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 = ( nByte = (
sizeof(AsyncFileData) + /* AsyncFileData structure */ sizeof(AsyncFileData) + /* AsyncFileData structure */
2 * pVfs->szOsFile + /* AsyncFileData.pBaseRead and pBaseWrite */ 2 * pVfs->szOsFile + /* AsyncFileData.pBaseRead and pBaseWrite */
@@ -1032,44 +1078,48 @@ static int asyncOpen(
pData->pBaseRead = (sqlite3_file*)z; pData->pBaseRead = (sqlite3_file*)z;
z += pVfs->szOsFile; z += pVfs->szOsFile;
pData->pBaseWrite = (sqlite3_file*)z; pData->pBaseWrite = (sqlite3_file*)z;
pData->close.pFileData = pData;
pData->close.op = ASYNC_CLOSE;
if( zName ){
z += pVfs->szOsFile; z += pVfs->szOsFile;
pData->zName = z; pData->zName = z;
pData->nName = nName; pData->nName = nName;
pData->close.pFileData = pData;
pData->close.op = ASYNC_CLOSE;
memcpy(pData->zName, zName, nName); memcpy(pData->zName, zName, nName);
}
if( !isExclusive ){ 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) ){ 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); pthread_mutex_lock(&async.lockMutex);
if( rc==SQLITE_OK ){ if( zName && rc==SQLITE_OK ){
pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName); pLock = findLock(pData->zName, pData->nName);
if( !pLock ){ if( !pLock ){
pLock = sqlite3MallocZero(pVfs->szOsFile + sizeof(AsyncLock)); int nByte = pVfs->szOsFile + sizeof(AsyncLock) + pData->nName + 1;
pLock = (AsyncLock *)sqlite3_malloc(nByte);
if( pLock ){ if( pLock ){
AsyncLock *pDelete; memset(pLock, 0, nByte);
#ifdef ENABLE_FILE_LOCKING #ifdef ENABLE_FILE_LOCKING
if( flags&SQLITE_OPEN_MAIN_DB ){ if( flags&SQLITE_OPEN_MAIN_DB ){
pLock->pFile = (sqlite3_file *)&pLock[1]; 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 ){ if( rc!=SQLITE_OK ){
sqlite3_free(pLock); sqlite3_free(pLock);
pLock = 0; pLock = 0;
} }
} }
#endif #endif
pDelete = sqlite3HashInsert( if( pLock ){
&async.aLock, pData->zName, pData->nName, (void *)pLock pLock->nFile = pData->nName;
); pLock->zFile = &((char *)(&pLock[1]))[pVfs->szOsFile];
if( pDelete ){ memcpy(pLock->zFile, pData->zName, pLock->nFile);
rc = SQLITE_NOMEM; pLock->pNext = async.pLock;
sqlite3_free(pLock); async.pLock = pLock;
} }
}else{ }else{
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
@@ -1078,21 +1128,24 @@ static int asyncOpen(
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
HashElem *pElem;
p->pMethod = &async_methods; p->pMethod = &async_methods;
p->pData = pData; p->pData = pData;
/* Link AsyncFileData.lock into the linked list of /* Link AsyncFileData.lock into the linked list of
** AsyncFileLock structures for this file. ** AsyncFileLock structures for this file.
*/ */
if( zName ){
pData->lock.pNext = pLock->pList; pData->lock.pNext = pLock->pList;
pLock->pList = &pData->lock; pLock->pList = &pData->lock;
pData->zName = pLock->zFile;
pElem = sqlite3HashFindElem(&async.aLock, pData->zName, pData->nName); }
pData->zName = (char *)sqliteHashKey(pElem);
}else{ }else{
sqlite3OsClose(pData->pBaseRead); if( pData->pBaseRead->pMethods ){
sqlite3OsClose(pData->pBaseWrite); pData->pBaseRead->pMethods->xClose(pData->pBaseRead);
}
if( pData->pBaseWrite->pMethods ){
pData->pBaseWrite->pMethods->xClose(pData->pBaseWrite);
}
sqlite3_free(pData); sqlite3_free(pData);
} }
@@ -1100,10 +1153,11 @@ static int asyncOpen(
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
incrOpenFileCount(); incrOpenFileCount();
pData->pLock = pLock;
} }
if( rc==SQLITE_OK && isExclusive ){ 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( rc==SQLITE_OK ){
if( pOutFlags ) *pOutFlags = flags; if( pOutFlags ) *pOutFlags = flags;
}else{ }else{
@@ -1145,12 +1199,13 @@ static int asyncAccess(
); );
pthread_mutex_lock(&async.queueMutex); 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 ){ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
for(p=async.pQueueFirst; p; p = p->pNext){ for(p=async.pQueueFirst; p; p = p->pNext){
if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, zName) ){ if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, zName) ){
ret = 0; ret = 0;
}else if( p->op==ASYNC_OPENEXCLUSIVE }else if( p->op==ASYNC_OPENEXCLUSIVE
&& p->pFileData->zName
&& 0==strcmp(p->pFileData->zName, zName) && 0==strcmp(p->pFileData->zName, zName)
){ ){
ret = 1; ret = 1;
@@ -1178,7 +1233,7 @@ static int asyncFullPathname(
){ ){
int rc; int rc;
sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; 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 /* Because of the way intra-process file locking works, this backend
** needs to return a canonical path. The following block assumes the ** 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){ static void asyncEnable(int enable){
if( enable ){ if( enable ){
if( !async_vfs.pAppData ){ if( !async_vfs.pAppData ){
static int hashTableInit = 0;
async_vfs.pAppData = (void *)sqlite3_vfs_find(0); async_vfs.pAppData = (void *)sqlite3_vfs_find(0);
async_vfs.mxPathname = ((sqlite3_vfs *)async_vfs.pAppData)->mxPathname; async_vfs.mxPathname = ((sqlite3_vfs *)async_vfs.pAppData)->mxPathname;
sqlite3_vfs_register(&async_vfs, 1); sqlite3_vfs_register(&async_vfs, 1);
if( !hashTableInit ){
sqlite3HashInit(&async.aLock, SQLITE_HASH_BINARY, 1);
hashTableInit = 1;
}
} }
}else{ }else{
if( async_vfs.pAppData ){ if( async_vfs.pAppData ){
@@ -1398,27 +1448,31 @@ static void *asyncWriterThread(void *pIsStarted){
assert( pBase ); assert( pBase );
ASYNC_TRACE(("WRITE %s %d bytes at %d\n", ASYNC_TRACE(("WRITE %s %d bytes at %d\n",
p->pFileData->zName, p->nByte, p->iOffset)); 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; break;
case ASYNC_SYNC: case ASYNC_SYNC:
assert( pBase ); assert( pBase );
ASYNC_TRACE(("SYNC %s\n", p->pFileData->zName)); ASYNC_TRACE(("SYNC %s\n", p->pFileData->zName));
rc = sqlite3OsSync(pBase, p->nByte); rc = pBase->pMethods->xSync(pBase, p->nByte);
break; break;
case ASYNC_TRUNCATE: case ASYNC_TRUNCATE:
assert( pBase ); assert( pBase );
ASYNC_TRACE(("TRUNCATE %s to %d bytes\n", ASYNC_TRACE(("TRUNCATE %s to %d bytes\n",
p->pFileData->zName, p->iOffset)); p->pFileData->zName, p->iOffset));
rc = sqlite3OsTruncate(pBase, p->iOffset); rc = pBase->pMethods->xTruncate(pBase, p->iOffset);
break; break;
case ASYNC_CLOSE: { case ASYNC_CLOSE: {
AsyncFileData *pData = p->pFileData; AsyncFileData *pData = p->pFileData;
ASYNC_TRACE(("CLOSE %s\n", p->pFileData->zName)); ASYNC_TRACE(("CLOSE %s\n", p->pFileData->zName));
sqlite3OsClose(pData->pBaseWrite); if( pData->pBaseWrite->pMethods ){
sqlite3OsClose(pData->pBaseRead); 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 /* Unlink AsyncFileData.lock from the linked list of AsyncFileLock
** structures for this file. Obtain the async.lockMutex mutex ** structures for this file. Obtain the async.lockMutex mutex
@@ -1435,7 +1489,6 @@ static void *asyncWriterThread(void *pIsStarted){
} }
case ASYNC_UNLOCK: { case ASYNC_UNLOCK: {
AsyncLock *pLock;
AsyncFileData *pData = p->pFileData; AsyncFileData *pData = p->pFileData;
int eLock = p->nByte; int eLock = p->nByte;
pthread_mutex_lock(&async.lockMutex); pthread_mutex_lock(&async.lockMutex);
@@ -1443,15 +1496,14 @@ static void *asyncWriterThread(void *pIsStarted){
pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock) pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
); );
assert(pData->lock.eAsyncLock>=pData->lock.eLock); assert(pData->lock.eAsyncLock>=pData->lock.eLock);
pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName); rc = getFileLock(pData->pLock);
rc = getFileLock(pLock);
pthread_mutex_unlock(&async.lockMutex); pthread_mutex_unlock(&async.lockMutex);
break; break;
} }
case ASYNC_DELETE: case ASYNC_DELETE:
ASYNC_TRACE(("DELETE %s\n", p->zBuf)); 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; break;
case ASYNC_OPENEXCLUSIVE: { case ASYNC_OPENEXCLUSIVE: {
@@ -1459,7 +1511,7 @@ static void *asyncWriterThread(void *pIsStarted){
AsyncFileData *pData = p->pFileData; AsyncFileData *pData = p->pFileData;
ASYNC_TRACE(("OPEN %s flags=%d\n", p->zBuf, (int)p->iOffset)); ASYNC_TRACE(("OPEN %s flags=%d\n", p->zBuf, (int)p->iOffset));
assert(pData->pBaseRead->pMethods==0 && pData->pBaseWrite->pMethods==0); 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 ); assert( holdingMutex==0 );
pthread_mutex_lock(&async.queueMutex); pthread_mutex_lock(&async.queueMutex);
holdingMutex = 1; holdingMutex = 1;
@@ -1511,7 +1563,7 @@ static void *asyncWriterThread(void *pIsStarted){
if( async.ioError && !async.pQueueFirst ){ if( async.ioError && !async.pQueueFirst ){
pthread_mutex_lock(&async.lockMutex); pthread_mutex_lock(&async.lockMutex);
if( 0==sqliteHashFirst(&async.aLock) ){ if( 0==async.pLock ){
async.ioError = SQLITE_OK; async.ioError = SQLITE_OK;
} }
pthread_mutex_unlock(&async.lockMutex); pthread_mutex_unlock(&async.lockMutex);
@@ -1524,7 +1576,7 @@ static void *asyncWriterThread(void *pIsStarted){
pthread_mutex_unlock(&async.queueMutex); pthread_mutex_unlock(&async.queueMutex);
holdingMutex = 0; holdingMutex = 0;
if( async.ioDelay>0 ){ if( async.ioDelay>0 ){
sqlite3OsSleep(pVfs, async.ioDelay); pVfs->xSleep(pVfs, async.ioDelay);
}else{ }else{
sched_yield(); sched_yield();
} }