Compare commits

...

9 Commits

Author SHA1 Message Date
drh a2dab93215 Automatically retry system calls that fail with EINTR. This is a backport
of the changes from [b9d29ea385bafc] and [af9ba2a6d2c379].

FossilOrigin-Name: 8609a15dfad23a7c5311b52617d5c4818c0b8d1e
2011-02-23 14:33:31 +00:00
drh c2e57196cb Backport the os_unix.c error logging enhancements from
check-in [01076528a43b61a].

FossilOrigin-Name: a4333b1545c6f96caef5b6dfaf94c8446e1b5d44
2011-02-23 14:05:08 +00:00
drh 320cebe7d1 Pull in the fix to STAT2 processing from check-in
[70a3d81742f].

FossilOrigin-Name: 692aafb17e7fca4e303ca14da2925cb95a22f71e
2011-02-20 21:03:04 +00:00
drh f4ae60eb7a Do not report the database corruption if the the db size header field is
greater than the file size on disk unless the two change-counter header
fields are identical.  Fix for ticket [89b8c9ac54].  Backport by cherrypick
of [00c4596f0b270].

FossilOrigin-Name: e2616004dfaf61d776e448693971b6478552a635
2011-02-20 03:40:59 +00:00
drh bb250298e6 Make sure the change-counter and SQLite-version fields of the header are
set correctly even after vacuuming.  This is a backport of changes
[0be92a7576] and [04fa1e1690] to address ticket [5de63f876cc].

FossilOrigin-Name: 442be1358e7dff17548718c0c7c031ec320d135d
2011-02-20 03:32:54 +00:00
drh 7972768979 Do not raise an SQLITE_CORRUPT error in Recoverymode if the database size
in the header is larger than the physical file size.  This is a cherrypick
of checkin [114640d920e16c8]

FossilOrigin-Name: 7701b07759d63537408a68bac85cb1b8b27160b7
2011-02-20 03:27:52 +00:00
drh dd541f2a13 Backport the sqlite3.h generator fix so that it works with newer versions
of Fossil.  See [3513bf6ee090d9b] for the original.

