Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: third_party/sqlite/src/btmutex.c

Issue 3108030: Move bundled copy of sqlite one level deeper to better separate it... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/sqlite/src/bitvec.c ('k') | third_party/sqlite/src/btree.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 ** 2007 August 27
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 **
13 ** $Id: btmutex.c,v 1.17 2009/07/20 12:33:33 drh Exp $
14 **
15 ** This file contains code used to implement mutexes on Btree objects.
16 ** This code really belongs in btree.c. But btree.c is getting too
17 ** big and we want to break it down some. This packaged seemed like
18 ** a good breakout.
19 */
20 #include "btreeInt.h"
21 #ifndef SQLITE_OMIT_SHARED_CACHE
22 #if SQLITE_THREADSAFE
23
24 /*
25 ** Obtain the BtShared mutex associated with B-Tree handle p. Also,
26 ** set BtShared.db to the database handle associated with p and the
27 ** p->locked boolean to true.
28 */
29 static void lockBtreeMutex(Btree *p){
30 assert( p->locked==0 );
31 assert( sqlite3_mutex_notheld(p->pBt->mutex) );
32 assert( sqlite3_mutex_held(p->db->mutex) );
33
34 sqlite3_mutex_enter(p->pBt->mutex);
35 p->pBt->db = p->db;
36 p->locked = 1;
37 }
38
39 /*
40 ** Release the BtShared mutex associated with B-Tree handle p and
41 ** clear the p->locked boolean.
42 */
43 static void unlockBtreeMutex(Btree *p){
44 assert( p->locked==1 );
45 assert( sqlite3_mutex_held(p->pBt->mutex) );
46 assert( sqlite3_mutex_held(p->db->mutex) );
47 assert( p->db==p->pBt->db );
48
49 sqlite3_mutex_leave(p->pBt->mutex);
50 p->locked = 0;
51 }
52
53 /*
54 ** Enter a mutex on the given BTree object.
55 **
56 ** If the object is not sharable, then no mutex is ever required
57 ** and this routine is a no-op. The underlying mutex is non-recursive.
58 ** But we keep a reference count in Btree.wantToLock so the behavior
59 ** of this interface is recursive.
60 **
61 ** To avoid deadlocks, multiple Btrees are locked in the same order
62 ** by all database connections. The p->pNext is a list of other
63 ** Btrees belonging to the same database connection as the p Btree
64 ** which need to be locked after p. If we cannot get a lock on
65 ** p, then first unlock all of the others on p->pNext, then wait
66 ** for the lock to become available on p, then relock all of the
67 ** subsequent Btrees that desire a lock.
68 */
69 void sqlite3BtreeEnter(Btree *p){
70 Btree *pLater;
71
72 /* Some basic sanity checking on the Btree. The list of Btrees
73 ** connected by pNext and pPrev should be in sorted order by
74 ** Btree.pBt value. All elements of the list should belong to
75 ** the same connection. Only shared Btrees are on the list. */
76 assert( p->pNext==0 || p->pNext->pBt>p->pBt );
77 assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
78 assert( p->pNext==0 || p->pNext->db==p->db );
79 assert( p->pPrev==0 || p->pPrev->db==p->db );
80 assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
81
82 /* Check for locking consistency */
83 assert( !p->locked || p->wantToLock>0 );
84 assert( p->sharable || p->wantToLock==0 );
85
86 /* We should already hold a lock on the database connection */
87 assert( sqlite3_mutex_held(p->db->mutex) );
88
89 /* Unless the database is sharable and unlocked, then BtShared.db
90 ** should already be set correctly. */
91 assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
92
93 if( !p->sharable ) return;
94 p->wantToLock++;
95 if( p->locked ) return;
96
97 /* In most cases, we should be able to acquire the lock we
98 ** want without having to go throught the ascending lock
99 ** procedure that follows. Just be sure not to block.
100 */
101 if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
102 p->pBt->db = p->db;
103 p->locked = 1;
104 return;
105 }
106
107 /* To avoid deadlock, first release all locks with a larger
108 ** BtShared address. Then acquire our lock. Then reacquire
109 ** the other BtShared locks that we used to hold in ascending
110 ** order.
111 */
112 for(pLater=p->pNext; pLater; pLater=pLater->pNext){
113 assert( pLater->sharable );
114 assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
115 assert( !pLater->locked || pLater->wantToLock>0 );
116 if( pLater->locked ){
117 unlockBtreeMutex(pLater);
118 }
119 }
120 lockBtreeMutex(p);
121 for(pLater=p->pNext; pLater; pLater=pLater->pNext){
122 if( pLater->wantToLock ){
123 lockBtreeMutex(pLater);
124 }
125 }
126 }
127
128 /*
129 ** Exit the recursive mutex on a Btree.
130 */
131 void sqlite3BtreeLeave(Btree *p){
132 if( p->sharable ){
133 assert( p->wantToLock>0 );
134 p->wantToLock--;
135 if( p->wantToLock==0 ){
136 unlockBtreeMutex(p);
137 }
138 }
139 }
140
141 #ifndef NDEBUG
142 /*
143 ** Return true if the BtShared mutex is held on the btree, or if the
144 ** B-Tree is not marked as sharable.
145 **
146 ** This routine is used only from within assert() statements.
147 */
148 int sqlite3BtreeHoldsMutex(Btree *p){
149 assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
150 assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
151 assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
152 assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
153
154 return (p->sharable==0 || p->locked);
155 }
156 #endif
157
158
159 #ifndef SQLITE_OMIT_INCRBLOB
160 /*
161 ** Enter and leave a mutex on a Btree given a cursor owned by that
162 ** Btree. These entry points are used by incremental I/O and can be
163 ** omitted if that module is not used.
164 */
165 void sqlite3BtreeEnterCursor(BtCursor *pCur){
166 sqlite3BtreeEnter(pCur->pBtree);
167 }
168 void sqlite3BtreeLeaveCursor(BtCursor *pCur){
169 sqlite3BtreeLeave(pCur->pBtree);
170 }
171 #endif /* SQLITE_OMIT_INCRBLOB */
172
173
174 /*
175 ** Enter the mutex on every Btree associated with a database
176 ** connection. This is needed (for example) prior to parsing
177 ** a statement since we will be comparing table and column names
178 ** against all schemas and we do not want those schemas being
179 ** reset out from under us.
180 **
181 ** There is a corresponding leave-all procedures.
182 **
183 ** Enter the mutexes in accending order by BtShared pointer address
184 ** to avoid the possibility of deadlock when two threads with
185 ** two or more btrees in common both try to lock all their btrees
186 ** at the same instant.
187 */
188 void sqlite3BtreeEnterAll(sqlite3 *db){
189 int i;
190 Btree *p, *pLater;
191 assert( sqlite3_mutex_held(db->mutex) );
192 for(i=0; i<db->nDb; i++){
193 p = db->aDb[i].pBt;
194 assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db );
195 if( p && p->sharable ){
196 p->wantToLock++;
197 if( !p->locked ){
198 assert( p->wantToLock==1 );
199 while( p->pPrev ) p = p->pPrev;
200 /* Reason for ALWAYS: There must be at least on unlocked Btree in
201 ** the chain. Otherwise the !p->locked test above would have failed */
202 while( p->locked && ALWAYS(p->pNext) ) p = p->pNext;
203 for(pLater = p->pNext; pLater; pLater=pLater->pNext){
204 if( pLater->locked ){
205 unlockBtreeMutex(pLater);
206 }
207 }
208 while( p ){
209 lockBtreeMutex(p);
210 p = p->pNext;
211 }
212 }
213 }
214 }
215 }
216 void sqlite3BtreeLeaveAll(sqlite3 *db){
217 int i;
218 Btree *p;
219 assert( sqlite3_mutex_held(db->mutex) );
220 for(i=0; i<db->nDb; i++){
221 p = db->aDb[i].pBt;
222 if( p && p->sharable ){
223 assert( p->wantToLock>0 );
224 p->wantToLock--;
225 if( p->wantToLock==0 ){
226 unlockBtreeMutex(p);
227 }
228 }
229 }
230 }
231
232 #ifndef NDEBUG
233 /*
234 ** Return true if the current thread holds the database connection
235 ** mutex and all required BtShared mutexes.
236 **
237 ** This routine is used inside assert() statements only.
238 */
239 int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
240 int i;
241 if( !sqlite3_mutex_held(db->mutex) ){
242 return 0;
243 }
244 for(i=0; i<db->nDb; i++){
245 Btree *p;
246 p = db->aDb[i].pBt;
247 if( p && p->sharable &&
248 (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
249 return 0;
250 }
251 }
252 return 1;
253 }
254 #endif /* NDEBUG */
255
256 /*
257 ** Add a new Btree pointer to a BtreeMutexArray.
258 ** if the pointer can possibly be shared with
259 ** another database connection.
260 **
261 ** The pointers are kept in sorted order by pBtree->pBt. That
262 ** way when we go to enter all the mutexes, we can enter them
263 ** in order without every having to backup and retry and without
264 ** worrying about deadlock.
265 **
266 ** The number of shared btrees will always be small (usually 0 or 1)
267 ** so an insertion sort is an adequate algorithm here.
268 */
269 void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
270 int i, j;
271 BtShared *pBt;
272 if( pBtree==0 || pBtree->sharable==0 ) return;
273 #ifndef NDEBUG
274 {
275 for(i=0; i<pArray->nMutex; i++){
276 assert( pArray->aBtree[i]!=pBtree );
277 }
278 }
279 #endif
280 assert( pArray->nMutex>=0 );
281 assert( pArray->nMutex<ArraySize(pArray->aBtree)-1 );
282 pBt = pBtree->pBt;
283 for(i=0; i<pArray->nMutex; i++){
284 assert( pArray->aBtree[i]!=pBtree );
285 if( pArray->aBtree[i]->pBt>pBt ){
286 for(j=pArray->nMutex; j>i; j--){
287 pArray->aBtree[j] = pArray->aBtree[j-1];
288 }
289 pArray->aBtree[i] = pBtree;
290 pArray->nMutex++;
291 return;
292 }
293 }
294 pArray->aBtree[pArray->nMutex++] = pBtree;
295 }
296
297 /*
298 ** Enter the mutex of every btree in the array. This routine is
299 ** called at the beginning of sqlite3VdbeExec(). The mutexes are
300 ** exited at the end of the same function.
301 */
302 void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
303 int i;
304 for(i=0; i<pArray->nMutex; i++){
305 Btree *p = pArray->aBtree[i];
306 /* Some basic sanity checking */
307 assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
308 assert( !p->locked || p->wantToLock>0 );
309
310 /* We should already hold a lock on the database connection */
311 assert( sqlite3_mutex_held(p->db->mutex) );
312
313 /* The Btree is sharable because only sharable Btrees are entered
314 ** into the array in the first place. */
315 assert( p->sharable );
316
317 p->wantToLock++;
318 if( !p->locked ){
319 lockBtreeMutex(p);
320 }
321 }
322 }
323
324 /*
325 ** Leave the mutex of every btree in the group.
326 */
327 void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
328 int i;
329 for(i=0; i<pArray->nMutex; i++){
330 Btree *p = pArray->aBtree[i];
331 /* Some basic sanity checking */
332 assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
333 assert( p->locked );
334 assert( p->wantToLock>0 );
335
336 /* We should already hold a lock on the database connection */
337 assert( sqlite3_mutex_held(p->db->mutex) );
338
339 p->wantToLock--;
340 if( p->wantToLock==0 ){
341 unlockBtreeMutex(p);
342 }
343 }
344 }
345
346 #else
347 void sqlite3BtreeEnter(Btree *p){
348 p->pBt->db = p->db;
349 }
350 void sqlite3BtreeEnterAll(sqlite3 *db){
351 int i;
352 for(i=0; i<db->nDb; i++){
353 Btree *p = db->aDb[i].pBt;
354 if( p ){
355 p->pBt->db = p->db;
356 }
357 }
358 }
359 #endif /* if SQLITE_THREADSAFE */
360 #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
OLDNEW
« no previous file with comments | « third_party/sqlite/src/bitvec.c ('k') | third_party/sqlite/src/btree.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698