Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Further enhancements to comments in pager.c. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | experimental |
Files: | files | file ages | folders |
SHA1: |
876162c7e036af1cb447409b685afc72 |
User & Date: | dan 2010-08-06 17:18:01.000 |
Context
2010-08-07
| ||
05:15 | Add test case 'cgt_pager_1', intended for use with callgrind to detect performance regression in the pager module, to threadtest3.c. (check-in: b5d46f1ea0 user: dan tags: experimental) | |
2010-08-06
| ||
17:18 | Further enhancements to comments in pager.c. (check-in: 876162c7e0 user: dan tags: experimental) | |
14:37 | Fix some problems with running test scripts with the inmemory_journal permutation. (check-in: 7bd8ba084e user: dan tags: experimental) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
493 494 495 496 497 498 499 | ** The flag is cleared as soon as the journal file is finalized (either ** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the ** journal file from being successfully finalized, the setMaster flag ** is cleared anyway (and the pager will move to ERROR state). ** ** doNotSpill, doNotSyncSpill ** | > > > > | > > > > > | | > | | < < | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | ** The flag is cleared as soon as the journal file is finalized (either ** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the ** journal file from being successfully finalized, the setMaster flag ** is cleared anyway (and the pager will move to ERROR state). ** ** doNotSpill, doNotSyncSpill ** ** These two boolean variables control the behaviour of cache-spills ** (calls made by the pcache module to the pagerStress() routine to ** write cached data to the file-system in order to free up memory). ** ** When doNotSpill is non-zero, writing to the database from pagerStress() ** is disabled altogether. This is done in a very obscure case that ** comes up during savepoint rollback that requires the pcache module ** to allocate a new page to prevent the journal file from being written ** while it is being traversed by code in pager_playback(). ** ** If doNotSyncSpill is non-zero, writing to the database from pagerStress() ** is permitted, but syncing the journal file is not. This flag is set ** by sqlite3PagerWrite() when the file-system sector-size is larger than ** the database page-size in order to prevent a journal sync from happening ** in between the journalling of two pages on the same sector. ** ** subjInMemory ** ** This is a boolean variable. If true, then any required sub-journal ** is opened as an in-memory journal file. If false, then in-memory ** sub-journals are only used for in-memory pager files. ** |
︙ | ︙ | |||
1746 1747 1748 1749 1750 1751 1752 | /* ** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening ** the journal file or writing the very first journal-header of a ** database transaction. ** | > | | | 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 | /* ** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening ** the journal file or writing the very first journal-header of a ** database transaction. ** ** This routine is never called in PAGER_ERROR state. If it is called ** in PAGER_NONE or PAGER_SHARED state and the lock held is less ** exclusive than a RESERVED lock, it is a no-op. ** ** Otherwise, any active savepoints are released. ** ** If the journal file is open, then it is "finalized". Once a journal ** file has been finalized it is not possible to use it to roll back a ** transaction. Nor will it be considered to be a hot-journal by this ** or any other database connection. Exactly how a journal is finalized |
︙ | ︙ | |||
1778 1779 1780 1781 1782 1783 1784 | ** The journal file is closed and deleted using sqlite3OsDelete(). ** ** If the pager is running in exclusive mode, this method of finalizing ** the journal file is never used. Instead, if the journalMode is ** DELETE and the pager is in exclusive mode, the method described under ** journalMode==PERSIST is used instead. ** | | | < < < | < | > > > > > > > > > > > > | 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 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 1825 1826 1827 1828 1829 1830 | ** The journal file is closed and deleted using sqlite3OsDelete(). ** ** If the pager is running in exclusive mode, this method of finalizing ** the journal file is never used. Instead, if the journalMode is ** DELETE and the pager is in exclusive mode, the method described under ** journalMode==PERSIST is used instead. ** ** After the journal is finalized, the pager moves to PAGER_READER state. ** If running in non-exclusive rollback mode, the lock on the file is ** downgraded to a SHARED_LOCK. ** ** SQLITE_OK is returned if no error occurs. If an error occurs during ** any of the IO operations to finalize the journal file or unlock the ** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still ** tries to unlock the database file if not in exclusive mode. If the ** unlock operation fails as well, then the first error code related ** to the first error encountered (the journal finalization one) is ** returned. */ static int pager_end_transaction(Pager *pPager, int hasMaster){ int rc = SQLITE_OK; /* Error code from journal finalization operation */ int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ /* Do nothing if the pager does not have an open write transaction ** or at least a RESERVED lock. This function may be called when there ** is no write-transaction active but a RESERVED or greater lock is ** held under two circumstances: ** ** 1. After a successful hot-journal rollback, it is called with ** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK. ** ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE ** lock switches back to locking_mode=normal and then executes a ** read-transaction, this function is called with eState==PAGER_READER ** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed. */ assert( assert_pager_state(pPager) ); assert( pPager->eState!=PAGER_ERROR ); if( pPager->eState<PAGER_WRITER_LOCKED && pPager->eLock<RESERVED_LOCK ){ return SQLITE_OK; } releaseAllSavepoints(pPager); |
︙ | ︙ | |||
1877 1878 1879 1880 1881 1882 1883 | return (rc==SQLITE_OK?rc2:rc); } /* ** Execute a rollback if a transaction is active and unlock the ** database file. ** | | | | | | | | | | 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 | return (rc==SQLITE_OK?rc2:rc); } /* ** Execute a rollback if a transaction is active and unlock the ** database file. ** ** If the pager has already entered the ERROR state, do not attempt ** the rollback at this time. Instead, pager_unlock() is called. The ** call to pager_unlock() will discard all in-memory pages, unlock ** the database file and move the pager back to OPEN state. If this ** means that there is a hot-journal left in the file-system, the next ** connection to obtain a shared lock on the pager (which may be this one) ** will roll it back. ** ** If the pager has not already entered the ERROR state, but an IO or ** malloc error occurs during a rollback, then this will itself cause ** the pager to enter the ERROR state. Which will be cleared by the ** call to pager_unlock(), as described above. */ static void pagerUnlockAndRollback(Pager *pPager){ if( pPager->eState!=PAGER_ERROR && pPager->eState!=PAGER_OPEN ){ assert( assert_pager_state(pPager) ); if( pPager->eState>=PAGER_WRITER_LOCKED ){ sqlite3BeginBenignMalloc(); sqlite3PagerRollback(pPager); sqlite3EndBenignMalloc(); }else if( !pPager->exclusiveMode ){ assert( pPager->eState==PAGER_READER ); pager_end_transaction(pPager, 0); } } pager_unlock(pPager); } |
︙ | ︙ | |||
1955 1956 1957 1958 1959 1960 1961 | /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. ** The page begins at offset *pOffset into the file. The *pOffset ** value is increased to the start of the next page in the journal. ** | < | | | 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 | /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. ** The page begins at offset *pOffset into the file. The *pOffset ** value is increased to the start of the next page in the journal. ** ** The main rollback journal uses checksums - the statement journal does ** not. ** ** If the page number of the page record read from the (sub-)journal file ** is greater than the current value of Pager.dbSize, then playback is ** skipped and SQLITE_OK is returned. ** ** If pDone is not NULL, then it is a record of pages that have already ** been played back. If the page at *pOffset has already been played back |
︙ | ︙ | |||
2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 | assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */ assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */ aData = pPager->pTmpSpace; assert( aData ); /* Temp storage must have already been allocated */ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) ); /* Read the page number and page data from the journal or sub-journal ** file. Return an error code to the caller if an IO error occurs. */ jfd = isMainJrnl ? pPager->jfd : pPager->sjfd; rc = read32bits(jfd, *pOffset, &pgno); if( rc!=SQLITE_OK ) return rc; | > > > > > > > > > > > | 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 | assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */ assert( isMainJrnl || pDone ); /* pDone always used on sub-journals */ assert( isSavepnt || pDone==0 ); /* pDone never used on non-savepoint */ aData = pPager->pTmpSpace; assert( aData ); /* Temp storage must have already been allocated */ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) ); /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction ** or savepoint rollback done at the request of the caller) or this is ** a hot-journal rollback. If it is a hot-journal rollback, the pager ** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback ** only reads from the main journal, not the sub-journal. */ assert( pPager->eState>=PAGER_WRITER_CACHEMOD || (pPager->eState==PAGER_OPEN && pPager->eLock==EXCLUSIVE_LOCK) ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD || isMainJrnl ); /* Read the page number and page data from the journal or sub-journal ** file. Return an error code to the caller if an IO error occurs. */ jfd = isMainJrnl ? pPager->jfd : pPager->sjfd; rc = read32bits(jfd, *pOffset, &pgno); if( rc!=SQLITE_OK ) return rc; |
︙ | ︙ | |||
2047 2048 2049 2050 2051 2052 2053 | /* If this page has already been played by before during the current ** rollback, then don't bother to play it back again. */ if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){ return rc; } | < < < | 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 | /* If this page has already been played by before during the current ** rollback, then don't bother to play it back again. */ if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){ return rc; } /* When playing back page 1, restore the nReserve setting */ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ pPager->nReserve = ((u8*)aData)[20]; pagerReportSize(pPager); } |
︙ | ︙ | |||
2859 2860 2861 2862 2863 2864 2865 | if( rc==SQLITE_OK && changed ){ pager_reset(pPager); } return rc; } | < > > > | > > > > > > > > > > > > > > > > > | | 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 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 | if( rc==SQLITE_OK && changed ){ pager_reset(pPager); } return rc; } /* ** This function is called as part of the transition from PAGER_OPEN ** to PAGER_READER state to determine the size of the database file ** in pages (assuming the page size currently stored in Pager.pageSize). ** ** If no error occurs, SQLITE_OK is returned and the size of the database ** in pages is stored in *pnPage. Otherwise, an error code (perhaps ** SQLITE_IOERR_FSTAT) is returned and *pnPage is left unmodified. */ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ Pgno nPage; /* Value to return via *pnPage */ /* Query the WAL sub-system for the database size. The WalDbsize() ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or ** if the database size is not available. The database size is not ** available from the WAL sub-system if the log file is empty or ** contains no valid committed transactions. */ assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock ); nPage = sqlite3WalDbsize(pPager->pWal); /* If the database size was not available from the WAL sub-system, ** determine it based on the size of the database file. If the size ** of the database file is not an integer multiple of the page-size, ** round down to the nearest page. Except, any file larger than 0 ** bytes in size is considered to contain at least one page. */ if( nPage==0 ){ i64 n = 0; /* Size of db file in bytes */ assert( isOpen(pPager->fd) || pPager->tempFile ); if( isOpen(pPager->fd) ){ int rc = sqlite3OsFileSize(pPager->fd, &n); if( rc!=SQLITE_OK ){ return rc; } } nPage = (Pgno)(n / pPager->pageSize); if( nPage==0 && n>0 ){ nPage = 1; } } /* If the current number of pages in the file is greater than the ** configured maximum pager number, increase the allowed limit so ** that the file can be read. */ if( nPage>pPager->mxPgno ){ pPager->mxPgno = (Pgno)nPage; } |
︙ | ︙ | |||
2908 2909 2910 2911 2912 2913 2914 | ** If the database is not empty and the *-wal file exists, open the pager ** in WAL mode. If the database is empty or if no *-wal file exists and ** if no error occurs, make sure Pager.journalMode is not set to ** PAGER_JOURNALMODE_WAL. ** ** Return SQLITE_OK or an error code. ** | < < > > > < < < < < | 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 2991 2992 2993 | ** If the database is not empty and the *-wal file exists, open the pager ** in WAL mode. If the database is empty or if no *-wal file exists and ** if no error occurs, make sure Pager.journalMode is not set to ** PAGER_JOURNALMODE_WAL. ** ** Return SQLITE_OK or an error code. ** ** The caller must hold a SHARED lock on the database file to call this ** function. Because an EXCLUSIVE lock on the db file is required to delete ** a WAL on a none-empty database, this ensures there is no race condition ** between the xAccess() below and an xDelete() being executed by some ** other connection. */ static int pagerOpenWalIfPresent(Pager *pPager){ int rc = SQLITE_OK; assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock ); if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ Pgno nPage; /* Size of the database file */ rc = pagerPagecount(pPager, &nPage); if( rc ) return rc; if( nPage==0 ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); isWal = 0; }else{ rc = sqlite3OsAccess( pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal ); } if( rc==SQLITE_OK ){ if( isWal ){ testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); rc = sqlite3PagerOpenWal(pPager, 0); }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ pPager->journalMode = PAGER_JOURNALMODE_DELETE; } } } return rc; } |
︙ | ︙ | |||
4990 4991 4992 4993 4994 4995 4996 | ** write-transaction has already been opened, this function is a no-op. ** ** If the exFlag argument is false, then acquire at least a RESERVED ** lock on the database file. If exFlag is true, then acquire at least ** an EXCLUSIVE lock. If such a lock is already held, no locking ** functions need be called. ** | < < < < < < < < | 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 | ** write-transaction has already been opened, this function is a no-op. ** ** If the exFlag argument is false, then acquire at least a RESERVED ** lock on the database file. If exFlag is true, then acquire at least ** an EXCLUSIVE lock. If such a lock is already held, no locking ** functions need be called. ** ** If the subjInMemory argument is non-zero, then any sub-journal opened ** within this transaction will be opened as an in-memory file. This ** has no effect if the sub-journal is already opened (as it may be when ** running in exclusive mode) or if the transaction does not require a ** sub-journal. If the subjInMemory argument is zero, then any required ** sub-journal is implemented in-memory if pPager is an in-memory database, ** or using a temporary file otherwise. |
︙ | ︙ | |||
5043 5044 5045 5046 5047 5048 5049 | ** lock, but not when obtaining the RESERVED lock. */ rc = pagerLockDb(pPager, RESERVED_LOCK); if( rc==SQLITE_OK && exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } | < | 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 | ** lock, but not when obtaining the RESERVED lock. */ rc = pagerLockDb(pPager, RESERVED_LOCK); if( rc==SQLITE_OK && exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } if( rc==SQLITE_OK ){ /* Change to WRITER_LOCKED state. ** ** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD ** when it has an open transaction, but never to DBMOD or FINISHED. ** This is because in those states the code to roll back savepoint |
︙ | ︙ |