OLD | NEW |
1 /* | 1 /* |
2 ** 2007 August 27 | 2 ** 2007 August 27 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
(...skipping 20 matching lines...) Expand all Loading... |
31 | 31 |
32 sqlite3_mutex_enter(p->pBt->mutex); | 32 sqlite3_mutex_enter(p->pBt->mutex); |
33 p->pBt->db = p->db; | 33 p->pBt->db = p->db; |
34 p->locked = 1; | 34 p->locked = 1; |
35 } | 35 } |
36 | 36 |
37 /* | 37 /* |
38 ** Release the BtShared mutex associated with B-Tree handle p and | 38 ** Release the BtShared mutex associated with B-Tree handle p and |
39 ** clear the p->locked boolean. | 39 ** clear the p->locked boolean. |
40 */ | 40 */ |
41 static void unlockBtreeMutex(Btree *p){ | 41 static void SQLITE_NOINLINE unlockBtreeMutex(Btree *p){ |
42 BtShared *pBt = p->pBt; | 42 BtShared *pBt = p->pBt; |
43 assert( p->locked==1 ); | 43 assert( p->locked==1 ); |
44 assert( sqlite3_mutex_held(pBt->mutex) ); | 44 assert( sqlite3_mutex_held(pBt->mutex) ); |
45 assert( sqlite3_mutex_held(p->db->mutex) ); | 45 assert( sqlite3_mutex_held(p->db->mutex) ); |
46 assert( p->db==pBt->db ); | 46 assert( p->db==pBt->db ); |
47 | 47 |
48 sqlite3_mutex_leave(pBt->mutex); | 48 sqlite3_mutex_leave(pBt->mutex); |
49 p->locked = 0; | 49 p->locked = 0; |
50 } | 50 } |
51 | 51 |
| 52 /* Forward reference */ |
| 53 static void SQLITE_NOINLINE btreeLockCarefully(Btree *p); |
| 54 |
52 /* | 55 /* |
53 ** Enter a mutex on the given BTree object. | 56 ** Enter a mutex on the given BTree object. |
54 ** | 57 ** |
55 ** If the object is not sharable, then no mutex is ever required | 58 ** If the object is not sharable, then no mutex is ever required |
56 ** and this routine is a no-op. The underlying mutex is non-recursive. | 59 ** and this routine is a no-op. The underlying mutex is non-recursive. |
57 ** But we keep a reference count in Btree.wantToLock so the behavior | 60 ** But we keep a reference count in Btree.wantToLock so the behavior |
58 ** of this interface is recursive. | 61 ** of this interface is recursive. |
59 ** | 62 ** |
60 ** To avoid deadlocks, multiple Btrees are locked in the same order | 63 ** To avoid deadlocks, multiple Btrees are locked in the same order |
61 ** by all database connections. The p->pNext is a list of other | 64 ** by all database connections. The p->pNext is a list of other |
62 ** Btrees belonging to the same database connection as the p Btree | 65 ** Btrees belonging to the same database connection as the p Btree |
63 ** which need to be locked after p. If we cannot get a lock on | 66 ** which need to be locked after p. If we cannot get a lock on |
64 ** p, then first unlock all of the others on p->pNext, then wait | 67 ** p, then first unlock all of the others on p->pNext, then wait |
65 ** for the lock to become available on p, then relock all of the | 68 ** for the lock to become available on p, then relock all of the |
66 ** subsequent Btrees that desire a lock. | 69 ** subsequent Btrees that desire a lock. |
67 */ | 70 */ |
68 void sqlite3BtreeEnter(Btree *p){ | 71 void sqlite3BtreeEnter(Btree *p){ |
69 Btree *pLater; | |
70 | |
71 /* Some basic sanity checking on the Btree. The list of Btrees | 72 /* Some basic sanity checking on the Btree. The list of Btrees |
72 ** connected by pNext and pPrev should be in sorted order by | 73 ** connected by pNext and pPrev should be in sorted order by |
73 ** Btree.pBt value. All elements of the list should belong to | 74 ** Btree.pBt value. All elements of the list should belong to |
74 ** the same connection. Only shared Btrees are on the list. */ | 75 ** the same connection. Only shared Btrees are on the list. */ |
75 assert( p->pNext==0 || p->pNext->pBt>p->pBt ); | 76 assert( p->pNext==0 || p->pNext->pBt>p->pBt ); |
76 assert( p->pPrev==0 || p->pPrev->pBt<p->pBt ); | 77 assert( p->pPrev==0 || p->pPrev->pBt<p->pBt ); |
77 assert( p->pNext==0 || p->pNext->db==p->db ); | 78 assert( p->pNext==0 || p->pNext->db==p->db ); |
78 assert( p->pPrev==0 || p->pPrev->db==p->db ); | 79 assert( p->pPrev==0 || p->pPrev->db==p->db ); |
79 assert( p->sharable || (p->pNext==0 && p->pPrev==0) ); | 80 assert( p->sharable || (p->pNext==0 && p->pPrev==0) ); |
80 | 81 |
81 /* Check for locking consistency */ | 82 /* Check for locking consistency */ |
82 assert( !p->locked || p->wantToLock>0 ); | 83 assert( !p->locked || p->wantToLock>0 ); |
83 assert( p->sharable || p->wantToLock==0 ); | 84 assert( p->sharable || p->wantToLock==0 ); |
84 | 85 |
85 /* We should already hold a lock on the database connection */ | 86 /* We should already hold a lock on the database connection */ |
86 assert( sqlite3_mutex_held(p->db->mutex) ); | 87 assert( sqlite3_mutex_held(p->db->mutex) ); |
87 | 88 |
88 /* Unless the database is sharable and unlocked, then BtShared.db | 89 /* Unless the database is sharable and unlocked, then BtShared.db |
89 ** should already be set correctly. */ | 90 ** should already be set correctly. */ |
90 assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db ); | 91 assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db ); |
91 | 92 |
92 if( !p->sharable ) return; | 93 if( !p->sharable ) return; |
93 p->wantToLock++; | 94 p->wantToLock++; |
94 if( p->locked ) return; | 95 if( p->locked ) return; |
| 96 btreeLockCarefully(p); |
| 97 } |
| 98 |
| 99 /* This is a helper function for sqlite3BtreeLock(). By moving |
| 100 ** complex, but seldom used logic, out of sqlite3BtreeLock() and |
| 101 ** into this routine, we avoid unnecessary stack pointer changes |
| 102 ** and thus help the sqlite3BtreeLock() routine to run much faster |
| 103 ** in the common case. |
| 104 */ |
| 105 static void SQLITE_NOINLINE btreeLockCarefully(Btree *p){ |
| 106 Btree *pLater; |
95 | 107 |
96 /* In most cases, we should be able to acquire the lock we | 108 /* In most cases, we should be able to acquire the lock we |
97 ** want without having to go throught the ascending lock | 109 ** want without having to go through the ascending lock |
98 ** procedure that follows. Just be sure not to block. | 110 ** procedure that follows. Just be sure not to block. |
99 */ | 111 */ |
100 if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ | 112 if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){ |
101 p->pBt->db = p->db; | 113 p->pBt->db = p->db; |
102 p->locked = 1; | 114 p->locked = 1; |
103 return; | 115 return; |
104 } | 116 } |
105 | 117 |
106 /* To avoid deadlock, first release all locks with a larger | 118 /* To avoid deadlock, first release all locks with a larger |
107 ** BtShared address. Then acquire our lock. Then reacquire | 119 ** BtShared address. Then acquire our lock. Then reacquire |
108 ** the other BtShared locks that we used to hold in ascending | 120 ** the other BtShared locks that we used to hold in ascending |
109 ** order. | 121 ** order. |
110 */ | 122 */ |
111 for(pLater=p->pNext; pLater; pLater=pLater->pNext){ | 123 for(pLater=p->pNext; pLater; pLater=pLater->pNext){ |
112 assert( pLater->sharable ); | 124 assert( pLater->sharable ); |
113 assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); | 125 assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt ); |
114 assert( !pLater->locked || pLater->wantToLock>0 ); | 126 assert( !pLater->locked || pLater->wantToLock>0 ); |
115 if( pLater->locked ){ | 127 if( pLater->locked ){ |
116 unlockBtreeMutex(pLater); | 128 unlockBtreeMutex(pLater); |
117 } | 129 } |
118 } | 130 } |
119 lockBtreeMutex(p); | 131 lockBtreeMutex(p); |
120 for(pLater=p->pNext; pLater; pLater=pLater->pNext){ | 132 for(pLater=p->pNext; pLater; pLater=pLater->pNext){ |
121 if( pLater->wantToLock ){ | 133 if( pLater->wantToLock ){ |
122 lockBtreeMutex(pLater); | 134 lockBtreeMutex(pLater); |
123 } | 135 } |
124 } | 136 } |
125 } | 137 } |
126 | 138 |
| 139 |
127 /* | 140 /* |
128 ** Exit the recursive mutex on a Btree. | 141 ** Exit the recursive mutex on a Btree. |
129 */ | 142 */ |
130 void sqlite3BtreeLeave(Btree *p){ | 143 void sqlite3BtreeLeave(Btree *p){ |
131 if( p->sharable ){ | 144 if( p->sharable ){ |
132 assert( p->wantToLock>0 ); | 145 assert( p->wantToLock>0 ); |
133 p->wantToLock--; | 146 p->wantToLock--; |
134 if( p->wantToLock==0 ){ | 147 if( p->wantToLock==0 ){ |
135 unlockBtreeMutex(p); | 148 unlockBtreeMutex(p); |
136 } | 149 } |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 int i; | 291 int i; |
279 for(i=0; i<db->nDb; i++){ | 292 for(i=0; i<db->nDb; i++){ |
280 Btree *p = db->aDb[i].pBt; | 293 Btree *p = db->aDb[i].pBt; |
281 if( p ){ | 294 if( p ){ |
282 p->pBt->db = p->db; | 295 p->pBt->db = p->db; |
283 } | 296 } |
284 } | 297 } |
285 } | 298 } |
286 #endif /* if SQLITE_THREADSAFE */ | 299 #endif /* if SQLITE_THREADSAFE */ |
287 #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */ | 300 #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */ |
OLD | NEW |