Further tests for os_unix.c.
FossilOrigin-Name: a84f7711949ea3885b0e36e48118d2c76a8a5b82
This commit is contained in:
parent
f6cf1ffb39
commit
661d71af8c
23
manifest
23
manifest
@ -1,5 +1,5 @@
|
||||
C Do\snot\sgenerate\ssqlite_stat1\sentries\sfor\sempty\stables\swhen\srunning\nANALYZE.\s\sTicket\s[83ea97620bd31016451]
|
||||
D 2011-03-30T14:54:05.390
|
||||
C Further\stests\sfor\sos_unix.c.
|
||||
D 2011-03-30T19:08:03.321
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -162,7 +162,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 2596fd2d5d0976c6c0c628d0c3c7c4e7a724f4cf
|
||||
F src/os_unix.c 0b37759312e8adb58c0c7dab1ab8ca16957bf299
|
||||
F src/os_unix.c be9f9d3383a7b556a1f3805442e0061e436eb7ac
|
||||
F src/os_win.c 24d72407a90551969744cf9bcbb1b4c72c5fa845
|
||||
F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1
|
||||
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
|
||||
@ -185,7 +185,7 @@ F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c b020ebf3b4af58cae7875e217efd7ac22f485713
|
||||
F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290
|
||||
F src/test1.c 9ca440e80e16e53920904a0a5ac7feffb9b2c9a1
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
|
||||
F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
|
||||
@ -220,7 +220,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c d12e8cd163cd33b66d0a3d1b8daaf136d09d65c2
|
||||
F src/test_syscall.c 349a2b913e82b029f01527f58f65d66a02a09a84
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
|
||||
F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
|
||||
@ -672,8 +672,8 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
|
||||
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
|
||||
F test/syscall.test 125d9781d914c408e8629053b5f914dc920ab3eb
|
||||
F test/sysfault.test be42aa42f89a82305cf3807047d419595e430480
|
||||
F test/syscall.test d1dae1fee88613cf763d97ad0038d867509e0c42
|
||||
F test/sysfault.test a2c3ca66d82f3b4ac7d29f1aeaba8962f4f5a22a
|
||||
F test/table.test 04ba066432430657712d167ebf28080fe878d305
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
||||
@ -828,6 +828,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
|
||||
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
|
||||
F test/unixexcl.test 9d80a54d86d2261f660758928959368ffc36151e
|
||||
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test 29b60e8cc9e573b39676df6c4a75fe9e02d04a09
|
||||
@ -919,7 +920,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 3d2de011814002e2e25b7645f94ff8fc7aab9cdd
|
||||
R 0216cf925df143bd6cbc69301b702732
|
||||
U drh
|
||||
Z ebdb63d4898403f81a888e3e3a66ac94
|
||||
P 3a27af5b3c688c651ba1fae261026ef77b7ff5e3
|
||||
R 8aec69201b7794049bf0ef28fa4da45f
|
||||
U dan
|
||||
Z 9b217166a2b3bec7df70dcbc250ff848
|
||||
|
@ -1 +1 @@
|
||||
3a27af5b3c688c651ba1fae261026ef77b7ff5e3
|
||||
a84f7711949ea3885b0e36e48118d2c76a8a5b82
|
178
src/os_unix.c
178
src/os_unix.c
@ -593,9 +593,22 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){
|
||||
*/
|
||||
static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
|
||||
switch (posixError) {
|
||||
#if 0
|
||||
/* At one point this code was not commented out. In theory, this branch
|
||||
** should never be hit, as this function should only be called after
|
||||
** a locking-related function (i.e. fcntl()) has returned non-zero with
|
||||
** the value of errno as the first argument. Since a system call has failed,
|
||||
** errno should be non-zero.
|
||||
**
|
||||
** Despite this, if errno really is zero, we still don't want to return
|
||||
** SQLITE_OK. The system call failed, and *some* SQLite error should be
|
||||
** propagated back to the caller. Commenting this branch out means errno==0
|
||||
** will be handled by the "default:" case below.
|
||||
*/
|
||||
case 0:
|
||||
return SQLITE_OK;
|
||||
|
||||
#endif
|
||||
|
||||
case EAGAIN:
|
||||
case ETIMEDOUT:
|
||||
case EBUSY:
|
||||
@ -1037,7 +1050,7 @@ static void closePendingFds(unixFile *pFile){
|
||||
static void releaseInodeInfo(unixFile *pFile){
|
||||
unixInodeInfo *pInode = pFile->pInode;
|
||||
assert( unixMutexHeld() );
|
||||
if( pInode ){
|
||||
if( ALWAYS(pInode) ){
|
||||
pInode->nRef--;
|
||||
if( pInode->nRef==0 ){
|
||||
assert( pInode->pShmNode==0 );
|
||||
@ -1211,6 +1224,9 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
|
||||
** This function is a pass-through to fcntl(F_SETLK) if pFile is using
|
||||
** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
|
||||
** and is read-only.
|
||||
**
|
||||
** Zero is returned if the call completes successfully, or -1 if a call
|
||||
** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
|
||||
*/
|
||||
static int unixFileLock(unixFile *pFile, struct flock *pLock){
|
||||
int rc;
|
||||
@ -1307,7 +1323,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
unixInodeInfo *pInode = pFile->pInode;
|
||||
struct flock lock;
|
||||
int s = 0;
|
||||
int tErrno = 0;
|
||||
|
||||
assert( pFile );
|
||||
@ -1376,11 +1391,10 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
){
|
||||
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
|
||||
lock.l_start = PENDING_BYTE;
|
||||
s = unixFileLock(pFile, &lock);
|
||||
if( s==(-1) ){
|
||||
if( unixFileLock(pFile, &lock) ){
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
|
||||
if( IS_LOCK_ERROR(rc) ){
|
||||
if( rc!=SQLITE_BUSY ){
|
||||
pFile->lastErrno = tErrno;
|
||||
}
|
||||
goto end_lock;
|
||||
@ -1394,33 +1408,31 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
if( eFileLock==SHARED_LOCK ){
|
||||
assert( pInode->nShared==0 );
|
||||
assert( pInode->eFileLock==0 );
|
||||
assert( rc==SQLITE_OK );
|
||||
|
||||
/* Now get the read-lock */
|
||||
lock.l_start = SHARED_FIRST;
|
||||
lock.l_len = SHARED_SIZE;
|
||||
if( (s = unixFileLock(pFile, &lock))==(-1) ){
|
||||
if( unixFileLock(pFile, &lock) ){
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
|
||||
}
|
||||
|
||||
/* Drop the temporary PENDING lock */
|
||||
lock.l_start = PENDING_BYTE;
|
||||
lock.l_len = 1L;
|
||||
lock.l_type = F_UNLCK;
|
||||
if( unixFileLock(pFile, &lock)!=0 ){
|
||||
if( s != -1 ){
|
||||
/* This could happen with a network mount */
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
|
||||
if( IS_LOCK_ERROR(rc) ){
|
||||
pFile->lastErrno = tErrno;
|
||||
}
|
||||
goto end_lock;
|
||||
}
|
||||
if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
|
||||
/* This could happen with a network mount */
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
|
||||
}
|
||||
if( s==(-1) ){
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
|
||||
if( IS_LOCK_ERROR(rc) ){
|
||||
|
||||
if( rc ){
|
||||
if( rc!=SQLITE_BUSY ){
|
||||
pFile->lastErrno = tErrno;
|
||||
}
|
||||
goto end_lock;
|
||||
}else{
|
||||
pFile->eFileLock = SHARED_LOCK;
|
||||
pInode->nLock++;
|
||||
@ -1437,22 +1449,20 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
*/
|
||||
assert( 0!=pFile->eFileLock );
|
||||
lock.l_type = F_WRLCK;
|
||||
switch( eFileLock ){
|
||||
case RESERVED_LOCK:
|
||||
lock.l_start = RESERVED_BYTE;
|
||||
break;
|
||||
case EXCLUSIVE_LOCK:
|
||||
lock.l_start = SHARED_FIRST;
|
||||
lock.l_len = SHARED_SIZE;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
|
||||
assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK );
|
||||
if( eFileLock==RESERVED_LOCK ){
|
||||
lock.l_start = RESERVED_BYTE;
|
||||
lock.l_len = 1L;
|
||||
}else{
|
||||
lock.l_start = SHARED_FIRST;
|
||||
lock.l_len = SHARED_SIZE;
|
||||
}
|
||||
s = unixFileLock(pFile, &lock);
|
||||
if( s==(-1) ){
|
||||
|
||||
if( unixFileLock(pFile, &lock) ){
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
|
||||
if( IS_LOCK_ERROR(rc) ){
|
||||
if( rc!=SQLITE_BUSY ){
|
||||
pFile->lastErrno = tErrno;
|
||||
}
|
||||
}
|
||||
@ -1623,10 +1633,10 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = SHARED_FIRST;
|
||||
lock.l_len = SHARED_SIZE;
|
||||
if( unixFileLock(pFile, &lock)==(-1) ){
|
||||
if( unixFileLock(pFile, &lock) ){
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
|
||||
if( IS_LOCK_ERROR(rc) ){
|
||||
if( rc!=SQLITE_BUSY ){
|
||||
pFile->lastErrno = tErrno;
|
||||
}
|
||||
goto end_unlock;
|
||||
@ -1637,12 +1647,12 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = PENDING_BYTE;
|
||||
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
|
||||
if( unixFileLock(pFile, &lock)!=(-1) ){
|
||||
if( unixFileLock(pFile, &lock)==0 ){
|
||||
pInode->eFileLock = SHARED_LOCK;
|
||||
}else{
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
|
||||
if( IS_LOCK_ERROR(rc) ){
|
||||
if( rc!=SQLITE_BUSY ){
|
||||
pFile->lastErrno = tErrno;
|
||||
}
|
||||
goto end_unlock;
|
||||
@ -1661,12 +1671,12 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
SimulateIOErrorBenign(1);
|
||||
SimulateIOError( h=(-1) )
|
||||
SimulateIOErrorBenign(0);
|
||||
if( unixFileLock(pFile, &lock)!=(-1) ){
|
||||
if( unixFileLock(pFile, &lock)==0 ){
|
||||
pInode->eFileLock = NO_LOCK;
|
||||
}else{
|
||||
tErrno = errno;
|
||||
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
|
||||
if( IS_LOCK_ERROR(rc) ){
|
||||
if( rc!=SQLITE_BUSY ){
|
||||
pFile->lastErrno = tErrno;
|
||||
}
|
||||
pInode->eFileLock = NO_LOCK;
|
||||
@ -1714,29 +1724,27 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
|
||||
*/
|
||||
static int closeUnixFile(sqlite3_file *id){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
if( pFile ){
|
||||
if( pFile->dirfd>=0 ){
|
||||
robust_close(pFile, pFile->dirfd, __LINE__);
|
||||
pFile->dirfd=-1;
|
||||
}
|
||||
if( pFile->h>=0 ){
|
||||
robust_close(pFile, pFile->h, __LINE__);
|
||||
pFile->h = -1;
|
||||
}
|
||||
#if OS_VXWORKS
|
||||
if( pFile->pId ){
|
||||
if( pFile->isDelete ){
|
||||
unlink(pFile->pId->zCanonicalName);
|
||||
}
|
||||
vxworksReleaseFileId(pFile->pId);
|
||||
pFile->pId = 0;
|
||||
}
|
||||
#endif
|
||||
OSTRACE(("CLOSE %-3d\n", pFile->h));
|
||||
OpenCounter(-1);
|
||||
sqlite3_free(pFile->pUnused);
|
||||
memset(pFile, 0, sizeof(unixFile));
|
||||
if( pFile->dirfd>=0 ){
|
||||
robust_close(pFile, pFile->dirfd, __LINE__);
|
||||
pFile->dirfd=-1;
|
||||
}
|
||||
if( pFile->h>=0 ){
|
||||
robust_close(pFile, pFile->h, __LINE__);
|
||||
pFile->h = -1;
|
||||
}
|
||||
#if OS_VXWORKS
|
||||
if( pFile->pId ){
|
||||
if( pFile->isDelete ){
|
||||
unlink(pFile->pId->zCanonicalName);
|
||||
}
|
||||
vxworksReleaseFileId(pFile->pId);
|
||||
pFile->pId = 0;
|
||||
}
|
||||
#endif
|
||||
OSTRACE(("CLOSE %-3d\n", pFile->h));
|
||||
OpenCounter(-1);
|
||||
sqlite3_free(pFile->pUnused);
|
||||
memset(pFile, 0, sizeof(unixFile));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -1745,24 +1753,25 @@ static int closeUnixFile(sqlite3_file *id){
|
||||
*/
|
||||
static int unixClose(sqlite3_file *id){
|
||||
int rc = SQLITE_OK;
|
||||
if( id ){
|
||||
unixFile *pFile = (unixFile *)id;
|
||||
unixUnlock(id, NO_LOCK);
|
||||
unixEnterMutex();
|
||||
assert( pFile->pInode==0 || pFile->pInode->nLock>0
|
||||
|| pFile->pInode->bProcessLock==0 );
|
||||
if( pFile->pInode && pFile->pInode->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 pInode->pUnused list. It will be automatically closed
|
||||
** when the last lock is cleared.
|
||||
*/
|
||||
setPendingFd(pFile);
|
||||
}
|
||||
releaseInodeInfo(pFile);
|
||||
rc = closeUnixFile(id);
|
||||
unixLeaveMutex();
|
||||
unixFile *pFile = (unixFile *)id;
|
||||
unixUnlock(id, NO_LOCK);
|
||||
unixEnterMutex();
|
||||
|
||||
/* unixFile.pInode is always valid here. Otherwise, a different close
|
||||
** routine (e.g. nolockClose()) would be called instead.
|
||||
*/
|
||||
assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
|
||||
if( ALWAYS(pFile->pInode) && pFile->pInode->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 pInode->pUnused list. It will be automatically closed
|
||||
** when the last lock is cleared.
|
||||
*/
|
||||
setPendingFd(pFile);
|
||||
}
|
||||
releaseInodeInfo(pFile);
|
||||
rc = closeUnixFile(id);
|
||||
unixLeaveMutex();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3007,6 +3016,7 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
|
||||
do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
|
||||
#else
|
||||
newOffset = lseek(id->h, offset, SEEK_SET);
|
||||
SimulateIOError( newOffset-- );
|
||||
if( newOffset!=offset ){
|
||||
if( newOffset == -1 ){
|
||||
((unixFile*)id)->lastErrno = errno;
|
||||
@ -3375,12 +3385,16 @@ 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
|
||||
int rc;
|
||||
/* The code below is handling the return value of osFallocate()
|
||||
** correctly. posix_fallocate() is defined to "returns zero on success,
|
||||
** or an error number on failure". See the manpage for details. */
|
||||
int err;
|
||||
do{
|
||||
rc = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
|
||||
}while( rc<0 && errno==EINTR );
|
||||
if( rc ) return SQLITE_IOERR_WRITE;
|
||||
err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
|
||||
}while( err==EINTR );
|
||||
if( err ) 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
|
||||
|
39
src/test1.c
39
src/test1.c
@ -4888,6 +4888,44 @@ static int file_control_chunksize_test(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_sizehint_test DB DBNAME SIZE
|
||||
**
|
||||
** This TCL command runs the sqlite3_file_control interface and
|
||||
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
|
||||
** SQLITE_SET_LOCKPROXYFILE verbs.
|
||||
*/
|
||||
static int file_control_sizehint_test(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_int64 nSize; /* Hinted size */
|
||||
char *zDb; /* Db name ("main", "temp" etc.) */
|
||||
sqlite3 *db; /* Database handle */
|
||||
int rc; /* file_control() return code */
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
|
||||
|| Tcl_GetWideIntFromObj(interp, objv[3], &nSize)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
if( zDb[0]=='\0' ) zDb = NULL;
|
||||
|
||||
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize);
|
||||
if( rc ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_lockproxy_test DB PWD
|
||||
**
|
||||
@ -5608,6 +5646,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_lasterrno_test", file_control_lasterrno_test, 0 },
|
||||
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
|
||||
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
|
||||
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
|
||||
{ "sqlite3_vfs_list", vfs_list, 0 },
|
||||
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },
|
||||
|
||||
|
@ -121,7 +121,7 @@ struct TestSyscallArray {
|
||||
/* 4 */ { "stat", (sqlite3_syscall_ptr)ts_stat, 0, 0, 0 },
|
||||
/* 5 */ { "fstat", (sqlite3_syscall_ptr)ts_fstat, 0, 0, 0 },
|
||||
/* 6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, EIO, 0 },
|
||||
/* 7 */ { "fcntl", (sqlite3_syscall_ptr)ts_fcntl, 0, 0, 0 },
|
||||
/* 7 */ { "fcntl", (sqlite3_syscall_ptr)ts_fcntl, 0, EACCES, 0 },
|
||||
/* 8 */ { "read", (sqlite3_syscall_ptr)ts_read, 0, 0, 0 },
|
||||
/* 9 */ { "pread", (sqlite3_syscall_ptr)ts_pread, 0, 0, 0 },
|
||||
/* 10 */ { "pread64", (sqlite3_syscall_ptr)ts_pread64, 0, 0, 0 },
|
||||
@ -275,7 +275,7 @@ static int ts_ftruncate(int fd, off_t n){
|
||||
static int ts_fcntl(int fd, int cmd, ... ){
|
||||
va_list ap;
|
||||
void *pArg;
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("fcntl") ){
|
||||
return -1;
|
||||
}
|
||||
va_start(ap, cmd);
|
||||
@ -287,7 +287,7 @@ static int ts_fcntl(int fd, int cmd, ... ){
|
||||
** A wrapper around read().
|
||||
*/
|
||||
static int ts_read(int fd, void *aBuf, size_t nBuf){
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("read") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_read(fd, aBuf, nBuf);
|
||||
@ -297,7 +297,7 @@ static int ts_read(int fd, void *aBuf, size_t nBuf){
|
||||
** A wrapper around pread().
|
||||
*/
|
||||
static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("pread") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pread(fd, aBuf, nBuf, off);
|
||||
@ -307,7 +307,7 @@ static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
** A wrapper around pread64().
|
||||
*/
|
||||
static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("pread64") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pread64(fd, aBuf, nBuf, off);
|
||||
@ -317,7 +317,7 @@ static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
** A wrapper around write().
|
||||
*/
|
||||
static int ts_write(int fd, const void *aBuf, size_t nBuf){
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("write") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_write(fd, aBuf, nBuf);
|
||||
@ -327,7 +327,7 @@ static int ts_write(int fd, const void *aBuf, size_t nBuf){
|
||||
** A wrapper around pwrite().
|
||||
*/
|
||||
static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("pwrite") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pwrite(fd, aBuf, nBuf, off);
|
||||
@ -337,7 +337,7 @@ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
|
||||
** A wrapper around pwrite64().
|
||||
*/
|
||||
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
if( tsIsFailErrno("pwrite64") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pwrite64(fd, aBuf, nBuf, off);
|
||||
@ -531,11 +531,17 @@ static int test_syscall_errno(
|
||||
const char *z;
|
||||
int i;
|
||||
} aErrno[] = {
|
||||
{ "EACCES", EACCES },
|
||||
{ "EINTR", EINTR },
|
||||
{ "EIO", EIO },
|
||||
{ "EACCES", EACCES },
|
||||
{ "EINTR", EINTR },
|
||||
{ "EIO", EIO },
|
||||
{ "EOVERFLOW", EOVERFLOW },
|
||||
{ "ENOMEM", ENOMEM },
|
||||
{ "ENOMEM", ENOMEM },
|
||||
{ "EAGAIN", EAGAIN },
|
||||
{ "ETIMEDOUT", ETIMEDOUT },
|
||||
{ "EBUSY", EBUSY },
|
||||
{ "EPERM", EPERM },
|
||||
{ "EDEADLK", EDEADLK },
|
||||
{ "ENOLCK", ENOLCK },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -194,6 +194,57 @@ do_test 6.2 {
|
||||
db close
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a database file a single byte in size is treated as an empty
|
||||
# file. Whereas a file 2 bytes or larger might be considered corrupt.
|
||||
#
|
||||
catch { db close }
|
||||
forcedelete test.db test.db2
|
||||
|
||||
proc create_db_file {nByte} {
|
||||
set fd [open test.db w]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
puts -nonewline $fd [string range "xSQLite" 1 $nByte]
|
||||
close $fd
|
||||
}
|
||||
|
||||
foreach {nByte res} {
|
||||
1 {0 {}}
|
||||
2 {1 {file is encrypted or is not a database}}
|
||||
3 {1 {file is encrypted or is not a database}}
|
||||
} {
|
||||
do_test 7.$nByte {
|
||||
create_db_file $nByte
|
||||
sqlite3 db test.db
|
||||
catchsql { CREATE TABLE t1(a, b) }
|
||||
} $res
|
||||
catch { db close }
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
catch { db close }
|
||||
forcedelete test.db test.db2
|
||||
|
||||
do_test 8.1 {
|
||||
sqlite3 db test.db
|
||||
file_control_chunksize_test db main 4096
|
||||
file size test.db
|
||||
} {0}
|
||||
|
||||
foreach {tn hint size} {
|
||||
1 1000 4096
|
||||
2 1000 4096
|
||||
3 3000 4096
|
||||
4 4096 4096
|
||||
5 4197 8192
|
||||
} {
|
||||
do_test 8.2.$tn {
|
||||
file_control_sizehint_test db main $hint
|
||||
file size test.db
|
||||
} $size
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -66,7 +66,11 @@ do_faultsim_test 1 -faults vfsfault-* -prep {
|
||||
{1 {attempt to write a readonly database}}
|
||||
}
|
||||
|
||||
# Errors in the fstat() function when opening and writing a file.
|
||||
#-------------------------------------------------------------------------
|
||||
# Errors in the fstat() function when opening and writing a file. Cases
|
||||
# where fstat() fails and sets errno to ENOMEM and EOVERFLOW are both
|
||||
# tested. EOVERFLOW is interpreted as meaning that a file on disk is
|
||||
# too large to be opened by the OS.
|
||||
#
|
||||
foreach {tn errno errlist} {
|
||||
1 ENOMEM {{disk I/O error}}
|
||||
@ -85,12 +89,57 @@ foreach {tn errno errlist} {
|
||||
"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Various errors in locking functions.
|
||||
#
|
||||
foreach vfs {unix unix-excl} {
|
||||
foreach {tn errno errlist} {
|
||||
1 EAGAIN {{database is locked}}
|
||||
2 ETIMEDOUT {{database is locked}}
|
||||
3 EBUSY {{database is locked}}
|
||||
4 EINTR {{database is locked}}
|
||||
5 ENOLCK {{database is locked}}
|
||||
6 EACCES {{database is locked}}
|
||||
7 EPERM {{access permission denied}}
|
||||
8 EDEADLK {{disk I/O error}}
|
||||
9 ENOMEM {{disk I/O error}}
|
||||
} {
|
||||
proc vfsfault_install {} { test_syscall install fcntl }
|
||||
set errs [list]
|
||||
foreach e $errlist { lappend errs [list 1 $e] }
|
||||
|
||||
set body [string map [list %VFS% $vfs] {
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
set fd [open test.db-journal w]
|
||||
puts $fd "hello world"
|
||||
close $fd
|
||||
sqlite3 db test.db -vfs %VFS%
|
||||
db eval {
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
}]
|
||||
|
||||
do_faultsim_test 1.3.$vfs.$tn -faults vfsfault-* -prep {
|
||||
faultsim_restore
|
||||
} -body "
|
||||
test_syscall errno fcntl $errno
|
||||
$body
|
||||
" -test "
|
||||
faultsim_test_result {0 {1 2}} $errs
|
||||
"
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that a single EINTR error does not affect processing.
|
||||
#
|
||||
proc vfsfault_install {} {
|
||||
test_syscall reset
|
||||
test_syscall install {open ftruncate close}
|
||||
test_syscall install {open ftruncate close read pread pread64 write fallocate}
|
||||
}
|
||||
|
||||
forcedelete test.db test.db2
|
||||
@ -113,16 +162,25 @@ do_faultsim_test 2.1 -faults vfsfault-transient -prep {
|
||||
test_syscall errno open EINTR
|
||||
test_syscall errno ftruncate EINTR
|
||||
test_syscall errno close EINTR
|
||||
test_syscall errno read EINTR
|
||||
test_syscall errno pread EINTR
|
||||
test_syscall errno pread64 EINTR
|
||||
test_syscall errno write EINTR
|
||||
test_syscall errno fallocate EINTR
|
||||
|
||||
sqlite3 db test.db
|
||||
file_control_chunksize_test db main 8192
|
||||
|
||||
set res [db eval {
|
||||
ATTACH 'test.db2' AS 'aux';
|
||||
SELECT * FROM t1;
|
||||
PRAGMA journal_mode = truncate;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
|
||||
INSERT INTO t1 VALUES(randomblob(10000), 0, 0);
|
||||
UPDATE t2 SET x = 2;
|
||||
COMMIT;
|
||||
DELETE FROM t1 WHERE length(a)>3;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
}]
|
||||
@ -159,8 +217,31 @@ do_faultsim_test 2.2 -faults vfsfault-* -prep {
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
proc vfsfault_install {} {
|
||||
test_syscall reset
|
||||
test_syscall install {fstat fallocate}
|
||||
}
|
||||
do_faultsim_test 3 -faults vfsfault-* -prep {
|
||||
faultsim_delete_and_reopen
|
||||
file_control_chunksize_test db main 8192
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} -body {
|
||||
test_syscall errno fstat EIO
|
||||
test_syscall errno fallocate EIO
|
||||
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(randomblob(10000), randomblob(10000));
|
||||
SELECT length(a) + length(b) FROM t1;
|
||||
COMMIT;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 20000}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
83
test/unixexcl.test
Normal file
83
test/unixexcl.test
Normal file
@ -0,0 +1,83 @@
|
||||
# 2011 March 30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains tests for the "unix-excl" VFS module (part of
|
||||
# os_unix.c).
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
if {$::tcl_platform(platform)!="unix" || [info commands test_syscall]==""} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
set testprefix unixexcl
|
||||
|
||||
|
||||
|
||||
# Test that when using VFS "unix-excl", the first time the database is read
|
||||
# a process-wide exclusive lock is taken on it. This means other connections
|
||||
# within the process may still access the db normally, but connections from
|
||||
# outside the process cannot.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
do_test unixexcl-1.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES('hello', 'world');
|
||||
}
|
||||
} {}
|
||||
do_test unixexcl-1.$tn.2 { sql2 { SELECT * FROM t1 } } {hello world}
|
||||
do_test unixexcl-1.$tn.3 {
|
||||
code1 {
|
||||
db close
|
||||
sqlite3 db test.db -vfs unix-excl
|
||||
db eval { SELECT * FROM t1 }
|
||||
}
|
||||
} {hello world}
|
||||
if {$tn==1} {
|
||||
do_test unixexcl-1.$tn.4.multiproc {
|
||||
csql2 { SELECT * FROM t1 }
|
||||
} {1 {database is locked}}
|
||||
} else {
|
||||
do_test unixexcl-1.$tn.4.singleproc {
|
||||
csql2 { SELECT * FROM t1 }
|
||||
} {0 {hello world}}
|
||||
}
|
||||
}
|
||||
|
||||
# Test that when using VFS "unix-excl", if a file is opened in read-only mode
|
||||
# the behaviour is the same as if VFS "unix" were used.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
do_test unixexcl-2.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES('hello', 'world');
|
||||
}
|
||||
} {}
|
||||
do_test unixexcl-2.$tn.2 { sql2 { SELECT * FROM t1 } } {hello world}
|
||||
do_test unixexcl-2.$tn.3 {
|
||||
code1 {
|
||||
db close
|
||||
sqlite3 db test.db -readonly yes -vfs unix-excl
|
||||
db eval { SELECT * FROM t1 }
|
||||
}
|
||||
} {hello world}
|
||||
do_test unixexcl-2.$tn.4 {
|
||||
csql2 { SELECT * FROM t1 }
|
||||
} {0 {hello world}}
|
||||
}
|
||||
|
||||
finish_test
|
Loading…
Reference in New Issue
Block a user