FossilOrigin-Name: 29597a71d0848cd5faeb68b606a9127910c8dc57
2011-02-20 03:22:51 +00:00
drh 5abbf16602 Backport the changes of checkin [cf86affcb7d308949]
("Make wal_checkpoint a no-op if a prior checkpoint has already copied
all WAL content into the database.") to the 3.7.4 release.

FossilOrigin-Name: e6e540ab7779f5363bf0c93a9e1482b0f31782ce
2011-02-20 03:20:03 +00:00
drh 237768dad3 Backport the SQLITE_PROTOCOL fix and the extra defensive measure to version
3.7.4.

FossilOrigin-Name: bcc22c4b800e1f5b5619193890548d2a6bc19280
2011-02-20 03:11:27 +00:00
11 changed files with 391 additions and 101 deletions
+17 -16
View File
@@ -1,8 +1,8 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Version\s3.7.4\srelease\scandidate\s4
D 2010-12-07T20:14:09
C Automatically\sretry\ssystem\scalls\sthat\sfail\swith\sEINTR.\s\sThis\sis\sa\sbackport\nof\sthe\schanges\sfrom\s[b9d29ea385bafc]\sand\s[af9ba2a6d2c379].
D 2011-02-23T14:33:31.368
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 4547616ad2286053af6ccccefa242dc925e49bf0
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -122,7 +122,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c d5b0137bc20327af08c14772227cc35134839c30
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
F src/btree.c b70bf1dc563ec532851715ce51aa1ea0c0c592b9
F src/btree.c 9fd4438357ede1e67229cce75336f364e1ca58c9
F src/btree.h 10f9296bf4edf034f5adce921b7b4383a56a1c90
F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0
F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d
@@ -163,9 +163,9 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
F src/os_unix.c 0240c5b547b4cf585c8cac351a95c3e85ce00772
F src/os_unix.c ef71b9892af48871a448c7f4ca662ecd287e70dd
F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad
F src/pager.c c0aca5c733c15a16fe158c3215d857841a4e5381
F src/pager.c 5b2210b4307c626a3b3ed7312161ec533958c094
F src/pager.h 0ea59db2a33bc6c2c02cae34de33367e1effdf76
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
@@ -240,10 +240,10 @@ F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c
F src/vdbemem.c 411649a35686f54268ccabeda175322c4697f5a6
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
F src/wal.c f26b8d297bd11cb792e609917f9d4c6718ac8e0e
F src/wal.c 5b0f0a2a12208544721b5b46cc18f97efb203ea3
F src/wal.h c1aac6593a0b02b15dc625987e619edeab39292e
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c fa22d45b2577c77146f2e894d58011d472d64103
F src/where.c af069e6b53234118014dabfece96a9515b69d76b
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125
@@ -376,12 +376,12 @@ F test/enc4.test 4b575ef09e0eff896e73bd24076f96c2aa6a42de
F test/eqp.test 69670e7919030f21de29fb99bf1d68f97aedcbdb
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062
F test/exclusive2.test 76e63c05349cb70d09d60b99d2ae625525ff5155
F test/exclusive2.test c2f2b2242dc436a12df8dd531e06843053bd3b9a
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/expr.test 620a636cf7b7d4e5834a0b9d83a4da372e24a7b7
F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
F test/filefmt.test f77c92141960b7933bc6691631d2ad62257ef40a
F test/filefmt.test f178cfc29501a14565954c961b226e61877dd32c
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
F test/fkey2.test e028cd80aa0bd38541c99214e3ba2dfccadffe6f
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
@@ -578,6 +578,7 @@ F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
F test/null.test a8b09b8ed87852742343b33441a9240022108993
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
F test/oserror.test 5775264a41039856d211168713d916949227fedd
F test/pager1.test e066fb2e2dc1ac1cd9ef2b44a28ae3cc79a9150f
F test/pager2.test 0fbb6b6dc40ce1fecfe758c555a748ad2e9beaa3
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
@@ -875,7 +876,7 @@ F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c.tcl e0db70c2c52b0e3d0867ca931229e5b90ffe7837
F tool/mksqlite3h.tcl 03b6ca938c833814923674d8a160e91fcedb4571
F tool/mksqlite3h.tcl d76c226a5e8e1f3b5f6593bcabe5e98b3b1ec9ff
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
@@ -897,14 +898,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P fe441df9ba447d97571e919099846efa3ec87427
R 6bbeb99b0a61f7ea1af21c5b74072ff6
P a4333b1545c6f96caef5b6dfaf94c8446e1b5d44
R 110fc06a15d59c992fa93576aaf0f07d
U drh
Z 584aed3667b20c0c4d105810047e9fd4
Z 728d442c3a16d050cc4bf0099d5aa1fd
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFM/pWUoxKgR168RlERAuOQAJ9BLHxhysfzWC+psYkAVcf2xDsyTgCeIRqp
FF5a9ESJ6yucR80Re9sEWmU=
=ZPd3
iD8DBQFNZRq+oxKgR168RlERAjAUAJ4icN9NAHBEFsKwW+tePI8D7yuS5QCeJfkr
4CvelEbFUjjp0LZiOQzb+aA=
=6ZlI
-----END PGP SIGNATURE-----
+1 -1
View File
@@ -1 +1 @@
a586a4deeb25330037a49df295b36aaf624d0f45
8609a15dfad23a7c5311b52617d5c4818c0b8d1e
+1 -1
View File
@@ -2386,7 +2386,7 @@ static int lockBtree(BtShared *pBt){
pageSize-usableSize);
return rc;
}
if( nPageHeader>nPageFile ){
if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){
rc = SQLITE_CORRUPT_BKPT;
goto page1_init_failed;
}
+139 -37
View File
@@ -394,6 +394,19 @@ static int lockTrace(int fd, int op, struct flock *p){
#endif /* SQLITE_LOCK_TRACE */
/*
** Retry ftruncate() calls that fail due to EINTR
*/
#ifdef EINTR
static int robust_ftruncate(int h, sqlite3_int64 sz){
int rc;
do{ rc = ftruncate(h,sz); }while( rc<0 && errno==EINTR );
return rc;
}
#else
# define robust_ftruncate(a,b) ftruncate(a,b)
#endif
/*
** This routine translates a standard POSIX errno code into something
@@ -736,6 +749,75 @@ struct unixInodeInfo {
*/
static unixInodeInfo *inodeList = 0;
/*
**
** This function - unixLogError_x(), is only ever called via the macro
** unixLogError().
**
** It is invoked after an error occurs in an OS function and errno has been
** set. It logs a message using sqlite3_log() containing the current value of
** errno and, if possible, the human-readable equivalent from strerror() or
** strerror_r().
**
** The first argument passed to the macro should be the error code that
** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
** The two subsequent arguments should be the name of the OS function that
** failed (e.g. "unlink", "open") and the the associated file-system path,
** if any.
*/
#define unixLogError(a,b,c) unixLogError_x(a,b,c,__LINE__)
static int unixLogError_x(
int errcode, /* SQLite error code */
const char *zFunc, /* Name of OS function that failed */
const char *zPath, /* File path associated with error */
int iLine /* Source line number where error occurred */
){
char *zErr; /* Message from strerror() or equivalent */
/* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
** the strerror() function to obtain the human-readable error message
** equivalent to errno. Otherwise, use strerror_r().
*/
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
char aErr[80];
memset(aErr, 0, sizeof(aErr));
zErr = aErr;
/* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
** assume that the system provides the the GNU version of strerror_r() that
** returns a pointer to a buffer containing the error message. That pointer
** may point to aErr[], or it may point to some static storage somewhere.
** Otherwise, assume that the system provides the POSIX version of
** strerror_r(), which always writes an error message into aErr[].
**
** If the code incorrectly assumes that it is the POSIX version that is
** available, the error message will often be an empty string. Not a
** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
*/
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
zErr =
# endif
strerror_r(errno, aErr, sizeof(aErr)-1);
#elif SQLITE_THREADSAFE
/* This is a threadsafe build, but strerror_r() is not available. */
zErr = "";
#else
/* Non-threadsafe build, use strerror(). */
zErr = strerror(errno);
#endif
assert( errcode!=SQLITE_OK );
sqlite3_log(errcode,
"os_unix.c: %s() at line %d - \"%s\" errno=%d path=%s",
zFunc, iLine, zErr, errno, (zPath ? zPath : "n/a")
);
return errcode;
}
/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
** If all such file descriptors are closed without error, the list is
@@ -755,7 +837,7 @@ static int closePendingFds(unixFile *pFile){
pNext = p->pNext;
if( close(p->fd) ){
pFile->lastErrno = errno;
rc = SQLITE_IOERR_CLOSE;
rc = unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath);
p->pNext = pError;
pError = p;
}else{
@@ -843,7 +925,7 @@ static int findInodeInfo(
** the first page of the database, no damage is done.
*/
if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
rc = write(fd, "S", 1);
do{ rc = write(fd, "S", 1); }while( rc<0 && errno==EINTR );
if( rc!=1 ){
pFile->lastErrno = errno;
return SQLITE_IOERR;
@@ -1408,7 +1490,7 @@ static int closeUnixFile(sqlite3_file *id){
int err = close(pFile->dirfd);
if( err ){
pFile->lastErrno = errno;
return SQLITE_IOERR_DIR_CLOSE;
return unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath);
}else{
pFile->dirfd=-1;
}
@@ -1417,7 +1499,7 @@ static int closeUnixFile(sqlite3_file *id){
int err = close(pFile->h);
if( err ){
pFile->lastErrno = errno;
return SQLITE_IOERR_CLOSE;
return unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath);
}
}
#if OS_VXWORKS
@@ -1719,6 +1801,20 @@ static int dotlockClose(sqlite3_file *id) {
*/
#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
/*
** Retry flock() calls that fail with EINTR
*/
#ifdef EINTR
static int robust_flock(int fd, int op){
int rc;
do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR );
return rc;
}
#else
# define robust_flock(a,b) flock(a,b)
#endif
/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, set *pResOut
@@ -1742,10 +1838,10 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
/* Otherwise see if some other process holds it. */
if( !reserved ){
/* attempt to get the lock */
int lrc = flock(pFile->h, LOCK_EX | LOCK_NB);
int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
if( !lrc ){
/* got the lock, unlock it */
lrc = flock(pFile->h, LOCK_UN);
lrc = robust_flock(pFile->h, LOCK_UN);
if ( lrc ) {
int tErrno = errno;
/* unlock failed with an error */
@@ -1822,7 +1918,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
/* grab an exclusive lock */
if (flock(pFile->h, LOCK_EX | LOCK_NB)) {
if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
int tErrno = errno;
/* didn't get, must be busy */
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
@@ -1871,7 +1967,7 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
}
/* no, really, unlock. */
int rc = flock(pFile->h, LOCK_UN);
int rc = robust_flock(pFile->h, LOCK_UN);
if (rc) {
int r, tErrno = errno;
r = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
@@ -2608,10 +2704,10 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
#endif
TIMER_START;
#if defined(USE_PREAD)
got = pread(id->h, pBuf, cnt, offset);
do{ got = pread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
SimulateIOError( got = -1 );
#elif defined(USE_PREAD64)
got = pread64(id->h, pBuf, cnt, offset);
do{ got = pread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
SimulateIOError( got = -1 );
#else
newOffset = lseek(id->h, offset, SEEK_SET);
@@ -2624,7 +2720,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
}
return -1;
}
got = read(id->h, pBuf, cnt);
do{ got = read(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
#endif
TIMER_END;
if( got<0 ){
@@ -2686,9 +2782,9 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
#endif
TIMER_START;
#if defined(USE_PREAD)
got = pwrite(id->h, pBuf, cnt, offset);
do{ got = pwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
#elif defined(USE_PREAD64)
got = pwrite64(id->h, pBuf, cnt, offset);
do{ got = pwrite64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
#else
newOffset = lseek(id->h, offset, SEEK_SET);
if( newOffset!=offset ){
@@ -2699,7 +2795,7 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
}
return -1;
}
got = write(id->h, pBuf, cnt);
do{ got = write(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
#endif
TIMER_END;
if( got<0 ){
@@ -2939,7 +3035,7 @@ static int unixSync(sqlite3_file *id, int flags){
SimulateIOError( rc=1 );
if( rc ){
pFile->lastErrno = errno;
return SQLITE_IOERR_FSYNC;
return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
}
if( pFile->dirfd>=0 ){
int err;
@@ -2966,7 +3062,7 @@ static int unixSync(sqlite3_file *id, int flags){
pFile->dirfd = -1;
}else{
pFile->lastErrno = errno;
rc = SQLITE_IOERR_DIR_CLOSE;
rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath);
}
}
return rc;
@@ -2990,10 +3086,10 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
rc = ftruncate(pFile->h, (off_t)nByte);
rc = robust_ftruncate(pFile->h, (off_t)nByte);
if( rc ){
pFile->lastErrno = errno;
return SQLITE_IOERR_TRUNCATE;
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}else{
#ifndef NDEBUG
/* If we are doing a normal write to a database file (as opposed to
@@ -3065,9 +3161,11 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
if( nSize>(i64)buf.st_size ){
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
if( posix_fallocate(pFile->h, buf.st_size, nSize-buf.st_size) ){
return SQLITE_IOERR_WRITE;
}
int rc;
do{
rc = posix_fallocate(pFile-.h, buf.st_size, nSize-buf.st_size;
}while( rc<0 && errno=EINTR );
if( rc ) return SQLITE_IOERR_WRITE;
#else
/* If the OS does not have posix_fallocate(), fake it. First use
** ftruncate() to set the file size, then write a single byte to
@@ -3079,9 +3177,9 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
i64 iWrite; /* Next offset to write to */
int nWrite; /* Return value from seekAndWrite() */
if( ftruncate(pFile->h, nSize) ){
if( robust_ftruncate(pFile->h, nSize) ){
pFile->lastErrno = errno;
return SQLITE_IOERR_TRUNCATE;
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
do {
@@ -3427,7 +3525,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777));
if( pShmNode->h<0 ){
rc = SQLITE_CANTOPEN_BKPT;
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
goto shm_open_err;
}
@@ -3436,8 +3534,8 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
*/
rc = SQLITE_OK;
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
if( ftruncate(pShmNode->h, 0) ){
rc = SQLITE_IOERR_SHMOPEN;
if( robust_ftruncate(pShmNode->h, 0) ){
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
}
}
if( rc==SQLITE_OK ){
@@ -3542,8 +3640,8 @@ static int unixShmMap(
** the requested memory region.
*/
if( !bExtend ) goto shmpage_out;
if( ftruncate(pShmNode->h, nByte) ){
rc = SQLITE_IOERR_SHMSIZE;
if( robust_ftruncate(pShmNode->h, nByte) ){
rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename);
goto shmpage_out;
}
}
@@ -4262,7 +4360,7 @@ static int openDirectory(const char *zFilename, int *pFd){
}
}
*pFd = fd;
return (fd>=0?SQLITE_OK:SQLITE_CANTOPEN_BKPT);
return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
}
/*
@@ -4603,7 +4701,7 @@ static int unixOpen(
fd = open(zName, openFlags, openMode);
}
if( fd<0 ){
rc = SQLITE_CANTOPEN_BKPT;
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
goto open_finished;
}
}
@@ -4735,7 +4833,7 @@ static int unixDelete(
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
if( unlink(zPath)==(-1) && errno!=ENOENT ){
return SQLITE_IOERR_DELETE;
return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
}
#ifndef SQLITE_DISABLE_DIRSYNC
if( dirSync ){
@@ -4748,10 +4846,10 @@ static int unixDelete(
if( fsync(fd) )
#endif
{
rc = SQLITE_IOERR_DIR_FSYNC;
rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
}
if( close(fd)&&!rc ){
rc = SQLITE_IOERR_DIR_CLOSE;
rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", zPath);
}
}
}
@@ -4835,7 +4933,7 @@ static int unixFullPathname(
}else{
int nCwd;
if( getcwd(zOut, nOut-1)==0 ){
return SQLITE_CANTOPEN_BKPT;
return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
}
nCwd = (int)strlen(zOut);
sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
@@ -4939,7 +5037,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
nBuf = sizeof(t) + sizeof(pid);
}else{
nBuf = read(fd, zBuf, nBuf);
do{ nBuf = read(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
close(fd);
}
}
@@ -5699,7 +5797,7 @@ static int proxyTakeConch(unixFile *pFile){
strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
}
writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
ftruncate(conchFile->h, writeSize);
robust_ftruncate(conchFile->h, writeSize);
rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
fsync(conchFile->h);
/* If we created a new conch file (not just updated the contents of a
@@ -5707,6 +5805,7 @@ static int proxyTakeConch(unixFile *pFile){
*/
if( rc==SQLITE_OK && createConch ){
struct stat buf;
int rc;
int err = fstat(pFile->h, &buf);
if( err==0 ){
mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP |
@@ -5715,7 +5814,10 @@ static int proxyTakeConch(unixFile *pFile){
#ifndef SQLITE_PROXY_DEBUG
fchmod(conchFile->h, cmode);
#else
if( fchmod(conchFile->h, cmode)!=0 ){
do{
rc = fchmod(conchFile->h, cmode);
}while( rc==(-1) && errno==EINTR );
if( rc!=0 ){
int code = errno;
fprintf(stderr, "fchmod %o FAILED with %d %s\n",
cmode, code, strerror(code));
+51 -17
View File
@@ -2915,11 +2915,37 @@ static int pagerRollbackWal(Pager *pPager){
return rc;
}
/*
** Update the value of the change-counter at offsets 24 and 92 in
** the header and the sqlite version number at offset 96.
**
** This is an unconditional update. See also the pager_incr_changecounter()
** routine which only updates the change-counter if the update is actually
** needed, as determined by the pPager->changeCountDone state variable.
*/
static void pager_write_changecounter(PgHdr *pPg){
u32 change_counter;
/* Increment the value just read and write it back to byte 24. */
change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
put32bits(((char*)pPg->pData)+24, change_counter);
/* Also store the SQLite version number in bytes 96..99 and in
** bytes 92..95 store the change counter for which the version number
** is valid. */
put32bits(((char*)pPg->pData)+92, change_counter);
put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER);
}
/*
** This function is a wrapper around sqlite3WalFrames(). As well as logging
** the contents of the list of pages headed by pList (connected by pDirty),
** this function notifies any active backup processes that the pages have
** changed.
** changed.
**
** The list of pages passed into this routine is always sorted by page number.
** Hence, if page 1 appears anywhere on the list, it will be the first page.
*/
static int pagerWalFrames(
Pager *pPager, /* Pager object */
@@ -2929,8 +2955,19 @@ static int pagerWalFrames(
int syncFlags /* Flags to pass to OsSync() (or 0) */
){
int rc; /* Return code */
#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
PgHdr *p; /* For looping over pages */
#endif
assert( pPager->pWal );
#ifdef SQLITE_DEBUG
/* Verify that the page list is in accending order */
for(p=pList; p && p->pDirty; p=p->pDirty){
assert( p->pgno < p->pDirty->pgno );
}
#endif
if( pList->pgno==1 ) pager_write_changecounter(pList);
rc = sqlite3WalFrames(pPager->pWal,
pPager->pageSize, pList, nTruncate, isCommit, syncFlags
);
@@ -2942,9 +2979,8 @@ static int pagerWalFrames(
}
#ifdef SQLITE_CHECK_PAGES
{
PgHdr *p;
for(p=pList; p; p=p->pDirty) pager_set_pagehash(p);
for(p=pList; p; p=p->pDirty){
pager_set_pagehash(p);
}
#endif
@@ -3969,6 +4005,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
char *pData; /* Data to write */
assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
if( pList->pgno==1 ) pager_write_changecounter(pList);
/* Encode the database */
CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
@@ -5489,7 +5526,13 @@ void sqlite3PagerDontWrite(PgHdr *pPg){
/*
** This routine is called to increment the value of the database file
** change-counter, stored as a 4-byte big-endian integer starting at
** byte offset 24 of the pager file.
** byte offset 24 of the pager file. The secondary change counter at
** 92 is also updated, as is the SQLite version number at offset 96.
**
** But this only happens if the pPager->changeCountDone flag is false.
** To avoid excess churning of page 1, the update only happens once.
** See also the pager_write_changecounter() routine that does an
** unconditional update of the change counters.
**
** If the isDirectMode flag is zero, then this is done by calling
** sqlite3PagerWrite() on page 1, then modifying the contents of the
@@ -5530,7 +5573,6 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
if( !pPager->changeCountDone && pPager->dbSize>0 ){
PgHdr *pPgHdr; /* Reference to page 1 */
u32 change_counter; /* Initial value of change-counter field */
assert( !pPager->tempFile && isOpen(pPager->fd) );
@@ -5543,21 +5585,13 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
** direct mode, page 1 is always held in cache and hence the PagerGet()
** above is always successful - hence the ALWAYS on rc==SQLITE_OK.
*/
if( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){
if( !DIRECT_MODE && rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPgHdr);
}
if( rc==SQLITE_OK ){
/* Increment the value just read and write it back to byte 24. */
change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
change_counter++;
put32bits(((char*)pPgHdr->pData)+24, change_counter);
/* Also store the SQLite version number in bytes 96..99 and in
** bytes 92..95 store the change counter for which the version number
** is valid. */
put32bits(((char*)pPgHdr->pData)+92, change_counter);
put32bits(((char*)pPgHdr->pData)+96, SQLITE_VERSION_NUMBER);
/* Actually do the update of the change counter */
pager_write_changecounter(pPgHdr);
/* If running in direct mode, write the contents of page 1 to the file. */
if( DIRECT_MODE ){
+44 -22
View File
@@ -1573,7 +1573,8 @@ static int walCheckpoint(
szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
testcase( szPage<=32768 );
testcase( szPage>=65536 );
if( pWal->hdr.mxFrame==0 ) return SQLITE_OK;
pInfo = walCkptInfo(pWal);
if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
/* Allocate the iterator */
rc = walIteratorInit(pWal, &pIter);
@@ -1595,7 +1596,6 @@ static int walCheckpoint(
*/
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
pInfo = walCkptInfo(pWal);
for(i=1; i<WAL_NREADER; i++){
u32 y = pInfo->aReadMark[i];
if( mxSafeFrame>=y ){
@@ -1916,10 +1916,31 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
assert( pWal->readLock<0 ); /* Not currently locked */
/* Take steps to avoid spinning forever if there is a protocol error. */
/* Take steps to avoid spinning forever if there is a protocol error.
**
** Circumstances that cause a RETRY should only last for the briefest
** instances of time. No I/O or other system calls are done while the
** locks are held, so the locks should not be held for very long. But
** if we are unlucky, another process that is holding a lock might get
** paged out or take a page-fault that is time-consuming to resolve,
** during the few nanoseconds that it is holding the lock. In that case,
** it might take longer than normal for the lock to free.
**
** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
** is more of a scheduler yield than an actual delay. But on the 10th
** an subsequent retries, the delays start becoming longer and longer,
** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
** The total delay time before giving up is less than 1 second.
*/
if( cnt>5 ){
if( cnt>100 ) return SQLITE_PROTOCOL;
sqlite3OsSleep(pWal->pVfs, 1);
int nDelay = 1; /* Pause time in microseconds */
if( cnt>100 ){
VVA_ONLY( pWal->lockError = 1; )
return SQLITE_PROTOCOL;
}
if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */
sqlite3OsSleep(pWal->pVfs, nDelay);
}
if( !useWal ){
@@ -2001,22 +2022,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
mxI = i;
}
}
if( mxI==0 ){
/* If we get here, it means that all of the aReadMark[] entries between
** 1 and WAL_NREADER-1 are zero. Try to initialize aReadMark[1] to
** be mxFrame, then retry.
*/
rc = walLockExclusive(pWal, WAL_READ_LOCK(1), 1);
if( rc==SQLITE_OK ){
pInfo->aReadMark[1] = pWal->hdr.mxFrame;
walUnlockExclusive(pWal, WAL_READ_LOCK(1), 1);
rc = WAL_RETRY;
}else if( rc==SQLITE_BUSY ){
rc = WAL_RETRY;
}
return rc;
}else{
if( mxReadMark < pWal->hdr.mxFrame ){
/* There was once an "if" here. The extra "{" is to preserve indentation. */
{
if( mxReadMark < pWal->hdr.mxFrame || mxI==0 ){
for(i=1; i<WAL_NREADER; i++){
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
@@ -2029,6 +2037,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
}
}
if( mxI==0 ){
assert( rc==SQLITE_BUSY );
return WAL_RETRY;
}
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
if( rc ){
@@ -2089,6 +2101,10 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
do{
rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
}while( rc==WAL_RETRY );
testcase( (rc&0xff)==SQLITE_BUSY );
testcase( (rc&0xff)==SQLITE_IOERR );
testcase( rc==SQLITE_PROTOCOL );
testcase( rc==SQLITE_OK );
return rc;
}
@@ -2406,6 +2422,8 @@ static int walRestartLog(Wal *pWal){
volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
assert( pInfo->nBackfill==pWal->hdr.mxFrame );
if( pInfo->nBackfill>0 ){
u32 salt1;
sqlite3_randomness(4, &salt1);
rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
if( rc==SQLITE_OK ){
/* If all readers are using WAL_READ_LOCK(0) (in other words if no
@@ -2423,7 +2441,7 @@ static int walRestartLog(Wal *pWal){
pWal->nCkpt++;
pWal->hdr.mxFrame = 0;
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
sqlite3_randomness(4, &aSalt[1]);
aSalt[1] = salt1;
walIndexWriteHdr(pWal);
pInfo->nBackfill = 0;
for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
@@ -2440,6 +2458,10 @@ static int walRestartLog(Wal *pWal){
int notUsed;
rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
}while( rc==WAL_RETRY );
assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
testcase( (rc&0xff)==SQLITE_IOERR );
testcase( rc==SQLITE_PROTOCOL );
testcase( rc==SQLITE_OK );
}
return rc;
}
+3 -4
View File
@@ -2315,10 +2315,9 @@ static int valueFromExpr(
u8 aff,
sqlite3_value **pp
){
/* The evalConstExpr() function will have already converted any TK_VARIABLE
** expression involved in an comparison into a TK_REGISTER. */
assert( pExpr->op!=TK_VARIABLE );
if( pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE ){
if( pExpr->op==TK_VARIABLE
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
){
int iVar = pExpr->iColumn;
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-23257-02778 */
*pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
+2 -2
View File
@@ -299,13 +299,13 @@ do_test exclusive2-3.5 {
INSERT INTO t1 VALUES(randstr(10, 400));
}
readPagerChangeCounter test.db
} {4}
} {5}
do_test exclusive2-3.6 {
execsql {
INSERT INTO t1 VALUES(randstr(10, 400));
}
readPagerChangeCounter test.db
} {5}
} {6}
sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
finish_test
+20
View File
@@ -193,4 +193,24 @@ db close
sqlite3 db test.db
integrity_check filefmt-2.2.7
#--------------------------------------------------------------------------
# Check that ticket 89b8c9ac54 is fixed. Before the fix, the SELECT
# statement would return SQLITE_CORRUPT. The database file was not actually
# corrupted, but SQLite was reporting that it was.
#
db close
forcedelete test.db
sqlite3 db test.db
do_execsql_test filefmt-3.1 {
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(a, b);
} {}
do_test filefmt-3.2 {
sql36231 { DROP TABLE t1 }
} {}
do_execsql_test filefmt-3.3 {
SELECT * FROM sqlite_master;
PRAGMA integrity_check;
} {ok}
finish_test
+112
View File
@@ -0,0 +1,112 @@
# 2011 February 19
#
# 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 implements regression tests for SQLite library. The
# focus of this file is testing that error messages are logged via the
# sqlite3_log() mechanism when certain errors are encountered in the
# default unix or windows VFS modules.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {$::tcl_platform(platform)!="unix"} { finish_test ; return }
set ::testprefix oserror
db close
sqlite3_shutdown
test_sqlite3_log xLog
proc xLog {error_code msg} {
if {[string match os_* $msg]} {
lappend ::log $msg
}
}
proc do_re_test {tn script expression} {
uplevel do_test $tn [list [subst -nocommands {
set res [eval { $script }]
if {[regexp {$expression} [set res]]} {
set {} {$expression}
} else {
set res
}
}]] [list $expression]
}
#--------------------------------------------------------------------------
# Tests oserror-1.* test failures in the open() system call.
#
# Test a failure in open() due to too many files.
#
do_test 1.1.1 {
set ::log [list]
list [catch {
for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 }
} msg] $msg
} {1 {unable to open database file}}
do_test 1.1.2 {
catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } }
} {1}
do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
# Test a failure in open() due to the path being a directory.
#
do_test 1.2.1 {
file mkdir dir.db
set ::log [list]
list [catch { sqlite3 dbh dir.db } msg] $msg
} {1 {unable to open database file}}
do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c: open.*dir.db$}
# Test a failure in open() due to the path not existing.
#
do_test 1.3.1 {
set ::log [list]
list [catch { sqlite3 dbh /x/y/z/test.db } msg] $msg
} {1 {unable to open database file}}
do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
# Test a failure in open() due to the path not existing.
#
do_test 1.4.1 {
set ::log [list]
list [catch { sqlite3 dbh /root/test.db } msg] $msg
} {1 {unable to open database file}}
do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
#--------------------------------------------------------------------------
# Tests oserror-1.* test failures in the unlink() system call.
#
do_test 2.1.1 {
set ::log [list]
file mkdir test.db-wal
forcedelete test.db
sqlite3 dbh test.db
catchsql { SELECT * FROM sqlite_master } dbh
} {1 {disk I/O error}}
do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c: unlink.*test.db-wal$}
do_test 2.1.3 {
dbh close
forcedelete test.db-wal
} {}
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize
finish_test
+1 -1
View File
@@ -53,7 +53,7 @@ set in [open $TOP/manifest]
set zDate {}
while {![eof $in]} {
set line [gets $in]
if {[regexp {^D (2.*[0-9])} $line all date]} {
if {[regexp {^D (2[-0-9T:]+)} $line all date]} {
set zDate [string map {T { }} $date]
break
}