Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Incremental checkin on pager state refactoring. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | experimental |
Files: | files | file ages | folders |
SHA1: |
0a636798bdb6961a47327091715b254f |
User & Date: | dan 2010-08-03 06:42:40.000 |
Context
2010-08-03
| ||
12:48 | Add state diagram to comments in experimental version of pager.c. (check-in: 16dcf5a6d3 user: dan tags: experimental) | |
06:42 | Incremental checkin on pager state refactoring. (check-in: 0a636798bd user: dan tags: experimental) | |
2010-08-02
| ||
14:32 | Experimental refactoring of the Pager object state. This version is surely buggy. (check-in: 03a240514a user: dan tags: experimental) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 | #define FILEHANDLEID(fd) ((int)fd) /* ** The Pager.eState variable stores the current 'state' of a pager. A ** pager may be in any one of the following six states: ** ** NONE: ** * No read or write transaction is active. ** * Any lock, or no lock at all, may be held on the database file. ** ** READER: | > > > > > > > > > > | | > | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | #define FILEHANDLEID(fd) ((int)fd) /* ** The Pager.eState variable stores the current 'state' of a pager. A ** pager may be in any one of the following six states: ** ** NONE: ** The pager starts up in this state. Nothing is guaranteed in this ** state - the file may or may not be locked and the database size is ** unknown. The database may not be read or written. ** ** * No read or write transaction is active. ** * Any lock, or no lock at all, may be held on the database file. ** * The dbSize, dbOrigSize and dbFileSize variables may not be trusted. ** ** READER: ** In this state all the requirements for reading the database in ** rollback (non-WAL) mode are met. Unless the pager is (or recently ** was) in exclusive-locking mode, a user-level read transaction is ** open. The database size is known in this state. ** ** * A read transaction may be active. ** * A SHARED or greater lock is held on the database file. ** * The dbSize variable may be trusted (even if a user-level read ** transaction is not active). ** ** WRITER_INITIAL: ** * A write transaction is active. ** * A RESERVED or greater lock is held on the database file. ** * The dbSize, dbOrigSize and dbFileSize variables are all valid. ** * The contents of the pager cache have not been modified. ** |
︙ | ︙ | |||
163 164 165 166 167 168 169 | ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * All writing and syncing of journal and database data has finished. ** If no error occured, all that remains is to finalize the journal to ** commit the transaction. If an error did occur, the caller will need ** to rollback the transaction. ** | < | > > > > > > > > > > > > > | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 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 | ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. ** * All writing and syncing of journal and database data has finished. ** If no error occured, all that remains is to finalize the journal to ** commit the transaction. If an error did occur, the caller will need ** to rollback the transaction. ** ** Allowable transitions and the [function] that performs each: ** ** NONE -> READER [PagerSharedLock] ** READER -> WRITER_INITIAL [PagerBegin] ** WRITER_INITIAL -> WRITER_CACHEMOD [pager_open_journal] ** WRITER_CACHEMOD -> WRITER_DBMOD [syncJournal] ** WRITER_DBMOD -> WRITER_FINISHED [PagerCommitPhaseOne] ** ** WRITER_INITIAL -> READER [pager_end_transaction] ** WRITER_CACHEMOD -> READER [pager_end_transaction] ** WRITER_DBMOD -> READER [pager_end_transaction] ** WRITER_FINISHED -> READER [pager_end_transaction] ** ** READER -> NONE [pager_unlock] ** ** Notes: ** ** * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the ** connection is open in WAL mode. A WAL connection is always in one ** of the first four states. ** ** * Normally, a connection open in exclusive mode is never in PAGER_NONE ** state. There are two exceptions: immediately after exclusive-mode has ** been turned on (and before any read or write transactions are ** executed), and when the pager is leaving the "error state". ** ** * See also: assert_pager_state(). */ #define PAGER_NONE 0 #define PAGER_READER 1 #define PAGER_WRITER_INITIAL 2 #define PAGER_WRITER_CACHEMOD 3 #define PAGER_WRITER_DBMOD 4 #define PAGER_WRITER_FINISHED 5 |
︙ | ︙ | |||
421 422 423 424 425 426 427 | ** other variables in this block are described in the comment directly ** above this class definition. */ #if 0 u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ u8 dbModified; /* True if there are any changes to the Db */ u8 journalStarted; /* True if header of journal is synced */ | < > | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | ** other variables in this block are described in the comment directly ** above this class definition. */ #if 0 u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ u8 dbModified; /* True if there are any changes to the Db */ u8 journalStarted; /* True if header of journal is synced */ u8 dbSizeValid; /* Set when dbSize is correct */ #endif u8 eState; /* Pager state (NONE, READER, WRITER_INITIAL..) */ u8 eLock; /* Current lock held on database file */ u8 changeCountDone; /* Set after incrementing the change-counter */ u8 setMaster; /* True if a m-j name has been written to jrnl */ u8 doNotSpill; /* Do not spill the cache when non-zero */ u8 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */ |
︙ | ︙ | |||
619 620 621 622 623 624 625 | /* Check that MEMDB implies noSync. */ assert( !MEMDB || p->noSync ); switch( p->eState ){ case PAGER_NONE: assert( !MEMDB ); assert( !p->tempFile ); | < | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 | /* Check that MEMDB implies noSync. */ assert( !MEMDB || p->noSync ); switch( p->eState ){ case PAGER_NONE: assert( !MEMDB ); assert( !p->tempFile ); break; case PAGER_READER: assert( p->eLock>=SHARED_LOCK || p->noReadlock ); break; case PAGER_WRITER_INITIAL: |
︙ | ︙ | |||
1344 1345 1346 1347 1348 1349 1350 | ** ** TODO: Why can we not reset the pager while in error state? */ static void pager_reset(Pager *pPager){ if( SQLITE_OK==pPager->errCode ){ sqlite3BackupRestart(pPager->pBackup); sqlite3PcacheClear(pPager->pPCache); | < | 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 | ** ** TODO: Why can we not reset the pager while in error state? */ static void pager_reset(Pager *pPager){ if( SQLITE_OK==pPager->errCode ){ sqlite3BackupRestart(pPager->pBackup); sqlite3PcacheClear(pPager->pPCache); } } /* ** Free all structures in the Pager.aSavepoint[] array and set both ** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal ** if it is open and the pager is not in exclusive mode. |
︙ | ︙ | |||
1424 1425 1426 1427 1428 1429 1430 | sqlite3OsClose(pPager->jfd); } sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; releaseAllSavepoints(pPager); | < < < < < < < < | 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 | sqlite3OsClose(pPager->jfd); } sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; releaseAllSavepoints(pPager); if( pagerUseWal(pPager) ){ sqlite3WalEndReadTransaction(pPager->pWal); }else{ rc = osUnlock(pPager, NO_LOCK); } if( rc ){ pPager->errCode = rc; |
︙ | ︙ | |||
2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 | ** other writers or checkpointers. */ static int pagerBeginReadTransaction(Pager *pPager){ int rc; /* Return code */ int changed = 0; /* True if cache must be reset */ assert( pagerUseWal(pPager) ); /* sqlite3WalEndReadTransaction() was not called for the previous ** transaction in locking_mode=EXCLUSIVE. So call it now. If we ** are in locking_mode=NORMAL and EndRead() was previously called, ** the duplicate call is harmless. */ sqlite3WalEndReadTransaction(pPager->pWal); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); | > | < < | > | > | | | > > > > > > | > > > > > > > > | > > > > > > > | > | 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 | ** other writers or checkpointers. */ static int pagerBeginReadTransaction(Pager *pPager){ int rc; /* Return code */ int changed = 0; /* True if cache must be reset */ assert( pagerUseWal(pPager) ); assert( pPager->eState==PAGER_NONE || pPager->eState==PAGER_SHARED ); /* sqlite3WalEndReadTransaction() was not called for the previous ** transaction in locking_mode=EXCLUSIVE. So call it now. If we ** are in locking_mode=NORMAL and EndRead() was previously called, ** the duplicate call is harmless. */ sqlite3WalEndReadTransaction(pPager->pWal); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); if( rc==SQLITE_OK && changed ){ pager_reset(pPager); } return rc; } /* ** TODO: Description here. */ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ Pgno nPage; /* Value to return via *pnPage */ assert( pPager->eState==PAGER_NONE ); nPage = sqlite3WalDbsize(pPager->pWal); 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; } } *pnPage = nPage; return SQLITE_OK; } /* ** Check if the *-wal file that corresponds to the database opened by pPager ** exists if the database is not empy, or verify that the *-wal file does ** not exist (by deleting it) if the database file is empty. ** ** If the database is not empty and the *-wal file exists, open the pager |
︙ | ︙ | |||
2631 2632 2633 2634 2635 2636 2637 | ** between the xAccess() below and an xDelete() being executed by some ** other connection. */ static int pagerOpenWalIfPresent(Pager *pPager){ int rc = SQLITE_OK; if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ | | > | | | 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 | ** between the xAccess() below and an xDelete() being executed by some ** other connection. */ static int pagerOpenWalIfPresent(Pager *pPager){ int rc = SQLITE_OK; if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ Pgno nPage; /* Size of the database file */ assert( pPager->eState==PAGER_NONE ); assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock ); 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 ){ assert( sqlite3PcachePagecount(pPager->pPCache)==0 ); rc = sqlite3PagerOpenWal(pPager, 0); if( rc==SQLITE_OK ){ rc = pagerBeginReadTransaction(pPager); } }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ pPager->journalMode = PAGER_JOURNALMODE_DELETE; } |
︙ | ︙ | |||
2956 2957 2958 2959 2960 2961 2962 | if( rc==SQLITE_OK ){ u16 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); if( (pPager->memDb==0 || pPager->dbSize==0) && sqlite3PcacheRefCount(pPager->pPCache)==0 && pageSize && pageSize!=pPager->pageSize ){ | > > > > > > | > > | 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 | if( rc==SQLITE_OK ){ u16 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); if( (pPager->memDb==0 || pPager->dbSize==0) && sqlite3PcacheRefCount(pPager->pPCache)==0 && pageSize && pageSize!=pPager->pageSize ){ char *pNew; /* New temp space */ i64 nByte = 0; if( pPager->eState>PAGER_NONE && isOpen(pPager->fd) ){ rc = sqlite3OsFileSize(pPager->fd, &nByte); if( rc!=SQLITE_OK ) return rc; } pNew = (char *)sqlite3PageMalloc(pageSize); if( !pNew ){ rc = SQLITE_NOMEM; }else{ assert( pPager->eState==PAGER_NONE || pPager->eState==PAGER_READER ); pager_reset(pPager); pPager->dbSize = nByte/pageSize; pPager->pageSize = pageSize; sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); } } *pPageSize = (u16)pPager->pageSize; |
︙ | ︙ | |||
3084 3085 3086 3087 3088 3089 3090 3091 | ** ** Otherwise, if everything is successful, then SQLITE_OK is returned ** and *pnPage is set to the number of pages in the database. */ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){ Pgno nPage = 0; /* Value to return via *pnPage */ /* Determine the number of pages in the file. Store this in nPage. */ | > > > | | < | 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 | ** ** Otherwise, if everything is successful, then SQLITE_OK is returned ** and *pnPage is set to the number of pages in the database. */ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){ Pgno nPage = 0; /* Value to return via *pnPage */ assert( pPager->eState>=PAGER_SHARED ); assert( pPager->eState!=PAGER_WRITER_FINISHED ); /* Determine the number of pages in the file. Store this in nPage. */ if( pPager->eState>PAGER_NONE ){ nPage = pPager->dbSize; }else{ int rc; /* Error returned by OsFileSize() */ i64 n = 0; /* File size in bytes returned by OsFileSize() */ if( pagerUseWal(pPager) && pPager->eState!=PAGER_NONE ){ nPage = sqlite3WalDbsize(pPager->pWal); } if( nPage==0 ){ assert( isOpen(pPager->fd) || pPager->tempFile ); if( isOpen(pPager->fd) ){ if( SQLITE_OK!=(rc = sqlite3OsFileSize(pPager->fd, &n)) ){ pager_error(pPager, rc); return rc; } } if( n>0 && n<pPager->pageSize ){ nPage = 1; }else{ nPage = (Pgno)(n / pPager->pageSize); } } if( pPager->eState!=PAGER_NONE ){ pPager->dbSize = nPage; pPager->dbFileSize = nPage; } } /* 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. */ |
︙ | ︙ | |||
3231 3232 3233 3234 3235 3236 3237 | /* ** Truncate the in-memory database file image to nPage pages. This ** function does not actually modify the database file on disk. It ** just sets the internal state of the pager object so that the ** truncation will be done when the current transaction is committed. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ | < | 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 | /* ** Truncate the in-memory database file image to nPage pages. This ** function does not actually modify the database file on disk. It ** just sets the internal state of the pager object so that the ** truncation will be done when the current transaction is committed. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ assert( pPager->dbSize>=nPage ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage; assertTruncateConstraint(pPager); } |
︙ | ︙ | |||
4060 4061 4062 4063 4064 4065 4066 | IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) pPager->useJournal = (u8)useJournal; pPager->noReadlock = (noReadlock && readOnly) ?1:0; /* pPager->stmtOpen = 0; */ /* pPager->stmtInUse = 0; */ /* pPager->nRef = 0; */ | < | 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 | IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename)) pPager->useJournal = (u8)useJournal; pPager->noReadlock = (noReadlock && readOnly) ?1:0; /* pPager->stmtOpen = 0; */ /* pPager->stmtInUse = 0; */ /* pPager->nRef = 0; */ /* pPager->stmtSize = 0; */ /* pPager->stmtJSize = 0; */ /* pPager->nPage = 0; */ pPager->mxPgno = SQLITE_MAX_PAGE_COUNT; /* pPager->state = PAGER_UNLOCK; */ #if 0 assert( pPager->state == (tempFile ? PAGER_EXCLUSIVE : PAGER_UNLOCK) ); |
︙ | ︙ | |||
4142 4143 4144 4145 4146 4147 4148 | */ static int hasHotJournal(Pager *pPager, int *pExists){ sqlite3_vfs * const pVfs = pPager->pVfs; int rc = SQLITE_OK; /* Return code */ int exists = 1; /* True if a journal file is present */ int jrnlOpen = !!isOpen(pPager->jfd); | < | | 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 | */ static int hasHotJournal(Pager *pPager, int *pExists){ sqlite3_vfs * const pVfs = pPager->pVfs; int rc = SQLITE_OK; /* Return code */ int exists = 1; /* True if a journal file is present */ int jrnlOpen = !!isOpen(pPager->jfd); assert( pPager->useJournal ); assert( isOpen(pPager->fd) ); assert( pPager->eState==PAGER_NONE ); assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN )); *pExists = 0; if( !jrnlOpen ){ |
︙ | ︙ | |||
4168 4169 4170 4171 4172 4173 4174 | ** we get to the following sqlite3OsCheckReservedLock() call. If that ** is the case, this routine might think there is a hot journal when ** in fact there is none. This results in a false-positive which will ** be dealt with by the playback routine. Ticket #3883. */ rc = sqlite3OsCheckReservedLock(pPager->fd, &locked); if( rc==SQLITE_OK && !locked ){ | | | | 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 | ** we get to the following sqlite3OsCheckReservedLock() call. If that ** is the case, this routine might think there is a hot journal when ** in fact there is none. This results in a false-positive which will ** be dealt with by the playback routine. Ticket #3883. */ rc = sqlite3OsCheckReservedLock(pPager->fd, &locked); if( rc==SQLITE_OK && !locked ){ Pgno nPage; /* Number of pages in database file */ /* Check the size of the database file. If it consists of 0 pages, ** then delete the journal file. See the header comment above for ** the reasoning here. Delete the obsolete journal file under ** a RESERVED lock to avoid race conditions and to avoid violating ** [H33020]. */ rc = pagerPagecount(pPager, &nPage); if( rc==SQLITE_OK ){ if( nPage==0 ){ sqlite3BeginBenignMalloc(); if( sqlite3OsLock(pPager->fd, RESERVED_LOCK)==SQLITE_OK ){ sqlite3OsDelete(pVfs, pPager->zJournal, 0); sqlite3OsUnlock(pPager->fd, SHARED_LOCK); } |
︙ | ︙ | |||
4264 4265 4266 4267 4268 4269 4270 | ** file or rolling back a journal file, the IO error code is returned. */ int sqlite3PagerSharedLock(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ int isErrorReset = 0; /* True if recovering from error state */ /* This routine is only called from b-tree and only when there are no | | > > > > > > | < < < < | | | 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 | ** file or rolling back a journal file, the IO error code is returned. */ int sqlite3PagerSharedLock(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ int isErrorReset = 0; /* True if recovering from error state */ /* This routine is only called from b-tree and only when there are no ** outstanding pages. This implies that the pager state should either ** be NONE or READER. READER is only possible if the pager is or was in ** exclusive access mode. */ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( pPager->eState==PAGER_NONE || pPager->eState==PAGER_READER ); assert( assert_pager_state(pPager) ); if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; } /* If this database is in an error-state, now is a chance to clear ** the error. Discard the contents of the pager-cache and rollback ** any hot journal in the file-system. */ if( pPager->errCode ){ if( isOpen(pPager->jfd) || pPager->zJournal ){ isErrorReset = 1; } pPager->errCode = SQLITE_OK; pPager->eState = PAGER_NONE; pager_reset(pPager); } if( !pagerUseWal(pPager) && pPager->eState==PAGER_NONE ){ sqlite3_vfs * const pVfs = pPager->pVfs; assert( !MEMDB && !pPager->tempFile ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( pPager->noReadlock==0 || pPager->readOnly ); if( pPager->noReadlock==0 ){ rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ assert( pPager->eLock==PAGER_UNLOCK ); return pager_error(pPager, rc); } } /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. */ if( !isErrorReset ){ rc = hasHotJournal(pPager, &isErrorReset); if( rc!=SQLITE_OK ){ goto failed; } } if( isErrorReset ){ /* Get an EXCLUSIVE lock on the database file. At this point it is ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the ** database file, detect the RESERVED lock, and conclude that the ** database is safe to read while this process is still rolling the ** hot-journal back. ** |
︙ | ︙ | |||
4385 4386 4387 4388 4389 4390 4391 | ** the journal before playing it back. */ if( isOpen(pPager->jfd) ){ rc = pagerSyncHotJournal(pPager); if( rc==SQLITE_OK ){ pPager->eState = PAGER_WRITER_FINISHED; rc = pager_playback(pPager, 1); | | | | 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 | ** the journal before playing it back. */ if( isOpen(pPager->jfd) ){ rc = pagerSyncHotJournal(pPager); if( rc==SQLITE_OK ){ pPager->eState = PAGER_WRITER_FINISHED; rc = pager_playback(pPager, 1); pPager->eState = PAGER_NONE; } if( rc!=SQLITE_OK ){ rc = pager_error(pPager, rc); goto failed; } }else{ osUnlock(pPager, SHARED_LOCK); } assert( pPager->eState==PAGER_NONE ); assert( (pPager->eLock==SHARED_LOCK) || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) ); } if( pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0 ){ /* The shared-lock has just been acquired on the database file |
︙ | ︙ | |||
4418 4419 4420 4421 4422 4423 4424 | ** other bytes change randomly with each file change when ** a codec is in use. ** ** There is a vanishingly small chance that a change will not be ** detected. The chance of an undetected change is so small that ** it can be neglected. */ | | < < | | < < > > > > > > > > > > > | 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 | ** other bytes change randomly with each file change when ** a codec is in use. ** ** There is a vanishingly small chance that a change will not be ** detected. The chance of an undetected change is so small that ** it can be neglected. */ Pgno nPage = 0; char dbFileVers[sizeof(pPager->dbFileVers)]; rc = pagerPagecount(pPager, &nPage); if( rc ) goto failed; if( nPage>0 ){ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); if( rc!=SQLITE_OK ){ goto failed; } }else{ memset(dbFileVers, 0, sizeof(dbFileVers)); } if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ pager_reset(pPager); } } /* If there is a WAL file in the file-system, open this database in WAL ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); } if( pagerUseWal(pPager) && rc==SQLITE_OK ){ rc = pagerBeginReadTransaction(pPager); } if( pPager->eState==PAGER_NONE && rc==SQLITE_OK ){ pPager->eState = PAGER_NONE; rc = pagerPagecount(pPager, &pPager->dbSize); } failed: if( rc!=SQLITE_OK ){ /* pager_unlock() is a no-op for exclusive mode and in-memory databases. */ pager_unlock(pPager); }else{ pPager->eState = PAGER_READER; } return rc; } /* ** If the reference count has reached zero, rollback any active ** transaction and unlock the pager. |
︙ | ︙ | |||
4709 4710 4711 4712 4713 4714 4715 | /* If already in the error state, this function is a no-op. But on ** the other hand, this routine is never called if we are already in ** an error state. */ if( NEVER(pPager->errCode) ) return pPager->errCode; if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ | < | 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 | /* If already in the error state, this function is a no-op. But on ** the other hand, this routine is never called if we are already in ** an error state. */ if( NEVER(pPager->errCode) ) return pPager->errCode; if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ rc = sqlite3PagerPagecount(pPager, &nPage); if( rc ) return rc; pPager->pInJournal = sqlite3BitvecCreate(nPage); if( pPager->pInJournal==0 ){ return SQLITE_NOMEM; } |
︙ | ︙ | |||
5632 5633 5634 5635 5636 5637 5638 | if( rc==SQLITE_OK ){ rc = rc2; } }else{ rc = pager_playback(pPager, 0); } | < < < < | 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 | if( rc==SQLITE_OK ){ rc = rc2; } }else{ rc = pager_playback(pPager, 0); } /* If an error occurs during a ROLLBACK, we can no longer trust the pager ** cache. So call pager_error() on the way out to make any error ** persistent. */ rc = pager_error(pPager, rc); } return rc; |
︙ | ︙ | |||
5688 5689 5690 5691 5692 5693 5694 | ** This routine is used for testing and analysis only. */ int *sqlite3PagerStats(Pager *pPager){ static int a[11]; a[0] = sqlite3PcacheRefCount(pPager->pPCache); a[1] = sqlite3PcachePagecount(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); | | | 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 | ** This routine is used for testing and analysis only. */ int *sqlite3PagerStats(Pager *pPager){ static int a[11]; a[0] = sqlite3PcacheRefCount(pPager->pPCache); a[1] = sqlite3PcachePagecount(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); a[3] = pPager->eState==PAGER_NONE ? -1 : (int) pPager->dbSize; a[4] = pPager->eState; a[5] = pPager->errCode; a[6] = pPager->nHit; a[7] = pPager->nMiss; a[8] = 0; /* Used to be pPager->nOvfl */ a[9] = pPager->nRead; a[10] = pPager->nWrite; |
︙ | ︙ | |||
6006 6007 6008 6009 6010 6011 6012 | pPgOld = pager_lookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 ); if( pPgOld ){ pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( MEMDB ){ /* Do not discard pages from an in-memory database since we might ** need to rollback later. Just move the page out of the way. */ | < | 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 | pPgOld = pager_lookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 ); if( pPgOld ){ pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( MEMDB ){ /* Do not discard pages from an in-memory database since we might ** need to rollback later. Just move the page out of the way. */ sqlite3PcacheMove(pPgOld, pPager->dbSize+1); }else{ sqlite3PcacheDrop(pPgOld); } } origPgno = pPg->pgno; |
︙ | ︙ | |||
6283 6284 6285 6286 6287 6288 6289 | ** The caller must be holding a SHARED lock on the database file to call ** this function. ** ** If the pager passed as the first argument is open on a real database ** file (not a temp file or an in-memory database), and the WAL file ** is not already open, make an attempt to open it now. If successful, ** return SQLITE_OK. If an error occurs or the VFS used by the pager does | | | | > | > > | > | | 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 | ** The caller must be holding a SHARED lock on the database file to call ** this function. ** ** If the pager passed as the first argument is open on a real database ** file (not a temp file or an in-memory database), and the WAL file ** is not already open, make an attempt to open it now. If successful, ** return SQLITE_OK. If an error occurs or the VFS used by the pager does ** not support the xShmXXX() methods, return an error code. *pbOpen is ** not modified in either case. ** ** If the pager is open on a temp-file (or in-memory database), or if ** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK ** without doing anything. */ int sqlite3PagerOpenWal( Pager *pPager, /* Pager object */ int *pbOpen /* OUT: Set to true if call is a no-op */ ){ int rc = SQLITE_OK; /* Return code */ assert( assert_pager_state(pPager) ); assert( pPager->eState==PAGER_NONE || pbOpen ); assert( pPager->eState==PAGER_READER || !pbOpen ); assert( pbOpen==0 || *pbOpen==0 ); assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) ); if( !pPager->tempFile && !pPager->pWal ){ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN; /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), unlock the database file and ** return an error code. */ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal); if( rc==SQLITE_OK ){ pPager->journalMode = PAGER_JOURNALMODE_WAL; pPager->eState = PAGER_NONE; } }else{ *pbOpen = 1; } return rc; } /* ** This function is called to close the connection to the log file prior |
︙ | ︙ |
Changes to src/test_stat.c.
︙ | ︙ | |||
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | sqlite3_free(pCsr->zPath); pCsr->zPath = 0; if( pCsr->aPage[0].pPg==0 ){ rc = sqlite3_step(pCsr->pStmt); if( rc==SQLITE_ROW ){ u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1); rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; pCsr->aPage[0].zPath = sqlite3_mprintf("/"); pCsr->iPage = 0; }else{ pCsr->isEof = 1; | > > > > > > | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | sqlite3_free(pCsr->zPath); pCsr->zPath = 0; if( pCsr->aPage[0].pPg==0 ){ rc = sqlite3_step(pCsr->pStmt); if( rc==SQLITE_ROW ){ int nPage; u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1); sqlite3PagerPagecount(pPager, &nPage); if( nPage==0 ){ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; pCsr->aPage[0].zPath = sqlite3_mprintf("/"); pCsr->iPage = 0; }else{ pCsr->isEof = 1; |
︙ | ︙ | |||
482 483 484 485 486 487 488 | } static int statFilter( sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ | < < < < < < < < | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | } static int statFilter( sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ StatCursor *pCsr = (StatCursor *)pCursor; statResetCsr((StatCursor *)pCursor); return statNext(pCursor); } static int statColumn( sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
2162 2163 2164 2165 2166 2167 2168 | *pInWal = 0; return SQLITE_OK; } /* | | | | | > > | 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 | *pInWal = 0; return SQLITE_OK; } /* ** Return the size of the database in pages (or zero, if unknown). */ Pgno sqlite3WalDbsize(Wal *pWal){ if( pWal && pWal->readLock>=0 ){ return pWal->hdr.nPage; } return 0; } /* ** This function starts a write transaction on the WAL. ** ** A read transaction must have already been started by a prior call |
︙ | ︙ |
Changes to src/wal.h.
︙ | ︙ | |||
21 22 23 24 25 26 27 | #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 # define sqlite3WalClose(w,x,y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) # define sqlite3WalRead(v,w,x,y,z) 0 | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 # define sqlite3WalClose(w,x,y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) # define sqlite3WalRead(v,w,x,y,z) 0 # define sqlite3WalDbsize(y) 0 # define sqlite3WalBeginWriteTransaction(y) 0 # define sqlite3WalEndWriteTransaction(x) 0 # define sqlite3WalUndo(x,y,z) 0 # define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0 # define sqlite3WalCheckpoint(u,v,w,x) 0 |
︙ | ︙ | |||
57 58 59 60 61 62 63 | */ int sqlite3WalBeginReadTransaction(Wal *pWal, int *); void sqlite3WalEndReadTransaction(Wal *pWal); /* Read a page from the write-ahead log, if it is present. */ int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut); | | < | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | */ int sqlite3WalBeginReadTransaction(Wal *pWal, int *); void sqlite3WalEndReadTransaction(Wal *pWal); /* Read a page from the write-ahead log, if it is present. */ int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut); /* If the WAL is not empty, return the size of the database. */ Pgno sqlite3WalDbsize(Wal *pWal); /* Obtain or release the WRITER lock. */ int sqlite3WalBeginWriteTransaction(Wal *pWal); int sqlite3WalEndWriteTransaction(Wal *pWal); /* Undo any frames written (but not committed) to the log */ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx); |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
125 126 127 128 129 130 131 | lappend ::testsuitelist xxx test_suite "veryquick" -prefix "" -description { "Very" quick test suite. Runs in less than 5 minutes on a workstation. This test suite is the same as the "quick" tests, except that some files that test malloc and IO errors are omitted. } -files [ | | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | lappend ::testsuitelist xxx test_suite "veryquick" -prefix "" -description { "Very" quick test suite. Runs in less than 5 minutes on a workstation. This test suite is the same as the "quick" tests, except that some files that test malloc and IO errors are omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* ] test_suite "quick" -prefix "" -description { Quick test suite. Runs in around 10 minutes on a workstation. } -files [ test_set $allquicktests ] |
︙ | ︙ |