Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for #2854. "BEGIN EXCLUSIVE" excludes other shared cache users from using the database. (CVS 4642) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
2e59b1d07ee422bd799b5b7aeea44ebc |
User & Date: | danielk1977 2007-12-21 04:47:26.000 |
Context
2007-12-27
| ||
15:12 | Fix a race condition that can occur when reloading the database schema in shared-cache mode. (CVS 4643) (check-in: b37babef91 user: danielk1977 tags: trunk) | |
2007-12-21
| ||
04:47 | Fix for #2854. "BEGIN EXCLUSIVE" excludes other shared cache users from using the database. (CVS 4642) (check-in: 2e59b1d07e user: danielk1977 tags: trunk) | |
00:02 | Fix some issues with lemon. Tickets #2852 and #2835. (CVS 4641) (check-in: 5283e0d146 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.434 2007/12/21 04:47:26 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
98 99 100 101 102 103 104 105 106 107 108 109 110 111 | assert( sqlite3BtreeHoldsMutex(p) ); /* This is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } /* This (along with lockTable()) is where the ReadUncommitted flag is ** dealt with. If the caller is querying for a read-lock and the flag is ** set, it is unconditionally granted - even if there are write-locks ** on the table. If a write-lock is requested, the ReadUncommitted flag ** is not considered. ** | > > > > > > > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | assert( sqlite3BtreeHoldsMutex(p) ); /* This is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } /* If some other connection is holding an exclusive lock, the ** requested lock may not be obtained. */ if( pBt->pExclusive && pBt->pExclusive!=p ){ return SQLITE_LOCKED; } /* This (along with lockTable()) is where the ReadUncommitted flag is ** dealt with. If the caller is querying for a read-lock and the flag is ** set, it is unconditionally granted - even if there are write-locks ** on the table. If a write-lock is requested, the ReadUncommitted flag ** is not considered. ** |
︙ | ︙ | |||
208 209 210 211 212 213 214 | #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Release all the table locks (locks obtained via calls to the lockTable() ** procedure) held by Btree handle p. */ static void unlockAllTables(Btree *p){ | > | > > > > > | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Release all the table locks (locks obtained via calls to the lockTable() ** procedure) held by Btree handle p. */ static void unlockAllTables(Btree *p){ BtShared *pBt = p->pBt; BtLock **ppIter = &pBt->pLock; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->sharable || 0==*ppIter ); while( *ppIter ){ BtLock *pLock = *ppIter; assert( pBt->pExclusive==0 || pBt->pExclusive==pLock->pBtree ); if( pLock->pBtree==p ){ *ppIter = pLock->pNext; sqlite3_free(pLock); }else{ ppIter = &pLock->pNext; } } if( pBt->pExclusive==p ){ pBt->pExclusive = 0; } } #endif /* SQLITE_OMIT_SHARED_CACHE */ static void releasePage(MemPage *pPage); /* Forward reference */ /* ** Verify that the cursor holds a mutex on the BtShared |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 | ** requested, return SQLITE_BUSY. */ if( pBt->inTransaction==TRANS_WRITE && wrflag ){ rc = SQLITE_BUSY; goto trans_begun; } do { if( pBt->pPage1==0 ){ rc = lockBtree(pBt); } if( rc==SQLITE_OK && wrflag ){ if( pBt->readOnly ){ | > > > > > > > > > > > > | 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 | ** requested, return SQLITE_BUSY. */ if( pBt->inTransaction==TRANS_WRITE && wrflag ){ rc = SQLITE_BUSY; goto trans_begun; } #ifndef SQLITE_OMIT_SHARED_CACHE if( wrflag>1 ){ BtLock *pIter; for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->pBtree!=p ){ rc = SQLITE_BUSY; goto trans_begun; } } } #endif do { if( pBt->pPage1==0 ){ rc = lockBtree(pBt); } if( rc==SQLITE_OK && wrflag ){ if( pBt->readOnly ){ |
︙ | ︙ | |||
1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 | if( p->inTrans==TRANS_NONE ){ pBt->nTransaction++; } p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( p->inTrans>pBt->inTransaction ){ pBt->inTransaction = p->inTrans; } } trans_begun: btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; | > > > > > > | 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 | if( p->inTrans==TRANS_NONE ){ pBt->nTransaction++; } p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( p->inTrans>pBt->inTransaction ){ pBt->inTransaction = p->inTrans; } #ifndef SQLITE_OMIT_SHARED_CACHE if( wrflag>1 ){ assert( !pBt->pExclusive ); pBt->pExclusive = p; } #endif } trans_begun: btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; |
︙ | ︙ |
Changes to src/btreeInt.h.
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: btreeInt.h,v 1.15 2007/12/21 04:47:26 danielk1977 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. |
︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 401 402 403 404 | void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */ BusyHandler busyHdr; /* The busy handler for this btree */ #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 */ #endif }; /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure ** based on information extract from the raw disk page. | > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */ BusyHandler busyHdr; /* The busy handler for this btree */ #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 *pExclusive; /* Btree with an EXCLUSIVE lock on the whole db */ #endif }; /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure ** based on information extract from the raw disk page. |
︙ | ︙ |
Added test/tkt2854.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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | # 2007 December 20 # # 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: tkt2854.test,v 1.1 2007/12/21 04:47:27 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl db close ifcapable !shared_cache { finish_test return } set ::enable_shared_cache [sqlite3_enable_shared_cache 1] # Open 3 database connections. Connection "db" and "db2" share a cache. # Connection "db3" has its own cache. # do_test tkt2854-1.1 { sqlite3 db test.db sqlite3 db2 test.db sqlite3 db3 ./test.db db eval { CREATE TABLE abc(a, b, c); } } {} # Check that an exclusive lock cannot be obtained if some other # shared-cache connection has a read-lock on a table. # do_test tkt2854-1.2 { execsql { BEGIN; SELECT * FROM abc; } db2 } {} do_test tkt2854-1.3 { catchsql { BEGIN EXCLUSIVE } db } {1 {database is locked}} do_test tkt2854-1.4 { execsql { SELECT * FROM abc } db3 } {} do_test tkt2854-1.5 { catchsql { INSERT INTO abc VALUES(1, 2, 3) } db3 } {1 {database is locked}} do_test tkt2854-1.6 { execsql { COMMIT } db2 } {} # Check that an exclusive lock prevents other shared-cache users from # starting a transaction. # do_test tkt2854-1.7 { set ::DB2 [sqlite3_connection_pointer db2] set ::STMT1 [sqlite3_prepare $DB2 "SELECT * FROM abc" -1 TAIL] set ::STMT2 [sqlite3_prepare $DB2 "BEGIN EXCLUSIVE" -1 TAIL] set ::STMT3 [sqlite3_prepare $DB2 "BEGIN IMMEDIATE" -1 TAIL] set ::STMT4 [sqlite3_prepare $DB2 "BEGIN" -1 TAIL] set ::STMT5 [sqlite3_prepare $DB2 "COMMIT" -1 TAIL] execsql { BEGIN EXCLUSIVE } db } {} do_test tkt2854-1.8 { catchsql { BEGIN EXCLUSIVE } db2 } {1 {database schema is locked: main}} do_test tkt2854-1.9 { catchsql { BEGIN IMMEDIATE } db2 } {1 {database schema is locked: main}} do_test tkt2854-1.10 { # This fails because the schema of main cannot be verified. catchsql { BEGIN } db2 } {1 {database schema is locked: main}} # Check that an exclusive lock prevents other shared-cache users from # reading the database. Use stored statements so that the error occurs # at the b-tree level, not the schema level. # do_test tkt2854-1.11 { list [sqlite3_step $::STMT1] [sqlite3_finalize $::STMT1] } {SQLITE_ERROR SQLITE_LOCKED} do_test tkt2854-1.12 { list [sqlite3_step $::STMT2] [sqlite3_finalize $::STMT2] } {SQLITE_BUSY SQLITE_BUSY} do_test tkt2854-1.13 { list [sqlite3_step $::STMT3] [sqlite3_finalize $::STMT3] } {SQLITE_BUSY SQLITE_BUSY} do_test tkt2854-1.14 { # A regular "BEGIN" doesn't touch any databases. So it succeeds. list [sqlite3_step $::STMT4] [sqlite3_finalize $::STMT4] } {SQLITE_DONE SQLITE_OK} do_test tkt2854-1.15 { # As does a COMMIT. list [sqlite3_step $::STMT5] [sqlite3_finalize $::STMT5] } {SQLITE_DONE SQLITE_OK} # Try to read the database using connection "db3" (which does not share # a cache with "db"). The database should be locked. do_test tkt2854-1.16 { catchsql { SELECT * FROM abc } db3 } {1 {database is locked}} do_test tkt2854-1.17 { execsql { COMMIT } db } {} do_test tkt2854-1.18 { execsql { SELECT * FROM abc } db2 } {} # Check that if an attempt to obtain an exclusive lock fails because an # attached db cannot be locked, the internal exclusive flag used by # shared-cache users is correctly cleared. do_test tkt2854-1.19 { file delete -force test2.db test2.db-journal sqlite3 db4 test2.db execsql { CREATE TABLE def(d, e, f) } db4 execsql { ATTACH 'test2.db' AS aux } db } {} do_test tkt2854-1.20 { execsql {BEGIN IMMEDIATE} db4 catchsql {BEGIN EXCLUSIVE} db } {1 {database is locked}} do_test tkt2854-1.21 { execsql {SELECT * FROM abc} db2 } {} db close db2 close db3 close db4 close sqlite3_enable_shared_cache $::enable_shared_cache finish_test |