📄 test_async.c
字号:
*/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( 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); ASYNC_TRACE(("LOCK %d (%s) rc=%d\n", eLock, p->zName, rc)); return rc;}static int asyncUnlock(sqlite3_file *pFile, int eLock){ 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);}/*** This function is called when the pager layer first opens a database file** and is checking for a hot-journal.*/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){ if( pIter->eLock>=SQLITE_LOCK_RESERVED ){ ret = 1; } } pthread_mutex_unlock(&async.lockMutex); ASYNC_TRACE(("CHECK-LOCK %d (%s)\n", ret, p->zName)); *pResOut = ret; return SQLITE_OK;}/* ** This is a no-op, as the asynchronous backend does not support locking.*/static int asyncFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { pthread_mutex_lock(&async.lockMutex); *(int*)pArg = ((AsyncFile*)id)->pData->lock.eLock; pthread_mutex_unlock(&async.lockMutex); return SQLITE_OK; } } return SQLITE_ERROR;}/* ** Return the device characteristics and sector-size of the device. It** is not tricky to implement these correctly, as this backend might ** not have an open file handle at this point.*/static int asyncSectorSize(sqlite3_file *pFile){ return 512;}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.*/static int asyncOpen( sqlite3_vfs *pAsyncVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags){ static sqlite3_io_methods async_methods = { 1, /* iVersion */ asyncClose, /* xClose */ asyncRead, /* xRead */ asyncWrite, /* xWrite */ asyncTruncate, /* xTruncate */ asyncSync, /* xSync */ asyncFileSize, /* xFileSize */ asyncLock, /* xLock */ asyncUnlock, /* xUnlock */ asyncCheckReservedLock, /* xCheckReservedLock */ asyncFileControl, /* xFileControl */ asyncSectorSize, /* xSectorSize */ asyncDeviceCharacteristics /* xDeviceCharacteristics */ }; sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; AsyncFile *p = (AsyncFile *)pFile; int nName = strlen(zName)+1; int rc = SQLITE_OK; int nByte; AsyncFileData *pData; AsyncLock *pLock = 0; char *z; int isExclusive = (flags&SQLITE_OPEN_EXCLUSIVE); nByte = ( sizeof(AsyncFileData) + /* AsyncFileData structure */ 2 * pVfs->szOsFile + /* AsyncFileData.pBaseRead and pBaseWrite */ nName /* AsyncFileData.zName */ ); z = sqlite3_malloc(nByte); if( !z ){ return SQLITE_NOMEM; } memset(z, 0, nByte); pData = (AsyncFileData*)z; z += sizeof(pData[0]); 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( !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); } } pthread_mutex_lock(&async.lockMutex); if( rc==SQLITE_OK ){ pLock = sqlite3HashFind(&async.aLock, pData->zName, pData->nName); 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]; rc = sqlite3OsOpen(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); } }else{ rc = SQLITE_NOMEM; } } } 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); }else{ sqlite3OsClose(pData->pBaseRead); sqlite3OsClose(pData->pBaseWrite); sqlite3_free(pData); } pthread_mutex_unlock(&async.lockMutex); if( rc==SQLITE_OK ){ incrOpenFileCount(); } 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;}/*** Implementation of sqlite3OsDelete. Add an entry to the end of the ** write-op queue to perform the delete.*/static int asyncDelete(sqlite3_vfs *pAsyncVfs, const char *z, int syncDir){ return addNewAsyncWrite(0, ASYNC_DELETE, syncDir, strlen(z)+1, z);}/*** Implementation of sqlite3OsAccess. This method holds the mutex from** start to finish.*/static int asyncAccess( sqlite3_vfs *pAsyncVfs, const char *zName, int flags, int *pResOut){ int rc; int ret; AsyncWrite *p; sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; assert(flags==SQLITE_ACCESS_READWRITE || flags==SQLITE_ACCESS_READ || flags==SQLITE_ACCESS_EXISTS ); pthread_mutex_lock(&async.queueMutex); rc = sqlite3OsAccess(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 && 0==strcmp(p->pFileData->zName, zName) ){ ret = 1; } } } ASYNC_TRACE(("ACCESS(%s): %s = %d\n", flags==SQLITE_ACCESS_READWRITE?"read-write": flags==SQLITE_ACCESS_READ?"read":"exists" , zName, ret) ); pthread_mutex_unlock(&async.queueMutex); *pResOut = ret; return rc;}/*** Fill in zPathOut with the full path to the file identified by zPath.*/static int asyncFullPathname( sqlite3_vfs *pAsyncVfs, const char *zPath, int nPathOut, char *zPathOut){ int rc; sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; rc = sqlite3OsFullPathname(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 ** file-system uses unix style paths. */ if( rc==SQLITE_OK ){ int iIn; int iOut = 0; int nPathOut = strlen(zPathOut); for(iIn=0; iIn<nPathOut; iIn++){ /* Replace any occurences of "//" with "/" */ if( iIn<=(nPathOut-2) && zPathOut[iIn]=='/' && zPathOut[iIn+1]=='/' ){ continue; } /* Replace any occurences of "/./" with "/" */ if( iIn<=(nPathOut-3) && zPathOut[iIn]=='/' && zPathOut[iIn+1]=='.' && zPathOut[iIn+2]=='/' ){ iIn++; continue; } /* Replace any occurences of "<path-component>/../" with "" */ if( iOut>0 && iIn<=(nPathOut-4) && zPathOut[iIn]=='/' && zPathOut[iIn+1]=='.' && zPathOut[iIn+2]=='.' && zPathOut[iIn+3]=='/' ){ iIn += 3; iOut--; for( ; iOut>0 && zPathOut[iOut-1]!='/'; iOut--); continue; } zPathOut[iOut++] = zPathOut[iIn]; } zPathOut[iOut] = '\0'; } return rc;}static void *asyncDlOpen(sqlite3_vfs *pAsyncVfs, const char *zPath){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; return pVfs->xDlOpen(pVfs, zPath);}static void asyncDlError(sqlite3_vfs *pAsyncVfs, int nByte, char *zErrMsg){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; pVfs->xDlError(pVfs, nByte, zErrMsg);}static void *asyncDlSym( sqlite3_vfs *pAsyncVfs, void *pHandle, const char *zSymbol){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; return pVfs->xDlSym(pVfs, pHandle, zSymbol);}static void asyncDlClose(sqlite3_vfs *pAsyncVfs, void *pHandle){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; pVfs->xDlClose(pVfs, pHandle);}static int asyncRandomness(sqlite3_vfs *pAsyncVfs, int nByte, char *zBufOut){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; return pVfs->xRandomness(pVfs, nByte, zBufOut);}static int asyncSleep(sqlite3_vfs *pAsyncVfs, int nMicro){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; return pVfs->xSleep(pVfs, nMicro);}static int asyncCurrentTime(sqlite3_vfs *pAsyncVfs, double *pTimeOut){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData; return pVfs->xCurrentTime(pVfs, pTimeOut);}static sqlite3_vfs async_vfs = { 1, /* iVersion */ sizeof(AsyncFile), /* szOsFile */ 0, /* mxPathname */ 0, /* pNext */ "async", /* zName */ 0, /* pAppData */ asyncOpen, /* xOpen */ asyncDelete, /* xDelete */ asyncAccess, /* xAccess */ asyncFullPathname, /* xFullPathname */ asyncDlOpen, /* xDlOpen */ asyncDlError, /* xDlError */ asyncDlSym, /* xDlSym */ asyncDlClose, /* xDlClose */ asyncRandomness, /* xDlError */ asyncSleep, /* xDlSym */ asyncCurrentTime /* xDlClose */};/*** Call this routine to enable or disable the** asynchronous IO features implemented in this file. **** This routine is not even remotely threadsafe. Do not call** this routine while any SQLite database connections are open.*/static void asyncEnable(int enable){ if( enable ){ if( !async_vfs.pAppData ){ static int hashTableInit = 0; async_vfs.pAppData = (void *)sqlite3_vfs_find(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -