-C Add\sa\sdebugging\smemory\sallocator.\s(CVS\s4227)
-D 2007-08-15T17:07:57
+C Modify\sthe\scrash-recovery\stest\scode\sin\stest6.c\sfor\s3.5.\sAlso\schange\ssome\sother\scode\sto\suse\sthe\snew\ssqlite3_io_methods\sinterface.\sLots\sof\sthings\sare\sbroken\snow.\s(CVS\s4228)
+D 2007-08-15T17:08:46
F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/mem1.c ef73642a171d174cd556d0168f8edbceaf94933b
F src/mem2.c b8173ddcca23e99829617185154a35a6f046b214
F src/mutex.c 667dae0de95f8fb92a3ffc8c3f20c0d26115a1a6
-F src/os.c 1f10b47acc1177fb9225edb4f5f0d25ed716f9cb
-F src/os.h cea2e179bb33f4fc09dbb9fcd51b2246544bd2db
+F src/os.c e2faefbe0f5a8ca5e3b1c49ee1b5c6cfa0f0e279
+F src/os.h 8eff07babf74e5bc3f895f8a6c7c294dad5ff997
F src/os_common.h a5c446d3b93f09f369d13bf217de4bed3437dd1c
F src/os_os2.c cba4e96fadb949076c717108fe0599d1a3c2e446
F src/os_os2.h e5f17dd69333632bbc3112881ea407c37d245eb3
F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c
F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3
-F src/os_unix.c 9d2a421acc607262e63ccf31e3fe86e5f2520af6
+F src/os_unix.c 05ad65c32b4937fd47b17b472955aa5dfc438074
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c d868d5f9e95ec9c1b9e2a30c54c996053db6dddd
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c cdf561d3ae4009be902df714da4518dc3522e206
+F src/pager.c 05ea9dcbc4de4e9d9ca332ca1f8a9ba65fe2cbf5
F src/pager.h 94110a5570dca30d54a883e880a3633b2e4c05ae
F src/parse.y ad2ce25665be7f7303137f774a4e3e72e0d036ff
F src/pragma.c 7914a6b9ea05f158800116dfcae11e52ab8e39c4
F src/select.c 3b167744fc375bddfddcef87feb18f5171737677
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
-F src/sqlite.h.in 025e9fd6c519f2945296a9db46ca9da4571c22d7
+F src/sqlite.h.in 165913eb3426fbaa8a2a51d87f84593bfe5bee15
F src/sqlite3ext.h a27bedc222df5e5f0f458ac99726d0483b953a91
F src/sqliteInt.h fc9f6e8d916e182c04983a089c4ce4057fac5003
F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d
F src/tclsqlite.c 648e6f53041ce4974234d4963e71680926760925
F src/test1.c 94bd41c24a4d8d782e39c1275421511587d8b293
-F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
+F src/test2.c 5c3edc610852a8f67990cd08c5d5dbb79e3f8db9
F src/test3.c a280931fb40222b7c90da45eea926459beee8904
F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
F src/test5.c c40a4cf43266c1c6da7bcb737d294304a177e6cc
-F src/test6.c 2c4ed21787944bd8896cba80d4a544d8bed5473e
+F src/test6.c 4d812a5ea1fe08693f4189bfc974b341102a3bea
F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3
F src/test8.c 27a61c60f736066646a9e9ca21acdfdf0f3ea11e
F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
F src/vdbeInt.h c3514903cad9e36d6b3242be20261351d09db56c
F src/vdbeapi.c 220b81132abaf0f620edb8da48799a77daef12a7
-F src/vdbeaux.c d626e0f8cd78b4280bcb7af25d5c5566348ba87a
+F src/vdbeaux.c 8e6dbe3dac3bdd7d37c87ba553059b5251ba07e5
F src/vdbeblob.c bb30b3e387c35ba869949494b2736aff97159470
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F src/vdbemem.c ca4d3994507cb0a9504820293af69f5c778b4abd
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P c0fa3769790af199a4c8715c80bb8ff900730520
-R afa459b840a3b96de70924b91a0e1dbb
-U drh
-Z 9341f1481e29775e7a036e24546ed5fc
+P 8d2d1c4ff9dca61f75e3048107ee9712d346a28c
+R 7d9819ae0c3408fa1555b7b8d9a48850
+U danielk1977
+Z 41f21c80ce49e631fe5dbf7930bb9145
-8d2d1c4ff9dca61f75e3048107ee9712d346a28c
\ No newline at end of file
+af9503daf3f7703fcddad754bc1dc9e179830b6e
\ No newline at end of file
/*
** The following routines are convenience wrappers around methods
-** of the OsFile object. This is mostly just syntactic sugar. All
+** of the sqlite3_file object. This is mostly just syntactic sugar. All
** of this would be completely automatic if SQLite were coded using
** C++ instead of plain old C.
*/
-int sqlite3OsClose(OsFile **pId){
- OsFile *id;
+int sqlite3OsClose(sqlite3_file **pId){
+ int rc = SQLITE_OK;
+ sqlite3_file *id;
if( pId!=0 && (id = *pId)!=0 ){
- return id->pMethod->xClose(pId);
- }else{
- return SQLITE_OK;
+ rc = id->pMethods->xClose(id);
+ if( rc==SQLITE_OK ){
+ *pId = 0;
+ }
}
+ return rc;
}
-int sqlite3OsOpenDirectory(OsFile *id, const char *zName){
- return id->pMethod->xOpenDirectory(id, zName);
+int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
+ return id->pMethods->xRead(id, pBuf, amt, offset);
}
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
- return id->pMethod->xRead(id, pBuf, amt);
+int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
+ return id->pMethods->xWrite(id, pBuf, amt, offset);
}
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
- return id->pMethod->xWrite(id, pBuf, amt);
+int sqlite3OsTruncate(sqlite3_file *id, i64 size){
+ return id->pMethods->xTruncate(id, size);
}
-int sqlite3OsSeek(OsFile *id, i64 offset){
- return id->pMethod->xSeek(id, offset);
+int sqlite3OsSync(sqlite3_file *id, int fullsync){
+ return id->pMethods->xSync(id, fullsync);
}
-int sqlite3OsTruncate(OsFile *id, i64 size){
- return id->pMethod->xTruncate(id, size);
+int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
+ return id->pMethods->xFileSize(id, pSize);
}
-int sqlite3OsSync(OsFile *id, int fullsync){
- return id->pMethod->xSync(id, fullsync);
+int sqlite3OsLock(sqlite3_file *id, int lockType){
+ return id->pMethods->xLock(id, lockType);
}
-void sqlite3OsSetFullSync(OsFile *id, int value){
- id->pMethod->xSetFullSync(id, value);
+int sqlite3OsUnlock(sqlite3_file *id, int lockType){
+ return id->pMethods->xUnlock(id, lockType);
}
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
- return id->pMethod->xFileSize(id, pSize);
+int sqlite3OsBreakLock(sqlite3_file *id){
+ return id->pMethods->xBreakLock(id);
}
-int sqlite3OsLock(OsFile *id, int lockType){
- return id->pMethod->xLock(id, lockType);
+int sqlite3OsCheckReservedLock(sqlite3_file *id){
+ return id->pMethods->xCheckReservedLock(id);
}
-int sqlite3OsUnlock(OsFile *id, int lockType){
- return id->pMethod->xUnlock(id, lockType);
-}
-int sqlite3OsCheckReservedLock(OsFile *id){
- return id->pMethod->xCheckReservedLock(id);
-}
-int sqlite3OsSectorSize(OsFile *id){
- int (*xSectorSize)(OsFile*) = id->pMethod->xSectorSize;
+int sqlite3OsSectorSize(sqlite3_file *id){
+ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
return xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE;
}
+int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
+ return id->pMethods->xDeviceCharacteristics(id);
+}
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/* These methods are currently only used for testing and debugging. */
- int sqlite3OsFileHandle(OsFile *id){
- return id->pMethod->xFileHandle(id);
+ int sqlite3OsFileHandle(sqlite3_file *id){
+ /* return id->pMethods->xFileHandle(id); */
+ return 0;
}
- int sqlite3OsLockState(OsFile *id){
- return id->pMethod->xLockState(id);
+ int sqlite3OsLockState(sqlite3_file *id){
+ /* return id->pMethods->xLockState(id); */
+ return 0;
}
#endif
/*
** Prototypes for operating system interface routines.
*/
-int sqlite3OsClose(OsFile**);
-int sqlite3OsOpenDirectory(OsFile*, const char*);
-int sqlite3OsRead(OsFile*, void*, int amt);
-int sqlite3OsWrite(OsFile*, const void*, int amt);
-int sqlite3OsSeek(OsFile*, i64 offset);
-int sqlite3OsTruncate(OsFile*, i64 size);
-int sqlite3OsSync(OsFile*, int);
-void sqlite3OsSetFullSync(OsFile *id, int setting);
-int sqlite3OsFileSize(OsFile*, i64 *pSize);
-int sqlite3OsLock(OsFile*, int);
-int sqlite3OsUnlock(OsFile*, int);
-int sqlite3OsCheckReservedLock(OsFile *id);
-int sqlite3OsOpenReadWrite(const char*, OsFile**, int*);
-int sqlite3OsOpenExclusive(const char*, OsFile**, int);
-int sqlite3OsOpenReadOnly(const char*, OsFile**);
+int sqlite3OsClose(sqlite3_file**);
+int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
+int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
+int sqlite3OsTruncate(sqlite3_file*, i64 size);
+int sqlite3OsSync(sqlite3_file*, int);
+int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
+int sqlite3OsLock(sqlite3_file*, int);
+int sqlite3OsUnlock(sqlite3_file*, int);
+int sqlite3OsBreakLock(sqlite3_file*);
+int sqlite3OsCheckReservedLock(sqlite3_file *id);
+int sqlite3OsSectorSize(sqlite3_file *id);
+int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+
+int sqlite3OsOpenReadWrite(const char*, sqlite3_file**, int*);
+int sqlite3OsOpenExclusive(const char*, sqlite3_file**, int);
+int sqlite3OsOpenReadOnly(const char*, sqlite3_file**);
+
int sqlite3OsDelete(const char*);
int sqlite3OsFileExists(const char*);
char *sqlite3OsFullPathname(const char*);
int sqlite3OsIsDirWritable(char*);
int sqlite3OsSyncDirectory(const char*);
-int sqlite3OsSectorSize(OsFile *id);
int sqlite3OsTempFileName(char*);
int sqlite3OsRandomSeed(char*);
int sqlite3OsSleep(int ms);
int sqlite3OsDlclose(void*);
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
- int sqlite3OsFileHandle(OsFile *id);
- int sqlite3OsLockState(OsFile *id);
+ int sqlite3OsFileHandle(sqlite3_file *id);
+ int sqlite3OsLockState(sqlite3_file *id);
#endif
/*
** operating system interfaces or behaviors.
*/
struct sqlite3OsVtbl {
- int (*xOpenReadWrite)(const char*, OsFile**, int*);
- int (*xOpenExclusive)(const char*, OsFile**, int);
- int (*xOpenReadOnly)(const char*, OsFile**);
+ int (*xOpenReadWrite)(const char*, sqlite3_file**, int*);
+ int (*xOpenExclusive)(const char*, sqlite3_file**, int);
+ int (*xOpenReadOnly)(const char*, sqlite3_file**);
int (*xDelete)(const char*);
int (*xFileExists)(const char*);
*/
typedef struct unixFile unixFile;
struct unixFile {
- IoMethod const *pMethod; /* Always the first entry */
+ sqlite3_io_methods const *pMethod; /* Always the first entry */
struct openCnt *pOpen; /* Info about all open fd's on this inode */
struct lockInfo *pLock; /* Info about locks on this inode */
#ifdef SQLITE_ENABLE_LOCKING_STYLE
#endif
};
+
/*
** Provide the ability to override some OS-layer functions during
** testing. This is used to simulate OS crashes to verify that
*/
#ifdef SQLITE_CRASH_TEST
extern int sqlite3CrashTestEnable;
- extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*);
- extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int);
- extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int);
-# define CRASH_TEST_OVERRIDE(X,A,B,C) \
- if(sqlite3CrashTestEnable){ return X(A,B,C); }
+ int sqlite3CrashFileWrap(sqlite3_file *, const char *, sqlite3_file **);
+ static int CRASH_TEST_OVERRIDE(const char *zFile, sqlite3_file **pId, int rc){
+ if( rc==SQLITE_OK && sqlite3CrashTestEnable ){
+ rc = sqlite3CrashFileWrap(*pId, zFile, pId);
+ }
+ return rc;
+ }
#else
-# define CRASH_TEST_OVERRIDE(X,A,B,C) /* no-op */
+# define CRASH_TEST_OVERRIDE(A,B,C) C
#endif
/* Forward declaration */
static int allocateUnixFile(
int h, /* File descriptor of the open file */
- OsFile **pId, /* Write the real file descriptor here */
+ sqlite3_file **pId, /* Write the real file descriptor here */
const char *zFilename, /* Name of the file being opened */
int delFlag /* If true, make sure the file deletes on close */
);
*/
int sqlite3UnixOpenReadWrite(
const char *zFilename,
- OsFile **pId,
+ sqlite3_file **pId,
int *pReadonly
){
int h;
- CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly);
assert( 0==*pId );
h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
SQLITE_DEFAULT_FILE_PERMISSIONS);
}else{
*pReadonly = 0;
}
- return allocateUnixFile(h, pId, zFilename, 0);
+
+ return CRASH_TEST_OVERRIDE(
+ zFilename, pId, allocateUnixFile(h, pId, zFilename, 0)
+ );
}
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
+int sqlite3UnixOpenExclusive(
+ const char *zFilename,
+ sqlite3_file **pId,
+ int delFlag
+){
int h;
- CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag);
assert( 0==*pId );
h = open(zFilename,
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
if( h<0 ){
return SQLITE_CANTOPEN;
}
- return allocateUnixFile(h, pId, zFilename, delFlag);
+ return CRASH_TEST_OVERRIDE(
+ zFilename, pId, allocateUnixFile(h, pId, zFilename, delFlag)
+ );
}
/*
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){
+int sqlite3UnixOpenReadOnly(const char *zFilename, sqlite3_file **pId){
int h;
- CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0);
assert( 0==*pId );
h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
if( h<0 ){
return SQLITE_CANTOPEN;
}
- return allocateUnixFile(h, pId, zFilename, 0);
+ return CRASH_TEST_OVERRIDE(
+ zFilename, pId, allocateUnixFile(h, pId, zFilename, 0)
+ );
}
/*
** Seek to the offset in id->offset then read cnt bytes into pBuf.
** Return the number of bytes actually read. Update the offset.
*/
-static int seekAndRead(unixFile *id, void *pBuf, int cnt){
+static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
int got;
i64 newOffset;
TIMER_START;
#if defined(USE_PREAD)
- got = pread(id->h, pBuf, cnt, id->offset);
+ got = pread(id->h, pBuf, cnt, offset);
SimulateIOError( got = -1 );
#elif defined(USE_PREAD64)
- got = pread64(id->h, pBuf, cnt, id->offset);
+ got = pread64(id->h, pBuf, cnt, offset);
SimulateIOError( got = -1 );
#else
- newOffset = lseek(id->h, id->offset, SEEK_SET);
+ newOffset = lseek(id->h, offset, SEEK_SET);
SimulateIOError( newOffset-- );
- if( newOffset!=id->offset ){
+ if( newOffset!=offset ){
return -1;
}
got = read(id->h, pBuf, cnt);
#endif
TIMER_END;
OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
- if( got>0 ){
- id->offset += got;
- }
return got;
}
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-static int unixRead(OsFile *id, void *pBuf, int amt){
+static int unixRead(
+ sqlite3_file *id,
+ void *pBuf,
+ int amt,
+ sqlite3_int64 offset
+){
int got;
assert( id );
- got = seekAndRead((unixFile*)id, pBuf, amt);
+ got = seekAndRead((unixFile*)id, offset, pBuf, amt);
if( got==amt ){
return SQLITE_OK;
}else if( got<0 ){
** Seek to the offset in id->offset then read cnt bytes into pBuf.
** Return the number of bytes actually read. Update the offset.
*/
-static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
+static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
int got;
i64 newOffset;
TIMER_START;
#if defined(USE_PREAD)
- got = pwrite(id->h, pBuf, cnt, id->offset);
+ got = pwrite(id->h, pBuf, cnt, offset);
#elif defined(USE_PREAD64)
- got = pwrite64(id->h, pBuf, cnt, id->offset);
+ got = pwrite64(id->h, pBuf, cnt, offset);
#else
- newOffset = lseek(id->h, id->offset, SEEK_SET);
- if( newOffset!=id->offset ){
+ newOffset = lseek(id->h, offset, SEEK_SET);
+ if( newOffset!=offset ){
return -1;
}
got = write(id->h, pBuf, cnt);
#endif
TIMER_END;
- OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
- if( got>0 ){
- id->offset += got;
- }
+ OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED);
return got;
}
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
-static int unixWrite(OsFile *id, const void *pBuf, int amt){
+static int unixWrite(
+ sqlite3_file *id,
+ const void *pBuf,
+ int amt,
+ sqlite3_int64 offset
+){
int wrote = 0;
assert( id );
assert( amt>0 );
- while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){
+ while( amt>0 && (wrote = seekAndWrite((unixFile*)id, offset, pBuf, amt))>0 ){
amt -= wrote;
+ offset += wrote;
pBuf = &((char*)pBuf)[wrote];
}
SimulateIOError(( wrote=(-1), amt=1 ));
** the directory entry for the journal was never created) and the transaction
** will not roll back - possibly leading to database corruption.
*/
-static int unixSync(OsFile *id, int dataOnly){
+static int unixSync(sqlite3_file *id, int dataOnly){
int rc;
unixFile *pFile = (unixFile*)id;
assert( pFile );
/*
** Truncate an open file to a specified size
*/
-static int unixTruncate(OsFile *id, i64 nByte){
+static int unixTruncate(sqlite3_file *id, i64 nByte){
int rc;
assert( id );
rc = ftruncate(((unixFile*)id)->h, (off_t)nByte);
/*
** Determine the current size of a file in bytes
*/
-static int unixFileSize(OsFile *id, i64 *pSize){
+static int unixFileSize(sqlite3_file *id, i64 *pSize){
int rc;
struct stat buf;
assert( id );
** non-zero. If the file is unlocked or holds only SHARED locks, then
** return zero.
*/
-static int unixCheckReservedLock(OsFile *id){
+static int unixCheckReservedLock(sqlite3_file *id){
int r = 0;
unixFile *pFile = (unixFile*)id;
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int unixLock(OsFile *id, int locktype){
+static int unixLock(sqlite3_file *id, int locktype){
/* The following describes the implementation of the various locks and
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int unixUnlock(OsFile *id, int locktype){
+static int unixUnlock(sqlite3_file *id, int locktype){
struct lockInfo *pLock;
struct flock lock;
int rc = SQLITE_OK;
/*
** Close a file.
*/
-static int unixClose(OsFile **pId){
- unixFile *id = (unixFile*)*pId;
-
- if( !id ) return SQLITE_OK;
- unixUnlock(*pId, NO_LOCK);
- if( id->dirfd>=0 ) close(id->dirfd);
- id->dirfd = -1;
+static int unixClose(sqlite3_file *id){
+ unixFile *pFile = (unixFile *)id;
+ if( !pFile ) return SQLITE_OK;
+ unixUnlock(id, NO_LOCK);
+ if( pFile->dirfd>=0 ) close(pFile->dirfd);
+ pFile->dirfd = -1;
sqlite3OsEnterMutex();
- if( id->pOpen->nLock ){
+ if( pFile->pOpen->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
** descriptor to pOpen->aPending. It will be automatically closed when
** the last lock is cleared.
*/
int *aNew;
- struct openCnt *pOpen = id->pOpen;
+ struct openCnt *pOpen = pFile->pOpen;
aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
if( aNew==0 ){
/* If a malloc fails, just leak the file descriptor */
}else{
pOpen->aPending = aNew;
- pOpen->aPending[pOpen->nPending] = id->h;
+ pOpen->aPending[pOpen->nPending] = pFile->h;
pOpen->nPending++;
}
}else{
/* There are no outstanding locks so we can close the file immediately */
- close(id->h);
+ close(pFile->h);
}
- releaseLockInfo(id->pLock);
- releaseOpenCnt(id->pOpen);
+ releaseLockInfo(pFile->pLock);
+ releaseOpenCnt(pFile->pOpen);
sqlite3OsLeaveMutex();
- id->isOpen = 0;
- OSTRACE2("CLOSE %-3d\n", id->h);
+ pFile->isOpen = 0;
+ OSTRACE2("CLOSE %-3d\n", pFile->h);
OpenCounter(-1);
sqlite3ThreadSafeFree(id);
- *pId = 0;
return SQLITE_OK;
}
** a database and it's journal file) that the sector size will be the
** same for both.
*/
-static int unixSectorSize(OsFile *id){
+static int unixSectorSize(sqlite3_file *id){
return SQLITE_DEFAULT_SECTOR_SIZE;
}
+static int unixDeviceCharacteristics(sqlite3_file *id){
+ return 0;
+}
+
+static int unixBreakLock(sqlite3_file *id){
+ assert(!"TODO: unixBreakLock()");
+ return 0;
+}
+
/*
** This vector defines all the methods that can operate on an OsFile
** for unix.
*/
-static const IoMethod sqlite3UnixIoMethod = {
+static const sqlite3_io_methods sqlite3UnixIoMethod = {
+ 1, /* iVersion */
unixClose,
- unixOpenDirectory,
unixRead,
unixWrite,
- unixSeek,
unixTruncate,
unixSync,
- unixSetFullSync,
- unixFileHandle,
unixFileSize,
unixLock,
unixUnlock,
- unixLockState,
unixCheckReservedLock,
+ unixBreakLock,
unixSectorSize,
+ unixDeviceCharacteristics
};
#ifdef SQLITE_ENABLE_LOCKING_STYLE
#else /* SQLITE_ENABLE_LOCKING_STYLE */
static int allocateUnixFile(
int h, /* Open file descriptor on file being opened */
- OsFile **pId, /* Write the resul unixFile structure here */
+ sqlite3_file **pId, /* Write the resul unixFile structure here */
const char *zFilename, /* Name of the file being opened */
int delFlag /* If true, delete the file on or before closing */
){
}else{
*pNew = f;
pNew->pMethod = &sqlite3UnixIoMethod;
- *pId = (OsFile*)pNew;
+ *pId = (sqlite3_file*)pNew;
OpenCounter(+1);
return SQLITE_OK;
}
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.355 2007/08/11 00:26:21 drh Exp $
+** @(#) $Id: pager.c,v 1.356 2007/08/15 17:08:46 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
** to print out file-descriptors.
**
** PAGERID() takes a pointer to a Pager struct as it's argument. The
-** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile
+** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
** struct as it's argument.
*/
#define PAGERID(p) ((int)(p->fd))
char *zFilename; /* Name of the database file */
char *zJournal; /* Name of the journal file */
char *zDirectory; /* Directory hold database and journal files */
- OsFile *fd, *jfd; /* File descriptors for database and journal */
- OsFile *stfd; /* File descriptor for the statement subjournal*/
+ sqlite3_file *fd, *jfd; /* File descriptors for database and journal */
+ sqlite3_file *stfd; /* File descriptor for the statement subjournal*/
BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */
PgHdr *pFirst, *pLast; /* List of free pages */
PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */
**
** All values are stored on disk as big-endian.
*/
-static int read32bits(OsFile *fd, u32 *pRes){
+static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){
unsigned char ac[4];
- int rc = sqlite3OsRead(fd, ac, sizeof(ac));
+ int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset);
if( rc==SQLITE_OK ){
*pRes = sqlite3Get4byte(ac);
}
** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
** on success or an error code is something goes wrong.
*/
-static int write32bits(OsFile *fd, u32 val){
+static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
char ac[4];
put32bits(ac, val);
- return sqlite3OsWrite(fd, ac, 4);
+ return sqlite3OsWrite(fd, ac, 4, offset);
}
/*
** If no master journal file name is present *pzMaster is set to 0 and
** SQLITE_OK returned.
*/
-static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
+static int readMasterJournal(sqlite3_file *pJrnl, char **pzMaster){
int rc;
u32 len;
i64 szJ;
rc = sqlite3OsFileSize(pJrnl, &szJ);
if( rc!=SQLITE_OK || szJ<16 ) return rc;
- rc = sqlite3OsSeek(pJrnl, szJ-16);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = read32bits(pJrnl, &len);
+ rc = read32bits(pJrnl, szJ-16, &len);
if( rc!=SQLITE_OK ) return rc;
- rc = read32bits(pJrnl, &cksum);
+ rc = read32bits(pJrnl, szJ-12, &cksum);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(pJrnl, aMagic, 8);
+ rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8);
if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc;
- rc = sqlite3OsSeek(pJrnl, szJ-16-len);
- if( rc!=SQLITE_OK ) return rc;
-
*pzMaster = (char *)sqliteMalloc(len+1);
if( !*pzMaster ){
return SQLITE_NOMEM;
}
- rc = sqlite3OsRead(pJrnl, *pzMaster, len);
+ rc = sqlite3OsRead(pJrnl, *pzMaster, len, szJ-16-len);
if( rc!=SQLITE_OK ){
sqliteFree(*pzMaster);
*pzMaster = 0;
** 2000 2048
**
*/
-static int seekJournalHdr(Pager *pPager){
+static void seekJournalHdr(Pager *pPager){
i64 offset = 0;
i64 c = pPager->journalOff;
if( c ){
assert( offset>=c );
assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
pPager->journalOff = offset;
- return sqlite3OsSeek(pPager->jfd, pPager->journalOff);
}
/*
pPager->stmtHdrOff = pPager->journalOff;
}
- rc = seekJournalHdr(pPager);
- if( rc ) return rc;
-
+ seekJournalHdr(pPager);
pPager->journalHdr = pPager->journalOff;
- pPager->journalOff += JOURNAL_HDR_SZ(pPager);
/* FIX ME:
**
/* The assumed sector size for this process */
put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize);
IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, sizeof(zHeader)))
- rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader));
+ rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader),pPager->journalOff);
+ pPager->journalOff += JOURNAL_HDR_SZ(pPager);
/* The journal header has been written successfully. Seek the journal
** file descriptor to the end of the journal header sector.
*/
if( rc==SQLITE_OK ){
IOTRACE(("JTAIL %p %lld\n", pPager, pPager->journalOff-1))
- rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->jfd, "\000", 1);
- }
+ rc = sqlite3OsWrite(pPager->jfd, "\000", 1, pPager->journalOff-1);
}
return rc;
}
){
int rc;
unsigned char aMagic[8]; /* A buffer to hold the magic header */
+ i64 jrnlOff;
- rc = seekJournalHdr(pPager);
- if( rc ) return rc;
-
+ seekJournalHdr(pPager);
if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
return SQLITE_DONE;
}
+ jrnlOff = pPager->journalOff;
- rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic));
+ rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), jrnlOff);
if( rc ) return rc;
+ jrnlOff += sizeof(aMagic);
if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
return SQLITE_DONE;
}
- rc = read32bits(pPager->jfd, pNRec);
+ rc = read32bits(pPager->jfd, jrnlOff, pNRec);
if( rc ) return rc;
- rc = read32bits(pPager->jfd, &pPager->cksumInit);
+ rc = read32bits(pPager->jfd, jrnlOff+4, &pPager->cksumInit);
if( rc ) return rc;
- rc = read32bits(pPager->jfd, pDbSize);
+ rc = read32bits(pPager->jfd, jrnlOff+8, pDbSize);
if( rc ) return rc;
/* Update the assumed sector-size to match the value used by
** is being called from within pager_playback(). The local value
** of Pager.sectorSize is restored at the end of that routine.
*/
- rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize);
+ rc = read32bits(pPager->jfd, jrnlOff+12, (u32 *)&pPager->sectorSize);
if( rc ) return rc;
pPager->journalOff += JOURNAL_HDR_SZ(pPager);
- rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
- return rc;
+ return SQLITE_OK;
}
int rc;
int len;
int i;
+ i64 jrnlOff;
u32 cksum = 0;
char zBuf[sizeof(aJournalMagic)+2*4];
** the journal has already been synced.
*/
if( pPager->fullSync ){
- rc = seekJournalHdr(pPager);
- if( rc!=SQLITE_OK ) return rc;
+ seekJournalHdr(pPager);
}
+ jrnlOff = pPager->journalOff;
pPager->journalOff += (len+20);
- rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager));
+ rc = write32bits(pPager->jfd, jrnlOff, PAGER_MJ_PGNO(pPager));
if( rc!=SQLITE_OK ) return rc;
+ jrnlOff += 4;
- rc = sqlite3OsWrite(pPager->jfd, zMaster, len);
+ rc = sqlite3OsWrite(pPager->jfd, zMaster, len, jrnlOff);
if( rc!=SQLITE_OK ) return rc;
+ jrnlOff += len;
put32bits(zBuf, len);
put32bits(&zBuf[4], cksum);
memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic));
- rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic));
+ rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic), jrnlOff);
pPager->needSync = !pPager->noSync;
return rc;
}
if( pPager->journalOpen ){
if( pPager->exclusiveMode
&& (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){;
- sqlite3OsSeek(pPager->jfd, 0);
pPager->journalOff = 0;
pPager->journalStarted = 0;
}else{
** are not used in statement journals because statement journals do not
** need to survive power failures.
*/
-static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
+static int pager_playback_one_page(
+ Pager *pPager,
+ sqlite3_file *jfd,
+ i64 offset,
+ int useCksum
+){
int rc;
PgHdr *pPg; /* An existing page in the cache */
Pgno pgno; /* The page number of a page in journal */
assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) );
assert( aData );
- rc = read32bits(jfd, &pgno);
+ rc = read32bits(jfd, offset, &pgno);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(jfd, aData, pPager->pageSize);
+ rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4);
if( rc!=SQLITE_OK ) return rc;
pPager->journalOff += pPager->pageSize + 4;
return SQLITE_OK;
}
if( useCksum ){
- rc = read32bits(jfd, &cksum);
+ rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum);
if( rc ) return rc;
pPager->journalOff += 4;
if( pager_cksum(pPager, aData)!=cksum ){
PAGERTRACE4("PLAYBACK %d page %d hash(%08x)\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData));
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
- rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize);
- }
+ i64 offset = (pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize, offset);
if( pPg ){
makeClean(pPg);
}
static int pager_delmaster(const char *zMaster){
int rc;
int master_open = 0;
- OsFile *master = 0;
+ sqlite3_file *master = 0;
char *zMasterJournal = 0; /* Contents of master journal file */
i64 nMasterJournal; /* Size of master journal file */
rc = SQLITE_NOMEM;
goto delmaster_out;
}
- rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal);
+ rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal, 0);
if( rc!=SQLITE_OK ) goto delmaster_out;
zJournal = zMasterJournal;
** Open it and check if it points at the master journal. If
** so, return without deleting the master journal file.
*/
- OsFile *journal = 0;
+ sqlite3_file *journal = 0;
int c;
rc = sqlite3OsOpenReadOnly(zJournal, &journal);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
goto end_playback;
}
- sqlite3OsSeek(pPager->jfd, 0);
pPager->journalOff = 0;
/* This loop terminates either when the readJournalHdr() call returns
/* Copy original pages out of the journal and back into the database file.
*/
for(i=0; i<nRec; i++){
- rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
/* Figure out how many records are in the statement journal.
*/
assert( pPager->stmtInUse && pPager->journalOpen );
- sqlite3OsSeek(pPager->stfd, 0);
nRec = pPager->stmtNRec;
/* Copy original pages out of the statement journal and back into the
** each record since power-failure recovery is not important to statement
** journals.
*/
- for(i=nRec-1; i>=0; i--){
- rc = pager_playback_one_page(pPager, pPager->stfd, 0);
+ for(i=0; i<nRec; i++){
+ i64 offset = i*(4+pPager->pageSize);
+ rc = pager_playback_one_page(pPager, pPager->stfd, offset, 0);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
** If it is not zero, then Pager.stmtHdrOff is the offset to the start
** of the first journal header written during this statement transaction.
*/
- rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize);
- if( rc!=SQLITE_OK ){
- goto end_stmt_playback;
- }
pPager->journalOff = pPager->stmtJSize;
pPager->cksumInit = pPager->stmtCksum;
while( pPager->journalOff < hdrOff ){
- rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
}
for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){
- rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
** The OS will automatically delete the temporary file when it is
** closed.
*/
-static int sqlite3PagerOpentemp(OsFile **pFd){
+static int sqlite3PagerOpentemp(sqlite3_file **pFd){
int cnt = 8;
int rc;
char zFile[SQLITE_TEMPNAME_SIZE];
Pager *pPager = 0;
char *zFullPathname = 0;
int nameLen; /* Compiler is wrong. This is always initialized before use */
- OsFile *fd = 0;
+ sqlite3_file *fd = 0;
int rc = SQLITE_OK;
int i;
int tempFile = 0;
int rc = SQLITE_OK;
memset(pDest, 0, N);
if( MEMDB==0 ){
- disable_simulated_io_errors();
- sqlite3OsSeek(pPager->fd, 0);
- enable_simulated_io_errors();
IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
- rc = sqlite3OsRead(pPager->fd, pDest, N);
+ rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
}
#endif
{
+ i64 jrnlOff;
+
/* Write the nRec value into the journal file header. If in
** full-synchronous mode, sync the journal first. This ensures that
** all data has really hit the disk before nRec is updated to mark
rc = sqlite3OsSync(pPager->jfd, 0);
if( rc!=0 ) return rc;
}
- rc = sqlite3OsSeek(pPager->jfd,
- pPager->journalHdr + sizeof(aJournalMagic));
- if( rc ) return rc;
- IOTRACE(("JHDR %p %lld %d\n", pPager,
- pPager->journalHdr + sizeof(aJournalMagic), 4))
- rc = write32bits(pPager->jfd, pPager->nRec);
- if( rc ) return rc;
- rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
+ jrnlOff = pPager->journalHdr + sizeof(aJournalMagic);
+ IOTRACE(("JHDR %p %lld %d\n", pPager, jrnlOff, 4));
+ rc = write32bits(pPager->jfd, jrnlOff, pPager->nRec);
if( rc ) return rc;
}
PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager));
pList = sort_pagelist(pList);
while( pList ){
assert( pList->dirty );
- rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
- if( rc ) return rc;
/* If there are dirty pages in the page cache with page numbers greater
** than Pager.dbSize, this means sqlite3PagerTruncate() was called to
** make the file smaller (presumably by auto-vacuum code). Do not write
** any such pages to the file.
*/
if( pList->pgno<=pPager->dbSize ){
+ i64 offset = (pList->pgno-1)*(i64)pPager->pageSize;
char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
PAGERTRACE4("STORE %d page %d hash(%08x)\n",
PAGERID(pPager), pList->pgno, pager_pagehash(pList));
IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno));
- rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize);
+ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
PAGER_INCR(sqlite3_pager_writedb_count);
PAGER_INCR(pPager->nWrite);
if( pList->pgno==1 ){
*/
static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
int rc;
+ i64 offset;
assert( MEMDB==0 );
- rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
- pPager->pageSize);
- }
+ offset = (pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize, offset);
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
IOTRACE(("PGIN %p %d\n", pPager, pgno));
if( pPager->dbSize>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
- rc = sqlite3OsSeek(pPager->fd, 24);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers));
+ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
if( rc!=SQLITE_OK ){
return rc;
}
}
goto failed_to_open_journal;
}
+#if 0
sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync);
sqlite3OsSetFullSync(pPager->fd, pPager->full_fsync);
sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory);
+#endif
pPager->journalOpen = 1;
pPager->journalStarted = 0;
pPager->needSync = 0;
put32bits(pEnd, cksum);
szPg = pPager->pageSize+8;
put32bits(pData2, pPg->pgno);
- rc = sqlite3OsWrite(pPager->jfd, pData2, szPg);
+ rc = sqlite3OsWrite(pPager->jfd, pData2, szPg, pPager->journalOff);
IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
pPager->journalOff, szPg));
PAGER_INCR(sqlite3_pager_writej_count);
PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
page_add_to_stmt_list(pPg);
}else{
+ i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7)-4;
put32bits(pData2, pPg->pgno);
- rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4);
+ rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4, offset);
PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc!=SQLITE_OK ){
return rc;
PgHdr *pPg, *pNext;
PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
if( !MEMDB ){
- sqlite3OsSeek(pPager->stfd, 0);
/* sqlite3OsTruncate(pPager->stfd, 0); */
sqliteFree( pPager->aInStmt );
pPager->aInStmt = 0;
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
-** @(#) $Id: sqlite.h.in,v 1.223 2007/08/15 13:04:54 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.224 2007/08/15 17:08:46 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
int iVersion;
int (*xClose)(sqlite3_file*);
int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite_int64 iOfst);
- int (*xWrite)(sqlite3_file*, void*, int iAmt, sqlite_int64 iOfst);
+ int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite_int64 iOfst);
int (*xTruncate)(sqlite3_file*, sqlite_int64 size);
int (*xSync)(sqlite3_file*, int flags);
int (*xFileSize)(sqlite3_file*, sqlite_int64 *pSize);
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test2.c,v 1.43 2007/04/02 05:07:47 danielk1977 Exp $
+** $Id: test2.c,v 1.44 2007/08/15 17:08:46 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
}
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);
+ rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
sqlite3OsClose(&fd);
if( rc ){
Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
#ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */
-typedef struct crashFile crashFile;
+typedef struct CrashFile CrashFile;
+typedef struct CrashGlobal CrashGlobal;
typedef struct WriteBuffer WriteBuffer;
/*
** operation is one byte past the current end of the file, then option
** (1) is always selected.
*/
-struct WriteBuffer {
- i64 iOffset; /* Byte offset of the start of this write() */
- int nBuf; /* Number of bytes written */
- u8 *zBuf; /* Pointer to copy of written data */
- crashFile *pFile; /* File this write() applies to */
-};
/*
-** crashFile is a subclass of OsFile that is taylored for
-** the crash test module.
+** Each write operation in the write-list is represented by an instance
+** of the following structure.
+**
+** If zBuf is 0, then this structure represents a call to xTruncate(),
+** not xWrite(). In that case, iOffset is the size that the file is
+** truncated to.
*/
-struct crashFile {
- IoMethod const *pMethod; /* Must be first */
- u8 **apBlk; /* Array of blocks that have been written to. */
- int nBlk; /* Size of apBlock. */
- i64 offset; /* Next character to be read from the file */
- int nMaxWrite; /* Largest offset written to. */
- char *zName; /* File name */
- OsFile *pBase; /* The real file */
- crashFile *pNext; /* Next in a list of them all */
-};
+struct WriteBuffer {
+ i64 iOffset; /* Byte offset of the start of this write() */
+ int nBuf; /* Number of bytes written */
+ u8 *zBuf; /* Pointer to copy of written data */
+ CrashFile *pFile; /* File this write() applies to */
-/*
-** Size of a simulated disk block. Default is 512 bytes.
-*/
-static int BLOCKSIZE = 512;
-#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)
+ WriteBuffer *pNext; /* Next in CrashGlobal.pWriteList */
+};
+struct CrashFile {
+ const sqlite3_io_methods *pMethod; /* Must be first */
+ sqlite3_file *pRealFile; /* Underlying "real" file handle */
+ const char *zName;
+};
-/*
-** 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;
-static char zCrashFile[500];
+struct CrashGlobal {
+ WriteBuffer *pWriteList; /* Head of write-list */
-/*
-** A list of all open files.
-*/
-static crashFile *pAllFiles = 0;
+ int iSectorSize; /* Value of simulated sector size */
+ int iDeviceCharacteristics; /* Value of simulated device characteristics */
-/*
-** Set the value of the two crash parameters.
-*/
-static void setCrashParams(int iDelay, char const *zFile){
- sqlite3OsEnterMutex();
- assert( strlen(zFile)<sizeof(zCrashFile) );
- strcpy(zCrashFile, zFile);
- iCrashDelay = iDelay;
- sqlite3OsLeaveMutex();
-}
+ int iCrash; /* Crash on the iCrash'th call to xSync() */
+ char zCrashFile[500]; /* Crash during an xSync() on this file */
+};
-/*
-** Set the value of the simulated disk block size.
-*/
-static void setBlocksize(int iBlockSize){
- sqlite3OsEnterMutex();
- assert( !pAllFiles );
- BLOCKSIZE = iBlockSize;
- sqlite3OsLeaveMutex();
-}
+static CrashGlobal g = {0, SQLITE_DEFAULT_SECTOR_SIZE, 0, 0};
/*
-** File zPath is being sync()ed. Return non-zero if this should
-** cause a crash.
+** Set this global variable to 1 to enable crash testing.
*/
-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;
-}
-
-/* Forward reference */
-static void initFile(OsFile **pId, char const *zName, OsFile *pBase);
+int sqlite3CrashTestEnable = 0;
/*
-** Undo the work done by initFile. Delete the OsFile structure
-** and unlink the structure from the pAllFiles list.
+** Flush the write-list as if xSync() had been called on file handle
+** pFile. If isCrash is true, simulate a crash.
*/
-static void closeFile(crashFile **pId){
- crashFile *pFile = *pId;
- if( pFile==pAllFiles ){
- pAllFiles = pFile->pNext;
- }else{
- crashFile *p;
- for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){
- assert( p );
+static int writeListSync(CrashFile *pFile, int isCrash){
+ int rc = SQLITE_OK;
+ int iDc = g.iDeviceCharacteristics;
+
+ WriteBuffer *pWrite;
+ WriteBuffer **ppPtr;
+
+ /* Set pFinal to point to the last element of the write-list that
+ ** is associated with file handle pFile.
+ */
+ WriteBuffer *pFinal = 0;
+ if( !isCrash ){
+ for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
+ if( pWrite->pFile==pFile ){
+ pFinal = pWrite;
+ }
}
- p->pNext = pFile->pNext;
- }
- sqliteFree(*pId);
- *pId = 0;
-}
-
-/*
-** Read block 'blk' off of the real disk file and into the cache of pFile.
-*/
-static int readBlockIntoCache(crashFile *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;
+ ppPtr = &g.pWriteList;
+ for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
+
+ /* (eAction==1) -> write block out normally,
+ ** (eAction==2) -> do nothing,
+ ** (eAction==3) -> trash sectors.
+ */
+ int eAction = 0;
+ if( !isCrash ){
+ eAction = 2;
+ if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){
+ eAction = 1;
+ }
+ }else{
+ char random;
+ sqlite3Randomness(1, &random);
- rc = sqlite3OsFileSize(pFile->pBase, &filesize);
- if( rc!=SQLITE_OK ) return rc;
+ if( iDc&SQLITE_IOCAP_ATOMIC || pWrite->zBuf==0 ){
+ random &= 0x01;
+ }
- if( BLOCK_OFFSET(blk)<filesize ){
- int len = BLOCKSIZE;
- rc = sqlite3OsSeek(pFile->pBase, blk*BLOCKSIZE);
- if( BLOCK_OFFSET(blk+1)>filesize ){
- len = filesize - BLOCK_OFFSET(blk);
+ if( (random&0x06)==0x06 ){
+ eAction = 3;
+ }else{
+ eAction = ((random&0x01)?2:1);
}
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(pFile->pBase, p, len);
- if( rc!=SQLITE_OK ) return rc;
}
- }
- return SQLITE_OK;
-}
-
-/*
-** 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(crashFile *pFile, int crash){
- int i;
- int nMax = pFile->nMaxWrite;
- int rc = SQLITE_OK;
-
- 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_WRITECACHE
-printf("Trashing block %d of %s\n", i, pFile->zName);
-#endif
- }else{
- skip = 1;
-#ifdef TRACE_WRITECACHE
-printf("Skiping block %d of %s\n", i, pFile->zName);
-#endif
- }
+ switch( eAction ){
+ case 1: { /* Write out correctly */
+ if( pWrite->zBuf ){
+ rc = sqlite3OsWrite(
+ pFile->pRealFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset
+ );
}else{
-#ifdef TRACE_WRITECACHE
-printf("Writing block %d of %s\n", i, pFile->zName);
-#endif
+ rc = sqlite3OsTruncate(pFile->pRealFile, pWrite->iOffset);
}
+ *ppPtr = pWrite->pNext;
+ sqliteFree(pWrite);
+ break;
}
- if( rc==SQLITE_OK ){
- rc = sqlite3OsSeek(pFile->pBase, BLOCK_OFFSET(i));
+ case 2: { /* Do nothing */
+ ppPtr = &pWrite->pNext;
+ break;
}
- 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);
+ case 3: { /* Trash sectors */
+ u8 *zGarbage;
+ sqlite3_int64 iFirst = (pWrite->iOffset%g.iSectorSize);
+ sqlite3_int64 iLast = (pWrite->iOffset+pWrite->nBuf-1)%g.iSectorSize;
+
+ zGarbage = sqliteMalloc(g.iSectorSize);
+ if( zGarbage ){
+ sqlite3_int64 i;
+ for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
+ sqlite3Randomness(g.iSectorSize, zGarbage);
+ rc = sqlite3OsWrite(
+ pFile->pRealFile, i*g.iSectorSize, zGarbage, g.iSectorSize
+ );
}
- rc = sqlite3OsWrite(pFile->pBase, p, len);
+ sqliteFree(zGarbage);
+ }else{
+ rc = SQLITE_NOMEM;
}
+
+ ppPtr = &pWrite->pNext;
+ break;
}
- sqliteFree(p);
+
+ default:
+ assert(!"Cannot happen");
}
+
+ if( pWrite==pFinal ) break;
+ }
+
+ if( rc==SQLITE_OK && isCrash ){
+ exit(-1);
}
- sqliteFree(pFile->apBlk);
- pFile->nBlk = 0;
- pFile->apBlk = 0;
- pFile->nMaxWrite = 0;
+
return rc;
}
/*
-** Write the cache to disk.
+** Add an entry to the end of the write-list.
*/
-static int writeCache(crashFile *pFile){
- if( pFile->apBlk ){
- int c = crashRequired(pFile->zName);
- if( c ){
- crashFile *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);
- }
+static int writeListAppend(
+ sqlite3_file *pFile,
+ sqlite3_int64 iOffset,
+ const u8 *zBuf,
+ int nBuf
+){
+ WriteBuffer *pNew;
+
+ assert((zBuf && nBuf) || (!nBuf && !zBuf));
+
+ pNew = (WriteBuffer *)sqliteMalloc(sizeof(WriteBuffer) + nBuf);
+ pNew->iOffset = iOffset;
+ pNew->nBuf = nBuf;
+ pNew->pFile = (CrashFile *)pFile;
+ if( zBuf ){
+ pNew->zBuf = (u8 *)&pNew[1];
+ memcpy(pNew->zBuf, zBuf, nBuf);
}
- return SQLITE_OK;
-}
-/*
-** Close the file.
-*/
-static int crashClose(OsFile **pId){
- crashFile *pFile = (crashFile*)*pId;
- if( pFile ){
- /* printf("CLOSE %s (%d blocks)\n", pFile->zName, pFile->nBlk); */
- writeCache(pFile);
- sqlite3OsClose(&pFile->pBase);
+ if( g.pWriteList ){
+ WriteBuffer *pEnd;
+ for(pEnd=g.pWriteList; pEnd->pNext; pEnd=pEnd->pNext);
+ pEnd->pNext = pNew;
+ }else{
+ g.pWriteList = pNew;
}
- closeFile(&pFile);
- *pId = 0;
+
return SQLITE_OK;
}
-static int crashSeek(OsFile *id, i64 offset){
- ((crashFile*)id)->offset = offset;
+/*
+** Close a crash-file.
+*/
+int cfClose(sqlite3_file *pFile){
+ CrashFile *pCrash = (CrashFile *)pFile;
+ writeListSync(pCrash, 0);
+ sqlite3OsClose(&pCrash->pRealFile);
return SQLITE_OK;
}
-static int crashRead(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;
- crashFile *pFile = (crashFile*)id;
-
- offset = pFile->offset;
- end = offset+amt;
- blk = (offset/BLOCKSIZE);
+/*
+** Read data from a crash-file.
+*/
+int cfRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst){
+ CrashFile *pCrash = (CrashFile *)pFile;
+ sqlite3_int64 iSize;
+ int rc;
+ WriteBuffer *pWrite;
- zCsr = (u8 *)pBuf;
- for(i=blk; i*BLOCKSIZE<end; i++){
- int off = 0;
- int len = 0;
+ /* Check the file-size to see if this is a short-read */
+ rc = sqlite3OsFileSize(pFile, &iSize);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ if( iSize<(iOfst+iAmt) ){
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ /* Zero the output buffer */
+ memset(zBuf, 0, iAmt);
- 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);
+ /* Read some data from the real file */
+ rc = sqlite3OsFileSize(pCrash->pRealFile, &iSize);
+ if( rc==SQLITE_OK && iSize>iOfst ){
+ int nRead = iAmt;
+ if( iSize<(iOfst+iAmt) ){
+ nRead = iSize - iOfst;
}
-
- if( i<pFile->nBlk && pFile->apBlk[i]){
- u8 *pBlk = pFile->apBlk[i];
- memcpy(zCsr, &pBlk[off], len);
- }else{
- rc = sqlite3OsSeek(pFile->pBase, BLOCK_OFFSET(i) + off);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(pFile->pBase, zCsr, len);
- if( rc!=SQLITE_OK ) return rc;
- }
-
- zCsr += len;
+ rc = sqlite3OsRead(pCrash->pRealFile, zBuf, nRead, iOfst);
}
- assert( zCsr==&((u8 *)pBuf)[amt] );
-
- pFile->offset = end;
- return rc;
-}
-
-static int crashWrite(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;
- crashFile *pFile = (crashFile*)id;
-
- offset = pFile->offset;
- 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 = readBlockIntoCache(pFile, i);
- if( rc!=SQLITE_OK ) return rc;
- /* Write into the cache */
- pBlk = pFile->apBlk[i];
- assert( pBlk );
+ /* Fill in the buffer by traversing the write-list */
+ for(pWrite=g.pWriteList; rc==SQLITE_OK && pWrite; pWrite=pWrite->pNext){
+ if( pWrite->pFile==pCrash ){
+ int iWriteOffset;
+ int nWriteBuf;
+ u8 *zWriteBuf;
+
+ iWriteOffset = pWrite->iOffset - iOfst;
+ nWriteBuf = pWrite->nBuf;
+ zWriteBuf = pWrite->zBuf;
+ if( iWriteOffset<0 ){
+ nWriteBuf += iWriteOffset;
+ zWriteBuf -= iWriteOffset;
+ iWriteOffset = 0;
+ }
+ if( (iWriteOffset+nWriteBuf)>iAmt ){
+ nWriteBuf = iAmt - iWriteOffset;
+ }
+
+ if( pWrite->zBuf && nWriteBuf>0){
+ /* Copy data to the buffer */
+ memcpy(&((u8 *)zBuf)[iWriteOffset], zWriteBuf, nWriteBuf);
+ }
- 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( pWrite->zBuf==0 && iWriteOffset<iAmt ){
+ /* Zero part of the buffer to simulate a truncate */
+ memset(&((u8 *)zBuf)[iWriteOffset], 0, iAmt-iWriteOffset);
+ }
}
- memcpy(&pBlk[off], zCsr, len);
- zCsr += len;
- }
- if( pFile->nMaxWrite<end ){
- pFile->nMaxWrite = end;
}
- assert( zCsr==&((u8 *)pBuf)[amt] );
- pFile->offset = end;
+
return rc;
}
/*
-** Sync the file. First flush the write-cache to disk, then call the
-** real sync() function.
+** Write data to a crash-file.
*/
-static int crashSync(OsFile *id, int dataOnly){
- return writeCache((crashFile*)id);
+int cfWrite(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst){
+ return writeListAppend(pFile, iOfst, zBuf, iAmt);
}
/*
-** 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.
+** Truncate a crash-file.
*/
-static int crashTruncate(OsFile *id, i64 nByte){
- crashFile *pFile = (crashFile*)id;
- pFile->nMaxWrite = nByte;
- return sqlite3OsTruncate(pFile->pBase, nByte);
+int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ return writeListAppend(pFile, size, 0, 0);
}
/*
-** 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.
+** Sync a crash-file.
*/
-static int crashFileSize(OsFile *id, i64 *pSize){
- crashFile *pFile = (crashFile*)id;
- int rc = sqlite3OsFileSize(pFile->pBase, pSize);
- if( rc==SQLITE_OK && pSize && *pSize<pFile->nMaxWrite ){
- *pSize = pFile->nMaxWrite;
+int cfSync(sqlite3_file *pFile, int flags){
+ CrashFile *pCrash = (CrashFile *)pFile;
+ int isCrash = 0;
+
+ if( 0==strcmp(pCrash->zName, g.zCrashFile) ){
+ if( (--g.iCrash==0) ){
+ isCrash = 1;
+ }
}
- return rc;
-}
-/*
-** Set this global variable to 1 to enable crash testing.
-*/
-int sqlite3CrashTestEnable = 0;
+ return writeListSync(pCrash, isCrash);
+}
/*
-** 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.
+** Return the current file-size of the crash-file.
*/
-int sqlite3CrashOpenReadWrite(const char *zFilename, OsFile **pId,int *pRdonly){
- OsFile *pBase = 0;
+int cfFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ CrashFile *pCrash = (CrashFile *)pFile;
+ WriteBuffer *pWrite;
int rc;
+ sqlite_int64 iSize;
- sqlite3CrashTestEnable = 0;
- rc = sqlite3OsOpenReadWrite(zFilename, &pBase, pRdonly);
- sqlite3CrashTestEnable = 1;
- if( !rc ){
- initFile(pId, zFilename, pBase);
+ rc = sqlite3OsFileSize(pCrash->pRealFile, &iSize);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
- return rc;
-}
-int sqlite3CrashOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
- OsFile *pBase = 0;
- int rc;
- sqlite3CrashTestEnable = 0;
- rc = sqlite3OsOpenExclusive(zFilename, &pBase, delFlag);
- sqlite3CrashTestEnable = 1;
- if( !rc ){
- initFile(pId, zFilename, pBase);
- }
- return rc;
-}
-int sqlite3CrashOpenReadOnly(const char *zFilename, OsFile **pId, int NotUsed){
- OsFile *pBase = 0;
- int rc;
-
- sqlite3CrashTestEnable = 0;
- rc = sqlite3OsOpenReadOnly(zFilename, &pBase);
- sqlite3CrashTestEnable = 1;
- if( !rc ){
- initFile(pId, zFilename, pBase);
+ for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
+ sqlite_int64 iEnd = pWrite->nBuf+pWrite->iOffset;
+ if( pWrite->pFile==pCrash && (pWrite->zBuf==0 || iEnd>iSize) ){
+ iSize = iEnd;
+ }
}
- return rc;
-}
+ *pSize = iSize;
-/*
-** OpenDirectory is a no-op
-*/
-static int crashOpenDir(OsFile *id, const char *zName){
return SQLITE_OK;
}
/*
-** Locking primitives are passed through into the underlying
-** file descriptor.
+** Calls related to file-locks are passed on to the real file handle.
*/
-int crashLock(OsFile *id, int lockType){
- return sqlite3OsLock(((crashFile*)id)->pBase, lockType);
+int cfLock(sqlite3_file *pFile, int eLock){
+ return sqlite3OsLock(((CrashFile *)pFile)->pRealFile, eLock);
}
-int crashUnlock(OsFile *id, int lockType){
- return sqlite3OsUnlock(((crashFile*)id)->pBase, lockType);
+int cfUnlock(sqlite3_file *pFile, int eLock){
+ return sqlite3OsUnlock(((CrashFile *)pFile)->pRealFile, eLock);
}
-int crashCheckReservedLock(OsFile *id){
- return sqlite3OsCheckReservedLock(((crashFile*)id)->pBase);
+int cfCheckReservedLock(sqlite3_file *pFile){
+ return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile);
}
-void crashSetFullSync(OsFile *id, int setting){
- return; /* This is a no-op */
-}
-int crashLockState(OsFile *id){
- return sqlite3OsLockState(((crashFile*)id)->pBase);
+int cfBreakLock(sqlite3_file *pFile){
+ return sqlite3OsBreakLock(((CrashFile *)pFile)->pRealFile);
}
/*
-** Return the underlying file handle.
+** The xSectorSize() and xDeviceCharacteristics() functions return
+** the global values configured by the [sqlite_crashparams] tcl
+* interface.
*/
-int crashFileHandle(OsFile *id){
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
- return sqlite3OsFileHandle(((crashFile*)id)->pBase);
-#endif
- return 0;
+int cfSectorSize(sqlite3_file *pFile){
+ return g.iSectorSize;
+}
+int cfDeviceCharacteristics(sqlite3_file *pFile){
+ return g.iDeviceCharacteristics;
}
+static const sqlite3_io_methods CrashFileVtab = {
+ 1, /* iVersion */
+ cfClose, /* xClose */
+ cfRead, /* xRead */
+ cfWrite, /* xWrite */
+ cfTruncate, /* xTruncate */
+ cfSync, /* xSync */
+ cfFileSize, /* xFileSize */
+ cfLock, /* xLock */
+ cfUnlock, /* xUnlock */
+ cfCheckReservedLock, /* xCheckReservedLock */
+ cfBreakLock, /* xBreakLock */
+ cfSectorSize, /* xSectorSize */
+ cfDeviceCharacteristics /* xDeviceCharacteristics */
+};
+
/*
-** Return the simulated file-system sector size.
+** Open a crash-file file handle. The vfs pVfs is used to open
+** the underlying real file.
*/
-int crashSectorSize(OsFile *id){
- return BLOCKSIZE;
+int sqlite3CrashFileOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ CrashFile *pWrapper = (CrashFile *)pFile;
+ int rc = SQLITE_NOMEM;
+ sqlite3_file *pReal;
+ pReal = (sqlite3_file *)sqliteMalloc(pVfs->szOsFile);
+ if( pReal ){
+ pWrapper->pMethod = &CrashFileVtab;
+ pWrapper->zName = zName;
+ rc = pVfs->xOpen(pVfs->pAppData, zName, pReal, flags, pOutFlags);
+ if( rc==SQLITE_OK ){
+ pWrapper->pRealFile = pFile;
+ }else{
+ sqliteFree(pReal);
+ }
+ }
+ return rc;
}
-/*
-** This vector defines all the methods that can operate on an OsFile
-** for the crash tester.
-*/
-static const IoMethod crashIoMethod = {
- crashClose,
- crashOpenDir,
- crashRead,
- crashWrite,
- crashSeek,
- crashTruncate,
- crashSync,
- crashSetFullSync,
- crashFileHandle,
- crashFileSize,
- crashLock,
- crashUnlock,
- crashLockState,
- crashCheckReservedLock,
- crashSectorSize,
-};
+int sqlite3CrashFileWrap(
+ sqlite3_file *pFile,
+ const char *zName,
+ sqlite3_file **ppWrapper
+){
+ CrashFile *pWrapper;
+ pWrapper = (CrashFile *)sqliteMalloc(sizeof(CrashFile)+strlen(zName)+1);
+ if( !pWrapper ){
+ return SQLITE_NOMEM;
+ }
+ pWrapper->pMethod = &CrashFileVtab;
+ pWrapper->pRealFile = pFile;
+ pWrapper->zName = &pWrapper[1];
+ memcpy(pWrapper->zName, zName, strlen(zName)+1);
-/*
-** Initialise the os_test.c specific fields of pFile.
-*/
-static void initFile(OsFile **pId, char const *zName, OsFile *pBase){
- crashFile *pFile = sqliteMalloc(sizeof(crashFile) + strlen(zName)+1);
- pFile->pMethod = &crashIoMethod;
- pFile->nMaxWrite = 0;
- pFile->offset = 0;
- pFile->nBlk = 0;
- pFile->apBlk = 0;
- pFile->zName = (char *)(&pFile[1]);
- strcpy(pFile->zName, zName);
- pFile->pBase = pBase;
- pFile->pNext = pAllFiles;
- pAllFiles = pFile;
- *pId = (OsFile*)pFile;
+ *ppWrapper = (sqlite3_file *)pWrapper;
+ return SQLITE_OK;
}
+int sqlite3CrashFileSize(){
+ return (int)sizeof(CrashFile);
+}
+
/*
-** tclcmd: sqlite_crashparams DELAY CRASHFILE ?BLOCKSIZE?
+** tclcmd: sqlite_crashparams ?OPTIONS? DELAY CRASHFILE
**
** This procedure implements a TCL command that enables crash testing
** in testfixture. Once enabled, crash testing cannot be disabled.
+**
+** Available options are "-characteristics" and "-sectorsize". Both require
+** an argument. For -sectorsize, this is the simulated sector size in
+** bytes. For -characteristics, the argument must be a list of io-capability
+** flags to simulate. Valid flags are "atomic", "atomic512", "atomic1K",
+** "atomic2K", "atomic4K", "atomic8K", "atomic16K", "atomic32K",
+** "atomic64K", "sequential" and "safe_append".
+**
+** Example:
+**
+** sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
+**
*/
static int crashParamsObjCmd(
void * clientData,
int objc,
Tcl_Obj *CONST objv[]
){
+ int i;
+
int iDelay;
- const char *zFile;
- int nFile;
+ const char *zCrashFile;
+ int nCrashFile;
+
+ int iDc = 0;
+ int iSectorSize = 0;
+ int setSectorsize = 0;
+ int setDeviceChar = 0;
+
+ struct DeviceFlag {
+ char *zName;
+ int iValue;
+ } aFlag[] = {
+ { "atomic", SQLITE_IOCAP_ATOMIC },
+ { "atomic512", SQLITE_IOCAP_ATOMIC512 },
+ { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
+ { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
+ { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
+ { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
+ { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
+ { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
+ { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
+ { "sequential", SQLITE_IOCAP_SEQUENTIAL },
+ { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
+ { 0, 0 }
+ };
+
+ if( objc<3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
+ return TCL_ERROR;
+ }
- if( objc!=3 && objc!=4 ){
- Tcl_WrongNumArgs(interp, 1, objv, "DELAY CRASHFILE ?BLOCKSIZE?");
+ zCrashFile = sqlite3OsFullPathname(Tcl_GetString(objv[objc-1]));
+ nCrashFile = strlen(zCrashFile);
+ if( nCrashFile>=sizeof(g.zCrashFile) ){
+ Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
return TCL_ERROR;
}
- if( Tcl_GetIntFromObj(interp, objv[1], &iDelay) ) return TCL_ERROR;
- zFile = Tcl_GetStringFromObj(objv[2], &nFile);
- if( nFile>=sizeof(zCrashFile)-1 ){
- Tcl_AppendResult(interp, "crash file name too big", 0);
+ if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
return TCL_ERROR;
}
- setCrashParams(iDelay, zFile);
- if( objc==4 ){
- int iBlockSize = 0;
- if( Tcl_GetIntFromObj(interp, objv[3], &iBlockSize) ) return TCL_ERROR;
- if( pAllFiles ){
- char *zErr = "Cannot modify blocksize after opening files";
- Tcl_SetResult(interp, zErr, TCL_STATIC);
+
+ for(i=1; i<(objc-2); i+=2){
+ int nOpt;
+ char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);
+
+ if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt))
+ && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
+ ){
+ Tcl_AppendResult(interp,
+ "Bad option: \"", zOpt,
+ "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
+ );
+ return TCL_ERROR;
+ }
+ if( i==objc-3 ){
+ Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
return TCL_ERROR;
}
- setBlocksize(iBlockSize);
+
+ if( zOpt[1]=='s' ){
+ if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
+ return TCL_ERROR;
+ }
+ setSectorsize = 1;
+ }else{
+ int j;
+ Tcl_Obj **apObj;
+ int nObj;
+ if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
+ return TCL_ERROR;
+ }
+ for(j=0; j<nObj; j++){
+ int rc;
+ int iChoice;
+ Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
+ Tcl_IncrRefCount(pFlag);
+ Tcl_UtfToLower(Tcl_GetString(pFlag));
+
+ rc = Tcl_GetIndexFromObjStruct(
+ interp, pFlag, aFlag, sizeof(aFlag[0]), "no such flag", 0, &iChoice
+ );
+ Tcl_DecrRefCount(pFlag);
+ if( rc ){
+ return TCL_ERROR;
+ }
+
+ iDc |= aFlag[iChoice].iValue;
+ }
+ setDeviceChar = 1;
+ }
+ }
+
+ if( setDeviceChar ){
+ g.iDeviceCharacteristics = iDc;
}
+ if( setSectorsize ){
+ g.iSectorSize = iSectorSize;
+ }
+ g.iCrash = iDelay;
+ memcpy(g.zCrashFile, zCrashFile, nCrashFile+1);
+
sqlite3CrashTestEnable = 1;
return TCL_OK;
}
int needSync = 0;
char *zMaster = 0; /* File-name for the master journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
- OsFile *master = 0;
+ sqlite3_file *master = 0;
+ i64 offset = 0;
/* Select a master journal file name */
do {
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
needSync = 1;
}
- rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1);
+ rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1, offset);
+ offset += strlen(zFile)+1;
if( rc!=SQLITE_OK ){
sqlite3OsClose(&master);
sqlite3OsDelete(zMaster);
** the master journal file is store in so that it gets synced too.
*/
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
+#if 0
rc = sqlite3OsOpenDirectory(master, zMainFile);
if( rc!=SQLITE_OK ||
(needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){
sqliteFree(zMaster);
return rc;
}
+#endif
/* Sync all the db files involved in the transaction. The same call
** sets the master journal pointer in each individual journal. If