Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Cherry-pick the multi-file transaction fix for ticket [f3e5abed55] out of the experimental branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
40f7f0a583e6bba66cd006253a0ef462 |
User & Date: | drh 2010-07-30 11:20:36.000 |
Context
2010-07-30
| ||
11:31 | Changes to the comments describing the Pager.setMaster variable in pager.c. Add an assert() statement to verify that two master journal pointers are not written to a single journal file. (check-in: ad78ccacb0 user: dan tags: trunk) | |
11:20 | Cherry-pick the multi-file transaction fix for ticket [f3e5abed55] out of the experimental branch. (check-in: 40f7f0a583 user: drh tags: trunk) | |
05:06 | Add tests to check that the ICU regexp() function can only be called with exactly two arguments. (check-in: 451d965742 user: dan tags: trunk) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 | if( pPager->noSync ){ rc = SQLITE_OK; }else{ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags); } return rc; } /* ** 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). ** | > > > > > > > > > > > > > > > > > > > > | 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 | if( pPager->noSync ){ rc = SQLITE_OK; }else{ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags); } return rc; } /* ** This function may only be called while a write-transaction is active in ** rollback. If the connection is in WAL mode, this call is a no-op. ** Otherwise, if the connection does not already have an EXCLUSIVE lock on ** 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->state>=PAGER_RESERVED ); if( 0==pagerUseWal(pPager) ){ rc = pager_wait_on_lock(pPager, PAGER_EXCLUSIVE); } return rc; } /* ** 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.
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 | void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ int sqlite3PagerPagecount(Pager*, int*); int sqlite3PagerBegin(Pager*, int exFlag, int); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); int sqlite3PagerSync(Pager *pPager); int sqlite3PagerCommitPhaseTwo(Pager*); int sqlite3PagerRollback(Pager*); int sqlite3PagerOpenSavepoint(Pager *pPager, int n); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); int sqlite3PagerSharedLock(Pager *pPager); | > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | void *sqlite3PagerGetData(DbPage *); void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ int sqlite3PagerPagecount(Pager*, int*); int sqlite3PagerBegin(Pager*, int exFlag, int); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); int sqlite3PagerExclusiveLock(Pager*); int sqlite3PagerSync(Pager *pPager); 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.
︙ | ︙ | |||
1642 1643 1644 1645 1646 1647 1648 | /* Before doing anything else, call the xSync() callback for any ** virtual module tables written in this transaction. This has to ** be done before determining whether a master journal file is ** required, as an xSync() callback may add an attached database ** to the transaction. */ rc = sqlite3VtabSync(db, &p->zErrMsg); | < < < | > > > > | 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 | /* Before doing anything else, call the xSync() callback for any ** virtual module tables written in this transaction. This has to ** be done before determining whether a master journal file is ** required, as an xSync() callback may add an attached database ** to the transaction. */ rc = sqlite3VtabSync(db, &p->zErrMsg); /* This loop determines (a) if the commit hook should be invoked and ** (b) how many database files have open write transactions, not ** including the temp database. (b) is important because if more than ** one database file has an open write transaction, a master journal ** 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++; rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt)); } } if( rc!=SQLITE_OK ){ return rc; } /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ rc = db->xCommitCallback(db->pCommitArg); if( rc ){ return SQLITE_CONSTRAINT; |
︙ | ︙ | |||
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 | for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster); } } sqlite3OsCloseFree(pMaster); if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zMaster); return rc; } /* Delete the master journal file. This commits the transaction. After ** doing this the directory is synced again before any individual | > | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 | for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster); } } sqlite3OsCloseFree(pMaster); assert( rc!=SQLITE_BUSY ); if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zMaster); return rc; } /* Delete the master journal file. This commits the transaction. After ** doing this the directory is synced again before any individual |
︙ | ︙ |
Added test/tkt-f3e5abed55.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | # 2010 July 29 # # 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl foreach f [glob -nocomplain test.db*mj*] { file delete -force $f } file delete -force test.db2 do_test tkt-f3e5abed55-1.1 { execsql { ATTACH 'test.db2' AS aux; CREATE TABLE main.t1(a, b); CREATE TABLE aux.t2(c, d); } } {} do_test tkt-f3e5abed55-1.2 { glob -nocomplain test.db*mj* } {} do_test tkt-f3e5abed55-1.3 { sqlite3 db2 test.db execsql { BEGIN; SELECT * FROM t1 } db2 } {} do_test tkt-f3e5abed55-1.4 { execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); INSERT INTO t2 VALUES(1, 2); } catchsql COMMIT } {1 {database is locked}} do_test tkt-f3e5abed55-1.5 { execsql COMMIT db2 execsql COMMIT } {} do_test tkt-f3e5abed55-1.6 { glob -nocomplain test.db*mj* } {} foreach f [glob -nocomplain test.db*mj*] { file delete -force $f } db close db2 close # Set up a testvfs so that the next time SQLite tries to delete the # file "test.db-journal", a snapshot of the current file-system contents # is taken. # testvfs tvfs -default 1 tvfs script xDelete tvfs filter xDelete proc xDelete {method file args} { if {[file tail $file] == "test.db-journal"} { faultsim_save tvfs filter {} } return "SQLITE_OK" } sqlite3 db test.db sqlite3 db2 test.db do_test tkt-f3e5abed55-2.1 { execsql { ATTACH 'test.db2' AS aux; BEGIN; INSERT INTO t1 VALUES(3, 4); INSERT INTO t2 VALUES(3, 4); } } {} do_test tkt-f3e5abed55-2.2 { execsql { BEGIN; SELECT * FROM t1 } db2 } {1 2} do_test tkt-f3e5abed55-2.3 { catchsql COMMIT } {1 {database is locked}} do_test tkt-f3e5abed55-2.4 { execsql COMMIT db2 execsql { COMMIT; SELECT * FROM t1; SELECT * FROM t2; } } {1 2 3 4 1 2 3 4} do_test tkt-f3e5abed55-2.5 { db close db2 close faultsim_restore_and_reopen execsql { ATTACH 'test.db2' AS aux; SELECT * FROM t1; SELECT * FROM t2; } } {1 2 3 4 1 2 3 4} finish_test |