Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Changes from ENABLE_CONCURRENT (default off) to OMIT_CONCURRENT (default on). This is not a clear-cut decision and might be changed back. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | begin-concurrent |
Files: | files | file ages | folders |
SHA1: |
f8ae9bfd05abc35293ad6bc62ab1bdbe |
User & Date: | drh 2015-09-03 15:17:12.457 |
Context
2015-09-03
| ||
20:52 | Merge performance enhancements from trunk. This branch now runs (slightly) faster than the 3.8.11.1 release, though still slightly slower than trunk. (check-in: c490bfb150 user: drh tags: begin-concurrent) | |
15:17 | Changes from ENABLE_CONCURRENT (default off) to OMIT_CONCURRENT (default on). This is not a clear-cut decision and might be changed back. (check-in: f8ae9bfd05 user: drh tags: begin-concurrent) | |
14:04 | Merge trunk optimizations. (check-in: 71e7299e8d user: drh tags: begin-concurrent) | |
Changes
Changes to src/btree.c.
︙ | ︙ | |||
436 437 438 439 440 441 442 | } } } #endif /* SQLITE_OMIT_SHARED_CACHE */ | | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | } } } #endif /* SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_CONCURRENT /* ** The following structure - BtreePtrmap - stores the in-memory pointer map ** used for newly allocated pages in CONCURRENT transactions. Such pages are ** always allocated in a contiguous block (from the end of the file) starting ** with page BtreePtrmap.iFirst. */ typedef struct RollbackEntry RollbackEntry; |
︙ | ︙ | |||
469 470 471 472 473 474 475 | int *aSvpt; /* First aRollback[] entry for savepoint i */ int nRollback; /* Used size of aRollback[] array */ int nRollbackAlloc; /* Allocated size of aRollback[] array */ RollbackEntry *aRollback; /* Array of rollback entries */ }; | > | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | int *aSvpt; /* First aRollback[] entry for savepoint i */ int nRollback; /* Used size of aRollback[] array */ int nRollbackAlloc; /* Allocated size of aRollback[] array */ RollbackEntry *aRollback; /* Array of rollback entries */ }; /* !defined(SQLITE_OMIT_CONCURRENT) ** ** If page number pgno is greater than or equal to BtreePtrmap.iFirst, ** store an entry for it in the pointer-map structure. */ static int btreePtrmapStore( BtShared *pBt, Pgno pgno, u8 eType, |
︙ | ︙ | |||
527 528 529 530 531 532 533 | pMap->aPtr[iEntry].parent = parent; pMap->aPtr[iEntry].eType = eType; } return SQLITE_OK; } | > | | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | pMap->aPtr[iEntry].parent = parent; pMap->aPtr[iEntry].eType = eType; } return SQLITE_OK; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** Open savepoint iSavepoint, if it is not already open. */ static int btreePtrmapBegin(BtShared *pBt, int nSvpt){ BtreePtrmap *pMap = pBt->pMap; if( pMap && nSvpt<pMap->nSvpt ){ int i; if( nSvpt>=pMap->nSvptAlloc ){ |
︙ | ︙ | |||
554 555 556 557 558 559 560 | } pMap->nSvpt = nSvpt; } return SQLITE_OK; } | > | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | } pMap->nSvpt = nSvpt; } return SQLITE_OK; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** Rollback (if op==SAVEPOINT_ROLLBACK) or release (if op==SAVEPOINT_RELEASE) ** savepoint iSvpt. */ static void btreePtrmapEnd(BtShared *pBt, int op, int iSvpt){ BtreePtrmap *pMap = pBt->pMap; if( pMap ){ assert( op==SAVEPOINT_ROLLBACK || op==SAVEPOINT_RELEASE ); |
︙ | ︙ | |||
583 584 585 586 587 588 589 | } pMap->nSvpt = iSvpt + (op==SAVEPOINT_ROLLBACK); pMap->nRollback = pMap->aSvpt[iSvpt]; } } } | > | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | } pMap->nSvpt = iSvpt + (op==SAVEPOINT_ROLLBACK); pMap->nRollback = pMap->aSvpt[iSvpt]; } } } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** This function is called after an CONCURRENT transaction is opened on the ** database. It allocates the BtreePtrmap structure used to track pointers ** to allocated pages and zeroes the nFree/iTrunk fields in the database ** header on page 1. */ static int btreePtrmapAllocate(BtShared *pBt){ int rc = SQLITE_OK; |
︙ | ︙ | |||
605 606 607 608 609 610 611 | pMap->iFirst = pBt->nPage + 1; pBt->pMap = pMap; } } return rc; } | > | | | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | pMap->iFirst = pBt->nPage + 1; pBt->pMap = pMap; } } return rc; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** Free any BtreePtrmap structure allocated by an earlier call to ** btreePtrmapAllocate(). */ static void btreePtrmapDelete(BtShared *pBt){ BtreePtrmap *pMap = pBt->pMap; if( pMap ){ sqlite3_free(pMap->aRollback); sqlite3_free(pMap->aPtr); sqlite3_free(pMap->aSvpt); sqlite3_free(pMap); pBt->pMap = 0; } } #else /* SQLITE_OMIT_CONCURRENT */ # define btreePtrmapAllocate(x) SQLITE_OK # define btreePtrmapDelete(x) # define btreePtrmapBegin(x,y) SQLITE_OK # define btreePtrmapEnd(x,y,z) #endif /* SQLITE_OMIT_CONCURRENT */ static void releasePage(MemPage *pPage); /* Forward reference */ /* ***** This routine is used inside of assert() only **** ** ** Verify that the cursor holds the mutex on its BtShared |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | if( *pRC ) return; assert( sqlite3_mutex_held(pBt->mutex) ); /* The master-journal page number is never added to a pointer-map page */ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); | | | 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 | if( *pRC ) return; assert( sqlite3_mutex_held(pBt->mutex) ); /* The master-journal page number is never added to a pointer-map page */ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); #ifndef SQLITE_OMIT_CONCURRENT if( pBt->pMap ){ *pRC = btreePtrmapStore(pBt, key, eType, parent); return; } #endif assert( pBt->autoVacuum ); |
︙ | ︙ | |||
3393 3394 3395 3396 3397 3398 3399 | } } } } trans_begun: | | | 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 | } } } } trans_begun: #ifndef SQLITE_OMIT_CONCURRENT if( bConcurrent && rc==SQLITE_OK && sqlite3PagerIsWal(pBt->pPager) ){ rc = sqlite3PagerBeginConcurrent(pBt->pPager); if( rc==SQLITE_OK && wrflag ){ rc = btreePtrmapAllocate(pBt); } } #endif |
︙ | ︙ | |||
3848 3849 3850 3851 3852 3853 3854 | return rc; } #else /* ifndef SQLITE_OMIT_AUTOVACUUM */ # define setChildPtrmaps(x) SQLITE_OK #endif | | | 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 | return rc; } #else /* ifndef SQLITE_OMIT_AUTOVACUUM */ # define setChildPtrmaps(x) SQLITE_OK #endif #ifndef SQLITE_OMIT_CONCURRENT /* ** This function is called as part of merging an CONCURRENT transaction with ** the snapshot at the head of the wal file. It relocates all pages in the ** range iFirst..iLast, inclusive. It is assumed that the BtreePtrmap ** structure at BtShared.pMap contains the location of the pointers to each ** page in the range. ** |
︙ | ︙ | |||
3916 3917 3918 3919 3920 3921 3922 | releasePage(pPg); } } } return rc; } | > | | 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 | releasePage(pPg); } } } return rc; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** The b-tree handle passed as the only argument is about to commit an ** CONCURRENT transaction. At this point it is guaranteed that this is ** possible - the wal WRITER lock is held and it is known that there are ** no conflicts with committed transactions. */ static int btreeFixUnlocked(Btree *p){ BtShared *pBt = p->pBt; |
︙ | ︙ | |||
4007 4008 4009 4010 4011 4012 4013 | sqlite3PagerSetDbsize(pPager, nFin); } return rc; } #else # define btreeFixUnlocked(X) SQLITE_OK | | | 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 | sqlite3PagerSetDbsize(pPager, nFin); } return rc; } #else # define btreeFixUnlocked(X) SQLITE_OK #endif /* SQLITE_OMIT_CONCURRENT */ /* ** 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 |
︙ | ︙ |
Changes to src/btreeInt.h.
︙ | ︙ | |||
444 445 446 447 448 449 450 | #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ | | | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ #ifndef SQLITE_OMIT_CONCURRENT BtreePtrmap *pMap; #endif }; /* ** Allowed values for BtShared.btsFlags */ |
︙ | ︙ | |||
653 654 655 656 657 658 659 | /* ** The ISAUTOVACUUM macro is used within balance_nonroot() to determine ** if the database supports auto-vacuum or not. Because it is used ** within an expression that is an argument to another macro ** (sqliteMallocRaw), it is not possible to use conditional compilation. ** So, this macro is defined instead. */ | | | | | | | | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | /* ** The ISAUTOVACUUM macro is used within balance_nonroot() to determine ** if the database supports auto-vacuum or not. Because it is used ** within an expression that is an argument to another macro ** (sqliteMallocRaw), it is not possible to use conditional compilation. ** So, this macro is defined instead. */ #ifdef SQLITE_OMIT_AUTOVACUUM #define ISAUTOVACUUM 0 #else #define ISAUTOVACUUM (pBt->autoVacuum) #endif #ifdef SQLITE_OMIT_CONCURRENT # define ISCONCURRENT 0 #else # define ISCONCURRENT (pBt->pMap!=0) #endif #define REQUIRE_PTRMAP (ISAUTOVACUUM || ISCONCURRENT) /* ** This structure is passed around through all the sanity checking routines ** in order to keep track of some global state information. |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
653 654 655 656 657 658 659 | Pgno dbFileSize; /* Number of pages in the database file */ Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */ int errCode; /* One of several kinds of errors */ int nRec; /* Pages journalled since last j-header written */ u32 cksumInit; /* Quasi-random value added to every checksum */ u32 nSubRec; /* Number of records written to sub-journal */ Bitvec *pInJournal; /* One bit for each page in the database file */ | | | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | Pgno dbFileSize; /* Number of pages in the database file */ Pgno dbHintSize; /* Value passed to FCNTL_SIZE_HINT call */ int errCode; /* One of several kinds of errors */ int nRec; /* Pages journalled since last j-header written */ u32 cksumInit; /* Quasi-random value added to every checksum */ u32 nSubRec; /* Number of records written to sub-journal */ Bitvec *pInJournal; /* One bit for each page in the database file */ #ifndef SQLITE_OMIT_CONCURRENT Bitvec *pAllRead; /* Pages read within current CONCURRENT trans. */ #endif sqlite3_file *fd; /* File descriptor for database */ sqlite3_file *jfd; /* File descriptor for main journal */ sqlite3_file *sjfd; /* File descriptor for sub-journal */ i64 journalOff; /* Current write offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ |
︙ | ︙ | |||
902 903 904 905 906 907 908 | case PAGER_WRITER_LOCKED: assert( p->eLock!=UNKNOWN_LOCK ); assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) ){ assert( p->eLock>=RESERVED_LOCK ); } | | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | case PAGER_WRITER_LOCKED: assert( p->eLock!=UNKNOWN_LOCK ); assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) ){ assert( p->eLock>=RESERVED_LOCK ); } #ifndef SQLITE_OMIT_CONCURRENT assert( pPager->dbSize==pPager->dbOrigSize || pPager->pAllRead ); #endif assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); assert( pPager->setMaster==0 ); break; |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 | testcase( rc==SQLITE_NOMEM ); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); } } return rc; } | | > | > | | | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 | testcase( rc==SQLITE_NOMEM ); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); } } return rc; } #ifndef SQLITE_OMIT_CONCURRENT /* ** If they are not already, begin recording all pages read from the pager layer ** by the b-tree layer This is used by concurrent transactions. Return ** SQLITE_OK if successful, or an SQLite error code (SQLITE_NOMEM) if an error ** occurs. */ int sqlite3PagerBeginConcurrent(Pager *pPager){ int rc = SQLITE_OK; if( pPager->pAllRead==0 ){ pPager->pAllRead = sqlite3BitvecCreate(pPager->dbSize); if( pPager->pAllRead==0 ){ rc = SQLITE_NOMEM; } } return rc; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** Stop recording all pages read from the pager layer by the b-tree layer ** and discard any current records. */ void sqlite3PagerEndConcurrent(Pager *pPager){ sqlite3BitvecDestroy(pPager->pAllRead); pPager->pAllRead = 0; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** Return true if the database is in wal mode. False otherwise. */ int sqlite3PagerIsWal(Pager *pPager){ return pPager->pWal!=0; } #endif /* SQLITE_OMIT_CONCURRENT */ /* ** Free the Pager.pInJournal and Pager.pAllRead bitvec objects. */ static void pagerFreeBitvecs(Pager *pPager){ sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; |
︙ | ︙ | |||
3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 | ** + Discard the cached page (if refcount==0), or ** + Reload page content from the database (if refcount>0). */ pPager->dbSize = pPager->dbOrigSize; rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager); pList = sqlite3PcacheDirtyList(pPager->pPCache); /* If this is an CONCURRENT transaction, then page 1 must be reread from ** the db file, even if it is not dirty. This is because the b-tree layer ** may have already zeroed the nFree and iTrunk header fields. */ | > < | 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 | ** + Discard the cached page (if refcount==0), or ** + Reload page content from the database (if refcount>0). */ pPager->dbSize = pPager->dbOrigSize; rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager); pList = sqlite3PcacheDirtyList(pPager->pPCache); #ifndef SQLITE_OMIT_CONCURRENT /* If this is an CONCURRENT transaction, then page 1 must be reread from ** the db file, even if it is not dirty. This is because the b-tree layer ** may have already zeroed the nFree and iTrunk header fields. */ if( rc==SQLITE_OK && (pList==0 || pList->pgno!=1) && pPager->pAllRead ){ rc = pagerUndoCallback((void*)pPager, 1); } #endif while( pList && rc==SQLITE_OK ){ PgHdr *pNext = pList->pDirty; |
︙ | ︙ | |||
4482 4483 4484 4485 4486 4487 4488 4489 4490 | || (pPg->flags & PGHDR_NEED_SYNC)!=0) ){ return SQLITE_OK; } pPg->pDirty = 0; if( pagerUseWal(pPager) ){ /* If the transaction is a "BEGIN CONCURRENT" transaction, the page ** cannot be flushed to disk. Return early in this case. */ | > < | 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 | || (pPg->flags & PGHDR_NEED_SYNC)!=0) ){ return SQLITE_OK; } pPg->pDirty = 0; if( pagerUseWal(pPager) ){ #ifndef SQLITE_OMIT_CONCURRENT /* If the transaction is a "BEGIN CONCURRENT" transaction, the page ** cannot be flushed to disk. Return early in this case. */ if( pPager->pAllRead ) return SQLITE_OK; #endif /* Write a single frame for this page to the log. */ rc = subjournalPageIfRequired(pPg); if( rc==SQLITE_OK ){ rc = pagerWalFrames(pPager, pPg, 0, 0); |
︙ | ︙ | |||
5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 | assert( noContent==0 || bMmapOk==0 ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } pPager->hasBeenUsed = 1; /* If this is an CONCURRENT transaction and the page being read was ** present in the database file when the transaction was opened, ** mark it as read in the pAllRead vector. */ | > < | 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 | assert( noContent==0 || bMmapOk==0 ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } pPager->hasBeenUsed = 1; #ifndef SQLITE_OMIT_CONCURRENT /* If this is an CONCURRENT transaction and the page being read was ** present in the database file when the transaction was opened, ** mark it as read in the pAllRead vector. */ if( pPager->pAllRead && pgno<=pPager->dbOrigSize ){ rc = sqlite3BitvecSet(pPager->pAllRead, pgno); if( rc!=SQLITE_OK ) goto pager_acquire_err; } #endif /* If the pager is in the error state, return an error immediately. |
︙ | ︙ | |||
5966 5967 5968 5969 5970 5971 5972 | } /* ** Return TRUE if the page given in the argument was previously passed ** to sqlite3PagerWrite(). In other words, return TRUE if it is ok ** to change the content of the page. */ | | | 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 | } /* ** Return TRUE if the page given in the argument was previously passed ** to sqlite3PagerWrite(). In other words, return TRUE if it is ok ** to change the content of the page. */ #if !defined(SQLITE_OMIT_CONCURRENT) || !defined(NDEBUG) int sqlite3PagerIswriteable(DbPage *pPg){ return pPg->flags & PGHDR_WRITEABLE; } #endif /* ** A call to this routine tells the pager that it is not necessary to |
︙ | ︙ | |||
6147 6148 6149 6150 6151 6152 6153 | || pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( 0==pagerUseWal(pPager) ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } | | | | | 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 | || pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( 0==pagerUseWal(pPager) ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } #ifndef SQLITE_OMIT_CONCURRENT else{ if( pPager->pAllRead ){ /* This is an CONCURRENT transaction. Attempt to lock the wal database ** here. If SQLITE_BUSY (but not SQLITE_BUSY_SNAPSHOT) is returned, ** invoke the busy-handler and try again for as long as it returns ** non-zero. */ do { rc = sqlite3WalLockForCommit(pPager->pWal, pPage1, pPager->pAllRead); }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) ); } } #endif /* SQLITE_OMIT_CONCURRENT */ return rc; } #ifndef SQLITE_OMIT_CONCURRENT /* ** This function is called as part of committing an CONCURRENT transaction. ** At this point the wal WRITER lock is held, and all pages in the cache ** except for page 1 are compatible with the snapshot at the head of the ** wal file. ** ** This function updates the in-memory data structures and reloads the |
︙ | ︙ | |||
6194 6195 6196 6197 6198 6199 6200 | if( rc==SQLITE_OK ){ rc = readDbPage(pPage1, iFrame); } return rc; } | > | > | | | 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 | if( rc==SQLITE_OK ){ rc = readDbPage(pPage1, iFrame); } return rc; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** Set the in-memory cache of the database file size to nSz pages. */ void sqlite3PagerSetDbsize(Pager *pPager, Pgno nSz){ pPager->dbSize = nSz; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** If this is a WAL mode connection and the WRITER lock is currently held, ** relinquish it. */ void sqlite3PagerDropExclusiveLock(Pager *pPager){ if( pagerUseWal(pPager) ){ sqlite3WalEndWriteTransaction(pPager->pWal); } } #endif /* SQLITE_OMIT_CONCURRENT */ /* ** 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). |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
190 191 192 193 194 195 196 | int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); void sqlite3PagerRekey(DbPage*, Pgno, u16); | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); void sqlite3PagerRekey(DbPage*, Pgno, u16); #ifndef SQLITE_OMIT_CONCURRENT void sqlite3PagerEndConcurrent(Pager*); int sqlite3PagerBeginConcurrent(Pager*); void sqlite3PagerDropExclusiveLock(Pager*); int sqlite3PagerUpgradeSnapshot(Pager *pPager, DbPage*); void sqlite3PagerSetDbsize(Pager *pPager, Pgno); int sqlite3PagerIsWal(Pager*); #else |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
569 570 571 572 573 574 575 | #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "1", TCL_GLOBAL_ONLY); #endif | | | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "1", TCL_GLOBAL_ONLY); #endif #ifndef SQLITE_OMIT_CONCURRENT Tcl_SetVar2(interp, "sqlite_options", "concurrent", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "concurrent", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_UTF16 Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
3223 3224 3225 3226 3227 3228 3229 | assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); pIn3 = &aMem[pOp->p3]; sqlite3VdbeMemIntegerify(pIn3); | | | 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 | assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); pIn3 = &aMem[pOp->p3]; sqlite3VdbeMemIntegerify(pIn3); #ifndef SQLITE_OMIT_CONCURRENT if( db->bConcurrent && (pOp->p2==BTREE_USER_VERSION || pOp->p2==BTREE_APPLICATION_ID) ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "cannot modify %s within CONCURRENT transaction", pOp->p2==BTREE_USER_VERSION ? "user_version" : "application_id" ); |
︙ | ︙ | |||
6111 6112 6113 6114 6115 6116 6117 | ** P2 contains the root-page of the table to lock. ** ** P4 contains a pointer to the name of the table being locked. This is only ** used to generate an error message if the lock cannot be obtained. */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; | | | 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 | ** P2 contains the root-page of the table to lock. ** ** P4 contains a pointer to the name of the table being locked. This is only ** used to generate an error message if the lock cannot be obtained. */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; #ifndef SQLITE_OMIT_CONCURRENT if( isWriteLock && db->bConcurrent && pOp->p2==1 ){ rc = SQLITE_ERROR; sqlite3VdbeError(p, "cannot modify database schema within CONCURRENT transaction"); break; } #endif |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
2037 2038 2039 2040 2041 2042 2043 | if( sqlite3BtreeIsInTrans(pBt) ){ needXcommit = 1; if( i!=1 ) nTrans++; rc = sqlite3BtreeExclusiveLock(pBt); } } | | | 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 | if( sqlite3BtreeIsInTrans(pBt) ){ needXcommit = 1; if( i!=1 ) nTrans++; rc = sqlite3BtreeExclusiveLock(pBt); } } #ifndef SQLITE_OMIT_CONCURRENT if( db->bConcurrent && (rc & 0xFF)==SQLITE_BUSY ){ /* An SQLITE_BUSY or SQLITE_BUSY_SNAPSHOT was encountered while ** attempting to take the WRITER lock on a wal file. Release the ** WRITER locks on all wal files and return early. */ for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeIsInTrans(pBt) ){ |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
2622 2623 2624 2625 2626 2627 2628 | testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); return rc; } | | | 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 | testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); return rc; } #ifndef SQLITE_OMIT_CONCURRENT /* ** This function is only ever called when committing a "BEGIN CONCURRENT" ** transaction. It may be assumed that no frames have been written to ** the wal file. The second parameter is a pointer to the in-memory ** representation of page 1 of the database (which may or may not be ** dirty). The third is a bitvec with a bit set for each page in the ** database file that was read by the current concurrent transaction. |
︙ | ︙ | |||
2748 2749 2750 2751 2752 2753 2754 | } } } return rc; } | > | | 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 | } } } return rc; } /* !defined(SQLITE_OMIT_CONCURRENT) ** ** This function is called as part of committing an CONCURRENT transaction. ** It is assumed that sqlite3WalLockForCommit() has already been successfully ** called and so (a) the WRITER lock is held and (b) it is known that the ** wal-index-header stored in shared memory is not corrupt. ** ** Before returning, this function upgrades the client so that it is ** operating on the database snapshot currently at the head of the wal file |
︙ | ︙ | |||
2774 2775 2776 2777 2778 2779 2780 | ** any reads performed between now and committing the transaction will ** read from the old snapshot - not the one just upgraded to. */ if( pWal->readLock==0 && pWal->hdr.mxFrame!=walCkptInfo(pWal)->nBackfill ){ rc = walUpgradeReadlock(pWal); } return rc; } | | | 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 | ** any reads performed between now and committing the transaction will ** read from the old snapshot - not the one just upgraded to. */ if( pWal->readLock==0 && pWal->hdr.mxFrame!=walCkptInfo(pWal)->nBackfill ){ rc = walUpgradeReadlock(pWal); } return rc; } #endif /* SQLITE_OMIT_CONCURRENT */ /* ** End a write transaction. The commit has already been done. This ** routine merely releases the lock. */ int sqlite3WalEndWriteTransaction(Wal *pWal){ if( pWal->writeLock ){ |
︙ | ︙ |
Changes to src/wal.h.
︙ | ︙ | |||
122 123 124 125 126 127 128 | /* Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the ** WAL module is using shared-memory, return false. */ int sqlite3WalHeapMemory(Wal *pWal); | | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | /* Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the ** WAL module is using shared-memory, return false. */ int sqlite3WalHeapMemory(Wal *pWal); #ifndef SQLITE_OMIT_CONCURRENT /* Tell the wal layer that we want to commit a concurrent transaction */ int sqlite3WalLockForCommit(Wal *pWal, PgHdr *pPg, Bitvec *pRead); /* Upgrade the state of the client to take into account changes written ** by other connections */ int sqlite3WalUpgradeSnapshot(Wal *pWal); #endif /* SQLITE_OMIT_CONCURRENT */ #ifdef SQLITE_ENABLE_ZIPVFS /* If the WAL file is not empty, return the number of bytes of content ** stored in each frame (i.e. the db page-size when the WAL was created). */ int sqlite3WalFramesize(Wal *pWal); #endif |
︙ | ︙ |