void testAppend(){ OsFile id;/* I don't like the implementation since OSFile need to create by myself*/ int Readonly; int i,nPages; double time; char * buf=sqlite3Malloc(config.pagesize); rc = sqlite3OsOpenReadWrite( config.datfile, &id, &Readonly); errorHandle(rc, "can't open the file"); for(nPages=1; nPages<=config.pagenum; nPages++){ printf("append %d pages!\n",nPages); start_timer(); for(i=0;i<nPages;i++){ sqlite3Randomness(config.pagesize, buf); rc = sqlite3OsWrite(&id, buf, config.pagesize); errorHandle(rc, "write error"); } time = get_timer(); pr_times(config.recordfile, time); } rc= sqlite3OsClose(&id); errorHandle(rc, "can't close the file"); //TODO can't find the defintion, do it later //sqlite3Free((void *)buf); }
int sqlite3OsCloseFree(sqlite3_file *pFile){ int rc = SQLITE_OK; assert( pFile ); rc = sqlite3OsClose(pFile); sqlite3_free(pFile); return rc; }
/* ** Close the file. */ static int jrnlClose(sqlite3_file *pJfd){ JournalFile *p = (JournalFile *)pJfd; if( p->pReal ){ sqlite3OsClose(p->pReal); } sqlite3_free(p->zBuf); return SQLITE_OK; }
/* ** Open a crash-file file handle. ** ** The caller will have allocated pVfs->szOsFile bytes of space ** at pFile. This file uses this space for the CrashFile structure ** and allocates space for the "real" file structure using ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is ** equal or greater than sizeof(CrashFile). */ static int cfOpen( sqlite3_vfs *pCfVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; int rc; CrashFile *pWrapper = (CrashFile *)pFile; sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1]; memset(pWrapper, 0, sizeof(CrashFile)); rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags); if( rc==SQLITE_OK ){ i64 iSize; pWrapper->pMethod = &CrashFileVtab; pWrapper->zName = (char *)zName; pWrapper->pRealFile = pReal; rc = sqlite3OsFileSize(pReal, &iSize); pWrapper->iSize = (int)iSize; pWrapper->flags = flags; } if( rc==SQLITE_OK ){ pWrapper->nData = (4096 + pWrapper->iSize); pWrapper->zData = crash_malloc(pWrapper->nData); if( pWrapper->zData ){ /* os_unix.c contains an assert() that fails if the caller attempts ** to read data from the 512-byte locking region of a file opened ** with the SQLITE_OPEN_MAIN_DB flag. This region of a database file ** never contains valid data anyhow. So avoid doing such a read here. */ const int isDb = (flags&SQLITE_OPEN_MAIN_DB); i64 iChunk = pWrapper->iSize; if( iChunk>PENDING_BYTE && isDb ){ iChunk = PENDING_BYTE; } memset(pWrapper->zData, 0, pWrapper->nData); rc = sqlite3OsRead(pReal, pWrapper->zData, iChunk, 0); if( SQLITE_OK==rc && pWrapper->iSize>(PENDING_BYTE+512) && isDb ){ i64 iOff = PENDING_BYTE+512; iChunk = pWrapper->iSize - iOff; rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], iChunk, iOff); } }else{ rc = SQLITE_NOMEM; } } if( rc!=SQLITE_OK && pWrapper->pMethod ){ sqlite3OsClose(pFile); } return rc; }
/* ** Open a crash-file file handle. ** ** The caller will have allocated pVfs->szOsFile bytes of space ** at pFile. This file uses this space for the CrashFile structure ** and allocates space for the "real" file structure using ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is ** equal or greater than sizeof(CrashFile). */ static int cfOpen( sqlite3_vfs *pCfVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; int rc; CrashFile *pWrapper = (CrashFile *)pFile; sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1]; memset(pWrapper, 0, sizeof(CrashFile)); rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags); if( rc==SQLITE_OK ){ i64 iSize; pWrapper->pMethod = &CrashFileVtab; pWrapper->zName = (char *)zName; pWrapper->pRealFile = pReal; rc = sqlite3OsFileSize(pReal, &iSize); pWrapper->iSize = (int)iSize; pWrapper->flags = flags; } if( rc==SQLITE_OK ){ pWrapper->nData = (int)(4096 + pWrapper->iSize); pWrapper->zData = crash_malloc(pWrapper->nData); if( pWrapper->zData ){ /* os_unix.c contains an assert() that fails if the caller attempts ** to read data from the 512-byte locking region of a file opened ** with the SQLITE_OPEN_MAIN_DB flag. This region of a database file ** never contains valid data anyhow. So avoid doing such a read here. ** ** UPDATE: It also contains an assert() verifying that each call ** to the xRead() method reads less than 128KB of data. */ i64 iOff; memset(pWrapper->zData, 0, pWrapper->nData); for(iOff=0; iOff<pWrapper->iSize; iOff += 512){ int nRead = (int)(pWrapper->iSize - iOff); if( nRead>512 ) nRead = 512; rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], nRead, iOff); } }else{ rc = SQLITE_NOMEM; } } if( rc!=SQLITE_OK && pWrapper->pMethod ){ sqlite3OsClose(pFile); } return rc; }
void VfsOpenTempFileFileIoErrTest() { //Delete all temp files in this test private data cage. TInt err = DoDeleteTempFiles(); TEST(err == KErrNone || err == KErrNotFound); sqlite3_vfs* vfs = sqlite3_vfs_find(NULL); TEST(vfs != NULL); sqlite3_file* osFile = (sqlite3_file*)User::Alloc(vfs->szOsFile); TEST(osFile != NULL); err = SQLITE_ERROR; TInt cnt = 1; while(err != SQLITE_OK) { TInt processHandleCnt = 0; TInt threadHandleCnt = 0; RThread().HandleCount(processHandleCnt, threadHandleCnt); TInt allocCellsCnt = User::CountAllocCells(); TheTest.Printf(_L("%d "), cnt); (void)TheFs.SetErrorCondition(KErrGeneral, cnt); int outFlags = 0; err = sqlite3OsOpen(vfs, NULL, osFile, SQLITE_OPEN_READWRITE, &outFlags); if(err == SQLITE_OK) { //Since this is a temp file, its creation will be delayed till the first file write operation. err = sqlite3OsWrite(osFile, "1234", 4, 0); (void)sqlite3OsClose(osFile); } (void)TheFs.SetErrorCondition(KErrNone); if(err != SQLITE_OK) { TInt processHandleCnt2 = 0; TInt threadHandleCnt2 = 0; RThread().HandleCount(processHandleCnt2, threadHandleCnt2); TEST2(processHandleCnt2, processHandleCnt); TEST2(threadHandleCnt2, threadHandleCnt); TInt allocCellsCnt2 = User::CountAllocCells(); TEST2(allocCellsCnt2, allocCellsCnt); ++cnt; } //If the iteration has failed, then no temp file should exist in the test private data cage. //If the iteration has succeeded, then sqlite3OsClose() should have deleted the temp file. TInt err2 = DoDeleteTempFiles(); TEST2(err2, KErrNotFound); } TEST2(err, SQLITE_OK); TheTest.Printf(_L("\r\n=== TVfs::Open(<temp file>) file I/O error simulation test succeeded at iteration %d\r\n"), cnt); User::Free(osFile); }
/* ** Close an jt-file. */ static int jtClose(sqlite3_file *pFile){ jt_file **pp; jt_file *p = (jt_file *)pFile; closeTransaction(p); enterJtMutex(); if( p->zName ){ for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext); *pp = p->pNext; } leaveJtMutex(); return sqlite3OsClose(p->pReal); }
//Lock/unlock tests void Test5() { sqlite3_vfs* vfs = sqlite3_vfs_find(KSymbianVfsNameZ); TEST(vfs != NULL); sqlite3_file* osFile = (sqlite3_file*)User::Alloc(vfs->szOsFile); TEST(osFile != NULL); //Creating a new file int res = 0; int err = sqlite3OsAccess(vfs, KTestFile1Z, SQLITE_ACCESS_EXISTS, &res); TEST2(err, SQLITE_OK); TEST2(res, 0); err = sqlite3OsOpen(vfs, KTestFile1Z, osFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); TEST2(err, SQLITE_OK); //Lock/unlock //SHARED_LOCK err = sqlite3OsLock(osFile, SHARED_LOCK); TEST2(err, SQLITE_OK); err = sqlite3OsCheckReservedLock(osFile, &res); TEST2(err, SQLITE_OK); TEST2(res, 0); //RESERVED_LOCK err = sqlite3OsLock(osFile, RESERVED_LOCK); TEST2(err, SQLITE_OK); err = sqlite3OsCheckReservedLock(osFile, &res); TEST2(err, SQLITE_OK); TEST2(res, 1); //PENDING_LOCK err = sqlite3OsLock(osFile, PENDING_LOCK); TEST2(err, SQLITE_OK); //EXCLUSIVE_LOCK err = sqlite3OsLock(osFile, EXCLUSIVE_LOCK); TEST2(err, SQLITE_OK); //back to SHARED_LOCK err = sqlite3OsLock(osFile, SHARED_LOCK); TEST2(err, SQLITE_OK); //UNLOCK err = sqlite3OsUnlock(osFile, NO_LOCK); //Close the file err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); // err = sqlite3OsDelete(vfs, KTestFile1Z, 0); TEST2(err, SQLITE_OK); User::Free(osFile); }
void VfsOpenTempFileOomTest() { //Delete all temp files in this test private data cage. TInt err = DoDeleteTempFiles(); TEST(err == KErrNone || err == KErrNotFound); sqlite3_vfs* vfs = sqlite3_vfs_find(NULL); TEST(vfs != NULL); sqlite3_file* osFile = (sqlite3_file*)User::Alloc(vfs->szOsFile); TEST(osFile != NULL); TheTest.Printf(_L("Iteration: ")); TInt failingAllocNum = 0; err = SQLITE_IOERR_NOMEM; while(err == SQLITE_IOERR_NOMEM) { ++failingAllocNum; TheTest.Printf(_L("%d "), failingAllocNum); OomPreStep(failingAllocNum); int outFlags = 0; err = sqlite3OsOpen(vfs, NULL, osFile, SQLITE_OPEN_READWRITE, &outFlags); if(err == SQLITE_OK) { //Since this is a temp file, its creation will be delayed till the first file write operation. err = sqlite3OsWrite(osFile, "1234", 4, 0); (void)sqlite3OsClose(osFile); } OomPostStep(); if(err != SQLITE_OK) { TEST2(err, SQLITE_IOERR_NOMEM); } //If the iteration has failed, then no temp file should exist in the test private data cage. //If the iteration has succeeded, then sqlite3OsClose() should have deleted the temp file. TInt err2 = DoDeleteTempFiles(); TEST2(err2, KErrNotFound); } TEST2(err, SQLITE_OK); TheTest.Printf(_L("\r\n=== TVfs::Open(<temp file>) OOM test succeeded at allcoation %d\r\n"), failingAllocNum); User::Free(osFile); }
/* ** Open a crash-file file handle. ** ** The caller will have allocated pVfs->szOsFile bytes of space ** at pFile. This file uses this space for the CrashFile structure ** and allocates space for the "real" file structure using ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is ** equal or greater than sizeof(CrashFile). */ static int cfOpen( sqlite3_vfs *pCfVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; int rc; CrashFile *pWrapper = (CrashFile *)pFile; sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1]; memset(pWrapper, 0, sizeof(CrashFile)); rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags); if( rc==SQLITE_OK ){ i64 iSize; pWrapper->pMethod = &CrashFileVtab; pWrapper->zName = (char *)zName; pWrapper->pRealFile = pReal; rc = sqlite3OsFileSize(pReal, &iSize); pWrapper->iSize = (int)iSize; } if( rc==SQLITE_OK ){ pWrapper->nData = (4096 + pWrapper->iSize); pWrapper->zData = sqlite3_malloc(pWrapper->nData); if( pWrapper->zData ){ memset(pWrapper->zData, 0, pWrapper->nData); rc = sqlite3OsRead(pReal, pWrapper->zData, pWrapper->iSize, 0); }else{ rc = SQLITE_NOMEM; } } if( rc!=SQLITE_OK && pWrapper->pMethod ){ sqlite3OsClose(pFile); } return rc; }
void VfsCreateDeleteOnCloseFileOomTest() { sqlite3_vfs* vfs = sqlite3_vfs_find(NULL); TEST(vfs != NULL); sqlite3_file* osFile = (sqlite3_file*)User::Alloc(vfs->szOsFile); TEST(osFile != NULL); TheTest.Printf(_L("Iteration: ")); TInt failingAllocNum = 0; TInt err = SQLITE_IOERR_NOMEM; while(err == SQLITE_IOERR_NOMEM) { ++failingAllocNum; TheTest.Printf(_L("%d "), failingAllocNum); OomPreStep(failingAllocNum); int outFlags = 0; err = sqlite3OsOpen(vfs, KTestFile4Z, osFile, SQLITE_OPEN_CREATE | SQLITE_OPEN_DELETEONCLOSE, &outFlags); if(err == SQLITE_OK) { err = sqlite3OsClose(osFile); } OomPostStep(); if(err != SQLITE_OK) { TEST2(err, SQLITE_IOERR_NOMEM); } //Whether the iteration has failed or succeeded, the file should not exist. TPtrC8 ptrname((const TUint8*)KTestFile4Z); TBuf<50> fname; fname.Copy(ptrname); TInt err2 = TheFs.Delete(fname); TEST2(err2, KErrNotFound); } TEST2(err, SQLITE_OK); TheTest.Printf(_L("\r\n=== TVfs::Open(<delete on close file>) OOM test succeeded at allcoation %d\r\n"), failingAllocNum); User::Free(osFile); }
/* ** Usage: fake_big_file N FILENAME ** ** Write a few bytes at the N megabyte point of FILENAME. This will ** create a large file. If the file was a valid SQLite database, then ** the next time the database is opened, SQLite will begin allocating ** new pages after N. If N is 2096 or bigger, this will test the ** ability of SQLite to write to large files. */ static int fake_big_file( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int rc; int n; i64 offset; OsFile *fd = 0; int readOnly = 0; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N-MEGABYTES FILE\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; rc = sqlite3OsOpenReadWrite(argv[2], &fd, &readOnly); if( rc ){ Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0); return TCL_ERROR; } offset = n; offset *= 1024*1024; rc = sqlite3OsSeek(fd, offset); if( rc ){ Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0); return TCL_ERROR; } rc = sqlite3OsWrite(fd, "Hello, World!", 14); sqlite3OsClose(&fd); if( rc ){ Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0); return TCL_ERROR; } return TCL_OK; }
/* ** Close an tvfs-file. */ static int tvfsClose(sqlite3_file *pFile){ int rc; TestvfsFile *pTestfile = (TestvfsFile *)pFile; TestvfsFd *pFd = pTestfile->pFd; Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){ tvfsExecTcl(p, "xClose", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0 ); } if( pFd->pShmId ){ Tcl_DecrRefCount(pFd->pShmId); pFd->pShmId = 0; } if( pFile->pMethods ){ ckfree((char *)pFile->pMethods); } rc = sqlite3OsClose(pFd->pReal); ckfree((char *)pFd); pTestfile->pFd = 0; return rc; }
/* ** Close a crash-file. */ static int cfClose(sqlite3_file *pFile){ CrashFile *pCrash = (CrashFile *)pFile; writeListSync(pCrash, 0); sqlite3OsClose(pCrash->pRealFile); return SQLITE_OK; }
/* ** This routine does most of the work of opening a file and building ** the OsFile structure. */ static int asyncOpenFile( const char *zName, /* The name of the file to be opened */ OsFile **pFile, /* Put the OsFile structure here */ OsFile *pBaseRead, /* The real OsFile from the real I/O routine */ int openForWriting /* Open a second file handle for writing if true */ ){ int rc, i, n; AsyncFile *p; OsFile *pBaseWrite = 0; static IoMethod iomethod = { asyncClose, asyncOpenDirectory, asyncRead, asyncWrite, asyncSeek, asyncTruncate, asyncSync, asyncSetFullSync, asyncFileHandle, asyncFileSize, asyncLock, asyncUnlock, asyncLockState, asyncCheckReservedLock, asyncSectorSize, }; if( openForWriting && SQLITE_ASYNC_TWO_FILEHANDLES ){ int dummy; rc = xOrigOpenReadWrite(zName, &pBaseWrite, &dummy); if( rc!=SQLITE_OK ){ goto error_out; } } 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; *pFile = (OsFile *)p; return SQLITE_OK; error_out: assert(!p); sqlite3OsClose(&pBaseRead); sqlite3OsClose(&pBaseWrite); *pFile = 0; return rc; }
/* ** This procedure runs in a separate thread, reading messages off of the ** write queue and processing them one by one. ** ** If async.writerHaltNow is true, then this procedure exits ** after processing a single message. ** ** If async.writerHaltWhenIdle is true, then this procedure exits when ** the write queue is empty. ** ** If both of the above variables are false, this procedure runs ** indefinately, waiting for operations to be added to the write queue ** and processing them in the order in which they arrive. ** ** An artifical delay of async.ioDelay milliseconds is inserted before ** each write operation in order to simulate the effect of a slow disk. ** ** Only one instance of this procedure may be running at a time. */ 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 ){ OsFile *pBase = 0; if( !holdingMutex ){ pthread_mutex_lock(&async.queueMutex); } while( (p = async.pQueueFirst)==0 ){ pthread_cond_broadcast(&async.emptySignal); if( async.writerHaltWhenIdle ){ pthread_mutex_unlock(&async.queueMutex); break; }else{ ASYNC_TRACE(("IDLE\n")); pthread_cond_wait(&async.queueSignal, &async.queueMutex); ASYNC_TRACE(("WAKEUP\n")); } } 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 ** the general case, we hold on to the mutex for the entire body of ** the loop. ** ** However in the cases enumerated below, we relinquish the mutex, ** perform the IO, and then re-request the mutex before removing 'p' from ** the head of the write-op queue. The idea is to increase concurrency with ** sqlite threads. ** ** * An ASYNC_CLOSE operation. ** * An ASYNC_OPENEXCLUSIVE operation. For this one, we relinquish ** the mutex, call the underlying xOpenExclusive() function, then ** re-aquire the mutex before seting the AsyncFile.pBaseRead ** variable. ** * ASYNC_SYNC and ASYNC_WRITE operations, if ** 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->op==ASYNC_CLOSE || p->op==ASYNC_OPENEXCLUSIVE || (pBase && (p->op==ASYNC_SYNC || p->op==ASYNC_WRITE) ) ){ pthread_mutex_unlock(&async.queueMutex); holdingMutex = 0; } if( !pBase ){ pBase = p->pFile->pBaseRead; } } switch( p->op ){ case ASYNC_NOOP: break; case ASYNC_WRITE: assert( pBase ); ASYNC_TRACE(("WRITE %s %d bytes at %d\n", p->pFile->zName, p->nByte, p->iOffset)); rc = sqlite3OsSeek(pBase, p->iOffset); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pBase, (const void *)(p->zBuf), p->nByte); } break; case ASYNC_SYNC: assert( pBase ); ASYNC_TRACE(("SYNC %s\n", p->pFile->zName)); rc = sqlite3OsSync(pBase, p->nByte); break; case ASYNC_TRUNCATE: assert( pBase ); ASYNC_TRACE(("TRUNCATE %s to %d bytes\n", p->pFile->zName, p->iOffset)); rc = sqlite3OsTruncate(pBase, p->iOffset); break; case ASYNC_CLOSE: ASYNC_TRACE(("CLOSE %s\n", p->pFile->zName)); sqlite3OsClose(&p->pFile->pBaseWrite); sqlite3OsClose(&p->pFile->pBaseRead); sqlite3OsFree(p->pFile); break; case ASYNC_OPENDIRECTORY: assert( pBase ); ASYNC_TRACE(("OPENDIR %s\n", p->zBuf)); sqlite3OsOpenDirectory(pBase, p->zBuf); break; case ASYNC_SETFULLSYNC: assert( pBase ); ASYNC_TRACE(("SETFULLSYNC %s %d\n", p->pFile->zName, p->nByte)); sqlite3OsSetFullSync(pBase, p->nByte); break; case ASYNC_DELETE: ASYNC_TRACE(("DELETE %s\n", p->zBuf)); rc = xOrigDelete(p->zBuf); break; case ASYNC_SYNCDIRECTORY: ASYNC_TRACE(("SYNCDIR %s\n", p->zBuf)); rc = xOrigSyncDirectory(p->zBuf); break; case ASYNC_OPENEXCLUSIVE: { AsyncFile *pFile = p->pFile; int delFlag = ((p->iOffset)?1:0); OsFile *pBase = 0; ASYNC_TRACE(("OPEN %s delFlag=%d\n", p->zBuf, delFlag)); assert(pFile->pBaseRead==0 && pFile->pBaseWrite==0); rc = xOrigOpenExclusive(p->zBuf, &pBase, delFlag); assert( holdingMutex==0 ); pthread_mutex_lock(&async.queueMutex); holdingMutex = 1; if( rc==SQLITE_OK ){ pFile->pBaseRead = pBase; } break; } default: assert(!"Illegal value for AsyncWrite.op"); } /* 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. */ if( !holdingMutex ){ pthread_mutex_lock(&async.queueMutex); holdingMutex = 1; } /* ASYNC_TRACE(("UNLINK %p\n", p)); */ if( p==async.pQueueLast ){ async.pQueueLast = 0; } async.pQueueFirst = p->pNext; 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. */ if( !async.pQueueFirst || !async.ioError ){ sqlite3ApiExit(0, 0); pthread_mutex_unlock(&async.queueMutex); holdingMutex = 0; if( async.ioDelay>0 ){ sqlite3OsSleep(async.ioDelay); }else{ sched_yield(); } } } pthread_mutex_unlock(&async.writerMutex); return 0; }
/* ** Close an devsym-file. */ static int devsymClose(sqlite3_file *pFile){ devsym_file *p = (devsym_file *)pFile; sqlite3OsClose(p->pReal); return SQLITE_OK; }
/* ** Close an devsym-file. */ static int devsymClose(sqlite3_file *pFile){ devsym_file *p = (devsym_file *)pFile; return sqlite3OsClose(p->pReal); }
//Create/open/close/delete a file void Test1() { sqlite3_vfs* vfs = sqlite3_vfs_find(KSymbianVfsNameZ); TEST(vfs != NULL); sqlite3_file* osFile = (sqlite3_file*)User::Alloc(vfs->szOsFile); TEST(osFile != NULL); //Creating a new file int outFlags = 0; int err = sqlite3OsOpen(vfs, KTestFile1Z, osFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, &outFlags); TEST2(err, SQLITE_OK); TEST(outFlags & SQLITE_OPEN_READWRITE); err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); //Opening an existing file for R/W err = sqlite3OsOpen(vfs, KTestFile1Z, osFile, SQLITE_OPEN_READWRITE, &outFlags); TEST2(err, SQLITE_OK); TEST(outFlags & SQLITE_OPEN_READWRITE); err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); //Opening a read-only file err = sqlite3OsOpen(vfs, KTestFile2Z, osFile, SQLITE_OPEN_READWRITE, &outFlags); TEST2(err, SQLITE_OK); TEST(outFlags & SQLITE_OPEN_READONLY); //Truncate a read-only file err = osFile->pMethods->xTruncate(osFile, 0); TEST2(err, SQLITE_IOERR); //xAccess - read-only file int res = 0; err = vfs->xAccess(vfs, KTestFile2Z, SQLITE_ACCESS_READ, &res); TEST2(err, SQLITE_OK); TEST(res != 0); //xAccess - invalid request res = 0; err = vfs->xAccess(vfs, KTestFile2Z, 122, &res); TEST2(err, SQLITE_OK); TEST2(res, 0); // err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); //Creating a new file err = sqlite3OsOpen(vfs, KTestFile3Z, osFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, &outFlags); TEST2(err, SQLITE_OK); TEST(outFlags & SQLITE_OPEN_READWRITE); err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); //Open a file for a read-only access err = sqlite3OsOpen(vfs, KTestFile1Z, osFile, SQLITE_OPEN_READONLY, &outFlags); TEST2(err, SQLITE_OK); TEST(outFlags & SQLITE_OPEN_READONLY); err = sqlite3OsWrite(osFile, "1234", 4, 0); TEST(err != SQLITE_OK); err = sqlite3SymbianLastOsError(); TEST2(err, KErrAccessDenied); err = vfs->xGetLastError(vfs, 0, 0); TEST2(err, 0);//Default implementation err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); //Delete KTestFile3Z file err = sqlite3OsDelete(vfs, KTestFile3Z, 0); TEST2(err, SQLITE_OK); res = 0; err = sqlite3OsAccess(vfs, KTestFile3Z, SQLITE_ACCESS_EXISTS, &res); TEST2(err, SQLITE_OK); TEST2(res, 0); //Open a file for an exclusive access err = sqlite3OsOpen(vfs, KTestFile3Z, osFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_EXCLUSIVE, &outFlags); TEST2(err, SQLITE_OK); err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); //The file should not exist now err = sqlite3OsAccess(vfs, KTestFile3Z, SQLITE_ACCESS_EXISTS, &res); TEST2(err, SQLITE_OK); TEST2(res, 0); //Open a file for an exclusive access without deleting it after err = sqlite3OsOpen(vfs, KTestFile3Z, osFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE, &outFlags); TEST2(err, SQLITE_OK); err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); //The file should exist now err = sqlite3OsAccess(vfs, KTestFile3Z, SQLITE_ACCESS_EXISTS, &res); TEST2(err, SQLITE_OK); TEST2(res, 1); //Delete KTestFile3Z file err = sqlite3OsDelete(vfs, KTestFile3Z, 0); TEST2(err, SQLITE_OK); err = sqlite3OsAccess(vfs, KTestFile3Z, SQLITE_ACCESS_EXISTS, &res); TEST2(err, SQLITE_OK); TEST2(res, 0); // User::Free(osFile); }
/* ** A read or write transaction may or may not be active on database handle ** db. If a transaction is active, commit it. If there is a ** write-transaction spanning more than one database file, this routine ** takes care of the master journal trickery. */ static int vdbeCommit(sqlite3 *db){ int i; int nTrans = 0; /* Number of databases with an active write-transaction */ int rc = SQLITE_OK; int needXcommit = 0; for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsInTrans(pBt) ){ needXcommit = 1; if( i!=1 ) nTrans++; } } /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ int rc; sqlite3SafetyOff(db); rc = db->xCommitCallback(db->pCommitArg); sqlite3SafetyOn(db); if( rc ){ return SQLITE_CONSTRAINT; } } /* The simple case - no more than one database file (not counting the ** TEMP database) has a transaction active. There is no need for the ** master-journal. ** ** If the return value of sqlite3BtreeGetFilename() is a zero length ** string, it means the main database is :memory:. In that case we do ** not support atomic multi-file commits, so use the simple case then ** too. */ if( 0==strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeSync(pBt, 0); } } /* Do the commit only if all databases successfully synced */ if( rc==SQLITE_OK ){ for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ sqlite3BtreeCommit(pBt); } } } } /* The complex case - There is a multi-file write-transaction active. ** This requires a master journal file to ensure the transaction is ** committed atomicly. */ else{ char *zMaster = 0; /* File-name for the master journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); OsFile master; /* Select a master journal file name */ do { u32 random; sqliteFree(zMaster); sqlite3Randomness(sizeof(random), &random); zMaster = sqlite3MPrintf("%s-mj%08X", zMainFile, random&0x7fffffff); if( !zMaster ){ return SQLITE_NOMEM; } }while( sqlite3OsFileExists(zMaster) ); /* Open the master journal. */ memset(&master, 0, sizeof(master)); rc = sqlite3OsOpenExclusive(zMaster, &master, 0); if( rc!=SQLITE_OK ){ sqliteFree(zMaster); return rc; } /* Write the name of each database file in the transaction into the new ** master journal file. If an error occurs at this point close ** and delete the master journal file. All the individual journal files ** still have 'null' as the master journal pointer, so they will roll ** back independantly if a failure occurs. */ for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( i==1 ) continue; /* Ignore the TEMP database */ if( pBt && sqlite3BtreeIsInTrans(pBt) ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile[0]==0 ) continue; /* Ignore :memory: databases */ rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1); if( rc!=SQLITE_OK ){ sqlite3OsClose(&master); sqlite3OsDelete(zMaster); sqliteFree(zMaster); return rc; } } } /* Sync the master journal file. Before doing this, open the directory ** the master journal file is store in so that it gets synced too. */ zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt); rc = sqlite3OsOpenDirectory(zMainFile, &master); if( rc!=SQLITE_OK ){ sqlite3OsClose(&master); sqlite3OsDelete(zMaster); sqliteFree(zMaster); return rc; } rc = sqlite3OsSync(&master); if( rc!=SQLITE_OK ){ sqlite3OsClose(&master); sqliteFree(zMaster); return rc; } /* Sync all the db files involved in the transaction. The same call ** sets the master journal pointer in each individual journal. If ** an error occurs here, do not delete the master journal file. ** ** If the error occurs during the first call to sqlite3BtreeSync(), ** then there is a chance that the master journal file will be ** orphaned. But we cannot delete it, in case the master journal ** file name was written into the journal file before the failure ** occured. */ for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsInTrans(pBt) ){ rc = sqlite3BtreeSync(pBt, zMaster); if( rc!=SQLITE_OK ){ sqlite3OsClose(&master); sqliteFree(zMaster); return rc; } } } sqlite3OsClose(&master); /* Delete the master journal file. This commits the transaction. After ** doing this the directory is synced again before any individual ** transaction files are deleted. */ rc = sqlite3OsDelete(zMaster); assert( rc==SQLITE_OK ); sqliteFree(zMaster); zMaster = 0; rc = sqlite3OsSyncDirectory(zMainFile); if( rc!=SQLITE_OK ){ /* This is not good. The master journal file has been deleted, but ** the directory sync failed. There is no completely safe course of ** action from here. The individual journals contain the name of the ** master journal file, but there is no way of knowing if that ** master journal exists now or if it will exist after the operating ** system crash that may follow the fsync() failure. */ assert(0); sqliteFree(zMaster); return rc; } /* All files and directories have already been synced, so the following ** calls to sqlite3BtreeCommit() are only closing files and deleting ** journals. If something goes wrong while this is happening we don't ** really care. The integrity of the transaction is already guaranteed, ** but some stray 'cold' journals may be lying around. Returning an ** error code won't help matters. */ for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ sqlite3BtreeCommit(pBt); } } } return rc; }
//Read/Write/Seek/Truncate test void Test2() { sqlite3_vfs* vfs = sqlite3_vfs_find(KSymbianVfsNameZ); TEST(vfs != NULL); sqlite3_file* osFile = (sqlite3_file*)User::Alloc(vfs->szOsFile); TEST(osFile != NULL); //Creating a new file int err = sqlite3OsDelete(vfs, KTestFile1Z, 0); TEST2(err, SQLITE_OK); int res = 0; err = sqlite3OsAccess(vfs, KTestFile1Z, SQLITE_ACCESS_EXISTS, &res); TEST2(err, SQLITE_OK); TEST2(res, 0); err = sqlite3OsOpen(vfs, KTestFile1Z, osFile, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); TEST2(err, SQLITE_OK); //Writing at the beginning of the file err = sqlite3OsWrite(osFile, "123456", 6, 0); TEST2(err, SQLITE_OK); //Verify the written data char data[20]; err = sqlite3OsRead(osFile, data, 6, 0); TEST2(err, SQLITE_OK); err = memcmp(data, "123456", 6); TEST2(err, 0); //Writing at beyond the end of the file err = sqlite3OsWrite(osFile, "abcdefgh", 8, 100); TEST2(err, SQLITE_OK); //Verify the written data err = sqlite3OsRead(osFile, data, 8, 100); TEST2(err, SQLITE_OK); err = memcmp(data, "abcdefgh", 8); TEST2(err, 0); //Truncate the file err = sqlite3OsTruncate(osFile, 3); TEST2(err, SQLITE_OK); //Write more data err = sqlite3OsWrite(osFile, "xyz", 3, 3); TEST2(err, SQLITE_OK); //Verify the written data err = sqlite3OsRead(osFile, data, 6, 0); TEST2(err, SQLITE_OK); err = memcmp(data, "123xyz", 6); TEST2(err, 0); //Check the file size TInt64 fileSize = 0; err = sqlite3OsFileSize(osFile, &fileSize); TEST2(err, SQLITE_OK); TEST(fileSize == 6); //FileControl - lock type int lockType = -1; err = osFile->pMethods->xFileControl(osFile, SQLITE_FCNTL_LOCKSTATE, &lockType); TEST2(err, SQLITE_OK); TEST2(lockType, NO_LOCK); //FileControl - set callback - NULL callback err = osFile->pMethods->xFileControl(osFile, KSqlFcntlRegisterFreePageCallback, 0); TEST2(err, SQLITE_ERROR); //FileControl - set callback - invalid callback object TSqlFreePageCallback cbck; err = osFile->pMethods->xFileControl(osFile, KSqlFcntlRegisterFreePageCallback, &cbck); TEST2(err, SQLITE_ERROR); //FileControl - invalid op-code err = osFile->pMethods->xFileControl(osFile, 90234, 0); TEST2(err, SQLITE_ERROR); //Close the file err = sqlite3OsClose(osFile); TEST2(err, SQLITE_OK); // err = sqlite3OsDelete(vfs, KTestFile1Z, 0); TEST2(err, SQLITE_OK); User::Free(osFile); }