Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Refactoring the btree and pager routines into distinct two-phase commit routines. We've always done a two-phase commit - this change is just making that more apparent in the code. (CVS 3762) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
66b3ad09ea657d25d48cb75ec2671ea2 |
User & Date: | drh 2007-03-30 14:06:34.000 |
Context
2007-03-30
| ||
14:46 | Tease apart the two phases of pager commit. (CVS 3763) (check-in: e5f17078a2 user: drh tags: trunk) | |
14:06 | Refactoring the btree and pager routines into distinct two-phase commit routines. We've always done a two-phase commit - this change is just making that more apparent in the code. (CVS 3762) (check-in: 66b3ad09ea user: drh tags: trunk) | |
13:35 | Make yypMinor available to the stack overflow callbacks in lemon generated parsers. This does not effect SQLite. (CVS 3761) (check-in: 70c8c7e2ce user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* ** $Id: btree.c,v 1.347 2007/03/30 14:06:34 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 | assert( nRef==sqlite3PagerRefcount(pPager) ); if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); } return rc; } #endif /* ** Commit the transaction currently in progress. ** ** This routine implements the second phase of a 2-phase commit. The ** sqlite3BtreeSync() routine does the first phase and should be invoked ** prior to calling this routine. The sqlite3BtreeSync() routine did ** all the work of writing information out to disk and flushing the ** contents so that they are written onto the disk platter. All this ** routine has to do is delete or truncate the rollback journal ** (which causes the transaction to commit) and drop locks. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases 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 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 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 | assert( nRef==sqlite3PagerRefcount(pPager) ); if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); } return rc; } #endif /* ** This routine does the first phase of a two-phase commit. This routine ** causes a rollback journal to be created (if it does not already exist) ** and populated with enough information so that if a power loss occurs ** the database can be restored to its original state by playing back ** the journal. Then the contents of the journal are flushed out to ** the disk. After the journal is safely on oxide, the changes to the ** database are written into the database file and flushed to oxide. ** At the end of this call, the rollback journal still exists on the ** disk and we are still holding all locks, so the transaction has not ** committed. See sqlite3BtreeCommit() for the second phase of the ** commit process. ** ** This call is a no-op if no write-transaction is currently active on pBt. ** ** Otherwise, sync the database file for the btree pBt. zMaster points to ** the name of a master journal file that should be written into the ** individual journal file, or is NULL, indicating no master journal file ** (single database transaction). ** ** When this is called, the master journal should already have been ** created, populated with this journal pointer and synced to disk. ** ** Once this is routine has returned, the only thing required to commit ** the write-transaction for this database file is to delete the journal. */ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ int rc = SQLITE_OK; if( p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; Pgno nTrunc = 0; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ rc = autoVacuumCommit(pBt, &nTrunc); if( rc!=SQLITE_OK ){ return rc; } } #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, nTrunc); } return rc; } /* ** Commit the transaction currently in progress. ** ** This routine implements the second phase of a 2-phase commit. The ** sqlite3BtreeSync() routine does the first phase and should be invoked ** prior to calling this routine. The sqlite3BtreeSync() routine did ** all the work of writing information out to disk and flushing the ** contents so that they are written onto the disk platter. All this ** routine has to do is delete or truncate the rollback journal ** (which causes the transaction to commit) and drop locks. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ int sqlite3BtreeCommitPhaseTwo(Btree *p){ BtShared *pBt = p->pBt; btreeIntegrity(p); /* If the handle has a write-transaction open, commit the shared-btrees ** transaction and set the shared state to TRANS_READ. */ if( p->inTrans==TRANS_WRITE ){ int rc; assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); if( rc!=SQLITE_OK ){ return rc; } pBt->inTransaction = TRANS_READ; pBt->inStmt = 0; } unlockAllTables(p); |
︙ | ︙ | |||
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 | */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); btreeIntegrity(p); return SQLITE_OK; } #ifndef NDEBUG /* ** Return the number of write-cursors open on this handle. This is for use ** in assert() expressions, so it is only compiled if NDEBUG is not ** defined. */ | > > > > > > > > > > > > | 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 | */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); btreeIntegrity(p); return SQLITE_OK; } /* ** Do both phases of a commit. */ int sqlite3BtreeCommit(Btree *p){ int rc; rc = sqlite3BtreeCommitPhaseOne(p, 0); if( rc==SQLITE_OK ){ rc = sqlite3BtreeCommitPhaseTwo(p); } return rc; } #ifndef NDEBUG /* ** Return the number of write-cursors open on this handle. This is for use ** in assert() expressions, so it is only compiled if NDEBUG is not ** defined. */ |
︙ | ︙ | |||
6518 6519 6520 6521 6522 6523 6524 | /* ** Return non-zero if a read (or write) transaction is active. */ int sqlite3BtreeIsInReadTrans(Btree *p){ return (p && (p->inTrans!=TRANS_NONE)); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 | /* ** Return non-zero if a read (or write) transaction is active. */ int sqlite3BtreeIsInReadTrans(Btree *p){ return (p && (p->inTrans!=TRANS_NONE)); } /* ** This function returns a pointer to a blob of memory associated with ** a single shared-btree. The memory is used by client code for it's own ** purposes (for example, to store a high-level schema associated with ** the shared-btree). The btree layer manages reference counting issues. ** ** The first time this is called on a shared-btree, nBytes bytes of memory |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** ** @(#) $Id: btree.h,v 1.74 2007/03/30 14:06:34 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ |
︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSetPageSize(Btree*,int,int); int sqlite3BtreeGetPageSize(Btree*); int sqlite3BtreeGetReserve(Btree*); int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommit(Btree*); int sqlite3BtreeRollback(Btree*); int sqlite3BtreeBeginStmt(Btree*); int sqlite3BtreeCommitStmt(Btree*); int sqlite3BtreeRollbackStmt(Btree*); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); int sqlite3BtreeIsInStmt(Btree*); int sqlite3BtreeIsInReadTrans(Btree*); | > > < | 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 | int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSetPageSize(Btree*,int,int); int sqlite3BtreeGetPageSize(Btree*); int sqlite3BtreeGetReserve(Btree*); int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseTwo(Btree*); int sqlite3BtreeCommit(Btree*); int sqlite3BtreeRollback(Btree*); int sqlite3BtreeBeginStmt(Btree*); int sqlite3BtreeCommitStmt(Btree*); int sqlite3BtreeRollbackStmt(Btree*); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); int sqlite3BtreeIsInStmt(Btree*); int sqlite3BtreeIsInReadTrans(Btree*); void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); int sqlite3BtreeSchemaLocked(Btree *); int sqlite3BtreeLockTable(Btree *, int, u8); const char *sqlite3BtreeGetFilename(Btree *); const char *sqlite3BtreeGetDirname(Btree *); const char *sqlite3BtreeGetJournalname(Btree *); |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.307 2007/03/30 14:06:34 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
156 157 158 159 160 161 162 | PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */ PgHdr *pNextAll; /* A list of all pages */ PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */ u8 inJournal; /* TRUE if has been written to journal */ u8 inStmt; /* TRUE if in the statement subjournal */ u8 dirty; /* TRUE if we need to write back changes */ u8 needSync; /* Sync journal before writing this page */ | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */ PgHdr *pNextAll; /* A list of all pages */ PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */ u8 inJournal; /* TRUE if has been written to journal */ u8 inStmt; /* TRUE if in the statement subjournal */ u8 dirty; /* TRUE if we need to write back changes */ u8 needSync; /* Sync journal before writing this page */ u8 alwaysRollback; /* Disable DontRollback() for this page */ short int nRef; /* Number of users of this page */ PgHdr *pDirty, *pPrevDirty; /* Dirty pages */ u32 notUsed; /* Buffer space */ #ifdef SQLITE_CHECK_PAGES u32 pageHash; #endif /* pPager->pageSize bytes of page data follow this header */ |
︙ | ︙ | |||
232 233 234 235 236 237 238 | u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 full_fsync; /* Use F_FULLFSYNC when available */ u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 needSync; /* True if an fsync() is needed on the journal */ u8 dirtyCache; /* True if cached pages have changed */ | | > > > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 full_fsync; /* Use F_FULLFSYNC when available */ u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 needSync; /* True if an fsync() is needed on the journal */ u8 dirtyCache; /* True if cached pages have changed */ u8 alwaysRollback; /* Disable DontRollback() for all pages */ u8 memDb; /* True to inhibit all file I/O */ u8 setMaster; /* True if a m-j name has been written to jrnl */ u8 doNotSync; /* Boolean. While true, do not spill the cache */ u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */ u8 changeCountDone; /* Set after incrementing the change-counter */ int errCode; /* One of several kinds of errors */ int dbSize; /* Number of pages in the file */ int origDbSize; /* dbSize before the current change */ int stmtSize; /* Size of database (in pages) at stmt_begin() */ int nRec; /* Number of pages written to the journal */ u32 cksumInit; /* Quasi-random value added to every checksum */ int stmtNRec; /* Number of records in stmt subjournal */ |
︙ | ︙ | |||
282 283 284 285 286 287 288 | int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Linked list of pagers in this thread */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ u32 iChangeCount; /* Db change-counter for which cache is valid */ | < < < | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Linked list of pagers in this thread */ #endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ u32 iChangeCount; /* Db change-counter for which cache is valid */ }; /* ** If SQLITE_TEST is defined then increment the variable given in ** the argument */ #ifdef SQLITE_TEST |
︙ | ︙ | |||
906 907 908 909 910 911 912 913 | sqliteFree(pPager->aHash); pPager->nPage = 0; pPager->aHash = 0; pPager->nRef = 0; } /* ** When this routine is called, the pager has the journal file open and | > > > | | > > > > | | | 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | sqliteFree(pPager->aHash); pPager->nPage = 0; pPager->aHash = 0; pPager->nRef = 0; } /* ** This routine ends a transaction. A transaction is ended by either ** a COMMIT or a ROLLBACK. ** ** When this routine is called, the pager has the journal file open and ** a RESERVED or EXCLUSIVE lock on the database. This routine will release ** the database lock and acquires a SHARED lock in its place if that is ** the appropriate thing to do. Release locks usually is appropriate, ** unless we are in exclusive access mode or unless this is a ** COMMIT AND BEGIN or ROLLBACK AND BEGIN operation. ** ** The journal file is either deleted or truncated. ** ** TODO: Consider keeping the journal file open for temporary databases. ** This might give a performance improvement on windows where opening ** a file is an expensive operation. */ static int pager_end_transaction(Pager *pPager){ PgHdr *pPg; int rc = SQLITE_OK; int rc2 = SQLITE_OK; assert( !MEMDB ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } |
︙ | ︙ | |||
1419 1420 1421 1422 1423 1424 1425 | } } /*NOTREACHED*/ assert( 0 ); end_playback: if( rc==SQLITE_OK ){ | | | 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 | } } /*NOTREACHED*/ assert( 0 ); end_playback: if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager); } if( zMaster ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ if( rc==SQLITE_OK ){ rc = pager_delmaster(zMaster); |
︙ | ︙ | |||
2559 2560 2561 2562 2563 2564 2565 | return rc; } } assert( pPg->dirty==0 ); /* If the page we are recycling is marked as alwaysRollback, then ** set the global alwaysRollback flag, thus disabling the | | | 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 | return rc; } } assert( pPg->dirty==0 ); /* If the page we are recycling is marked as alwaysRollback, then ** set the global alwaysRollback flag, thus disabling the ** sqlite3PagerDontRollback() optimization for the rest of this transaction. ** It is necessary to do this because the page marked alwaysRollback ** might be reloaded at a later time but at that point we won't remember ** that is was marked alwaysRollback. This means that all pages must ** be marked as alwaysRollback from here on out. */ if( pPg->alwaysRollback ){ IOTRACE(("ALWAYS_ROLLBACK %p\n", pPager)) |
︙ | ︙ | |||
3092 3093 3094 3095 3096 3097 3098 | rc = writeJournalHdr(pPager); if( pPager->stmtAutoopen && rc==SQLITE_OK ){ rc = sqlite3PagerStmtBegin(pPager); } if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ | | | 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 | rc = writeJournalHdr(pPager); if( pPager->stmtAutoopen && rc==SQLITE_OK ){ rc = sqlite3PagerStmtBegin(pPager); } if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ rc = pager_end_transaction(pPager); if( rc==SQLITE_OK ){ rc = SQLITE_FULL; } } return rc; failed_to_open_journal: |
︙ | ︙ | |||
3123 3124 3125 3126 3127 3128 3129 | return rc; } /* ** Acquire a write-lock on the database. The lock is removed when ** the any of the following happen: ** | | | 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 | return rc; } /* ** Acquire a write-lock on the database. The lock is removed when ** the any of the following happen: ** ** * sqlite3PagerCommitPhaseTwo() is called. ** * sqlite3PagerRollback() is called. ** * sqlite3PagerClose() is called. ** * sqlite3PagerUnref() is called to on every outstanding page. ** ** The first parameter to this routine is a pointer to any open page of the ** database file. Nothing changes about the page - it is used merely to ** acquire a pointer to the Pager structure and as proof that there is |
︙ | ︙ | |||
3524 3525 3526 3527 3528 3529 3530 | ** When this routine is called, set the alwaysRollback flag to true. ** Subsequent calls to sqlite3PagerDontRollback() for the same page ** will thereafter be ignored. This is necessary to avoid a problem ** where a page with data is added to the freelist during one part of ** a transaction then removed from the freelist during a later part ** of the same transaction and reused for some other purpose. When it ** is first added to the freelist, this routine is called. When reused, | | | | | 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 | ** When this routine is called, set the alwaysRollback flag to true. ** Subsequent calls to sqlite3PagerDontRollback() for the same page ** will thereafter be ignored. This is necessary to avoid a problem ** where a page with data is added to the freelist during one part of ** a transaction then removed from the freelist during a later part ** of the same transaction and reused for some other purpose. When it ** is first added to the freelist, this routine is called. When reused, ** the sqlite3PagerDontRollback() routine is called. But because the ** page contains critical data, we still need to be sure it gets ** rolled back in spite of the sqlite3PagerDontRollback() call. */ void sqlite3PagerDontWrite(Pager *pPager, Pgno pgno){ PgHdr *pPg; if( MEMDB ) return; pPg = pager_lookup(pPager, pgno); |
︙ | ︙ | |||
3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 | assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize ); assert( pPager->aInStmt!=0 ); pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); page_add_to_stmt_list(pPg); } } /* ** Commit all changes to the database and release the write lock. ** ** If the commit fails for any reason, a rollback attempt is made ** and an error code is returned. If the commit worked, SQLITE_OK ** is returned. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 | assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize ); assert( pPager->aInStmt!=0 ); pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7); page_add_to_stmt_list(pPg); } } /* ** This routine is called to increment the database file change-counter, ** stored at byte 24 of the pager file. */ static int pager_incr_changecounter(Pager *pPager){ PgHdr *pPgHdr; u32 change_counter; int rc; if( !pPager->changeCountDone ){ /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr); if( rc!=SQLITE_OK ) return rc; rc = sqlite3PagerWrite(pPgHdr); if( rc!=SQLITE_OK ) return rc; /* Read the current value at byte 24. */ change_counter = retrieve32bits(pPgHdr, 24); /* Increment the value just read and write it back to byte 24. */ change_counter++; put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); pPager->iChangeCount = change_counter; /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); pPager->changeCountDone = 1; } return SQLITE_OK; } /* ** Sync the database file for the pager pPager. zMaster points to the name ** of a master journal file that should be written into the individual ** journal file. zMaster may be NULL, which is interpreted as no master ** journal (a single database transaction). ** ** This routine ensures that the journal is synced, all dirty pages written ** to the database file and the database file synced. The only thing that ** remains to commit the transaction is to delete the journal file (or ** master journal file if specified). ** ** Note that if zMaster==NULL, this does not overwrite a previous value ** passed to an sqlite3PagerCommitPhaseOne() call. ** ** If parameter nTrunc is non-zero, then the pager file is truncated to ** nTrunc pages (this is used by auto-vacuum databases). */ int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){ int rc = SQLITE_OK; PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n", pPager->zFilename, zMaster, nTrunc); /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is a no-op. */ if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){ PgHdr *pPg; assert( pPager->journalOpen ); /* If a master journal file name has already been written to the ** journal file, then no sync is required. This happens when it is ** written, then the process fails to upgrade from a RESERVED to an ** EXCLUSIVE lock. The next time the process tries to commit the ** transaction the m-j name will have already been written. */ if( !pPager->setMaster ){ rc = pager_incr_changecounter(pPager); if( rc!=SQLITE_OK ) goto sync_exit; #ifndef SQLITE_OMIT_AUTOVACUUM if( nTrunc!=0 ){ /* If this transaction has made the database smaller, then all pages ** being discarded by the truncation must be written to the journal ** file. */ Pgno i; int iSkip = PAGER_MJ_PGNO(pPager); for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){ if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){ rc = sqlite3PagerGet(pPager, i, &pPg); if( rc!=SQLITE_OK ) goto sync_exit; rc = sqlite3PagerWrite(pPg); sqlite3PagerUnref(pPg); if( rc!=SQLITE_OK ) goto sync_exit; } } } #endif rc = writeMasterJournal(pPager, zMaster); if( rc!=SQLITE_OK ) goto sync_exit; rc = syncJournal(pPager); if( rc!=SQLITE_OK ) goto sync_exit; } #ifndef SQLITE_OMIT_AUTOVACUUM if( nTrunc!=0 ){ rc = sqlite3PagerTruncate(pPager, nTrunc); if( rc!=SQLITE_OK ) goto sync_exit; } #endif /* Write all dirty pages to the database file */ pPg = pager_get_all_dirty_pages(pPager); rc = pager_write_pagelist(pPg); if( rc!=SQLITE_OK ) goto sync_exit; /* Sync the database file. */ if( !pPager->noSync ){ rc = sqlite3OsSync(pPager->fd, 0); } IOTRACE(("DBSYNC %p\n", pPager)) pPager->state = PAGER_SYNCED; }else if( MEMDB && nTrunc!=0 ){ rc = sqlite3PagerTruncate(pPager, nTrunc); } sync_exit: return rc; } /* ** Commit all changes to the database and release the write lock. ** ** If the commit fails for any reason, a rollback attempt is made ** and an error code is returned. If the commit worked, SQLITE_OK ** is returned. */ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ int rc; PgHdr *pPg; if( pPager->errCode ){ return pPager->errCode; } if( pPager->state<PAGER_RESERVED ){ |
︙ | ︙ | |||
3636 3637 3638 3639 3640 3641 3642 | pPager->state = PAGER_SHARED; return SQLITE_OK; } if( pPager->dirtyCache==0 ){ /* Exit early (without doing the time-consuming sqlite3OsSync() calls) ** if there have been no changes to the database file. */ assert( pPager->needSync==0 ); | | | | | 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 | pPager->state = PAGER_SHARED; return SQLITE_OK; } if( pPager->dirtyCache==0 ){ /* Exit early (without doing the time-consuming sqlite3OsSync() calls) ** if there have been no changes to the database file. */ assert( pPager->needSync==0 ); rc = pager_end_transaction(pPager); }else{ assert( pPager->journalOpen ); rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0); if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager); } } return pager_error(pPager, rc); } /* ** Rollback all changes. The database falls back to PAGER_SHARED mode. |
︙ | ︙ | |||
3699 3700 3701 3702 3703 3704 3705 | memoryTruncate(pPager); pPager->stmtInUse = 0; pPager->state = PAGER_SHARED; return SQLITE_OK; } if( !pPager->dirtyCache || !pPager->journalOpen ){ | | | | 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 | memoryTruncate(pPager); pPager->stmtInUse = 0; pPager->state = PAGER_SHARED; return SQLITE_OK; } if( !pPager->dirtyCache || !pPager->journalOpen ){ rc = pager_end_transaction(pPager); return rc; } if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){ if( pPager->state>=PAGER_EXCLUSIVE ){ pager_playback(pPager, 0); } return pPager->errCode; } if( pPager->state==PAGER_RESERVED ){ int rc2; rc = pager_playback(pPager, 0); rc2 = pager_end_transaction(pPager); if( rc==SQLITE_OK ){ rc = rc2; } }else{ rc = pager_playback(pPager, 0); } pPager->dbSize = -1; |
︙ | ︙ | |||
3922 3923 3924 3925 3926 3927 3928 | void *(*xCodec)(void*,void*,Pgno,int), void *pCodecArg ){ pPager->xCodec = xCodec; pPager->pCodecArg = pCodecArg; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 | void *(*xCodec)(void*,void*,Pgno,int), void *pCodecArg ){ pPager->xCodec = xCodec; pPager->pCodecArg = pCodecArg; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Move the page identified by pData to location pgno in the file. ** ** There must be no references to the current page pgno. If current page ** pgno is not already in the rollback journal, it is not written there by ** by this routine. The same applies to the page pData refers to on entry to |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** ** @(#) $Id: pager.h,v 1.57 2007/03/30 14:06:34 drh Exp $ */ #ifndef _PAGER_H_ #define _PAGER_H_ /* ** The default size of a database page. |
︙ | ︙ | |||
97 98 99 100 101 102 103 | Pgno sqlite3PagerPagenumber(DbPage*); int sqlite3PagerWrite(DbPage*); int sqlite3PagerIswriteable(DbPage*); int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*); int sqlite3PagerPagecount(Pager*); int sqlite3PagerTruncate(Pager*,Pgno); int sqlite3PagerBegin(DbPage*, int exFlag); | | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | Pgno sqlite3PagerPagenumber(DbPage*); int sqlite3PagerWrite(DbPage*); int sqlite3PagerIswriteable(DbPage*); int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*); int sqlite3PagerPagecount(Pager*); int sqlite3PagerTruncate(Pager*,Pgno); int sqlite3PagerBegin(DbPage*, int exFlag); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, Pgno); int sqlite3PagerCommitPhaseTwo(Pager*); int sqlite3PagerRollback(Pager*); int sqlite3PagerIsreadonly(Pager*); int sqlite3PagerStmtBegin(Pager*); int sqlite3PagerStmtCommit(Pager*); int sqlite3PagerStmtRollback(Pager*); void sqlite3PagerDontRollback(DbPage*); void sqlite3PagerDontWrite(Pager*, Pgno); |
︙ | ︙ |
Changes to src/test2.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test2.c,v 1.42 2007/03/30 14:06:34 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include "pager.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
159 160 161 162 163 164 165 | int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TextToPtr(argv[1]); | > > > > > | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TextToPtr(argv[1]); rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } rc = sqlite3PagerCommitPhaseTwo(pPager); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return TCL_OK; } |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 | ** not support atomic multi-file commits, so use the simple case then ** too. */ if( 0==strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ | | | | | | | | 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 | ** not support atomic multi-file commits, so use the simple case then ** too. */ if( 0==strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseOne(pBt, 0); } } /* Do the commit only if all databases successfully complete phase 1. ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an ** IO error while deleting or truncating a journal file. It is unlikely, ** but could happen. In this case abandon processing and return the error. */ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseTwo(pBt); } } if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } } |
︙ | ︙ | |||
1178 1179 1180 1181 1182 1183 1184 | return rc; } /* Sync all the db files involved in the transaction. The same call ** sets the master journal pointer in each individual journal. If ** an error occurs here, do not delete the master journal file. ** | | | | | | | | 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 | return rc; } /* Sync all the db files involved in the transaction. The same call ** sets the master journal pointer in each individual journal. If ** an error occurs here, do not delete the master journal file. ** ** If the error occurs during the first call to ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the ** master journal file will be orphaned. But we cannot delete it, ** in case the master journal file name was written into the journal ** file before the failure occured. */ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsInTrans(pBt) ){ rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster); } } sqlite3OsClose(&master); if( rc!=SQLITE_OK ){ sqliteFree(zMaster); return rc; } |
︙ | ︙ | |||
1219 1220 1221 1222 1223 1224 1225 | ** master journal exists now or if it will exist after the operating ** system crash that may follow the fsync() failure. */ return rc; } /* All files and directories have already been synced, so the following | | | | | | | | 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 | ** master journal exists now or if it will exist after the operating ** system crash that may follow the fsync() failure. */ return rc; } /* All files and directories have already been synced, so the following ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and ** deleting or truncating journals. If something goes wrong while ** this is happening we don't really care. The integrity of the ** transaction is already guaranteed, but some stray 'cold' journals ** may be lying around. Returning an error code won't help matters. */ disable_simulated_io_errors(); for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ sqlite3BtreeCommitPhaseTwo(pBt); } } enable_simulated_io_errors(); sqlite3VtabCommit(db); } #endif |
︙ | ︙ |