-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
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
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
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
**
** 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.
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,
#define ASYNC_CLOSE 4
#define ASYNC_OPENDIRECTORY 5
#define ASYNC_SETFULLSYNC 6
-
#define ASYNC_DELETE 7
#define ASYNC_OPENEXCLUSIVE 8
#define ASYNC_SYNCDIRECTORY 9
*/
static const char *azOpcodeName[] = {
"NOOP", "WRITE", "SYNC", "TRUNCATE", "CLOSE",
- "OPENDIR", "SETFULLSYNC", "DELETE", "OPENEX", "SYNCDIR"
+ "OPENDIR", "SETFULLSYNC", "DELETE", "OPENEX", "SYNCDIR",
};
/*
** 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
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 */
};
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);
}
/*
-** 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);
}
/*
** 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;
}
/*
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;
}
}
- 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;
}
}
+ TRACE(("EXISTS: %s = %d\n", z, ret));
pthread_mutex_unlock(&async.queueMutex);
return ret;
}
*/
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;
sqlite3Os.xSyncDirectory = asyncSyncDirectory;
}
if( !enable && xOrigOpenReadWrite!=0 ){
+ sqlite3HashClear(&async.aLock);
+
sqlite3Os.xOpenReadWrite = xOrigOpenReadWrite;
sqlite3Os.xOpenReadOnly = xOrigOpenReadOnly;
sqlite3Os.xOpenExclusive = xOrigOpenExclusive;
}
}
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
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;
}