Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch branch-3.7.4 Excluding Merge-Ins
This is equivalent to a diff from a586a4deeb to 8609a15dfa
2011-02-23
| ||
14:33 | Automatically retry system calls that fail with EINTR. This is a backport of the changes from [b9d29ea385bafc] and [af9ba2a6d2c379]. (Leaf check-in: 8609a15dfa user: drh tags: branch-3.7.4) | |
14:05 | Backport the os_unix.c error logging enhancements from check-in [01076528a43b61a]. (check-in: a4333b1545 user: drh tags: branch-3.7.4) | |
2011-02-20
| ||
03:11 | Backport the SQLITE_PROTOCOL fix and the extra defensive measure to version 3.7.4. (check-in: bcc22c4b80 user: drh tags: branch-3.7.4) | |
2010-12-07
| ||
23:24 | Improved documentation for SQLITE_FCNTL_FILE_POINTER. (check-in: 43935548ae user: drh tags: trunk) | |
20:14 | Version 3.7.4 (check-in: a586a4deeb user: drh tags: trunk, release, version-3.7.4) | |
17:12 | Work around restriction in Windows file locking. (check-in: fe441df9ba user: shaneh tags: trunk) | |
Changes to src/btree.c.
︙ | ︙ | |||
2382 2383 2384 2385 2386 2387 2388 | pBt->usableSize = usableSize; pBt->pageSize = pageSize; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); return rc; } | | | 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 | pBt->usableSize = usableSize; pBt->pageSize = pageSize; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); return rc; } if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } if( usableSize<480 ){ goto page1_init_failed; } pBt->pageSize = pageSize; |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 | errno = savedErrno; return s; } #define fcntl lockTrace #endif /* SQLITE_LOCK_TRACE */ /* ** This routine translates a standard POSIX errno code into something ** useful to the clients of the sqlite3 functions. Specifically, it is ** intended to translate a variety of "try again" errors into SQLITE_BUSY ** and a variety of "please close the file descriptor NOW" errors into ** SQLITE_IOERR | > > > > > > > > > > > > > | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | errno = savedErrno; return s; } #define fcntl lockTrace #endif /* SQLITE_LOCK_TRACE */ /* ** Retry ftruncate() calls that fail due to EINTR */ #ifdef EINTR static int robust_ftruncate(int h, sqlite3_int64 sz){ int rc; do{ rc = ftruncate(h,sz); }while( rc<0 && errno==EINTR ); return rc; } #else # define robust_ftruncate(a,b) ftruncate(a,b) #endif /* ** This routine translates a standard POSIX errno code into something ** useful to the clients of the sqlite3 functions. Specifically, it is ** intended to translate a variety of "try again" errors into SQLITE_BUSY ** and a variety of "please close the file descriptor NOW" errors into ** SQLITE_IOERR |
︙ | ︙ | |||
731 732 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 | #endif }; /* ** A lists of all unixInodeInfo objects. */ static unixInodeInfo *inodeList = 0; /* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. ** If all such file descriptors are closed without error, the list is ** cleared and SQLITE_OK returned. ** ** Otherwise, if an error occurs, then successfully closed file descriptor ** entries are removed from the list, and SQLITE_IOERR_CLOSE returned. ** not deleted and SQLITE_IOERR_CLOSE returned. */ static int closePendingFds(unixFile *pFile){ int rc = SQLITE_OK; unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *pError = 0; UnixUnusedFd *p; UnixUnusedFd *pNext; for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; if( close(p->fd) ){ pFile->lastErrno = errno; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 | #endif }; /* ** A lists of all unixInodeInfo objects. */ static unixInodeInfo *inodeList = 0; /* ** ** This function - unixLogError_x(), is only ever called via the macro ** unixLogError(). ** ** It is invoked after an error occurs in an OS function and errno has been ** set. It logs a message using sqlite3_log() containing the current value of ** errno and, if possible, the human-readable equivalent from strerror() or ** strerror_r(). ** ** The first argument passed to the macro should be the error code that ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed (e.g. "unlink", "open") and the the associated file-system path, ** if any. */ #define unixLogError(a,b,c) unixLogError_x(a,b,c,__LINE__) static int unixLogError_x( int errcode, /* SQLite error code */ const char *zFunc, /* Name of OS function that failed */ const char *zPath, /* File path associated with error */ int iLine /* Source line number where error occurred */ ){ char *zErr; /* Message from strerror() or equivalent */ /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use ** the strerror() function to obtain the human-readable error message ** equivalent to errno. Otherwise, use strerror_r(). */ #if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R) char aErr[80]; memset(aErr, 0, sizeof(aErr)); zErr = aErr; /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, ** assume that the system provides the the GNU version of strerror_r() that ** returns a pointer to a buffer containing the error message. That pointer ** may point to aErr[], or it may point to some static storage somewhere. ** Otherwise, assume that the system provides the POSIX version of ** strerror_r(), which always writes an error message into aErr[]. ** ** If the code incorrectly assumes that it is the POSIX version that is ** available, the error message will often be an empty string. Not a ** huge problem. Incorrectly concluding that the GNU version is available ** could lead to a segfault though. */ #if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) zErr = # endif strerror_r(errno, aErr, sizeof(aErr)-1); #elif SQLITE_THREADSAFE /* This is a threadsafe build, but strerror_r() is not available. */ zErr = ""; #else /* Non-threadsafe build, use strerror(). */ zErr = strerror(errno); #endif assert( errcode!=SQLITE_OK ); sqlite3_log(errcode, "os_unix.c: %s() at line %d - \"%s\" errno=%d path=%s", zFunc, iLine, zErr, errno, (zPath ? zPath : "n/a") ); return errcode; } /* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. ** If all such file descriptors are closed without error, the list is ** cleared and SQLITE_OK returned. ** ** Otherwise, if an error occurs, then successfully closed file descriptor ** entries are removed from the list, and SQLITE_IOERR_CLOSE returned. ** not deleted and SQLITE_IOERR_CLOSE returned. */ static int closePendingFds(unixFile *pFile){ int rc = SQLITE_OK; unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *pError = 0; UnixUnusedFd *p; UnixUnusedFd *pNext; for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; if( close(p->fd) ){ pFile->lastErrno = errno; rc = unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath); p->pNext = pError; pError = p; }else{ sqlite3_free(p); } } pInode->pUnused = pError; |
︙ | ︙ | |||
839 840 841 842 843 844 845 | ** prior to accessing the inode number. The one byte written is ** an ASCII 'S' character which also happens to be the first byte ** in the header of every SQLite database. In this way, if there ** is a race condition such that another thread has already populated ** the first page of the database, no damage is done. */ if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){ | | | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | ** prior to accessing the inode number. The one byte written is ** an ASCII 'S' character which also happens to be the first byte ** in the header of every SQLite database. In this way, if there ** is a race condition such that another thread has already populated ** the first page of the database, no damage is done. */ if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){ do{ rc = write(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ pFile->lastErrno = errno; return SQLITE_IOERR; } rc = fstat(fd, &statbuf); if( rc!=0 ){ pFile->lastErrno = errno; |
︙ | ︙ | |||
1404 1405 1406 1407 1408 1409 1410 | static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; if( pFile ){ if( pFile->dirfd>=0 ){ int err = close(pFile->dirfd); if( err ){ pFile->lastErrno = errno; | | | | 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 | static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; if( pFile ){ if( pFile->dirfd>=0 ){ int err = close(pFile->dirfd); if( err ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath); }else{ pFile->dirfd=-1; } } if( pFile->h>=0 ){ int err = close(pFile->h); if( err ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_CLOSE, "close", pFile->zPath); } } #if OS_VXWORKS if( pFile->pId ){ if( pFile->isDelete ){ unlink(pFile->pId->zCanonicalName); } |
︙ | ︙ | |||
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | ** only a single process can be reading the database at a time. ** ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if ** compiling for VXWORKS. */ #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ | > > > > > > > > > > > > > > | 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 | ** only a single process can be reading the database at a time. ** ** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if ** compiling for VXWORKS. */ #if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS /* ** Retry flock() calls that fail with EINTR */ #ifdef EINTR static int robust_flock(int fd, int op){ int rc; do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR ); return rc; } #else # define robust_flock(a,b) flock(a,b) #endif /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, set *pResOut ** to a non-zero value otherwise *pResOut is set to zero. The return value ** is set to SQLITE_OK unless an I/O error occurs during lock checking. */ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ |
︙ | ︙ | |||
1738 1739 1740 1741 1742 1743 1744 | if( pFile->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ /* attempt to get the lock */ | | | | 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 | if( pFile->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ if( !reserved ){ /* attempt to get the lock */ int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB); if( !lrc ){ /* got the lock, unlock it */ lrc = robust_flock(pFile->h, LOCK_UN); if ( lrc ) { int tErrno = errno; /* unlock failed with an error */ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(lrc) ){ pFile->lastErrno = tErrno; rc = lrc; |
︙ | ︙ | |||
1818 1819 1820 1821 1822 1823 1824 | if (pFile->eFileLock > NO_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* grab an exclusive lock */ | | | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 | if (pFile->eFileLock > NO_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* grab an exclusive lock */ if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) { int tErrno = errno; /* didn't get, must be busy */ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } } else { |
︙ | ︙ | |||
1867 1868 1869 1870 1871 1872 1873 | /* shared can just be set because we always have an exclusive */ if (eFileLock==SHARED_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* no, really, unlock. */ | | | 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 | /* shared can just be set because we always have an exclusive */ if (eFileLock==SHARED_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } /* no, really, unlock. */ int rc = robust_flock(pFile->h, LOCK_UN); if (rc) { int r, tErrno = errno; r = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(r) ){ pFile->lastErrno = tErrno; } #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS |
︙ | ︙ | |||
2604 2605 2606 2607 2608 2609 2610 | static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; #if defined(USE_PREAD) | | | | | 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 | static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ int got; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; #if defined(USE_PREAD) do{ got = pread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); SimulateIOError( got = -1 ); #elif defined(USE_PREAD64) do{ got = pread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); SimulateIOError( got = -1 ); #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; } do{ got = read(id->h, pBuf, cnt); }while( got<0 && errno==EINTR ); #endif TIMER_END; if( got<0 ){ ((unixFile*)id)->lastErrno = errno; } OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED)); return got; |
︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 | static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ int got; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; #if defined(USE_PREAD) | | | | | 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 | static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ int got; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; #if defined(USE_PREAD) do{ got = pwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ got = pwrite64(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; } do{ got = write(id->h, pBuf, cnt); }while( got<0 && errno==EINTR ); #endif TIMER_END; if( got<0 ){ ((unixFile*)id)->lastErrno = errno; } OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED)); |
︙ | ︙ | |||
2935 2936 2937 2938 2939 2940 2941 | assert( pFile ); OSTRACE(("SYNC %-3d\n", pFile->h)); rc = full_fsync(pFile->h, isFullsync, isDataOnly); SimulateIOError( rc=1 ); if( rc ){ pFile->lastErrno = errno; | | | 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 | assert( pFile ); OSTRACE(("SYNC %-3d\n", pFile->h)); rc = full_fsync(pFile->h, isFullsync, isDataOnly); SimulateIOError( rc=1 ); if( rc ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); } if( pFile->dirfd>=0 ){ int err; OSTRACE(("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd, HAVE_FULLFSYNC, isFullsync)); #ifndef SQLITE_DISABLE_DIRSYNC /* The directory sync is only attempted if full_fsync is |
︙ | ︙ | |||
2962 2963 2964 2965 2966 2967 2968 | } #endif err = close(pFile->dirfd); /* Only need to sync once, so close the */ if( err==0 ){ /* directory when we are done */ pFile->dirfd = -1; }else{ pFile->lastErrno = errno; | | | 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 | } #endif err = close(pFile->dirfd); /* Only need to sync once, so close the */ if( err==0 ){ /* directory when we are done */ pFile->dirfd = -1; }else{ pFile->lastErrno = errno; rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", pFile->zPath); } } return rc; } /* ** Truncate an open file to a specified size |
︙ | ︙ | |||
2986 2987 2988 2989 2990 2991 2992 | ** actual file size after the operation may be larger than the requested ** size). */ if( pFile->szChunk ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } | | | | 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 | ** actual file size after the operation may be larger than the requested ** size). */ if( pFile->szChunk ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } rc = robust_ftruncate(pFile->h, (off_t)nByte); if( rc ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); }else{ #ifndef NDEBUG /* If we are doing a normal write to a database file (as opposed to ** doing a hot-journal rollback or a write to some file other than a ** normal database file) and we truncate the file to zero length, ** that effectively updates the change counter. This might happen ** when restoring a database using the backup API from a zero-length |
︙ | ︙ | |||
3061 3062 3063 3064 3065 3066 3067 | struct stat buf; /* Used to hold return values of fstat() */ if( fstat(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 | > > | > | < | | | 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 | struct stat buf; /* Used to hold return values of fstat() */ if( fstat(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 int rc; do{ rc = posix_fallocate(pFile-.h, buf.st_size, nSize-buf.st_size; }while( rc<0 && errno=EINTR ); if( rc ) return SQLITE_IOERR_WRITE; #else /* If the OS does not have posix_fallocate(), fake it. First use ** ftruncate() to set the file size, then write a single byte to ** 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. */ int nBlk = buf.st_blksize; /* File-system block size */ i64 iWrite; /* Next offset to write to */ int nWrite; /* Return value from seekAndWrite() */ if( robust_ftruncate(pFile->h, nSize) ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); } iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1; do { nWrite = seekAndWrite(pFile, iWrite, "", 1); iWrite += nBlk; } while( nWrite==1 && iWrite<nSize ); if( nWrite!=1 ) return SQLITE_IOERR_WRITE; |
︙ | ︙ | |||
3423 3424 3425 3426 3427 3428 3429 | if( pShmNode->mutex==0 ){ rc = SQLITE_NOMEM; goto shm_open_err; } pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777)); if( pShmNode->h<0 ){ | | | | | 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 | if( pShmNode->mutex==0 ){ rc = SQLITE_NOMEM; goto shm_open_err; } pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777)); if( pShmNode->h<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename); goto shm_open_err; } /* Check to see if another process is holding the dead-man switch. ** If not, truncate the file to zero length. */ rc = SQLITE_OK; if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ if( robust_ftruncate(pShmNode->h, 0) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename); } } if( rc==SQLITE_OK ){ rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1); } if( rc ) goto shm_open_err; } |
︙ | ︙ | |||
3538 3539 3540 3541 3542 3543 3544 | /* The requested memory region does not exist. If bExtend is set to ** false, exit early. *pp will be set to NULL and SQLITE_OK returned. ** ** Alternatively, if bExtend is true, use ftruncate() to allocate ** the requested memory region. */ if( !bExtend ) goto shmpage_out; | | | | 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 | /* The requested memory region does not exist. If bExtend is set to ** false, exit early. *pp will be set to NULL and SQLITE_OK returned. ** ** Alternatively, if bExtend is true, use ftruncate() to allocate ** the requested memory region. */ if( !bExtend ) goto shmpage_out; if( robust_ftruncate(pShmNode->h, nByte) ){ rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename); goto shmpage_out; } } /* Map the requested memory region into this processes address space. */ apNew = (char **)sqlite3_realloc( pShmNode->apRegion, (iRegion+1)*sizeof(char *) |
︙ | ︙ | |||
4258 4259 4260 4261 4262 4263 4264 | #ifdef FD_CLOEXEC fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); } } *pFd = fd; | | | 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 | #ifdef FD_CLOEXEC fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); } } *pFd = fd; return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname)); } /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. */ static const char *unixTempFileDir(void){ |
︙ | ︙ | |||
4599 4600 4601 4602 4603 4604 4605 | flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); openFlags &= ~(O_RDWR|O_CREAT); flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; fd = open(zName, openFlags, openMode); } if( fd<0 ){ | | | 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 | flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); openFlags &= ~(O_RDWR|O_CREAT); flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; fd = open(zName, openFlags, openMode); } if( fd<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); goto open_finished; } } assert( fd>=0 ); if( pOutFlags ){ *pOutFlags = flags; } |
︙ | ︙ | |||
4731 4732 4733 4734 4735 4736 4737 | const char *zPath, /* Name of file to be deleted */ int dirSync /* If true, fsync() directory after deleting file */ ){ int rc = SQLITE_OK; UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); if( unlink(zPath)==(-1) && errno!=ENOENT ){ | | | | | 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 | const char *zPath, /* Name of file to be deleted */ int dirSync /* If true, fsync() directory after deleting file */ ){ int rc = SQLITE_OK; UNUSED_PARAMETER(NotUsed); SimulateIOError(return SQLITE_IOERR_DELETE); if( unlink(zPath)==(-1) && errno!=ENOENT ){ return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); } #ifndef SQLITE_DISABLE_DIRSYNC if( dirSync ){ int fd; rc = openDirectory(zPath, &fd); if( rc==SQLITE_OK ){ #if OS_VXWORKS if( fsync(fd)==-1 ) #else if( fsync(fd) ) #endif { rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } if( close(fd)&&!rc ){ rc = unixLogError(SQLITE_IOERR_DIR_CLOSE, "close", zPath); } } } #endif return rc; } |
︙ | ︙ | |||
4831 4832 4833 4834 4835 4836 4837 | zOut[nOut-1] = '\0'; if( zPath[0]=='/' ){ sqlite3_snprintf(nOut, zOut, "%s", zPath); }else{ int nCwd; if( getcwd(zOut, nOut-1)==0 ){ | | | 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 | zOut[nOut-1] = '\0'; if( zPath[0]=='/' ){ sqlite3_snprintf(nOut, zOut, "%s", zPath); }else{ int nCwd; if( getcwd(zOut, nOut-1)==0 ){ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); } nCwd = (int)strlen(zOut); sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath); } return SQLITE_OK; } |
︙ | ︙ | |||
4935 4936 4937 4938 4939 4940 4941 | time(&t); memcpy(zBuf, &t, sizeof(t)); pid = getpid(); memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf ); nBuf = sizeof(t) + sizeof(pid); }else{ | | | 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 | time(&t); memcpy(zBuf, &t, sizeof(t)); pid = getpid(); memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf ); nBuf = sizeof(t) + sizeof(pid); }else{ do{ nBuf = read(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR ); close(fd); } } #endif return nBuf; } |
︙ | ︙ | |||
5695 5696 5697 5698 5699 5700 5701 | memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); if( pCtx->lockProxyPath!=NULL ){ strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN); }else{ strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN); } writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]); | | > > | > > | 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 | memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); if( pCtx->lockProxyPath!=NULL ){ strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, MAXPATHLEN); }else{ strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN); } writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]); robust_ftruncate(conchFile->h, writeSize); rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0); fsync(conchFile->h); /* If we created a new conch file (not just updated the contents of a ** valid conch file), try to match the permissions of the database */ if( rc==SQLITE_OK && createConch ){ struct stat buf; int rc; int err = fstat(pFile->h, &buf); if( err==0 ){ mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH); /* try to match the database file R/W permissions, ignore failure */ #ifndef SQLITE_PROXY_DEBUG fchmod(conchFile->h, cmode); #else do{ rc = fchmod(conchFile->h, cmode); }while( rc==(-1) && errno==EINTR ); if( rc!=0 ){ int code = errno; fprintf(stderr, "fchmod %o FAILED with %d %s\n", cmode, code, strerror(code)); } else { fprintf(stderr, "fchmod %o SUCCEDED\n",cmode); } }else{ |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 | rc = pagerUndoCallback((void *)pPager, pList->pgno); pList = pNext; } return rc; } /* ** This function is a wrapper around sqlite3WalFrames(). As well as logging ** the contents of the list of pages headed by pList (connected by pDirty), ** this function notifies any active backup processes that the pages have | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > < < | > | 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 | rc = pagerUndoCallback((void *)pPager, pList->pgno); pList = pNext; } return rc; } /* ** Update the value of the change-counter at offsets 24 and 92 in ** the header and the sqlite version number at offset 96. ** ** This is an unconditional update. See also the pager_incr_changecounter() ** routine which only updates the change-counter if the update is actually ** needed, as determined by the pPager->changeCountDone state variable. */ static void pager_write_changecounter(PgHdr *pPg){ u32 change_counter; /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1; put32bits(((char*)pPg->pData)+24, change_counter); /* Also store the SQLite version number in bytes 96..99 and in ** bytes 92..95 store the change counter for which the version number ** is valid. */ put32bits(((char*)pPg->pData)+92, change_counter); put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER); } /* ** This function is a wrapper around sqlite3WalFrames(). As well as logging ** the contents of the list of pages headed by pList (connected by pDirty), ** this function notifies any active backup processes that the pages have ** changed. ** ** The list of pages passed into this routine is always sorted by page number. ** Hence, if page 1 appears anywhere on the list, it will be the first page. */ static int pagerWalFrames( Pager *pPager, /* Pager object */ PgHdr *pList, /* List of frames to log */ Pgno nTruncate, /* Database size after this commit */ int isCommit, /* True if this is a commit */ int syncFlags /* Flags to pass to OsSync() (or 0) */ ){ int rc; /* Return code */ #if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES) PgHdr *p; /* For looping over pages */ #endif assert( pPager->pWal ); #ifdef SQLITE_DEBUG /* Verify that the page list is in accending order */ for(p=pList; p && p->pDirty; p=p->pDirty){ assert( p->pgno < p->pDirty->pgno ); } #endif if( pList->pgno==1 ) pager_write_changecounter(pList); rc = sqlite3WalFrames(pPager->pWal, pPager->pageSize, pList, nTruncate, isCommit, syncFlags ); if( rc==SQLITE_OK && pPager->pBackup ){ PgHdr *p; for(p=pList; p; p=p->pDirty){ sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData); } } #ifdef SQLITE_CHECK_PAGES for(p=pList; p; p=p->pDirty){ pager_set_pagehash(p); } #endif return rc; } /* |
︙ | ︙ | |||
3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 | ** set (set by sqlite3PagerDontWrite()). */ if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */ char *pData; /* Data to write */ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); /* Encode the database */ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData); /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); | > | 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 | ** set (set by sqlite3PagerDontWrite()). */ if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */ char *pData; /* Data to write */ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); /* Encode the database */ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData); /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); |
︙ | ︙ | |||
5485 5486 5487 5488 5489 5490 5491 | pager_set_pagehash(pPg); } } /* ** This routine is called to increment the value of the database file ** change-counter, stored as a 4-byte big-endian integer starting at | | > > > > > > | 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 | pager_set_pagehash(pPg); } } /* ** This routine is called to increment the value of the database file ** change-counter, stored as a 4-byte big-endian integer starting at ** byte offset 24 of the pager file. The secondary change counter at ** 92 is also updated, as is the SQLite version number at offset 96. ** ** But this only happens if the pPager->changeCountDone flag is false. ** To avoid excess churning of page 1, the update only happens once. ** See also the pager_write_changecounter() routine that does an ** unconditional update of the change counters. ** ** If the isDirectMode flag is zero, then this is done by calling ** sqlite3PagerWrite() on page 1, then modifying the contents of the ** page data. In this case the file will be updated when the current ** transaction is committed. ** ** The isDirectMode flag may only be non-zero if the library was compiled |
︙ | ︙ | |||
5526 5527 5528 5529 5530 5531 5532 | UNUSED_PARAMETER(isDirectMode); #else # define DIRECT_MODE isDirectMode #endif if( !pPager->changeCountDone && pPager->dbSize>0 ){ PgHdr *pPgHdr; /* Reference to page 1 */ | < | < < | < | < < < < < | 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 | UNUSED_PARAMETER(isDirectMode); #else # define DIRECT_MODE isDirectMode #endif if( !pPager->changeCountDone && pPager->dbSize>0 ){ PgHdr *pPgHdr; /* Reference to page 1 */ assert( !pPager->tempFile && isOpen(pPager->fd) ); /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr); assert( pPgHdr==0 || rc==SQLITE_OK ); /* If page one was fetched successfully, and this function is not ** operating in direct-mode, make page 1 writable. When not in ** direct mode, page 1 is always held in cache and hence the PagerGet() ** above is always successful - hence the ALWAYS on rc==SQLITE_OK. */ if( !DIRECT_MODE && rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPgHdr); } if( rc==SQLITE_OK ){ /* Actually do the update of the change counter */ pager_write_changecounter(pPgHdr); /* If running in direct mode, write the contents of page 1 to the file. */ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf); if( rc==SQLITE_OK ){ |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
1569 1570 1571 1572 1573 1574 1575 | u32 mxPage; /* Max database page to write */ int i; /* Loop counter */ volatile WalCkptInfo *pInfo; /* The checkpoint status information */ szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); testcase( szPage<=32768 ); testcase( szPage>=65536 ); | > | | 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 | u32 mxPage; /* Max database page to write */ int i; /* Loop counter */ volatile WalCkptInfo *pInfo; /* The checkpoint status information */ szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); testcase( szPage<=32768 ); testcase( szPage>=65536 ); pInfo = walCkptInfo(pWal); if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK; /* Allocate the iterator */ rc = walIteratorInit(pWal, &pIter); if( rc!=SQLITE_OK ){ return rc; } assert( pIter ); |
︙ | ︙ | |||
1591 1592 1593 1594 1595 1596 1597 | /* Compute in mxSafeFrame the index of the last frame of the WAL that is ** safe to write into the database. Frames beyond mxSafeFrame might ** overwrite database pages that are in use by active readers and thus ** cannot be backfilled from the WAL. */ mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; | < | 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 | /* Compute in mxSafeFrame the index of the last frame of the WAL that is ** safe to write into the database. Frames beyond mxSafeFrame might ** overwrite database pages that are in use by active readers and thus ** cannot be backfilled from the WAL. */ mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; for(i=1; i<WAL_NREADER; i++){ u32 y = pInfo->aReadMark[i]; if( mxSafeFrame>=y ){ assert( y<=pWal->hdr.mxFrame ); rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ pInfo->aReadMark[i] = READMARK_NOT_USED; |
︙ | ︙ | |||
1912 1913 1914 1915 1916 1917 1918 | u32 mxReadMark; /* Largest aReadMark[] value */ int mxI; /* Index of largest aReadMark[] value */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ assert( pWal->readLock<0 ); /* Not currently locked */ | | > > > > > > > > > > > > > > > > > | > > > > | | 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 | u32 mxReadMark; /* Largest aReadMark[] value */ int mxI; /* Index of largest aReadMark[] value */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ assert( pWal->readLock<0 ); /* Not currently locked */ /* Take steps to avoid spinning forever if there is a protocol error. ** ** Circumstances that cause a RETRY should only last for the briefest ** instances of time. No I/O or other system calls are done while the ** locks are held, so the locks should not be held for very long. But ** if we are unlucky, another process that is holding a lock might get ** paged out or take a page-fault that is time-consuming to resolve, ** during the few nanoseconds that it is holding the lock. In that case, ** it might take longer than normal for the lock to free. ** ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this ** is more of a scheduler yield than an actual delay. But on the 10th ** an subsequent retries, the delays start becoming longer and longer, ** so that on the 100th (and last) RETRY we delay for 21 milliseconds. ** The total delay time before giving up is less than 1 second. */ if( cnt>5 ){ int nDelay = 1; /* Pause time in microseconds */ if( cnt>100 ){ VVA_ONLY( pWal->lockError = 1; ) return SQLITE_PROTOCOL; } if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */ sqlite3OsSleep(pWal->pVfs, nDelay); } if( !useWal ){ rc = walIndexReadHdr(pWal, pChanged); if( rc==SQLITE_BUSY ){ /* If there is not a recovery running in another thread or process ** then convert BUSY errors to WAL_RETRY. If recovery is known to |
︙ | ︙ | |||
1997 1998 1999 2000 2001 2002 2003 | u32 thisMark = pInfo->aReadMark[i]; if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; mxI = i; } } | | < < < < < < < < < < < < < < > | > > > > | 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 | u32 thisMark = pInfo->aReadMark[i]; if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; mxI = i; } } /* There was once an "if" here. The extra "{" is to preserve indentation. */ { if( mxReadMark < pWal->hdr.mxFrame || mxI==0 ){ for(i=1; i<WAL_NREADER; i++){ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame; mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; }else if( rc!=SQLITE_BUSY ){ return rc; } } } if( mxI==0 ){ assert( rc==SQLITE_BUSY ); return WAL_RETRY; } rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); if( rc ){ return rc==SQLITE_BUSY ? WAL_RETRY : rc; } /* Now that the read-lock has been obtained, check that neither the ** value in the aReadMark[] array or the contents of the wal-index |
︙ | ︙ | |||
2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 | int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ int cnt = 0; /* Number of TryBeginRead attempts */ do{ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); }while( rc==WAL_RETRY ); return rc; } /* ** Finish with a read transaction. All this does is release the ** read-lock. */ | > > > > | 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 | int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ int cnt = 0; /* Number of TryBeginRead attempts */ do{ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); }while( rc==WAL_RETRY ); testcase( (rc&0xff)==SQLITE_BUSY ); testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); return rc; } /* ** Finish with a read transaction. All this does is release the ** read-lock. */ |
︙ | ︙ | |||
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 | int rc = SQLITE_OK; int cnt; if( pWal->readLock==0 ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); if( pInfo->nBackfill>0 ){ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ /* If all readers are using WAL_READ_LOCK(0) (in other words if no ** readers are currently using the WAL), then the transactions ** frames will overwrite the start of the existing log. Update the ** wal-index header to reflect this. ** ** In theory it would be Ok to update the cache of the header only ** at this point. But updating the actual wal-index header is also ** safe and means there is no special case for sqlite3WalUndo() ** to handle if this transaction is rolled back. */ int i; /* Loop counter */ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ pWal->nCkpt++; pWal->hdr.mxFrame = 0; sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); | > > | > > > > | 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 | int rc = SQLITE_OK; int cnt; if( pWal->readLock==0 ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); assert( pInfo->nBackfill==pWal->hdr.mxFrame ); if( pInfo->nBackfill>0 ){ u32 salt1; sqlite3_randomness(4, &salt1); rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ /* If all readers are using WAL_READ_LOCK(0) (in other words if no ** readers are currently using the WAL), then the transactions ** frames will overwrite the start of the existing log. Update the ** wal-index header to reflect this. ** ** In theory it would be Ok to update the cache of the header only ** at this point. But updating the actual wal-index header is also ** safe and means there is no special case for sqlite3WalUndo() ** to handle if this transaction is rolled back. */ int i; /* Loop counter */ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ pWal->nCkpt++; pWal->hdr.mxFrame = 0; sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); aSalt[1] = salt1; walIndexWriteHdr(pWal); pInfo->nBackfill = 0; for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED; assert( pInfo->aReadMark[0]==0 ); walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); }else if( rc!=SQLITE_BUSY ){ return rc; } } walUnlockShared(pWal, WAL_READ_LOCK(0)); pWal->readLock = -1; cnt = 0; do{ int notUsed; rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt); }while( rc==WAL_RETRY ); assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */ testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); } return rc; } /* ** Write a set of frames to the log. The caller must hold the write-lock ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
2311 2312 2313 2314 2315 2316 2317 | #ifdef SQLITE_ENABLE_STAT2 static int valueFromExpr( Parse *pParse, Expr *pExpr, u8 aff, sqlite3_value **pp ){ | < < | | > | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 | #ifdef SQLITE_ENABLE_STAT2 static int valueFromExpr( Parse *pParse, Expr *pExpr, u8 aff, sqlite3_value **pp ){ if( pExpr->op==TK_VARIABLE || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) ){ int iVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-23257-02778 */ *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff); return SQLITE_OK; } return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp); } |
︙ | ︙ |
Changes to test/exclusive2.test.
︙ | ︙ | |||
295 296 297 298 299 300 301 | } {4} do_test exclusive2-3.5 { execsql { PRAGMA locking_mode = normal; INSERT INTO t1 VALUES(randstr(10, 400)); } readPagerChangeCounter test.db | | | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | } {4} do_test exclusive2-3.5 { execsql { PRAGMA locking_mode = normal; INSERT INTO t1 VALUES(randstr(10, 400)); } readPagerChangeCounter test.db } {5} do_test exclusive2-3.6 { execsql { INSERT INTO t1 VALUES(randstr(10, 400)); } readPagerChangeCounter test.db } {6} sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) finish_test |
Changes to test/filefmt.test.
︙ | ︙ | |||
188 189 190 191 192 193 194 195 196 | } {ok} integrity_check filefmt-2.2.5 do_execsql_test filefmt-2.2.6 { COMMIT } {} db close sqlite3 db test.db integrity_check filefmt-2.2.7 finish_test | > > > > > > > > > > > > > > > > > > > > | 188 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 | } {ok} integrity_check filefmt-2.2.5 do_execsql_test filefmt-2.2.6 { COMMIT } {} db close sqlite3 db test.db integrity_check filefmt-2.2.7 #-------------------------------------------------------------------------- # Check that ticket 89b8c9ac54 is fixed. Before the fix, the SELECT # statement would return SQLITE_CORRUPT. The database file was not actually # corrupted, but SQLite was reporting that it was. # db close forcedelete test.db sqlite3 db test.db do_execsql_test filefmt-3.1 { PRAGMA auto_vacuum = 1; CREATE TABLE t1(a, b); } {} do_test filefmt-3.2 { sql36231 { DROP TABLE t1 } } {} do_execsql_test filefmt-3.3 { SELECT * FROM sqlite_master; PRAGMA integrity_check; } {ok} finish_test |
Added test/oserror.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 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 | # 2011 February 19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing that error messages are logged via the # sqlite3_log() mechanism when certain errors are encountered in the # default unix or windows VFS modules. # set testdir [file dirname $argv0] source $testdir/tester.tcl if {$::tcl_platform(platform)!="unix"} { finish_test ; return } set ::testprefix oserror db close sqlite3_shutdown test_sqlite3_log xLog proc xLog {error_code msg} { if {[string match os_* $msg]} { lappend ::log $msg } } proc do_re_test {tn script expression} { uplevel do_test $tn [list [subst -nocommands { set res [eval { $script }] if {[regexp {$expression} [set res]]} { set {} {$expression} } else { set res } }]] [list $expression] } #-------------------------------------------------------------------------- # Tests oserror-1.* test failures in the open() system call. # # Test a failure in open() due to too many files. # do_test 1.1.1 { set ::log [list] list [catch { for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } } msg] $msg } {1 {unable to open database file}} do_test 1.1.2 { catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } } } {1} do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c: open.*test.db$} # Test a failure in open() due to the path being a directory. # do_test 1.2.1 { file mkdir dir.db set ::log [list] list [catch { sqlite3 dbh dir.db } msg] $msg } {1 {unable to open database file}} do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c: open.*dir.db$} # Test a failure in open() due to the path not existing. # do_test 1.3.1 { set ::log [list] list [catch { sqlite3 dbh /x/y/z/test.db } msg] $msg } {1 {unable to open database file}} do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$} # Test a failure in open() due to the path not existing. # do_test 1.4.1 { set ::log [list] list [catch { sqlite3 dbh /root/test.db } msg] $msg } {1 {unable to open database file}} do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$} #-------------------------------------------------------------------------- # Tests oserror-1.* test failures in the unlink() system call. # do_test 2.1.1 { set ::log [list] file mkdir test.db-wal forcedelete test.db sqlite3 dbh test.db catchsql { SELECT * FROM sqlite_master } dbh } {1 {disk I/O error}} do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c: unlink.*test.db-wal$} do_test 2.1.3 { dbh close forcedelete test.db-wal } {} sqlite3_shutdown test_sqlite3_log sqlite3_initialize finish_test |
Changes to tool/mksqlite3h.tcl.
︙ | ︙ | |||
49 50 51 52 53 54 55 | # Get the fossil-scm check-in date from the "D" card of $TOP/manifest. # set in [open $TOP/manifest] set zDate {} while {![eof $in]} { set line [gets $in] | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | # Get the fossil-scm check-in date from the "D" card of $TOP/manifest. # set in [open $TOP/manifest] set zDate {} while {![eof $in]} { set line [gets $in] if {[regexp {^D (2[-0-9T:]+)} $line all date]} { set zDate [string map {T { }} $date] break } } close $in # Set up patterns for recognizing API declarations. |
︙ | ︙ |