Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Only allow UNLOCKED transactions to commit if none of the pages read by the transaction have been modified since it was opened. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | begin-concurrent |
Files: | files | file ages | folders |
SHA1: |
0b9718426e44df092850c5d095ce1b84 |
User & Date: | dan 2015-07-29 12:14:28.276 |
Context
2015-08-15
| ||
18:16 | Handle writes to auto-vacuum databases within UNLOCKED transactions in the same way as for non-UNLOCKED transactions. (check-in: de1ea450db user: dan tags: begin-concurrent) | |
2015-07-29
| ||
12:14 | Only allow UNLOCKED transactions to commit if none of the pages read by the transaction have been modified since it was opened. (check-in: 0b9718426e user: dan tags: begin-concurrent) | |
2015-07-28
| ||
16:46 | Add some test cases and fix some small problems with BEGIN UNLOCKED transactions. (check-in: 6da0e962ad user: dan tags: begin-concurrent) | |
Changes
Changes to src/btree.c.
︙ | ︙ | |||
9586 9587 9588 9589 9590 9591 9592 | return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; } /* ** Return the size of the header added to each page by this module. */ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } | < < < < < < < < < < < < | 9586 9587 9588 9589 9590 9591 9592 | return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; } /* ** Return the size of the header added to each page by this module. */ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } |
Changes to src/btree.h.
︙ | ︙ | |||
266 267 268 269 270 271 272 | # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif | < < | 266 267 268 269 270 271 272 273 | # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif #endif /* _BTREE_H_ */ |
Changes to src/pager.c.
︙ | ︙ | |||
653 654 655 656 657 658 659 660 661 662 663 664 665 666 | 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 */ 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 */ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ | > | 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 */ Bitvec *pAllRead; /* Pages read within current UNLOCKED trans. */ 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 */ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ |
︙ | ︙ | |||
1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 | rc |= sqlite3BitvecSet(p->pInSavepoint, pgno); testcase( rc==SQLITE_NOMEM ); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); } } return rc; } /* ** This function is a no-op if the pager is in exclusive mode and not ** in the ERROR state. Otherwise, it switches the pager to PAGER_OPEN ** state. ** ** If the pager is not in exclusive-access mode, the database file is | > > > > > > > > > > | 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 | rc |= sqlite3BitvecSet(p->pInSavepoint, pgno); testcase( rc==SQLITE_NOMEM ); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); } } return rc; } /* ** Free the Pager.pInJournal and Pager.pAllRead bitvec objects. */ static void pagerFreeBitvecs(Pager *pPager){ sqlite3BitvecDestroy(pPager->pInJournal); sqlite3BitvecDestroy(pPager->pAllRead); pPager->pInJournal = 0; pPager->pAllRead = 0; } /* ** This function is a no-op if the pager is in exclusive mode and not ** in the ERROR state. Otherwise, it switches the pager to PAGER_OPEN ** state. ** ** If the pager is not in exclusive-access mode, the database file is |
︙ | ︙ | |||
1758 1759 1760 1761 1762 1763 1764 | static void pager_unlock(Pager *pPager){ assert( pPager->eState==PAGER_READER || pPager->eState==PAGER_OPEN || pPager->eState==PAGER_ERROR ); | < | | 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 | static void pager_unlock(Pager *pPager){ assert( pPager->eState==PAGER_READER || pPager->eState==PAGER_OPEN || pPager->eState==PAGER_ERROR ); pagerFreeBitvecs(pPager); releaseAllSavepoints(pPager); if( pagerUseWal(pPager) ){ assert( !isOpen(pPager->jfd) ); sqlite3WalEndReadTransaction(pPager->pWal); pPager->eState = PAGER_OPEN; }else if( !pPager->exclusiveMode ){ |
︙ | ︙ | |||
1995 1996 1997 1998 1999 2000 2001 | if( p ){ p->pageHash = 0; sqlite3PagerUnrefNotNull(p); } } #endif | < | | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 | if( p ){ p->pageHash = 0; sqlite3PagerUnrefNotNull(p); } } #endif pagerFreeBitvecs(pPager); pPager->nRec = 0; sqlite3PcacheCleanAll(pPager->pPCache); sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE |
︙ | ︙ | |||
4078 4079 4080 4081 4082 4083 4084 | assert( pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); assert( !pagerUseWal(pPager) ); | | | 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 | assert( pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); assert( !pagerUseWal(pPager) ); rc = sqlite3PagerExclusiveLock(pPager); if( rc!=SQLITE_OK ) return rc; if( !pPager->noSync ){ assert( !pPager->tempFile ); if( isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){ const int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); assert( isOpen(pPager->jfd) ); |
︙ | ︙ | |||
4428 4429 4430 4431 4432 4433 4434 | return SQLITE_OK; } pPg->pDirty = 0; if( pagerUseWal(pPager) ){ /* If the transaction is a "BEGIN UNLOCKED" transaction, the page ** cannot be flushed to disk. Return early in this case. */ | | | 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 | return SQLITE_OK; } pPg->pDirty = 0; if( pagerUseWal(pPager) ){ /* If the transaction is a "BEGIN UNLOCKED" transaction, the page ** cannot be flushed to disk. Return early in this case. */ if( pPager->pAllRead ) return SQLITE_OK; /* Write a single frame for this page to the log. */ rc = subjournalPageIfRequired(pPg); if( rc==SQLITE_OK ){ rc = pagerWalFrames(pPager, pPg, 0, 0); } }else{ |
︙ | ︙ | |||
5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 | assert( assert_pager_state(pPager) ); assert( noContent==0 || bMmapOk==0 ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } pPager->hasBeenUsed = 1; /* If the pager is in the error state, return an error immediately. ** Otherwise, request the page from the PCache layer. */ if( pPager->errCode!=SQLITE_OK ){ rc = pPager->errCode; }else{ if( bMmapOk && pagerUseWal(pPager) ){ | > > > > > > > > | 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 | assert( assert_pager_state(pPager) ); assert( noContent==0 || bMmapOk==0 ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } pPager->hasBeenUsed = 1; /* If this is an UNLOCKED 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; } /* If the pager is in the error state, return an error immediately. ** Otherwise, request the page from the PCache layer. */ if( pPager->errCode!=SQLITE_OK ){ rc = pPager->errCode; }else{ if( bMmapOk && pagerUseWal(pPager) ){ |
︙ | ︙ | |||
5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 | if( pPager->errCode ) return pPager->errCode; assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR ); pPager->subjInMemory = (u8)subjInMemory; if( ALWAYS(pPager->eState==PAGER_READER) ){ assert( pPager->pInJournal==0 ); if( pagerUseWal(pPager) ){ /* If the pager is configured to use locking_mode=exclusive, and an ** exclusive lock on the database is not already held, obtain it now. */ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; } sqlite3WalExclusiveMode(pPager->pWal, 1); } /* Grab the write lock on the log file. If successful, upgrade to ** PAGER_RESERVED state. Otherwise, return an error code to the caller. ** The busy-handler is not invoked if another connection already ** holds the write-lock. If possible, the upper layer will call it. */ if( exFlag>=0 ){ rc = sqlite3WalBeginWriteTransaction(pPager->pWal); } }else{ /* Obtain a RESERVED lock on the database file. If the exFlag parameter ** is true, then immediately upgrade this to an EXCLUSIVE lock. The ** busy-handler callback can be used when upgrading to the EXCLUSIVE ** lock, but not when obtaining the RESERVED lock. */ | > > > > > > > > | 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 | if( pPager->errCode ) return pPager->errCode; assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR ); pPager->subjInMemory = (u8)subjInMemory; if( ALWAYS(pPager->eState==PAGER_READER) ){ assert( pPager->pInJournal==0 ); assert( pPager->pAllRead==0 ); if( pagerUseWal(pPager) ){ /* If the pager is configured to use locking_mode=exclusive, and an ** exclusive lock on the database is not already held, obtain it now. */ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; } sqlite3WalExclusiveMode(pPager->pWal, 1); } /* Grab the write lock on the log file. If successful, upgrade to ** PAGER_RESERVED state. Otherwise, return an error code to the caller. ** The busy-handler is not invoked if another connection already ** holds the write-lock. If possible, the upper layer will call it. */ if( exFlag>=0 ){ rc = sqlite3WalBeginWriteTransaction(pPager->pWal); }else{ pPager->pAllRead = sqlite3BitvecCreate(pPager->dbSize); if( pPager->pAllRead==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3BitvecSet(pPager->pAllRead, 1); } } }else{ /* Obtain a RESERVED lock on the database file. If the exFlag parameter ** is true, then immediately upgrade this to an EXCLUSIVE lock. The ** busy-handler callback can be used when upgrading to the EXCLUSIVE ** lock, but not when obtaining the RESERVED lock. */ |
︙ | ︙ | |||
6062 6063 6064 6065 6066 6067 6068 | ** the database file, an attempt is made to obtain one. ** ** If the EXCLUSIVE lock is already held or the attempt to obtain it is ** successful, or the connection is in WAL mode, SQLITE_OK is returned. ** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is ** returned. */ | | | < < < < < < < | | 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 | ** the database file, an attempt is made to obtain one. ** ** If the EXCLUSIVE lock is already held or the attempt to obtain it is ** successful, or the connection is in WAL mode, SQLITE_OK is returned. ** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is ** returned. */ int sqlite3PagerExclusiveLock(Pager *pPager){ int rc = SQLITE_OK; assert( pPager->eState==PAGER_WRITER_CACHEMOD || 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); }else{ if( pPager->pAllRead ){ /* This is an UNLOCKED 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 = sqlite3WalBeginWriteTransaction(pWal); */ rc = sqlite3WalLockForCommit(pPager->pWal, pPager->pAllRead); }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) ); } } return rc; } |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
146 147 148 149 150 151 152 | void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ void sqlite3PagerPagecount(Pager*, int*); int sqlite3PagerBegin(Pager*, int exFlag, int); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ void sqlite3PagerPagecount(Pager*, int*); int sqlite3PagerBegin(Pager*, int exFlag, int); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); int sqlite3PagerExclusiveLock(Pager*); int sqlite3PagerSync(Pager *pPager, const char *zMaster); int sqlite3PagerCommitPhaseTwo(Pager*); int sqlite3PagerRollback(Pager*); int sqlite3PagerOpenSavepoint(Pager *pPager, int n); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); int sqlite3PagerSharedLock(Pager *pPager); |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
2016 2017 2018 2019 2020 2021 2022 | ** file is required for an atomic commit. */ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeIsInTrans(pBt) ){ needXcommit = 1; if( i!=1 ) nTrans++; | | > > | 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 | ** file is required for an atomic commit. */ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeIsInTrans(pBt) ){ needXcommit = 1; if( i!=1 ) nTrans++; sqlite3BtreeEnter(pBt); rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); } } if( db->bUnlocked && (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. */ |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
2569 2570 2571 2572 2573 2574 2575 | /* ** TODO: Combine some code with BeginWriteTransaction() ** ** This function is only ever called when committing a "BEGIN UNLOCKED" ** transaction. It may be assumed that no frames have been written to ** the wal file. */ | | < < | > > | | < < < | < < > | < < < < < | < < | < < < < < < | | < < | < | > | < > > | | < > > > | | | > > | 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 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 | /* ** TODO: Combine some code with BeginWriteTransaction() ** ** This function is only ever called when committing a "BEGIN UNLOCKED" ** transaction. It may be assumed that no frames have been written to ** the wal file. */ int sqlite3WalLockForCommit(Wal *pWal, Bitvec *pAllRead){ int rc = walWriteLock(pWal); /* If the database has been modified since this transaction was started, ** check if it is still possible to commit. The transaction can be ** committed if: ** ** a) None of the pages in pList have been modified since the ** transaction opened, and ** ** b) The database schema cookie has not been modified since the ** transaction was started. */ if( rc==SQLITE_OK ){ volatile WalIndexHdr *pHead; /* Head of the wal file */ pHead = walIndexHdr(pWal); if( memcmp(&pWal->hdr, (void*)pHead, sizeof(WalIndexHdr))!=0 ){ /* TODO: Is this safe? Because it holds the WRITER lock this thread ** has exclusive access to the live header, but might it be corrupt? ** This code should check that the wal-index-header is Ok, and return ** SQLITE_BUSY_SNAPSHOT if it is not. */ int iHash; int iLastHash = walFramePage(pHead->mxFrame); for(iHash=walFramePage(pWal->hdr.mxFrame+1); iHash<=iLastHash; iHash++){ volatile ht_slot *aHash; volatile u32 *aPgno; u32 iZero; rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero); if( rc==SQLITE_OK ){ int i; int iMin = (pWal->hdr.mxFrame+1 - iZero); int iMax = (iHash==0) ? HASHTABLE_NPAGE_ONE : HASHTABLE_NPAGE; if( iMin<1 ) iMin = 1; if( iMax>pHead->mxFrame ) iMax = pHead->mxFrame; for(i=iMin; i<=iMax; i++){ if( sqlite3BitvecTestNotNull(pAllRead, aPgno[i]) ){ sqlite3_log(SQLITE_OK, "cannot commit UNLOCKED transaction (conflict at page %d)", (int)aPgno[i] ); rc = SQLITE_BUSY_SNAPSHOT; } } } if( rc!=SQLITE_OK ) break; } } } return rc; } |
︙ | ︙ | |||
3289 3290 3291 3292 3293 3294 3295 | ** 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){ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ); } | < < < < < < < | 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 | ** 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){ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ); } #ifdef SQLITE_ENABLE_ZIPVFS /* ** If the argument is not NULL, it points to a Wal object that holds a ** read-lock. This function returns the database page-size if it is known, ** or zero if it is not (or if pWal is NULL). */ int sqlite3WalFramesize(Wal *pWal){ assert( pWal==0 || pWal->readLock>=0 ); return (pWal ? pWal->szPage : 0); } #endif #endif /* #ifndef SQLITE_OMIT_WAL */ |
Changes to src/wal.h.
︙ | ︙ | |||
123 124 125 126 127 128 129 | /* 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); /* Return true if the WRITER lock is held. False otherwise. */ | < | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | /* 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); /* Return true if the WRITER lock is held. False otherwise. */ int sqlite3WalLockForCommit(Wal *pWal, Bitvec *pRead); int sqlite3WalCommitRequiresUpgrade(Wal *pWal); #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); |
︙ | ︙ |
Changes to test/unlocked.test.
︙ | ︙ | |||
296 297 298 299 300 301 302 | do_test 2.$tn.5.4 { sql2 { PRAGMA integrity_check } } {ok} catch { sql1 ROLLBACK } #----------------------------------------------------------------------- | < | | > > > > > > | < | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | do_test 2.$tn.5.4 { sql2 { PRAGMA integrity_check } } {ok} catch { sql1 ROLLBACK } #----------------------------------------------------------------------- # # 1. Begin an UNLOCKED write to "t1" using [db] # # 2. Lots of inserts into t2. Enough to grow the db file and modify page 1. # # 3. Check that the UNLOCKED transaction can not be committed. # do_test 2.$tn.6.1 { sql1 { BEGIN UNLOCKED; INSERT INTO t1 VALUES(6, 'six'); } } {} do_test 2.$tn.6.2 { sql2 { WITH src(a,b) AS ( VALUES(1,1) UNION ALL SELECT a+1,b+1 FROM src WHERE a<10000 ) INSERT INTO t2 SELECT * FROM src; } } {} do_test 2.$tn.6.3 { sql1 { SELECT count(*) FROM t2 } list [catch { sql1 { COMMIT } } msg] $msg [sqlite3_errcode db] } {1 {database is locked} SQLITE_BUSY_SNAPSHOT} sql1 ROLLBACK do_test 2.$tn.6.4 { sql1 { SELECT count(*) FROM t1; SELECT count(*) FROM t2; } } {5 10001} #----------------------------------------------------------------------- # # 1. Begin an big UNLOCKED write to "t1" using [db] - large enough to # grow the db file. # # 2. Lots of inserts into t2. Also enough to grow the db file. |
︙ | ︙ |