Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Further tests for os_unix.c. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
a84f7711949ea3885b0e36e48118d2c7 |
User & Date: | dan 2011-03-30 19:08:03.321 |
Context
2011-04-01
| ||
01:38 | Fix a compiler warning and an unreachable branch. Restore 100% branch test coverage. (check-in: 4dc148bb4c user: drh tags: trunk) | |
2011-03-31
| ||
02:03 | Change the ANALYZE command so that it will accept an index name as its argument and only reanalyze that one index. A quick smoke-test works. Need to study the implications to the query planner and test corner cases. (check-in: c8f9edd962 user: drh tags: analyze-idx) | |
2011-03-30
| ||
19:08 | Further tests for os_unix.c. (check-in: a84f771194 user: dan tags: trunk) | |
14:54 | Do not generate sqlite_stat1 entries for empty tables when running ANALYZE. Ticket [83ea97620bd31016451] (check-in: 3a27af5b3c user: drh tags: trunk) | |
Changes
Changes to src/os_unix.c.
︙ | ︙ | |||
589 590 591 592 593 594 595 596 597 | ** SQLITE_IOERR ** ** Errors during initialization of locks, or file system support for locks, ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. */ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { switch (posixError) { case 0: return SQLITE_OK; | > > > > > > > > > > > > > | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | ** SQLITE_IOERR ** ** Errors during initialization of locks, or file system support for locks, ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. */ 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: case EINTR: case ENOLCK: /* random NFS retry error, unless during file system support * introspection, in which it actually means what it says */ |
︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 | ** ** The mutex entered using the unixEnterMutex() function must be held ** when this function is called. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); | | | 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 | ** ** The mutex entered using the unixEnterMutex() function must be held ** when this function is called. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); if( ALWAYS(pInode) ){ pInode->nRef--; if( pInode->nRef==0 ){ assert( pInode->pShmNode==0 ); closePendingFds(pFile); if( pInode->pPrev ){ assert( pInode->pPrev->pNext==pInode ); pInode->pPrev->pNext = pInode->pNext; |
︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 | ** in order to coordinate access between separate database connections ** within this process, but all of that is handled in memory and the ** operating system does not participate. ** ** 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. */ static int unixFileLock(unixFile *pFile, struct flock *pLock){ int rc; unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); assert( pInode!=0 ); if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock) | > > > | 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 | ** in order to coordinate access between separate database connections ** within this process, but all of that is handled in memory and the ** operating system does not participate. ** ** 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; unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); assert( pInode!=0 ); if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock) |
︙ | ︙ | |||
1303 1304 1305 1306 1307 1308 1309 | ** locking a random byte from a range, concurrent SHARED locks may exist ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode = pFile->pInode; struct flock lock; | < | 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 | ** locking a random byte from a range, concurrent SHARED locks may exist ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode = pFile->pInode; struct flock lock; int tErrno = 0; assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), azFileLock(pInode->eFileLock), pInode->nShared , getpid())); |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 | lock.l_len = 1L; lock.l_whence = SEEK_SET; if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK) ){ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; | | < | > | > > | < | | | < < | < | < | | < > | > | | > | < | | < < < > | < | | 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 | lock.l_len = 1L; lock.l_whence = SEEK_SET; if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK) ){ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_lock; } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ 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( 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) && rc==SQLITE_OK ){ /* This could happen with a network mount */ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); } if( rc ){ if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_lock; }else{ pFile->eFileLock = SHARED_LOCK; pInode->nLock++; pInode->nShared = 1; } }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file ** already. */ assert( 0!=pFile->eFileLock ); lock.l_type = F_WRLCK; 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; } if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } } } #ifndef NDEBUG |
︙ | ︙ | |||
1619 1620 1621 1622 1623 1624 1625 | }else #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ { lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; | | | | | | | | 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 | }else #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ { lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_unlock; } } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = SHARED_LOCK; }else{ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } goto end_unlock; } } if( eFileLock==NO_LOCK ){ /* Decrement the shared lock counter. Release the lock using an ** OS call only when all threads in this same process have released ** the lock. */ pInode->nShared--; if( pInode->nShared==0 ){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; SimulateIOErrorBenign(1); SimulateIOError( h=(-1) ) SimulateIOErrorBenign(0); if( unixFileLock(pFile, &lock)==0 ){ pInode->eFileLock = NO_LOCK; }else{ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( rc!=SQLITE_BUSY ){ pFile->lastErrno = tErrno; } pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } } |
︙ | ︙ | |||
1710 1711 1712 1713 1714 1715 1716 | ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; | < | | | | | | | | | | | | | | | | | | | < < | | | | > > > | | | | | | | | | | | | < | 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 | ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; 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; } /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; 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; } /************** End of the posix advisory lock implementation ***************** ******************************************************************************/ /****************************************************************************** |
︙ | ︙ | |||
3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 | TIMER_START; #if defined(USE_PREAD) do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR); #else newOffset = lseek(id->h, offset, SEEK_SET); if( newOffset!=offset ){ if( newOffset == -1 ){ ((unixFile*)id)->lastErrno = errno; }else{ ((unixFile*)id)->lastErrno = 0; } return -1; | > | 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 | TIMER_START; #if defined(USE_PREAD) do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); #elif defined(USE_PREAD64) 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; }else{ ((unixFile*)id)->lastErrno = 0; } return -1; |
︙ | ︙ | |||
3371 3372 3373 3374 3375 3376 3377 3378 | i64 nSize; /* Required file size */ struct stat buf; /* Used to hold return values of fstat() */ if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT; nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk; if( nSize>(i64)buf.st_size ){ #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE | > > > > | | | | | 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 | i64 nSize; /* Required file size */ struct stat buf; /* Used to hold return values of fstat() */ if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT; nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk; if( nSize>(i64)buf.st_size ){ #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE /* 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{ 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 ** the last byte in each block within the extended region. This ** is the same technique used by glibc to implement posix_fallocate() ** on systems that do not have a real fallocate() system call. */ |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 | rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (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 ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and ** SQLITE_SET_LOCKPROXYFILE verbs. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 | rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize); if( rc ){ Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); return TCL_ERROR; } 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 ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and ** SQLITE_SET_LOCKPROXYFILE verbs. |
︙ | ︙ | |||
5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 | { "vfs_initfail_test", vfs_initfail_test, 0 }, { "vfs_unregister_all", vfs_unregister_all, 0 }, { "vfs_reregister_all", vfs_reregister_all, 0 }, { "file_control_test", file_control_test, 0 }, { "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 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, /* Functions from os.h */ #ifndef SQLITE_OMIT_UTF16 { "add_test_collate", test_collate, 0 }, { "add_test_collate_needed", test_collate_needed, 0 }, | > | 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 | { "vfs_initfail_test", vfs_initfail_test, 0 }, { "vfs_unregister_all", vfs_unregister_all, 0 }, { "vfs_reregister_all", vfs_reregister_all, 0 }, { "file_control_test", file_control_test, 0 }, { "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 }, /* Functions from os.h */ #ifndef SQLITE_OMIT_UTF16 { "add_test_collate", test_collate, 0 }, { "add_test_collate_needed", test_collate_needed, 0 }, |
︙ | ︙ |
Changes to src/test_syscall.c.
︙ | ︙ | |||
117 118 119 120 121 122 123 | /* 0 */ { "open", (sqlite3_syscall_ptr)ts_open, 0, EACCES, 0 }, /* 1 */ { "close", (sqlite3_syscall_ptr)ts_close, 0, 0, 0 }, /* 2 */ { "access", (sqlite3_syscall_ptr)ts_access, 0, 0, 0 }, /* 3 */ { "getcwd", (sqlite3_syscall_ptr)ts_getcwd, 0, 0, 0 }, /* 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 }, | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /* 0 */ { "open", (sqlite3_syscall_ptr)ts_open, 0, EACCES, 0 }, /* 1 */ { "close", (sqlite3_syscall_ptr)ts_close, 0, 0, 0 }, /* 2 */ { "access", (sqlite3_syscall_ptr)ts_access, 0, 0, 0 }, /* 3 */ { "getcwd", (sqlite3_syscall_ptr)ts_getcwd, 0, 0, 0 }, /* 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, 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 }, /* 11 */ { "write", (sqlite3_syscall_ptr)ts_write, 0, 0, 0 }, /* 12 */ { "pwrite", (sqlite3_syscall_ptr)ts_pwrite, 0, 0, 0 }, /* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 }, /* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 }, |
︙ | ︙ | |||
271 272 273 274 275 276 277 | /* ** A wrapper around fcntl(). */ static int ts_fcntl(int fd, int cmd, ... ){ va_list ap; void *pArg; | | | | | | | | | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | /* ** A wrapper around fcntl(). */ static int ts_fcntl(int fd, int cmd, ... ){ va_list ap; void *pArg; if( tsIsFailErrno("fcntl") ){ return -1; } va_start(ap, cmd); pArg = va_arg(ap, void *); return orig_fcntl(fd, cmd, pArg); } /* ** A wrapper around read(). */ static int ts_read(int fd, void *aBuf, size_t nBuf){ if( tsIsFailErrno("read") ){ return -1; } return orig_read(fd, aBuf, nBuf); } /* ** A wrapper around pread(). */ static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){ if( tsIsFailErrno("pread") ){ return -1; } return orig_pread(fd, aBuf, nBuf, off); } /* ** A wrapper around pread64(). */ static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){ if( tsIsFailErrno("pread64") ){ return -1; } return orig_pread64(fd, aBuf, nBuf, off); } /* ** A wrapper around write(). */ static int ts_write(int fd, const void *aBuf, size_t nBuf){ if( tsIsFailErrno("write") ){ return -1; } return orig_write(fd, aBuf, nBuf); } /* ** A wrapper around pwrite(). */ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){ if( tsIsFailErrno("pwrite") ){ return -1; } return orig_pwrite(fd, aBuf, nBuf, off); } /* ** A wrapper around pwrite64(). */ static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){ if( tsIsFailErrno("pwrite64") ){ return -1; } return orig_pwrite64(fd, aBuf, nBuf, off); } /* ** A wrapper around fchmod(). |
︙ | ︙ | |||
527 528 529 530 531 532 533 | int iErrno; int rc; struct Errno { const char *z; int i; } aErrno[] = { | | | | | > > > > > > | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | int iErrno; int rc; struct Errno { const char *z; int i; } aErrno[] = { { "EACCES", EACCES }, { "EINTR", EINTR }, { "EIO", EIO }, { "EOVERFLOW", EOVERFLOW }, { "ENOMEM", ENOMEM }, { "EAGAIN", EAGAIN }, { "ETIMEDOUT", ETIMEDOUT }, { "EBUSY", EBUSY }, { "EPERM", EPERM }, { "EDEADLK", EDEADLK }, { "ENOLCK", ENOLCK }, { 0, 0 } }; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL ERRNO"); return TCL_ERROR; } |
︙ | ︙ |
Changes to test/syscall.test.
︙ | ︙ | |||
189 190 191 192 193 194 195 196 197 198 199 | INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt; INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt; INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt; } db close } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt; INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt; INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt; } 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 |
Changes to test/sysfault.test.
︙ | ︙ | |||
62 63 64 65 66 67 68 | faultsim_restore } -body $open_and_write_body -test { faultsim_test_result {0 {wal 1 2 3 4}} \ {1 {unable to open database file}} \ {1 {attempt to write a readonly database}} } | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | faultsim_restore } -body $open_and_write_body -test { faultsim_test_result {0 {wal 1 2 3 4}} \ {1 {unable to open database file}} \ {1 {attempt to write a readonly database}} } #------------------------------------------------------------------------- # 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}} 2 EOVERFLOW {{disk I/O error} {large file support is disabled}} } { proc vfsfault_install {} { test_syscall install fstat } set errs [list] foreach e $errlist { lappend errs [list 1 $e] } do_faultsim_test 1.2.$tn -faults vfsfault-* -prep { faultsim_restore } -body " test_syscall errno fstat $errno $open_and_write_body " -test " faultsim_test_result {0 {wal 1 2 3 4}} $errs " } #------------------------------------------------------------------------- # 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 read pread pread64 write fallocate} } forcedelete test.db test.db2 sqlite3 db test.db do_test 2.setup { execsql { CREATE TABLE t1(a, b, c, PRIMARY KEY(a)); |
︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | do_faultsim_test 2.1 -faults vfsfault-transient -prep { catch { db close } faultsim_restore } -body { test_syscall errno open EINTR test_syscall errno ftruncate EINTR test_syscall errno close EINTR sqlite3 db test.db set res [db eval { ATTACH 'test.db2' AS 'aux'; SELECT * FROM t1; PRAGMA journal_mode = truncate; BEGIN; INSERT INTO t1 VALUES('jkl', 'mno', 'pqr'); UPDATE t2 SET x = 2; COMMIT; SELECT * FROM t1; SELECT * FROM t2; }] db close set res } -test { faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}} | > > > > > > > > > | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | do_faultsim_test 2.1 -faults vfsfault-transient -prep { catch { db close } faultsim_restore } -body { 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; }] db close set res } -test { faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}} |
︙ | ︙ | |||
155 156 157 158 159 160 161 | {1 {unable to open database file}} \ {1 {unable to open database: test.db2}} \ {1 {attempt to write a readonly database}} \ {1 {disk I/O error}} } #------------------------------------------------------------------------- | | > > > | > > > > > > > > > > > > > > > > > > > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | {1 {unable to open database file}} \ {1 {unable to open database: test.db2}} \ {1 {attempt to write a readonly database}} \ {1 {disk I/O error}} } #------------------------------------------------------------------------- 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 |
Added test/unixexcl.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 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 |