Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Always set BtShared.db when entering the BtShared mutex. Ticket #3793. (CVS 6480) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ed6620ba589ddbb6ca86f42a7652e3b0 |
User & Date: | danielk1977 2009-04-10 09:47:07.000 |
Context
2009-04-10
| ||
12:55 | Changes to ensure that when running in shared-cache mode with a non-threadsafe build, the correct busy-handler callback is always invoked. (CVS 6481) (check-in: 683e4bd747 user: danielk1977 tags: trunk) | |
09:47 | Always set BtShared.db when entering the BtShared mutex. Ticket #3793. (CVS 6480) (check-in: ed6620ba58 user: danielk1977 tags: trunk) | |
00:56 | Force 8-byte alignment of sqlite3_value objects in the sqlite3VdbeUnpackRecord() primitive. Ticket #3777. (CVS 6479) (check-in: 2cc68272b1 user: drh tags: trunk) | |
Changes
Changes to src/btmutex.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 August 27 ** ** 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 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 | /* ** 2007 August 27 ** ** 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: btmutex.c,v 1.14 2009/04/10 09:47:07 danielk1977 Exp $ ** ** This file contains code used to implement mutexes on Btree objects. ** This code really belongs in btree.c. But btree.c is getting too ** big and we want to break it down some. This packaged seemed like ** a good breakout. */ #include "btreeInt.h" #if SQLITE_THREADSAFE && !defined(SQLITE_OMIT_SHARED_CACHE) /* ** Obtain the BtShared mutex associated with B-Tree handle p. Also, ** set BtShared.db to the database handle associated with p and the ** p->locked boolean to true. */ static void lockBtreeMutex(Btree *p){ assert( p->locked==0 ); assert( sqlite3_mutex_notheld(p->pBt->mutex) ); assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3_mutex_enter(p->pBt->mutex); p->pBt->db = p->db; p->locked = 1; } /* ** Release the BtShared mutex associated with B-Tree handle p and ** clear the p->locked boolean. */ static void unlockBtreeMutex(Btree *p){ assert( p->locked==1 ); assert( sqlite3_mutex_held(p->pBt->mutex) ); assert( sqlite3_mutex_held(p->db->mutex) ); assert( p->db==p->pBt->db ); sqlite3_mutex_leave(p->pBt->mutex); p->locked = 0; } /* ** Enter a mutex on the given BTree object. ** ** If the object is not sharable, then no mutex is ever required ** and this routine is a no-op. The underlying mutex is non-recursive. ** But we keep a reference count in Btree.wantToLock so the behavior |
︙ | ︙ | |||
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 | /* Check for locking consistency */ assert( !p->locked || p->wantToLock>0 ); assert( p->sharable || p->wantToLock==0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); if( !p->sharable ) return; p->wantToLock++; if( p->locked ) return; /* In most cases, we should be able to acquire the lock we ** want without having to go throught the ascending lock ** procedure that follows. Just be sure not to block. */ if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ p->locked = 1; return; } /* To avoid deadlock, first release all locks with a larger ** BtShared address. Then acquire our lock. Then reacquire ** the other BtShared locks that we used to hold in ascending ** order. */ for(pLater=p->pNext; pLater; pLater=pLater->pNext){ assert( pLater->sharable ); assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); assert( !pLater->locked || pLater->wantToLock>0 ); if( pLater->locked ){ | > > > > > < | < | < | < < | | | < < > > > > > | < | 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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | /* Check for locking consistency */ assert( !p->locked || p->wantToLock>0 ); assert( p->sharable || p->wantToLock==0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); /* Unless the database is sharable and unlocked, then BtShared.db ** should already be set correctly. */ assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db ); if( !p->sharable ) return; p->wantToLock++; if( p->locked ) return; /* In most cases, we should be able to acquire the lock we ** want without having to go throught the ascending lock ** procedure that follows. Just be sure not to block. */ if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ p->pBt->db = p->db; p->locked = 1; return; } /* To avoid deadlock, first release all locks with a larger ** BtShared address. Then acquire our lock. Then reacquire ** the other BtShared locks that we used to hold in ascending ** order. */ for(pLater=p->pNext; pLater; pLater=pLater->pNext){ assert( pLater->sharable ); assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); assert( !pLater->locked || pLater->wantToLock>0 ); if( pLater->locked ){ unlockBtreeMutex(pLater); } } lockBtreeMutex(p); for(pLater=p->pNext; pLater; pLater=pLater->pNext){ if( pLater->wantToLock ){ lockBtreeMutex(pLater); } } } /* ** Exit the recursive mutex on a Btree. */ void sqlite3BtreeLeave(Btree *p){ if( p->sharable ){ assert( p->wantToLock>0 ); p->wantToLock--; if( p->wantToLock==0 ){ unlockBtreeMutex(p); } } } #ifndef NDEBUG /* ** Return true if the BtShared mutex is held on the btree, or if the ** B-Tree is not marked as sharable. ** ** This routine is used only from within assert() statements. */ int sqlite3BtreeHoldsMutex(Btree *p){ assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 ); assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db ); assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) ); assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) ); return (p->sharable==0 || p->locked); } #endif #ifndef SQLITE_OMIT_INCRBLOB /* ** Enter and leave a mutex on a Btree given a cursor owned by that |
︙ | ︙ | |||
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | */ void sqlite3BtreeEnterAll(sqlite3 *db){ int i; Btree *p, *pLater; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; i<db->nDb; i++){ p = db->aDb[i].pBt; if( p && p->sharable ){ p->wantToLock++; if( !p->locked ){ assert( p->wantToLock==1 ); while( p->pPrev ) p = p->pPrev; while( p->locked && p->pNext ) p = p->pNext; for(pLater = p->pNext; pLater; pLater=pLater->pNext){ if( pLater->locked ){ | > < | < | < < | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | */ void sqlite3BtreeEnterAll(sqlite3 *db){ int i; Btree *p, *pLater; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; i<db->nDb; i++){ p = db->aDb[i].pBt; assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db ); if( p && p->sharable ){ p->wantToLock++; if( !p->locked ){ assert( p->wantToLock==1 ); while( p->pPrev ) p = p->pPrev; while( p->locked && p->pNext ) p = p->pNext; for(pLater = p->pNext; pLater; pLater=pLater->pNext){ if( pLater->locked ){ unlockBtreeMutex(pLater); } } while( p ){ lockBtreeMutex(p); p = p->pNext; } } } } } void sqlite3BtreeLeaveAll(sqlite3 *db){ int i; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; i<db->nDb; i++){ p = db->aDb[i].pBt; if( p && p->sharable ){ assert( p->wantToLock>0 ); p->wantToLock--; if( p->wantToLock==0 ){ unlockBtreeMutex(p); } } } } #ifndef NDEBUG /* |
︙ | ︙ | |||
278 279 280 281 282 283 284 | assert( !p->locked || p->wantToLock>0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock++; if( !p->locked && p->sharable ){ | < | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | assert( !p->locked || p->wantToLock>0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock++; if( !p->locked && p->sharable ){ lockBtreeMutex(p); } } } /* ** Leave the mutex of every btree in the group. */ |
︙ | ︙ | |||
301 302 303 304 305 306 307 | assert( p->wantToLock>0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock--; if( p->wantToLock==0 && p->locked ){ | < | | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | assert( p->wantToLock>0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock--; if( p->wantToLock==0 && p->locked ){ unlockBtreeMutex(p); } } } #endif /* SQLITE_THREADSAFE && !SQLITE_OMIT_SHARED_CACHE */ |
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.594 2009/04/10 09:47:07 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" |
︙ | ︙ | |||
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 | EXTRA_SIZE, flags, vfsFlags); if( rc==SQLITE_OK ){ rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); } if( rc!=SQLITE_OK ){ goto btree_open_out; } sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt); p->pBt = pBt; sqlite3PagerSetReiniter(pBt->pPager, pageReinit); pBt->pCursor = 0; pBt->pPage1 = 0; pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager); | > | 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 | EXTRA_SIZE, flags, vfsFlags); if( rc==SQLITE_OK ){ rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); } if( rc!=SQLITE_OK ){ goto btree_open_out; } pBt->db = db; sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt); p->pBt = pBt; sqlite3PagerSetReiniter(pBt->pPager, pageReinit); pBt->pCursor = 0; pBt->pPage1 = 0; pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager); |
︙ | ︙ | |||
1643 1644 1645 1646 1647 1648 1649 | int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; BtCursor *pCur; /* Close all cursors opened via this handle. */ assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); | < | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 | int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; BtCursor *pCur; /* Close all cursors opened via this handle. */ assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); pCur = pBt->pCursor; while( pCur ){ BtCursor *pTmp = pCur; pCur = pCur->pNext; if( pTmp->pBtree==p ){ sqlite3BtreeCloseCursor(pTmp); } |
︙ | ︙ | |||
2122 2123 2124 2125 2126 2127 2128 | */ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ sqlite3 *pBlock = 0; BtShared *pBt = p->pBt; int rc = SQLITE_OK; sqlite3BtreeEnter(p); | < | 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 | */ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ sqlite3 *pBlock = 0; BtShared *pBt = p->pBt; int rc = SQLITE_OK; sqlite3BtreeEnter(p); btreeIntegrity(p); /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ |
︙ | ︙ | |||
2541 2542 2543 2544 2545 2546 2547 | ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); | < | 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 | ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ rc = SQLITE_DONE; }else{ invalidateAllOverflowCache(pBt); rc = incrVacuumStep(pBt, 0, pagerPagecount(pBt)); } |
︙ | ︙ | |||
2648 2649 2650 2651 2652 2653 2654 | ** 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; sqlite3BtreeEnter(p); | < | 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 | ** 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; sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ rc = autoVacuumCommit(pBt); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } |
︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 | ** 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; sqlite3BtreeEnter(p); | < | 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 | ** 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; sqlite3BtreeEnter(p); 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; |
︙ | ︙ | |||
2808 2809 2810 2811 2812 2813 2814 | */ int sqlite3BtreeRollback(Btree *p){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; sqlite3BtreeEnter(p); | < | 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 | */ int sqlite3BtreeRollback(Btree *p){ int rc; BtShared *pBt = p->pBt; MemPage *pPage1; sqlite3BtreeEnter(p); rc = saveAllCursors(pBt, 0, 0); #ifndef SQLITE_OMIT_SHARED_CACHE if( rc!=SQLITE_OK ){ /* This is a horrible situation. An IO or malloc() error occurred whilst ** trying to save cursor positions. If this is an automatic rollback (as ** the result of a constraint, malloc() failure or IO error) then ** the cache may be internally inconsistent (not contain valid trees) so |
︙ | ︙ | |||
2883 2884 2885 2886 2887 2888 2889 | ** iStatement is 1. This anonymous savepoint can be released or rolled back ** using the sqlite3BtreeSavepoint() function. */ int sqlite3BtreeBeginStmt(Btree *p, int iStatement){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); | < | 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 | ** iStatement is 1. This anonymous savepoint can be released or rolled back ** using the sqlite3BtreeSavepoint() function. */ int sqlite3BtreeBeginStmt(Btree *p, int iStatement){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); assert( pBt->readOnly==0 ); assert( iStatement>0 ); assert( iStatement>p->db->nSavepoint ); if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){ rc = SQLITE_INTERNAL; }else{ |
︙ | ︙ | |||
2922 2923 2924 2925 2926 2927 2928 | int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ int rc = SQLITE_OK; if( p && p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) ); sqlite3BtreeEnter(p); | < | 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 | int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ int rc = SQLITE_OK; if( p && p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) ); sqlite3BtreeEnter(p); rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); } sqlite3BtreeLeave(p); } return rc; |
︙ | ︙ | |||
3039 3040 3041 3042 3043 3044 3045 | int iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ BtCursor *pCur /* Write new cursor here */ ){ int rc; sqlite3BtreeEnter(p); | < | 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 | int iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ BtCursor *pCur /* Write new cursor here */ ){ int rc; sqlite3BtreeEnter(p); rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); sqlite3BtreeLeave(p); return rc; } /* ** Return the size of a BtCursor object in bytes. |
︙ | ︙ | |||
3097 3098 3099 3100 3101 3102 3103 | */ int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; if( pBtree ){ int i; BtShared *pBt = pCur->pBt; sqlite3BtreeEnter(pBtree); | < | 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 | */ int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; if( pBtree ){ int i; BtShared *pBt = pCur->pBt; sqlite3BtreeEnter(pBtree); sqlite3BtreeClearCursor(pCur); if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; }else{ pBt->pCursor = pCur->pNext; } if( pCur->pNext ){ |
︙ | ︙ | |||
6513 6514 6515 6516 6517 6518 6519 | sqlite3PagerUnref(pRoot->pDbPage); *piTable = (int)pgnoRoot; return SQLITE_OK; } int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ int rc; sqlite3BtreeEnter(p); | < | 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 | sqlite3PagerUnref(pRoot->pDbPage); *piTable = (int)pgnoRoot; return SQLITE_OK; } int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ int rc; sqlite3BtreeEnter(p); rc = btreeCreateTable(p, piTable, flags); sqlite3BtreeLeave(p); return rc; } /* ** Erase the given database page and all its children. Return |
︙ | ︙ | |||
6585 6586 6587 6588 6589 6590 6591 | ** integer value pointed to by pnChange is incremented by the number of ** entries in the table. */ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); | < | 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 | ** integer value pointed to by pnChange is incremented by the number of ** entries in the table. */ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); if( (rc = checkForReadConflicts(p, iTable, 0, 1))!=SQLITE_OK ){ /* nothing to do */ }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){ /* nothing to do */ }else{ rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); |
︙ | ︙ | |||
6727 6728 6729 6730 6731 6732 6733 | releasePage(pPage); } return rc; } int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; sqlite3BtreeEnter(p); | < | 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 | releasePage(pPage); } return rc; } int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; sqlite3BtreeEnter(p); rc = btreeDropTable(p, iTable, piMoved); sqlite3BtreeLeave(p); return rc; } /* |
︙ | ︙ | |||
6751 6752 6753 6754 6755 6756 6757 | int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ DbPage *pDbPage = 0; int rc; unsigned char *pP1; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); | < | 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 | int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ DbPage *pDbPage = 0; int rc; unsigned char *pP1; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); /* Reading a meta-data value requires a read-lock on page 1 (and hence ** the sqlite_master table. We grab this lock regardless of whether or ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page ** 1 is treated as a special case by querySharedCacheTableLock() ** and setSharedCacheTableLock()). */ |
︙ | ︙ | |||
6822 6823 6824 6825 6826 6827 6828 | */ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ BtShared *pBt = p->pBt; unsigned char *pP1; int rc; assert( idx>=1 && idx<=15 ); sqlite3BtreeEnter(p); | < | 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 | */ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ BtShared *pBt = p->pBt; unsigned char *pP1; int rc; assert( idx>=1 && idx<=15 ); sqlite3BtreeEnter(p); assert( p->inTrans==TRANS_WRITE ); assert( pBt->pPage1!=0 ); pP1 = pBt->pPage1->aData; rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc==SQLITE_OK ){ put4byte(&pP1[36 + idx*4], iMeta); #ifndef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
7296 7297 7298 7299 7300 7301 7302 | Pgno i; int nRef; IntegrityCk sCheck; BtShared *pBt = p->pBt; char zErr[100]; sqlite3BtreeEnter(p); | < | 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 | Pgno i; int nRef; IntegrityCk sCheck; BtShared *pBt = p->pBt; char zErr[100]; sqlite3BtreeEnter(p); nRef = sqlite3PagerRefcount(pBt->pPager); if( lockBtreeWithRetry(p)!=SQLITE_OK ){ *pnErr = 1; sqlite3BtreeLeave(p); return sqlite3DbStrDup(0, "cannot acquire a read lock on the database"); } sCheck.pBt = pBt; |
︙ | ︙ |
Added test/tkt3793.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 | # 2009 April 10 # # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3793 has been # fixed. # # $Id: tkt3793.test,v 1.1 2009/04/10 09:47:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !shared_cache||!attach { finish_test return } set ::enable_shared_cache [sqlite3_enable_shared_cache 1] do_test tkt3793-1.1 { sqlite3 db1 test.db sqlite3 db2 test.db execsql { BEGIN; CREATE TABLE t1(a, b); CREATE TABLE t2(a PRIMARY KEY, b); INSERT INTO t1 VALUES(randstr(50,50), randstr(50,50)); INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t1 SELECT randstr(50,50), randstr(50,50) FROM t1; INSERT INTO t2 SELECT * FROM t1; COMMIT; } } {} proc busyhandler {db args} { set ::busyconnection $db ; return 1 } db2 busy {busyhandler db2} db1 busy {busyhandler db1} # Establish a read-lock on the database file using connection [db]. # do_test tkt3793-1.2 { execsql { BEGIN; SELECT count(*) FROM t1; } } {1024} # Set the size of the cache shared by [db1] and [db2] to 10. Then update # more than 10 pages of table t1. At this point the shared-cache will # hold a RESERVED lock on the database file. Even though there are now # more than 10 dirty pages in memory, it cannot upgrade to an EXCLUSIVE # lock because of the read-lock held by [db]. # do_test tkt3793-1.3 { execsql { PRAGMA cache_size = 10; BEGIN; UPDATE t1 SET b = randstr(50,50); } db1 } {} set x 0 # Run one SELECT query on the shared-cache using [db1], then from within # the callback run another via [db2]. Because of the large number of dirty # pages within the cache, each time a new page is read from the database # SQLite will attempt to upgrade to an EXCLUSIVE lock, and hence invoke # the busy-handler. The tests here verify that the correct busy-handler # function is invoked (the busy-handler associated with the database # connection that called sqlite3_step()). When bug #3793 existed, sometimes # the [db2] busy-handler was invoked from within the call to sqlite3_step() # associated with [db1]. # # Note: Before the bug was fixed, if [db2] was opened with the "-fullmutex 1" # option, then this test case would cause an assert() to fail. # set ::busyconnection db1 db1 eval {SELECT * FROM t2 ORDER BY a LIMIT 20} { do_test tkt3793-2.[incr x] { set ::busyconnection } db1 set ::busyconnection db2 db2 eval { SELECT count(*) FROM t2 } do_test tkt3793-2.[incr x] { set ::busyconnection } db2 set ::busyconnection db1 } do_test tkt3793-3 { db1 close db2 close } {} sqlite3_enable_shared_cache $::enable_shared_cache finish_test |