📄 os_test.c
字号:
/*** 2004 May 22**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.************************************************************************************ This file contains code that is specific to Unix systems. It is used** for testing SQLite only.*/#if OS_TEST /* This file is used for the test backend only */#include "sqliteInt.h"#include "os.h" /* Must be first to enable large file support */#define sqlite3OsOpenReadWrite sqlite3RealOpenReadWrite#define sqlite3OsOpenExclusive sqlite3RealOpenExclusive#define sqlite3OsOpenReadOnly sqlite3RealOpenReadOnly#define sqlite3OsOpenDirectory sqlite3RealOpenDirectory#define sqlite3OsClose sqlite3RealClose#define sqlite3OsRead sqlite3RealRead#define sqlite3OsWrite sqlite3RealWrite#define sqlite3OsSeek sqlite3RealSeek#define sqlite3OsSync sqlite3RealSync#define sqlite3OsTruncate sqlite3RealTruncate#define sqlite3OsFileSize sqlite3RealFileSize#define sqlite3OsLock sqlite3RealLock#define sqlite3OsUnlock sqlite3RealUnlock#define sqlite3OsCheckReservedLock sqlite3RealCheckReservedLock#define OsFile OsRealFile#define OS_UNIX 1#include "os_unix.c"#undef OS_UNIX#undef OsFile#undef sqlite3OsOpenReadWrite #undef sqlite3OsOpenExclusive #undef sqlite3OsOpenReadOnly #undef sqlite3OsOpenDirectory #undef sqlite3OsClose #undef sqlite3OsRead #undef sqlite3OsWrite #undef sqlite3OsSeek #undef sqlite3OsSync #undef sqlite3OsTruncate #undef sqlite3OsFileSize #undef sqlite3OsLock #undef sqlite3OsUnlock #undef sqlite3OsCheckReservedLock #define BLOCKSIZE 512#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)/*** The following variables control when a simulated crash occurs.**** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of** a file that SQLite will call sqlite3OsSync() on. Each time this happens** iCrashDelay is decremented. If iCrashDelay is zero after being** decremented, a "crash" occurs during the sync() operation.**** In other words, a crash occurs the iCrashDelay'th time zCrashFile is** synced.*/static int iCrashDelay = 0;char zCrashFile[256];/*** Set the value of the two crash parameters.*/void sqlite3SetCrashParams(int iDelay, char const *zFile){ sqlite3OsEnterMutex(); assert( strlen(zFile)<256 ); strcpy(zCrashFile, zFile); iCrashDelay = iDelay; sqlite3OsLeaveMutex();}/*** File zPath is being sync()ed. Return non-zero if this should** cause a crash.*/static int crashRequired(char const *zPath){ int r; int n; sqlite3OsEnterMutex(); n = strlen(zCrashFile); if( zCrashFile[n-1]=='*' ){ n--; }else if( strlen(zPath)>n ){ n = strlen(zPath); } r = 0; if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){ iCrashDelay--; if( iCrashDelay<=0 ){ r = 1; } } sqlite3OsLeaveMutex(); return r;}static OsTestFile *pAllFiles = 0;/*** Initialise the os_test.c specific fields of pFile.*/static void initFile(OsFile *id, char const *zName){ OsTestFile *pFile = (OsTestFile *) sqliteMalloc(sizeof(OsTestFile) + strlen(zName)+1); pFile->nMaxWrite = 0; pFile->nBlk = 0; pFile->apBlk = 0; pFile->zName = (char *)(&pFile[1]); strcpy(pFile->zName, zName); *id = pFile; pFile->pNext = pAllFiles; pAllFiles = pFile;}/*** Undo the work done by initFile. Delete the OsTestFile structure** and unlink the structure from the pAllFiles list.*/static void closeFile(OsFile *id){ OsTestFile *pFile = *id; if( pFile==pAllFiles ){ pAllFiles = pFile->pNext; }else{ OsTestFile *p; for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){ assert( p ); } p->pNext = pFile->pNext; } sqliteFree(pFile); *id = 0;}/*** Return the current seek offset from the start of the file. This** is unix-only code.*/static i64 osTell(OsTestFile *pFile){ return lseek(pFile->fd.h, 0, SEEK_CUR);}/*** Load block 'blk' into the cache of pFile.*/static int cacheBlock(OsTestFile *pFile, int blk){ if( blk>=pFile->nBlk ){ int n = ((pFile->nBlk * 2) + 100 + blk); /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */ pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*)); if( !pFile->apBlk ) return SQLITE_NOMEM; memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*)); pFile->nBlk = n; } if( !pFile->apBlk[blk] ){ i64 filesize; int rc; u8 *p = sqliteMalloc(BLOCKSIZE); if( !p ) return SQLITE_NOMEM; pFile->apBlk[blk] = p; rc = sqlite3RealFileSize(&pFile->fd, &filesize); if( rc!=SQLITE_OK ) return rc; if( BLOCK_OFFSET(blk)<filesize ){ int len = BLOCKSIZE; rc = sqlite3RealSeek(&pFile->fd, blk*BLOCKSIZE); if( BLOCK_OFFSET(blk+1)>filesize ){ len = filesize - BLOCK_OFFSET(blk); } if( rc!=SQLITE_OK ) return rc; rc = sqlite3RealRead(&pFile->fd, p, len); if( rc!=SQLITE_OK ) return rc; } } return SQLITE_OK;}/* #define TRACE_WRITECACHE *//*** Write the cache of pFile to disk. If crash is non-zero, randomly** skip blocks when writing. The cache is deleted before returning.*/static int writeCache2(OsTestFile *pFile, int crash){ int i; int nMax = pFile->nMaxWrite; i64 offset; int rc = SQLITE_OK; offset = osTell(pFile); for(i=0; i<pFile->nBlk; i++){ u8 *p = pFile->apBlk[i]; if( p ){ int skip = 0; int trash = 0; if( crash ){ char random; sqlite3Randomness(1, &random); if( random & 0x01 ){ if( random & 0x02 ){ trash = 1;#ifdef TRACE_WRITECACHEprintf("Trashing block %d of %s\n", i, pFile->zName); #endif }else{ skip = 1;#ifdef TRACE_WRITECACHEprintf("Skiping block %d of %s\n", i, pFile->zName); #endif } }else{#ifdef TRACE_WRITECACHEprintf("Writing block %d of %s\n", i, pFile->zName); #endif } } if( rc==SQLITE_OK ){ rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i)); } if( rc==SQLITE_OK && !skip ){ int len = BLOCKSIZE; if( BLOCK_OFFSET(i+1)>nMax ){ len = nMax-BLOCK_OFFSET(i); } if( len>0 ){ if( trash ){ sqlite3Randomness(len, p); } rc = sqlite3RealWrite(&pFile->fd, p, len); } } sqliteFree(p); } } sqliteFree(pFile->apBlk); pFile->nBlk = 0; pFile->apBlk = 0; pFile->nMaxWrite = 0; if( rc==SQLITE_OK ){ rc = sqlite3RealSeek(&pFile->fd, offset); } return rc;}/*** Write the cache to disk.*/static int writeCache(OsTestFile *pFile){ if( pFile->apBlk ){ int c = crashRequired(pFile->zName); if( c ){ OsTestFile *p;#ifdef TRACE_WRITECACHE printf("\nCrash during sync of %s\n", pFile->zName);#endif for(p=pAllFiles; p; p=p->pNext){ writeCache2(p, 1); } exit(-1); }else{ return writeCache2(pFile, 0); } } return SQLITE_OK;}/*** Close the file.*/int sqlite3OsClose(OsFile *id){ if( !(*id) ) return SQLITE_OK; if( (*id)->fd.isOpen ){ /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ writeCache(*id); sqlite3RealClose(&(*id)->fd); } closeFile(id); return SQLITE_OK;}int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ i64 offset; /* The current offset from the start of the file */ i64 end; /* The byte just past the last byte read */ int blk; /* Block number the read starts on */ int i; u8 *zCsr; int rc = SQLITE_OK; OsTestFile *pFile = *id; offset = osTell(pFile); end = offset+amt; blk = (offset/BLOCKSIZE); zCsr = (u8 *)pBuf; for(i=blk; i*BLOCKSIZE<end; i++){ int off = 0; int len = 0; if( BLOCK_OFFSET(i) < offset ){ off = offset-BLOCK_OFFSET(i); } len = BLOCKSIZE - off; if( BLOCK_OFFSET(i+1) > end ){ len = len - (BLOCK_OFFSET(i+1)-end); } if( i<pFile->nBlk && pFile->apBlk[i]){ u8 *pBlk = pFile->apBlk[i]; memcpy(zCsr, &pBlk[off], len); }else{ rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i) + off); if( rc!=SQLITE_OK ) return rc; rc = sqlite3RealRead(&pFile->fd, zCsr, len); if( rc!=SQLITE_OK ) return rc; } zCsr += len; } assert( zCsr==&((u8 *)pBuf)[amt] ); rc = sqlite3RealSeek(&pFile->fd, end); return rc;}int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ i64 offset; /* The current offset from the start of the file */ i64 end; /* The byte just past the last byte written */ int blk; /* Block number the write starts on */ int i; const u8 *zCsr; int rc = SQLITE_OK; OsTestFile *pFile = *id; offset = osTell(pFile); end = offset+amt; blk = (offset/BLOCKSIZE); zCsr = (u8 *)pBuf; for(i=blk; i*BLOCKSIZE<end; i++){ u8 *pBlk; int off = 0; int len = 0; /* Make sure the block is in the cache */ rc = cacheBlock(pFile, i); if( rc!=SQLITE_OK ) return rc; /* Write into the cache */ pBlk = pFile->apBlk[i]; assert( pBlk ); if( BLOCK_OFFSET(i) < offset ){ off = offset-BLOCK_OFFSET(i); } len = BLOCKSIZE - off; if( BLOCK_OFFSET(i+1) > end ){ len = len - (BLOCK_OFFSET(i+1)-end); } memcpy(&pBlk[off], zCsr, len); zCsr += len; } if( pFile->nMaxWrite<end ){ pFile->nMaxWrite = end; } assert( zCsr==&((u8 *)pBuf)[amt] ); rc = sqlite3RealSeek(&pFile->fd, end); return rc;}/*** Sync the file. First flush the write-cache to disk, then call the** real sync() function.*/int sqlite3OsSync(OsFile *id){ int rc; /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ rc = writeCache(*id); if( rc!=SQLITE_OK ) return rc; rc = sqlite3RealSync(&(*id)->fd); return rc;}/*** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new** file size to ensure that nothing in the write-cache past this point** is written to disk.*/int sqlite3OsTruncate(OsFile *id, i64 nByte){ (*id)->nMaxWrite = nByte; return sqlite3RealTruncate(&(*id)->fd, nByte);}/*** Return the size of the file. If the cache contains a write that extended** the file, then return this size instead of the on-disk size.*/int sqlite3OsFileSize(OsFile *id, i64 *pSize){ int rc = sqlite3RealFileSize(&(*id)->fd, pSize); if( rc==SQLITE_OK && pSize && *pSize<(*id)->nMaxWrite ){ *pSize = (*id)->nMaxWrite; } return rc;}/*** The three functions used to open files. All that is required is to** initialise the os_test.c specific fields and then call the corresponding** os_unix.c function to really open the file.*/int sqlite3OsOpenReadWrite(const char *zFilename, OsFile *id, int *pReadonly){ initFile(id, zFilename); return sqlite3RealOpenReadWrite(zFilename, &(*id)->fd, pReadonly);}int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ initFile(id, zFilename); return sqlite3RealOpenExclusive(zFilename, &(*id)->fd, delFlag);}int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ initFile(id, zFilename); return sqlite3RealOpenReadOnly(zFilename, &(*id)->fd);}/*** These six function calls are passed straight through to the os_unix.c** backend.*/int sqlite3OsSeek(OsFile *id, i64 offset){ return sqlite3RealSeek(&(*id)->fd, offset);}int sqlite3OsCheckReservedLock(OsFile *id){ return sqlite3RealCheckReservedLock(&(*id)->fd);}int sqlite3OsLock(OsFile *id, int locktype){ return sqlite3RealLock(&(*id)->fd, locktype);}int sqlite3OsUnlock(OsFile *id, int locktype){ return sqlite3RealUnlock(&(*id)->fd, locktype);}int sqlite3OsOpenDirectory(const char *zDirname, OsFile *id){ return sqlite3RealOpenDirectory(zDirname, &(*id)->fd);}#endif /* OS_TEST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -