Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merging in cherry picked diffs for persist wal, alloc padding, wal-safe vacuum and sqlite3_file_control based lockstate checking |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | apple-osx-377 |
Files: | files | file ages | folders |
SHA1: |
db5b7b778c09c57501cb8266895a0ea4 |
User & Date: | adam 2011-10-10 22:11:44 |
References
2011-10-10
| ||
23:53 | Forward port the Apple-specific changes from [db5b7b778c] in the apple-osx-377 branch. Fix this up so that it will compile and run on Linux. (check-in: 6cb43f6c user: drh tags: apple-osx) | |
Context
2011-10-11
| ||
00:09 | Patches to the apple-osx-377 branch so that it will compile and run on non-Mac unix platforms. (Leaf check-in: b431a634 user: drh tags: apple-osx-377) | |
2011-10-10
| ||
23:53 | Forward port the Apple-specific changes from [db5b7b778c] in the apple-osx-377 branch. Fix this up so that it will compile and run on Linux. (check-in: 6cb43f6c user: drh tags: apple-osx) | |
22:11 | Merging in cherry picked diffs for persist wal, alloc padding, wal-safe vacuum and sqlite3_file_control based lockstate checking (check-in: db5b7b77 user: adam tags: apple-osx-377) | |
18:59 | Cherrypick the sqlite_data_count() changes from [d4f95b3b6e] and [9913996e7b] into the apple-osx branch for version 3.7.7. (check-in: aef7945c user: drh tags: apple-osx-377) | |
Changes
Changes to src/backup.c.
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 | if( rc==SQLITE_DONE && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK ){ int nDestTruncate; if( p->pDestDb ){ sqlite3ResetInternalSchema(p->pDestDb, -1); } /* Set nDestTruncate to the final number of pages in the destination ** database. The complication here is that the destination page ** size may be different to the source page size. ** ** If the source page size is smaller than the destination page size, | > > > > > > > > > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | if( rc==SQLITE_DONE && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK ){ int nDestTruncate; if( p->pDestDb ){ sqlite3ResetInternalSchema(p->pDestDb, -1); } if( destMode==PAGER_JOURNALMODE_WAL ){ /* This call cannot fail. The success of the BtreeUpdateMeta() ** method above indicates that a write transaction has been opened ** and page 1 is already dirty. Therefore this always succeeds. */ TESTONLY(int rc2 =) sqlite3BtreeSetVersion(p->pDest, 2); assert( rc2==SQLITE_OK ); } /* Set nDestTruncate to the final number of pages in the destination ** database. The complication here is that the destination page ** size may be different to the source page size. ** ** If the source page size is smaller than the destination page size, |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
8165 8166 8167 8168 8169 8170 8171 | ** "write version" (single byte at byte offset 19) fields in the database ** header to iVersion. */ int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ BtShared *pBt = pBtree->pBt; int rc; /* Return code */ | < | 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 | ** "write version" (single byte at byte offset 19) fields in the database ** header to iVersion. */ int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ BtShared *pBt = pBtree->pBt; int rc; /* Return code */ assert( iVersion==1 || iVersion==2 ); /* If setting the version fields to 1, do not automatically open the ** WAL connection, even if the version fields are currently set to 2. */ pBt->doNotUseWAL = (u8)(iVersion==1); |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
2975 2976 2977 2978 2979 2980 2981 | zFilename += sqlite3Strlen30(zFilename) + 1; if( x==0 ) return zFilename; zFilename += sqlite3Strlen30(zFilename) + 1; } return 0; } | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < | < < < < < | < < < < < < < < < < | | < < < < < < < < < | < < < < | | | 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 | zFilename += sqlite3Strlen30(zFilename) + 1; if( x==0 ) return zFilename; zFilename += sqlite3Strlen30(zFilename) + 1; } return 0; } #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) #include "sqlite3_private.h" /* ** Testing a file path for sqlite locks held by a process ID. ** Returns SQLITE_LOCKSTATE_ON if locks are present on path ** that would prevent writing to the database. */ int _sqlite3_lockstate(const char *path, pid_t pid){ sqlite3 *db = NULL; if( sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK ){ LockstatePID lockstate = {pid, -1}; sqlite3_file_control(db, NULL, SQLITE_FCNTL_LOCKSTATE_PID, &lockstate); sqlite3_close(db); int state = lockstate.state; return state; } return SQLITE_LOCKSTATE_ERROR; } #endif /* SQLITE_ENABLE_APPLE_SPI */ |
Changes to src/mem1.c.
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include <libkern/OSAtomic.h> static malloc_zone_t* _sqliteZone_; #define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) #define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); #define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y)) #endif /* ** Like malloc(), but remember the size of the allocation ** so that we can find it later using sqlite3MemSize(). ** ** For this low-level routine, we are guaranteed that nByte>0 because ** cases of nByte<=0 will be intercepted and dealt with by higher level ** routines. */ static void *sqlite3MemMalloc(int nByte){ sqlite3_int64 *p; assert( nByte>0 ); nByte = ROUND8(nByte); | > | | < < < < < < | < | | < < < | 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 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 | #include <libkern/OSAtomic.h> static malloc_zone_t* _sqliteZone_; #define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) #define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); #define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y)) #define SQLITE_MALLOCSIZE(x) (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x)) #endif /* ** Like malloc(), but remember the size of the allocation ** so that we can find it later using sqlite3MemSize(). ** ** For this low-level routine, we are guaranteed that nByte>0 because ** cases of nByte<=0 will be intercepted and dealt with by higher level ** routines. */ static void *sqlite3MemMalloc(int nByte){ sqlite3_int64 *p; assert( nByte>0 ); nByte = ROUND8(nByte); p = SQLITE_MALLOC( nByte ); if( !p ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); } return (void *)p; } /* ** Like free() but works for allocations obtained from sqlite3MemMalloc() ** or sqlite3MemRealloc(). ** ** For this low-level routine, we already know that pPrior!=0 since ** cases where pPrior==0 will have been intecepted and dealt with ** by higher-level routines. */ static void sqlite3MemFree(void *pPrior){ sqlite3_int64 *p = (sqlite3_int64*)pPrior; assert( pPrior!=0 ); SQLITE_FREE(p); } /* ** Report the allocated size of a prior return from xMalloc() ** or xRealloc(). */ static int sqlite3MemSize(void *pPrior){ sqlite3_int64 *p; if( pPrior==0 ) return 0; return (int)SQLITE_MALLOCSIZE(pPrior); } /* ** Like realloc(). Resize an allocation previously obtained from ** sqlite3MemMalloc(). ** ** For this low-level interface, we know that pPrior!=0. Cases where ** pPrior==0 while have been intercepted by higher-level routine and ** redirected to xMalloc. Similarly, we know that nByte>0 becauses ** cases where nByte<=0 will have been intercepted by higher-level ** routines and redirected to xFree. */ static void *sqlite3MemRealloc(void *pPrior, int nByte){ sqlite3_int64 *p = (sqlite3_int64*)pPrior; assert( pPrior!=0 && nByte>0 ); assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */ p = SQLITE_REALLOC(p, nByte ); if( !p ){ testcase( sqlite3GlobalConfig.xLog!=0 ); sqlite3_log(SQLITE_NOMEM, "failed memory resize %u to %u bytes", sqlite3MemSize(pPrior), nByte); } return (void*)p; } |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
254 255 256 257 258 259 260 | char aPadding[32]; #endif }; /* ** Allowed values for the unixFile.ctrlFlags bitmask: */ | | | > | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | char aPadding[32]; #endif }; /* ** Allowed values for the unixFile.ctrlFlags bitmask: */ #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ #define UNIXFILE_RDONLY 0x02 /* Connection is read only */ #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ /* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* |
︙ | ︙ | |||
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 | unixLeaveMutex(); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* ** Attempt to set a system-lock on the file pFile. The lock is ** described by pLock. ** ** If the pFile was opened read/write from unix-excl, then the only lock ** ever obtained is an exclusive lock, and it is obtained exactly once ** the first time any lock is attempted. All subsequent system locking ** operations become no-ops. Locking operations still happen internally, ** 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){ | > > > > > > > > > > | | 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 | unixLeaveMutex(); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } static int _unixFileLock(unixFile *pFile, struct flock *pLock, int retry); /* ** Attempt to set a system-lock on the file pFile. The lock is ** described by pLock. ** ** If the pFile was opened read/write from unix-excl, then the only lock ** ever obtained is an exclusive lock, and it is obtained exactly once ** the first time any lock is attempted. All subsequent system locking ** operations become no-ops. Locking operations still happen internally, ** 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){ return _unixFileLock(pFile, pLock, 0); } static int unixFileLock2(unixFile *pFile, struct flock *pLock){ return _unixFileLock(pFile, pLock, 10); } static int _unixFileLock(unixFile *pFile, struct flock *pLock, int retry) { int rc = 0; unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); assert( pInode!=0 ); if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock) && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0) ){ if( pInode->bProcessLock==0 ){ |
︙ | ︙ | |||
1577 1578 1579 1580 1581 1582 1583 | if( rc<0 ) return rc; pInode->bProcessLock = 1; pInode->nLock++; }else{ rc = 0; } }else{ | > > | > > > > | 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 | if( rc<0 ) return rc; pInode->bProcessLock = 1; pInode->nLock++; }else{ rc = 0; } }else{ int i = 0; do { rc = osFcntl(pFile->h, F_SETLK, pLock); if (rc && retry) { usleep(100 * (++i)); } } while (!rc && retry--); } return rc; } /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: |
︙ | ︙ | |||
1748 1749 1750 1751 1752 1753 1754 | 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; | | | 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 | 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( unixFileLock2(pFile, &lock) && rc==SQLITE_OK ){ /* This could happen with a network mount */ tErrno = errno; #if OSLOCKING_CHECK_BUSY_IOERR rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); #else rc = SQLITE_IOERR_UNLOCK; #endif |
︙ | ︙ | |||
1916 1917 1918 1919 1920 1921 1922 | if( eFileLock==SHARED_LOCK ){ #if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE (void)handleNFSUnlock; assert( handleNFSUnlock==0 ); #endif #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE | < | > | | > > > > | | < > < < < | > > > | | 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 | if( eFileLock==SHARED_LOCK ){ #if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE (void)handleNFSUnlock; assert( handleNFSUnlock==0 ); #endif #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE int tErrno; /* Error code from system call errors */ if( handleNFSUnlock ){ off_t divSize = SHARED_SIZE - 1; lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; if( unixFileLock2(pFile, &lock)==(-1) ){ tErrno = errno; #if OSLOCKING_CHECK_BUSY_IOERR rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); #else rc = SQLITE_IOERR_UNLOCK; #endif if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = divSize; if( unixFileLock2(pFile, &lock)==(-1) ){ tErrno = errno; #if OSLOCKING_CHECK_BUSY_IOERR rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); #else rc = SQLITE_IOERR_UNLOCK; #endif if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST+divSize; lock.l_len = SHARED_SIZE-divSize; if( unixFileLock2(pFile, &lock)==(-1) ){ tErrno = errno; #if OSLOCKING_CHECK_BUSY_IOERR rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); #else rc = SQLITE_IOERR_UNLOCK; #endif if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } }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( unixFileLock2(pFile, &lock) ){ tErrno = errno; #if OSLOCKING_CHECK_BUSY_IOERR rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); #else /* In theory, the call to unixFileLock() cannot fail because another ** process is holding an incompatible lock. If it does, this ** indicates that the other process is not following the locking ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning ** SQLITE_BUSY would confuse the upper layer (in practice it causes ** an assert to fail). */ rc = SQLITE_IOERR_RDLOCK; pFile->lastErrno = tErrno; #endif if( IS_LOCK_ERROR(rc) ){ 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( unixFileLock2(pFile, &lock)==0 ){ pInode->eFileLock = SHARED_LOCK; }else{ #if OSLOCKING_CHECK_BUSY_IOERR tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; |
︙ | ︙ | |||
2025 2026 2027 2028 2029 2030 2031 | 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); | | | 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 | 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( unixFileLock2(pFile, &lock)==0 ){ pInode->eFileLock = NO_LOCK; }else{ #if OSLOCKING_CHECK_BUSY_IOERR tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; |
︙ | ︙ | |||
3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 | #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) #include "sqlite3_private.h" #include <copyfile.h> static int getDbPathForUnixFile(unixFile *pFile, char *dbPath); #endif static int isProxyLockingMode(unixFile *); /* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > > > > > | | | < < < < < < | < < < < < < | < | < < < < < < < | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < < < | | | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 | #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) #include "sqlite3_private.h" #include <copyfile.h> static int getDbPathForUnixFile(unixFile *pFile, char *dbPath); #endif static int isProxyLockingMode(unixFile *); #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) static int unixTruncateDatabase(unixFile *, int); static int unixInvalidateSupportFiles(unixFile *, int); static int unixReplaceDatabase(unixFile *pFile, sqlite3 *srcdb) { sqlite3_file *id = (sqlite3_file *)pFile; Btree *pSrcBtree = NULL; sqlite3_file *src_file = NULL; unixFile *pSrcFile = NULL; char srcWalPath[MAXPATHLEN+5]; int srcWalFD = -1; int rc = SQLITE_OK; void *pLock = NULL; int flags = 0; sqlite3 *srcdb2 = NULL; copyfile_state_t s; int corruptSrcFileLock = 0; int corruptDstFileLock = 0; int isSrcCorrupt = 0; int isDstCorrupt = 0; if( !sqlite3SafetyCheckOk(srcdb) ){ return SQLITE_MISUSE; } #if SQLITE_ENABLE_DATA_PROTECTION flags |= pFile->protFlags; #endif #if SQLITE_ENABLE_LOCKING_STYLE if( isProxyLockingMode(pFile) ){ flags |= SQLITE_OPEN_AUTOPROXY; } #endif rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock); if( rc ){ if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){ isDstCorrupt = 1; rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock); } if( rc ){ return rc; } } /* get the src file descriptor adhering to the db struct access rules ** this code is modeled after sqlite3_file_control() in main.c */ sqlite3_mutex_enter(srcdb->mutex); if( srcdb->nDb>0 ){ pSrcBtree = srcdb->aDb[0].pBt; } if( pSrcBtree ){ Pager *pSrcPager; sqlite3BtreeEnter(pSrcBtree); pSrcPager = sqlite3BtreePager(pSrcBtree); assert( pSrcPager!=0 ); src_file = sqlite3PagerFile(pSrcPager); assert( src_file!=0 ); if( src_file->pMethods ){ int srcFlags = 0; pSrcFile = (unixFile *)src_file; /* wal mode db cannot be opened readonly */ if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) { srcFlags = SQLITE_OPEN_READWRITE; } else { srcFlags = SQLITE_OPEN_READONLY; } #if SQLITE_ENABLE_DATA_PROTECTION srcFlags |= pSrcFile->protFlags; #endif #if SQLITE_ENABLE_LOCKING_STYLE if( isProxyLockingMode(pSrcFile) ){ srcFlags |= SQLITE_OPEN_AUTOPROXY; } #endif rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0); if( rc==SQLITE_OK ){ /* start a deferred transaction and read to establish a read lock */ rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version", 0, 0, 0); if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){ isSrcCorrupt = 1; rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED, &corruptSrcFileLock); } } } } if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){ rc = SQLITE_INTERNAL; } if( rc!=SQLITE_OK ){ goto end_replace_database; } /* both databases are locked appropriately, copy the src wal journal if ** one exists and then the actual database file */ strlcpy(srcWalPath, pSrcFile->zPath, MAXPATHLEN+5); strlcat(srcWalPath, "-wal", MAXPATHLEN+5); srcWalFD = open(srcWalPath, O_RDONLY); if( !(srcWalFD<0) ){ char dstWalPath[MAXPATHLEN+5]; int dstWalFD = -1; strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5); strlcat(dstWalPath, "-wal", MAXPATHLEN+5); dstWalFD = open(dstWalPath, O_RDWR|O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS); if( !(dstWalFD<0) ){ s = copyfile_state_alloc(); lseek(srcWalFD, 0, SEEK_SET); lseek(dstWalFD, 0, SEEK_SET); if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){ int err=errno; switch(err) { case ENOMEM: rc = SQLITE_NOMEM; break; default: pFile->lastErrno = err; rc = SQLITE_IOERR; } } copyfile_state_free(s); close(dstWalFD); } close(srcWalFD); } if( rc==SQLITE_OK ){ /* before we copy, ensure that the file change counter will be modified */ uint32_t srcChange = 0; uint32_t dstChange = 0; pread(pSrcFile->h, &srcChange, 4, 24); pread(pFile->h, &dstChange, 4, 24); /* copy the actual database */ s = copyfile_state_alloc(); lseek(pSrcFile->h, 0, SEEK_SET); lseek(pFile->h, 0, SEEK_SET); if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){ int err=errno; switch(err) { case ENOMEM: rc = SQLITE_NOMEM; break; default: pFile->lastErrno = err; rc = SQLITE_IOERR; } } copyfile_state_free(s); if (srcChange == dstChange) { /* modify the change counter to force page zero to be reloaded */ dstChange ++; pwrite(pFile->h, &dstChange, 4, 24); } } if( isSrcCorrupt ){ sqlite3demo_superunlock_corrupt(src_file, corruptSrcFileLock); }else{ /* done with the source db so end the transaction */ sqlite3_exec(srcdb2, "COMMIT", 0, 0, 0); } /* zero out any old journal clutter */ if( rc==SQLITE_OK ){ int skipWAL = (srcWalFD<0)?0:1; unixInvalidateSupportFiles(pFile, skipWAL); } end_replace_database: if( pSrcBtree ){ sqlite3_close(srcdb2); sqlite3BtreeLeave(pSrcBtree); } sqlite3_mutex_leave(srcdb->mutex); if( isDstCorrupt ){ sqlite3demo_superunlock_corrupt(id, corruptDstFileLock); }else{ sqlite3demo_superunlock(pLock); } return rc; } #define SQLITE_FILE_HEADER_LEN 16 #include "btreeInt.h" /* Check for a conflicting lock. If one is found, print an this ** on standard output using the format string given and return 1. ** If there are no conflicting locks, return 0. */ static int unixIsLocked( pid_t pid, /* PID to test for lock owner */ int h, /* File descriptor to check */ int type, /* F_RDLCK or F_WRLCK */ unsigned int iOfst, /* First byte of the lock */ unsigned int iCnt, /* Number of bytes in the lock range */ const char *zType /* Type of lock */ ){ struct flock lk; int err; memset(&lk, 0, sizeof(lk)); lk.l_type = type; lk.l_whence = SEEK_SET; lk.l_start = iOfst; lk.l_len = iCnt; if( pid!=SQLITE_LOCKSTATE_ANYPID ){ #ifndef F_GETLKPID # warning F_GETLKPID undefined, _sqlite3_lockstate falling back to F_GETLK err = fcntl(h, F_GETLK, &lk); #else lk.l_pid = pid; err = fcntl(h, F_GETLKPID, &lk); #endif }else{ err = fcntl(h, F_GETLK, &lk); } if( err==(-1) ){ fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno); return -1; } if( lk.l_type!=F_UNLCK && (pid==SQLITE_LOCKSTATE_ANYPID || lk.l_pid==pid) ){ #ifdef SQLITE_DEBUG fprintf(stderr, "%s lock held by %d\n", zType, (int)lk.l_pid); #endif return 1; } return 0; } static int unixLockstatePid(unixFile *, pid_t, int *); #endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */ /* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; } case SQLITE_FCNTL_LAST_ERRNO: { *(int*)pArg = pFile->lastErrno; return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { return fcntlSizeHint(pFile, *(i64 *)pArg); } case SQLITE_FCNTL_PERSIST_WAL: { int bPersist = *(int*)pArg; if( bPersist<0 ){ *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0; }else if( bPersist==0 ){ pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL; }else{ pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL; } return SQLITE_OK; } #ifndef NDEBUG /* The pager calls this method to signal that it has done ** a rollback and that the database is therefore unchanged and ** it hence it is OK for the transaction change counter to be ** unchanged. */ case SQLITE_FCNTL_DB_UNCHANGED: { ((unixFile*)id)->dbUpdate = 0; return SQLITE_OK; } #endif #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) case SQLITE_FCNTL_SET_LOCKPROXYFILE: case SQLITE_FCNTL_GET_LOCKPROXYFILE: { return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) case SQLITE_FCNTL_TRUNCATE_DATABASE: { return unixTruncateDatabase(pFile, (pArg ? (*(int *)pArg) : 0)); } case SQLITE_FCNTL_REPLACE_DATABASE: { return unixReplaceDatabase(pFile, (sqlite3 *)pArg); } case SQLITE_FCNTL_LOCKSTATE_PID: { LockstatePID *pLockstate; int rc; if( pArg==NULL ){ return SQLITE_MISUSE; } pLockstate = (LockstatePID *)pArg; rc = unixLockstatePid(pFile, pLockstate->pid, &(pLockstate->state)); return rc; } #endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */ case SQLITE_FCNTL_SYNC_OMITTED: { return SQLITE_OK; /* A no-op */ } } |
︙ | ︙ | |||
4466 4467 4468 4469 4470 4471 4472 | pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pShmNode->mutex==0 ){ rc = SQLITE_NOMEM; goto shm_open_err; } if( pInode->bProcessLock==0 ){ | > > > > > > > | > | 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 | pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pShmNode->mutex==0 ){ rc = SQLITE_NOMEM; goto shm_open_err; } if( pInode->bProcessLock==0 ){ const char *zRO; zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm"); if( zRO && sqlite3GetBoolean(zRO) ){ pShmNode->h = robust_open(zShmFilename, O_RDONLY, (sStat.st_mode & 0777)); pShmNode->isReadonly = 1; }else{ pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777)); } if( pShmNode->h<0 ){ const char *zRO; zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm"); if( zRO && sqlite3GetBoolean(zRO) ){ pShmNode->h = robust_open(zShmFilename, O_RDONLY, (sStat.st_mode & 0777)); pShmNode->isReadonly = 1; |
︙ | ︙ | |||
4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 | #else # define unixShmMap 0 # define unixShmLock 0 # define unixShmBarrier 0 # define unixShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4877 4878 4879 4880 4881 4882 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 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 | #else # define unixShmMap 0 # define unixShmLock 0 # define unixShmBarrier 0 # define unixShmUnmap 0 #endif /* #ifndef SQLITE_OMIT_WAL */ #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) static const char *unixTempFileDir(void); static int unixInvalidateSupportFiles(unixFile *pFile, int skipWAL) { char jPath[MAXPATHLEN+9]; int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9); if( zLen<MAXPATHLEN ){ size_t jLen; const char extensions[3][9] = { "-wal", "-journal", "-shm" }; int j = (skipWAL ? 1 : 0); for( ; j<3; j++ ){ /* Check to see if the shm file is already opened for this pFile */ if( j==2 ){ unixEnterMutex(); /* Because pFile->pInode is shared across threads */ unixShmNode *pShmNode = pFile->pInode->pShmNode; if( pShmNode && !pShmNode->isReadonly ){ struct stat sStat; sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->h>=0 && !osFstat(pShmNode->h, &sStat) ){ unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4; if( size>0 ){ bzero(pShmNode->apRegion[0], size); sqlite3_mutex_leave(pShmNode->mutex); unixLeaveMutex(); continue; } } sqlite3_mutex_leave(pShmNode->mutex); } unixLeaveMutex(); } jLen = strlcpy(&jPath[zLen], extensions[j], 9); if( jLen < 9 ){ int jflags = (j<2) ? O_TRUNC : O_RDWR; int jfd = open(jPath, jflags); if( jfd==(-1) ){ if( errno!=ENOENT ){ perror(jPath); } } else { if( j==2 ){ struct stat sStat; if( !osFstat(jfd, &sStat) ){ unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4; if( size>0 ){ uint32_t zero = 0; pwrite(jfd, &zero, (size_t)size, 0); } } } fsync(jfd); close(jfd); } } } } return SQLITE_OK; } static int unixTruncateDatabase(unixFile *pFile, int bFlags) { sqlite3_file *id = (sqlite3_file *)pFile; int rc = SQLITE_OK; void *pLock = NULL; int flags = 0; int corruptFileLock = 0; int isCorrupt = 0; #if SQLITE_ENABLE_DATA_PROTECTION flags |= pFile->protFlags; #endif #if SQLITE_ENABLE_LOCKING_STYLE if( isProxyLockingMode(pFile) ){ flags |= SQLITE_OPEN_AUTOPROXY; } #endif rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock); if( rc ){ if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){ isCorrupt = 1; rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock); } if( rc ){ return rc; } } rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L); if( rc==SQLITE_OK ){ unixInvalidateSupportFiles(pFile, 0); } pFile->pMethod->xSync(id, SQLITE_SYNC_FULL); if( isCorrupt ){ sqlite3demo_superunlock_corrupt(id, corruptFileLock); }else{ sqlite3demo_superunlock(pLock); } return rc; } /* ** Lock locations for shared-memory locks used by WAL mode. */ #ifndef SHM_BASE # define SHM_BASE 120 # define SHM_WRITE SHM_BASE # define SHM_CHECKPOINT (SHM_BASE+1) # define SHM_RECOVER (SHM_BASE+2) # define SHM_READ_FIRST (SHM_BASE+3) # define SHM_READ_SIZE 5 #endif /* SHM_BASE */ /* ** This test only works for lock testing on unix/posix VFS. ** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce */ static int unixLockstatePid(unixFile *pFile, pid_t pid, int *pLockstate){ int hDb; /* File descriptor for the open database file */ int hShm = -1; /* File descriptor for WAL shared-memory file */ ssize_t got; /* Bytes read from header */ int isWal; /* True if in WAL mode */ int nLock = 0; /* Number of locks held */ unsigned char aHdr[100]; /* Database header */ assert(pLockstate); /* make sure we are dealing with a database file */ hDb = pFile->h; if( hDb<0 ){ *pLockstate = SQLITE_LOCKSTATE_ERROR; return SQLITE_ERROR; } assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN ); got = pread(hDb, aHdr, 100, 0); if( got<0 ){ *pLockstate = SQLITE_LOCKSTATE_ERROR; return SQLITE_ERROR; } if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){ *pLockstate = SQLITE_LOCKSTATE_NOTADB; return SQLITE_NOTADB; } /* First check for an exclusive lock */ nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE"); isWal = aHdr[18]==2; if( nLock==0 && isWal==0 ){ /* Rollback mode */ nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED"); } if( nLock==0 && isWal!=0 ){ /* lookup the file descriptor for the shared memory file if we have it open in this process */ unixEnterMutex(); /* Because pFile->pInode is shared across threads */ unixShmNode *pShmNode = pFile->pInode->pShmNode; if( pShmNode ){ sqlite3_mutex_enter(pShmNode->mutex); hShm = pShmNode->h; if( hShm >= 0){ if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") || unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){ nLock = 1; } } sqlite3_mutex_leave(pShmNode->mutex); } if( hShm<0 ){ /* the shared memory file isn't open in this process space, open our own FD */ char zShm[MAXPATHLEN]; /* WAL mode */ strlcpy(zShm, pFile->zPath, MAXPATHLEN); strlcat(zShm, "-shm", MAXPATHLEN); hShm = open(zShm, O_RDONLY, 0); if( hShm<0 ){ *pLockstate = SQLITE_LOCKSTATE_OFF; unixLeaveMutex(); return SQLITE_OK; } if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") || unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){ nLock = 1; } close(hShm); } unixLeaveMutex(); } if( nLock>0 ){ *pLockstate = SQLITE_LOCKSTATE_ON; } else { *pLockstate = SQLITE_LOCKSTATE_OFF; } return SQLITE_OK; } #endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */ /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
98 99 100 101 102 103 104 | ** portability layer. */ typedef struct winFile winFile; struct winFile { const sqlite3_io_methods *pMethod; /*** Must be first ***/ sqlite3_vfs *pVfs; /* The VFS used to open this file */ HANDLE h; /* Handle for accessing the file */ | | > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | ** portability layer. */ typedef struct winFile winFile; struct winFile { const sqlite3_io_methods *pMethod; /*** Must be first ***/ sqlite3_vfs *pVfs; /* The VFS used to open this file */ HANDLE h; /* Handle for accessing the file */ u8 locktype; /* Type of lock currently held on this file */ short sharedLockByte; /* Randomly chosen byte used as a shared lock */ u8 bPersistWal; /* True to persist WAL files */ DWORD lastErrno; /* The Windows errno from the last I/O error */ DWORD sectorSize; /* Sector size of the device file is on */ winShm *pShm; /* Instance of shared memory on this file */ const char *zPath; /* Full pathname of this file */ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ #if SQLITE_OS_WINCE WCHAR *zDeleteOnClose; /* Name of file to delete when closing */ |
︙ | ︙ | |||
1272 1273 1274 1275 1276 1277 1278 1279 1280 | return rc; } /* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { | > | | | > > > > > > > > > | 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 | return rc; } /* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ winFile *pFile = (winFile*)id; switch( op ){ case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->locktype; return SQLITE_OK; } case SQLITE_LAST_ERRNO: { *(int*)pArg = (int)pFile->lastErrno; return SQLITE_OK; } case SQLITE_FCNTL_CHUNK_SIZE: { pFile->szChunk = *(int *)pArg; return SQLITE_OK; } case SQLITE_FCNTL_SIZE_HINT: { sqlite3_int64 sz = *(sqlite3_int64*)pArg; SimulateIOErrorBenign(1); winTruncate(id, sz); SimulateIOErrorBenign(0); return SQLITE_OK; } case SQLITE_FCNTL_PERSIST_WAL: { int bPersist = *(int*)pArg; if( bPersist<0 ){ *(int*)pArg = pFile->bPersistWal; }else{ pFile->bPersistWal = bPersist!=0; } return SQLITE_OK; } case SQLITE_FCNTL_SYNC_OMITTED: { return SQLITE_OK; } } return SQLITE_NOTFOUND; } |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
6735 6736 6737 6738 6739 6740 6741 | /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ #if SQLITE_ENABLE_DATA_PROTECTION rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode, | | | | 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 | /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ #if SQLITE_ENABLE_DATA_PROTECTION rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, (pPager->vfsFlags & (SQLITE_OPEN_FILEPROTECTION_MASK | SQLITE_OPEN_READONLY)), &pPager->pWal); #else rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, (pPager->vfsFlags & SQLITE_OPEN_READONLY), &pPager->pWal); #endif } return rc; } |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
733 734 735 736 737 738 739 740 | ** when the database connection has [PRAGMA synchronous] set to OFF.)^ ** Some specialized VFSes need this signal in order to operate correctly ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most ** VFSes do not need this signal and should silently ignore this opcode. ** Applications should not call [sqlite3_file_control()] with this ** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. */ | > > > > > > > > > > > > > > > | | | | | | | | | > > > > | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 | ** when the database connection has [PRAGMA synchronous] set to OFF.)^ ** Some specialized VFSes need this signal in order to operate correctly ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most ** VFSes do not need this signal and should silently ignore this opcode. ** Applications should not call [sqlite3_file_control()] with this ** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. ** ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write AHead Log] setting. By default, the auxiliary ** write ahead log and shared memory files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not ** have write permission on the directory containing the database file want ** to read the database file, as the WAL and shared memory files must exist ** in order for the database to be readable. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable persistent WAL mode or 1 to enable persistent ** WAL mode. If the integer is -1, then it is overwritten with the current ** WAL persistence setting. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 #define SQLITE_FCNTL_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_PERSIST_WAL 10 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
︙ | ︙ |
Changes to src/sqlite3_private.h.
︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 | ** ** There is no support for identifying db files encrypted via SEE encryption ** currently. Zero byte files are tested for sqlite locks, but if no sqlite ** locks are present then SQLITE_LOCKSTATE_NOTADB is returned. */ extern int _sqlite3_lockstate(const char *path, pid_t pid); /* ** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control() ** to truncate a database and its associated journal file to zero length. */ | > > > > > > > > > | > | | 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 | ** ** There is no support for identifying db files encrypted via SEE encryption ** currently. Zero byte files are tested for sqlite locks, but if no sqlite ** locks are present then SQLITE_LOCKSTATE_NOTADB is returned. */ extern int _sqlite3_lockstate(const char *path, pid_t pid); /* ** Test an open database connection for sqlite locks held by a process ID, ** if a process has an open database connection this will avoid trashing file ** locks by re-using open file descriptors for the database file and support ** files (-shm) */ #define SQLITE_FCNTL_LOCKSTATE_PID 103 /* ** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control() ** to truncate a database and its associated journal file to zero length. */ #define SQLITE_FCNTL_TRUNCATE_DATABASE 101 #define SQLITE_TRUNCATE_DATABASE SQLITE_FCNTL_TRUNCATE_DATABASE /* ** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control() ** and a sqlite3 pointer to another open database file to safely copy the ** contents of that database file into the receiving database. */ #define SQLITE_FCNTL_REPLACE_DATABASE 102 #define SQLITE_REPLACE_DATABASE SQLITE_FCNTL_REPLACE_DATABASE #endif |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
3246 3247 3248 3249 3250 3251 3252 3253 | #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Might have been lookaside memory */ #define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ #define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ #define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */ #endif /* _SQLITEINT_H_ */ | > > > > > > > > > > > > > > > > > > > > > > > > > | 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 | #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Might have been lookaside memory */ #define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ #define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ #define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */ #if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) /* ** An instance of the following structure is used to hold the process ID ** and return-by-reference lockstate value. The SQLITE_FCNTL_LOCKSTATE_PID ** requires the 4th argument to sqlite3_file_control to be a pointer to an ** instance of LockstatePID initialized with a LockstatePID.pid value equal ** to a process ID to be tested, or the special value SQLITE_LOCKSTATE_ANYPID ** The Lockstate.state value is always set to one of the following values ** when sqlite3_file_control returns: ** ** SQLITE_LOCKSTATE_OFF no active sqlite file locks match the specified pid ** SQLITE_LOCKSTATE_ON active sqlite file locks match the specified pid ** SQLITE_LOCKSTATE_NOTADB path points to a file that is not an sqlite db file ** SQLITE_LOCKSTATE_ERROR path was not vaild or was unreadable */ typedef struct LockstatePID LockstatePID; struct LockstatePID { pid_t pid; /* Process ID to test */ int state; /* The state of the lock (return value) */ }; #endif #endif /* _SQLITEINT_H_ */ |
Changes to src/test1.c.
︙ | ︙ | |||
4986 4987 4988 4989 4990 4991 4992 4993 4994 | static int file_control_truncate_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 *db; int rc; | > | | > > > | | 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 | static int file_control_truncate_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 *db; int flags; int rc; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " DB FLAGS", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &flags) ){ return TCL_ERROR; } rc = sqlite3_file_control(db, NULL, SQLITE_TRUNCATE_DATABASE, &flags); if( rc ){ Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_ERROR; } return TCL_OK; } |
︙ | ︙ | |||
5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 | } #else Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); #endif return TCL_OK; } /* ** tclcmd: sqlite3_vfs_list ** ** Return a tcl list containing the names of all registered vfs's. */ static int vfs_list( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 | } #else Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); #endif return TCL_OK; } /* ** tclcmd: file_control_persist_wal DB PERSIST-FLAG ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_PERSIST_WAL opcode. */ static int file_control_persist_wal( 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 *db; int rc; int bPersist; char z[100]; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR; rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist); sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist); Tcl_AppendResult(interp, z, (char*)0); return TCL_OK; } /* ** tclcmd: sqlite3_vfs_list ** ** Return a tcl list containing the names of all registered vfs's. */ static int vfs_list( |
︙ | ︙ | |||
5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 | { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, #ifdef __APPLE__ { "file_control_truncate_test", file_control_truncate_test, 0 }, { "file_control_replace_test", file_control_replace_test, 0 }, #endif { "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 }, { "path_is_local", path_is_local, 0 }, { "path_is_dos", path_is_dos, 0 }, /* Functions from os.h */ #ifndef SQLITE_OMIT_UTF16 | > | 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 | { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, #ifdef __APPLE__ { "file_control_truncate_test", file_control_truncate_test, 0 }, { "file_control_replace_test", file_control_replace_test, 0 }, #endif { "file_control_chunksize_test", file_control_chunksize_test, 0 }, { "file_control_sizehint_test", file_control_sizehint_test, 0 }, { "file_control_persist_wal", file_control_persist_wal, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, { "path_is_local", path_is_local, 0 }, { "path_is_dos", path_is_dos, 0 }, /* Functions from os.h */ #ifndef SQLITE_OMIT_UTF16 |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | if( pParse->explain && nMem<10 ){ nMem = 10; } memset(zCsr, 0, zEnd-zCsr); zCsr += (zCsr - (u8*)0)&7; assert( EIGHT_BYTE_ALIGNMENT(zCsr) ); /* Memory for registers, parameters, cursor, etc, is allocated in two ** passes. On the first pass, we try to reuse unused space at the ** end of the opcode array. If we are unable to satisfy all memory ** requirements by reusing the opcode array tail, then the second ** pass will fill in the rest using a fresh allocation. ** ** This two-pass approach that reuses as much memory as possible from | > > | 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 | if( pParse->explain && nMem<10 ){ nMem = 10; } memset(zCsr, 0, zEnd-zCsr); zCsr += (zCsr - (u8*)0)&7; assert( EIGHT_BYTE_ALIGNMENT(zCsr) ); p->expired = 0; /* Memory for registers, parameters, cursor, etc, is allocated in two ** passes. On the first pass, we try to reuse unused space at the ** end of the opcode array. If we are unable to satisfy all memory ** requirements by reusing the opcode array tail, then the second ** pass will fill in the rest using a fresh allocation. ** ** This two-pass approach that reuses as much memory as possible from |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
1281 1282 1283 1284 1285 1286 1287 | pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); /* Open file handle on the write-ahead log file. */ | > > > | > | 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); /* Open file handle on the write-ahead log file. */ if( flags&SQLITE_OPEN_READONLY ){ vfsFlags = flags | SQLITE_OPEN_WAL; } else { vfsFlags = flags | (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); } rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, vfsFlags, &vfsFlags); if( rc==SQLITE_OK && vfsFlags&SQLITE_OPEN_READONLY ){ pRet->readOnly = WAL_RDONLY; } if( rc!=SQLITE_OK ){ walIndexClose(pRet, 0); |
︙ | ︙ | |||
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 | ** the database. In this case checkpoint the database and unlink both ** the wal and wal-index files. ** ** The EXCLUSIVE lock is not released before returning. */ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE); if( rc==SQLITE_OK ){ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } rc = sqlite3WalCheckpoint( pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 ); | > > | | 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 | ** the database. In this case checkpoint the database and unlink both ** the wal and wal-index files. ** ** The EXCLUSIVE lock is not released before returning. */ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE); if( rc==SQLITE_OK ){ int bPersistWal = -1; if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } rc = sqlite3WalCheckpoint( pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 ); sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal); if( rc==SQLITE_OK && bPersistWal!=1 ){ isDelete = 1; } } walIndexClose(pWal, isDelete); sqlite3OsClose(pWal->pWalFd); if( isDelete ){ |
︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 | ** ** There are two copies of the header at the beginning of the wal-index. ** When reading, read [0] first then [1]. Writes are in the reverse order. ** Memory barriers are used to prevent the compiler or the hardware from ** reordering the reads and writes. */ aHdr = walIndexHdr(pWal); memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ return 1; /* Dirty read */ } | > > > | 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 | ** ** There are two copies of the header at the beginning of the wal-index. ** When reading, read [0] first then [1]. Writes are in the reverse order. ** Memory barriers are used to prevent the compiler or the hardware from ** reordering the reads and writes. */ aHdr = walIndexHdr(pWal); if( aHdr==NULL ){ return 1; /* Shouldn't be getting NULL from walIndexHdr, but we are */ } memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ return 1; /* Dirty read */ } |
︙ | ︙ | |||
2044 2045 2046 2047 2048 2049 2050 | ** 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 ){ int nDelay = 1; /* Pause time in microseconds */ | | | 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 | ** 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 ){ int nDelay = 1; /* Pause time in microseconds */ if( cnt>500 ){ 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); } |
︙ | ︙ |
Added test/walpersist.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 | # 2011 July 26 # # 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 using WAL with persistent WAL file mode. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set ::testprefix walpersist do_test walpersist-1.0 { db eval { PRAGMA journal_mode=WAL; CREATE TABLE t1(a); INSERT INTO t1 VALUES(randomblob(5000)); } file exists test.db-wal } {1} do_test walpersist-1.1 { file exists test.db-shm } {1} do_test walpersist-1.2 { db close list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm] } {1 0 0} do_test walpersist-1.3 { sqlite3 db test.db db eval {SELECT length(a) FROM t1} } {5000} do_test walpersist-1.4 { list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm] } {1 1 1} do_test walpersist-1.5 { file_control_persist_wal db -1 } {0 0} do_test walpersist-1.6 { file_control_persist_wal db 1 } {0 1} do_test walpersist-1.7 { file_control_persist_wal db -1 } {0 1} do_test walpersist-1.8 { file_control_persist_wal db 0 } {0 0} do_test walpersist-1.9 { file_control_persist_wal db -1 } {0 0} do_test walpersist-1.10 { file_control_persist_wal db 1 } {0 1} do_test walpersist-1.11 { db close list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm] } {1 1 1} finish_test |