1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 2013 Oracle and/or its affiliates.  All rights reserved.
5  *
6  * $Id$
7  */
8 
9 #include "db_config.h"
10 
11 #include "db_int.h"
12 #include "dbinc/lock.h"
13 #include "dbinc/log.h"
14 
15 static int __lock_freelocker_int
16     __P((DB_LOCKTAB *, DB_LOCKREGION *, DB_LOCKER *, int));
17 
18 /*
19  * __lock_id_pp --
20  *	ENV->lock_id pre/post processing.
21  *
22  * PUBLIC: int __lock_id_pp __P((DB_ENV *, u_int32_t *));
23  */
24 int
__lock_id_pp(dbenv,idp)25 __lock_id_pp(dbenv, idp)
26 	DB_ENV *dbenv;
27 	u_int32_t *idp;
28 {
29 	DB_THREAD_INFO *ip;
30 	ENV *env;
31 	int ret;
32 
33 	env = dbenv->env;
34 
35 	ENV_REQUIRES_CONFIG(env,
36 	    env->lk_handle, "DB_ENV->lock_id", DB_INIT_LOCK);
37 
38 	ENV_ENTER(env, ip);
39 	REPLICATION_WRAP(env, (__lock_id(env, idp, NULL)), 0, ret);
40 	ENV_LEAVE(env, ip);
41 	return (ret);
42 }
43 
44 /*
45  * __lock_id --
46  *	ENV->lock_id.
47  *
48  * PUBLIC: int  __lock_id __P((ENV *, u_int32_t *, DB_LOCKER **));
49  */
50 int
__lock_id(env,idp,lkp)51 __lock_id(env, idp, lkp)
52 	ENV *env;
53 	u_int32_t *idp;
54 	DB_LOCKER **lkp;
55 {
56 	DB_LOCKER *lk;
57 	DB_LOCKREGION *region;
58 	DB_LOCKTAB *lt;
59 	u_int32_t id, *ids;
60 	int nids, ret;
61 
62 	lk = NULL;
63 	lt = env->lk_handle;
64 	region = lt->reginfo.primary;
65 	id = DB_LOCK_INVALIDID;
66 	ret = 0;
67 
68 	id = DB_LOCK_INVALIDID;
69 	lk = NULL;
70 
71 	LOCK_LOCKERS(env, region);
72 
73 	/*
74 	 * Allocate a new lock id.  If we wrap around then we find the minimum
75 	 * currently in use and make sure we can stay below that.  This code is
76 	 * similar to code in __txn_begin_int for recovering txn ids.
77 	 *
78 	 * Our current valid range can span the maximum valid value, so check
79 	 * for it and wrap manually.
80 	 */
81 	if (region->lock_id == DB_LOCK_MAXID &&
82 	    region->cur_maxid != DB_LOCK_MAXID)
83 		region->lock_id = DB_LOCK_INVALIDID;
84 	if (region->lock_id == region->cur_maxid) {
85 		if ((ret = __os_malloc(env,
86 		    sizeof(u_int32_t) * region->nlockers, &ids)) != 0)
87 			goto err;
88 		nids = 0;
89 		SH_TAILQ_FOREACH(lk, &region->lockers, ulinks, __db_locker)
90 			ids[nids++] = lk->id;
91 		region->lock_id = DB_LOCK_INVALIDID;
92 		region->cur_maxid = DB_LOCK_MAXID;
93 		if (nids != 0)
94 			__db_idspace(ids, nids,
95 			    &region->lock_id, &region->cur_maxid);
96 		__os_free(env, ids);
97 	}
98 	id = ++region->lock_id;
99 
100 	/* Allocate a locker for this id. */
101 	ret = __lock_getlocker_int(lt, id, 1, &lk);
102 
103 err:	UNLOCK_LOCKERS(env, region);
104 
105 	if (idp != NULL)
106 		*idp = id;
107 	if (lkp != NULL)
108 		*lkp = lk;
109 
110 	return (ret);
111 }
112 
113 /*
114  * __lock_set_thread_id --
115  *	Set the thread_id in an existing locker.
116  * PUBLIC: void __lock_set_thread_id __P((void *, pid_t, db_threadid_t));
117  */
118 void
__lock_set_thread_id(lref_arg,pid,tid)119 __lock_set_thread_id(lref_arg, pid, tid)
120 	void *lref_arg;
121 	pid_t pid;
122 	db_threadid_t tid;
123 {
124 	DB_LOCKER *lref;
125 
126 	lref = lref_arg;
127 	lref->pid = pid;
128 	lref->tid = tid;
129 }
130 
131 /*
132  * __lock_id_free_pp --
133  *	ENV->lock_id_free pre/post processing.
134  *
135  * PUBLIC: int __lock_id_free_pp __P((DB_ENV *, u_int32_t));
136  */
137 int
__lock_id_free_pp(dbenv,id)138 __lock_id_free_pp(dbenv, id)
139 	DB_ENV *dbenv;
140 	u_int32_t id;
141 {
142 	DB_LOCKER *sh_locker;
143 	DB_LOCKREGION *region;
144 	DB_LOCKTAB *lt;
145 	DB_THREAD_INFO *ip;
146 	ENV *env;
147 	int handle_check, ret, t_ret;
148 
149 	env = dbenv->env;
150 
151 	ENV_REQUIRES_CONFIG(env,
152 	    env->lk_handle, "DB_ENV->lock_id_free", DB_INIT_LOCK);
153 
154 	ENV_ENTER(env, ip);
155 
156 	/* Check for replication block. */
157 	handle_check = IS_ENV_REPLICATED(env);
158 	if (handle_check && (ret = __env_rep_enter(env, 0)) != 0) {
159 		handle_check = 0;
160 		goto err;
161 	}
162 
163 	lt = env->lk_handle;
164 	region = lt->reginfo.primary;
165 
166 	LOCK_LOCKERS(env, region);
167 	if ((ret =
168 	     __lock_getlocker_int(env->lk_handle, id, 0, &sh_locker)) == 0) {
169 		if (sh_locker != NULL)
170 			ret = __lock_freelocker_int(lt, region, sh_locker, 1);
171 		else {
172 			__db_errx(env, DB_STR_A("2045",
173 			    "Unknown locker id: %lx", "%lx"), (u_long)id);
174 			ret = EINVAL;
175 		}
176 	}
177 	UNLOCK_LOCKERS(env, region);
178 
179 	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
180 		ret = t_ret;
181 
182 err:	ENV_LEAVE(env, ip);
183 	return (ret);
184 }
185 
186 /*
187  * __lock_id_free --
188  *	Free a locker id.
189  *
190  * PUBLIC: int  __lock_id_free __P((ENV *, DB_LOCKER *));
191  */
192 int
__lock_id_free(env,sh_locker)193 __lock_id_free(env, sh_locker)
194 	ENV *env;
195 	DB_LOCKER *sh_locker;
196 {
197 	DB_LOCKREGION *region;
198 	DB_LOCKTAB *lt;
199 	int ret;
200 
201 	lt = env->lk_handle;
202 	region = lt->reginfo.primary;
203 	ret = 0;
204 
205 	if (sh_locker->nlocks != 0) {
206 		__db_errx(env, DB_STR("2046",
207 		    "Locker still has locks"));
208 		ret = EINVAL;
209 		goto err;
210 	}
211 
212 	LOCK_LOCKERS(env, region);
213 	ret = __lock_freelocker_int(lt, region, sh_locker, 1);
214 	UNLOCK_LOCKERS(env, region);
215 
216 err:	return (ret);
217 }
218 
219 /*
220  * __lock_id_set --
221  *	Set the current locker ID and current maximum unused ID (for
222  *	testing purposes only).
223  *
224  * PUBLIC: int __lock_id_set __P((ENV *, u_int32_t, u_int32_t));
225  */
226 int
__lock_id_set(env,cur_id,max_id)227 __lock_id_set(env, cur_id, max_id)
228 	ENV *env;
229 	u_int32_t cur_id, max_id;
230 {
231 	DB_LOCKREGION *region;
232 	DB_LOCKTAB *lt;
233 
234 	ENV_REQUIRES_CONFIG(env,
235 	    env->lk_handle, "lock_id_set", DB_INIT_LOCK);
236 
237 	lt = env->lk_handle;
238 	region = lt->reginfo.primary;
239 	region->lock_id = cur_id;
240 	region->cur_maxid = max_id;
241 
242 	return (0);
243 }
244 
245 /*
246  * __lock_getlocker --
247  *	Get a locker in the locker hash table.  The create parameter
248  * indicates if the locker should be created if it doesn't exist in
249  * the table.
250  *
251  * This must be called with the locker mutex lock if create == 1.
252  *
253  * PUBLIC: int __lock_getlocker __P((DB_LOCKTAB *,
254  * PUBLIC:     u_int32_t, int, DB_LOCKER **));
255  * PUBLIC: int __lock_getlocker_int __P((DB_LOCKTAB *,
256  * PUBLIC:     u_int32_t, int, DB_LOCKER **));
257  */
258 int
__lock_getlocker(lt,locker,create,retp)259 __lock_getlocker(lt, locker, create, retp)
260 	DB_LOCKTAB *lt;
261 	u_int32_t locker;
262 	int create;
263 	DB_LOCKER **retp;
264 {
265 	DB_LOCKREGION *region;
266 	ENV *env;
267 	int ret;
268 
269 	COMPQUIET(region, NULL);
270 	env = lt->env;
271 	region = lt->reginfo.primary;
272 
273 	LOCK_LOCKERS(env, region);
274 	ret = __lock_getlocker_int(lt, locker, create, retp);
275 	UNLOCK_LOCKERS(env, region);
276 
277 	return (ret);
278 }
279 
280 int
__lock_getlocker_int(lt,locker,create,retp)281 __lock_getlocker_int(lt, locker, create, retp)
282 	DB_LOCKTAB *lt;
283 	u_int32_t locker;
284 	int create;
285 	DB_LOCKER **retp;
286 {
287 	DB_LOCKER *sh_locker;
288 	DB_LOCKREGION *region;
289 	DB_THREAD_INFO *ip;
290 	ENV *env;
291 	db_mutex_t mutex;
292 	u_int32_t i, indx, nlockers;
293 	int ret;
294 
295 	env = lt->env;
296 	region = lt->reginfo.primary;
297 
298 	LOCKER_HASH(lt, region, locker, indx);
299 
300 	/*
301 	 * If we find the locker, then we can just return it.  If we don't find
302 	 * the locker, then we need to create it.
303 	 */
304 	SH_TAILQ_FOREACH(sh_locker, &lt->locker_tab[indx], links, __db_locker)
305 		if (sh_locker->id == locker)
306 			break;
307 	if (sh_locker == NULL && create) {
308 		nlockers = 0;
309 		/* Create new locker and then insert it into hash table. */
310 		if ((ret = __mutex_alloc(env, MTX_LOGICAL_LOCK,
311 		    DB_MUTEX_LOGICAL_LOCK | DB_MUTEX_SELF_BLOCK,
312 		    &mutex)) != 0)
313 			return (ret);
314 		else
315 			MUTEX_LOCK(env, mutex);
316 		if ((sh_locker = SH_TAILQ_FIRST(
317 		    &region->free_lockers, __db_locker)) == NULL) {
318 			nlockers = region->stat.st_lockers >> 2;
319 			/* Just in case. */
320 			if (nlockers == 0)
321 				nlockers = 1;
322 			if (region->stat.st_maxlockers != 0 &&
323 			    region->stat.st_maxlockers <
324 			    region->stat.st_lockers + nlockers)
325 				nlockers = region->stat.st_maxlockers -
326 				region->stat.st_lockers;
327 			/*
328 			 * Don't hold lockers when getting the region,
329 			 * we could deadlock.  When creating a locker
330 			 * there is no race since the id allocation
331 			 * is synchronized.
332 			 */
333 			UNLOCK_LOCKERS(env, region);
334 			LOCK_REGION_LOCK(env);
335 			/*
336 			 * If the max memory is not sized for max objects,
337 			 * allocate as much as possible.
338 			 */
339 			F_SET(&lt->reginfo, REGION_TRACKED);
340 			while (__env_alloc(&lt->reginfo, nlockers *
341 			    sizeof(struct __db_locker), &sh_locker) != 0)
342 				if ((nlockers >> 1) == 0)
343 					break;
344 			F_CLR(&lt->reginfo, REGION_TRACKED);
345 			LOCK_REGION_UNLOCK(lt->env);
346 			LOCK_LOCKERS(env, region);
347 			for (i = 0; i < nlockers; i++) {
348 				SH_TAILQ_INSERT_HEAD(&region->free_lockers,
349 				    sh_locker, links, __db_locker);
350 				sh_locker++;
351 			}
352 			if (nlockers == 0)
353 				return (__lock_nomem(env, "locker entries"));
354 			region->stat.st_lockers += nlockers;
355 			sh_locker = SH_TAILQ_FIRST(
356 			    &region->free_lockers, __db_locker);
357 		}
358 		SH_TAILQ_REMOVE(
359 		    &region->free_lockers, sh_locker, links, __db_locker);
360 		++region->nlockers;
361 #ifdef HAVE_STATISTICS
362 		STAT_PERFMON2(env, lock, nlockers, region->nlockers, locker);
363 		if (region->nlockers > region->stat.st_maxnlockers)
364 			STAT_SET(env, lock, maxnlockers,
365 			    region->stat.st_maxnlockers,
366 			    region->nlockers, locker);
367 #endif
368 		sh_locker->id = locker;
369 		env->dbenv->thread_id(
370 		    env->dbenv, &sh_locker->pid, &sh_locker->tid);
371 		sh_locker->mtx_locker = mutex;
372 		sh_locker->dd_id = 0;
373 		sh_locker->master_locker = INVALID_ROFF;
374 		sh_locker->parent_locker = INVALID_ROFF;
375 		SH_LIST_INIT(&sh_locker->child_locker);
376 		sh_locker->flags = 0;
377 		SH_LIST_INIT(&sh_locker->heldby);
378 		sh_locker->nlocks = 0;
379 		sh_locker->nwrites = 0;
380 		sh_locker->priority = DB_LOCK_DEFPRIORITY;
381 		sh_locker->lk_timeout = 0;
382 		timespecclear(&sh_locker->tx_expire);
383 		timespecclear(&sh_locker->lk_expire);
384 
385 		SH_TAILQ_INSERT_HEAD(
386 		    &lt->locker_tab[indx], sh_locker, links, __db_locker);
387 		SH_TAILQ_INSERT_HEAD(&region->lockers,
388 		    sh_locker, ulinks, __db_locker);
389 		ENV_GET_THREAD_INFO(env, ip);
390 #ifdef DIAGNOSTIC
391 		if (ip != NULL)
392 			ip->dbth_locker = R_OFFSET(&lt->reginfo, sh_locker);
393 #endif
394 	}
395 
396 	*retp = sh_locker;
397 	return (0);
398 }
399 
400 /*
401  * __lock_addfamilylocker
402  *	Put a locker entry in for a child transaction.
403  *
404  * PUBLIC: int __lock_addfamilylocker __P((ENV *,
405  * PUBLIC:     u_int32_t, u_int32_t, u_int32_t));
406  */
407 int
__lock_addfamilylocker(env,pid,id,is_family)408 __lock_addfamilylocker(env, pid, id, is_family)
409 	ENV *env;
410 	u_int32_t pid, id, is_family;
411 {
412 	DB_LOCKER *lockerp, *mlockerp;
413 	DB_LOCKREGION *region;
414 	DB_LOCKTAB *lt;
415 	int ret;
416 
417 	COMPQUIET(region, NULL);
418 	lt = env->lk_handle;
419 	region = lt->reginfo.primary;
420 	LOCK_LOCKERS(env, region);
421 
422 	/* get/create the  parent locker info */
423 	if ((ret = __lock_getlocker_int(lt, pid, 1, &mlockerp)) != 0)
424 		goto err;
425 
426 	/*
427 	 * We assume that only one thread can manipulate
428 	 * a single transaction family.
429 	 * Therefore the master locker cannot go away while
430 	 * we manipulate it, nor can another child in the
431 	 * family be created at the same time.
432 	 */
433 	if ((ret = __lock_getlocker_int(lt, id, 1, &lockerp)) != 0)
434 		goto err;
435 
436 	/* Point to our parent. */
437 	lockerp->parent_locker = R_OFFSET(&lt->reginfo, mlockerp);
438 
439 	/* See if this locker is the family master. */
440 	if (mlockerp->master_locker == INVALID_ROFF)
441 		lockerp->master_locker = R_OFFSET(&lt->reginfo, mlockerp);
442 	else {
443 		lockerp->master_locker = mlockerp->master_locker;
444 		mlockerp = R_ADDR(&lt->reginfo, mlockerp->master_locker);
445 	}
446 
447 	/*
448 	 * Set the family locker flag, so it is possible to distinguish
449 	 * between locks held by subtransactions and those with compatible
450 	 * lockers.
451 	 */
452 	if (is_family)
453 		F_SET(mlockerp, DB_LOCKER_FAMILY_LOCKER);
454 
455 	/*
456 	 * Link the child at the head of the master's list.
457 	 * The guess is when looking for deadlock that
458 	 * the most recent child is the one that's blocked.
459 	 */
460 	SH_LIST_INSERT_HEAD(
461 	    &mlockerp->child_locker, lockerp, child_link, __db_locker);
462 
463 err:	UNLOCK_LOCKERS(env, region);
464 
465 	return (ret);
466 }
467 
468 /*
469  * __lock_freelocker_int
470  *      Common code for deleting a locker; must be called with the
471  *	locker bucket locked.
472  */
473 static int
__lock_freelocker_int(lt,region,sh_locker,reallyfree)474 __lock_freelocker_int(lt, region, sh_locker, reallyfree)
475 	DB_LOCKTAB *lt;
476 	DB_LOCKREGION *region;
477 	DB_LOCKER *sh_locker;
478 	int reallyfree;
479 {
480 	ENV *env;
481 	u_int32_t indx;
482 	int ret;
483 
484 	env = lt->env;
485 
486 	if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) != NULL) {
487 		__db_errx(env, DB_STR("2047",
488 		    "Freeing locker with locks"));
489 		return (EINVAL);
490 	}
491 
492 	/* If this is part of a family, we must fix up its links. */
493 	if (sh_locker->master_locker != INVALID_ROFF) {
494 		SH_LIST_REMOVE(sh_locker, child_link, __db_locker);
495 		sh_locker->master_locker = INVALID_ROFF;
496 	}
497 
498 	if (reallyfree) {
499 		LOCKER_HASH(lt, region, sh_locker->id, indx);
500 		SH_TAILQ_REMOVE(&lt->locker_tab[indx], sh_locker,
501 		    links, __db_locker);
502 		if (sh_locker->mtx_locker != MUTEX_INVALID &&
503 		    (ret = __mutex_free(env, &sh_locker->mtx_locker)) != 0)
504 			return (ret);
505 		SH_TAILQ_INSERT_HEAD(&region->free_lockers, sh_locker,
506 		    links, __db_locker);
507 		SH_TAILQ_REMOVE(&region->lockers, sh_locker,
508 		    ulinks, __db_locker);
509 		region->nlockers--;
510 		STAT_PERFMON2(env,
511 		    lock, nlockers, region->nlockers, sh_locker->id);
512 	}
513 
514 	return (0);
515 }
516 
517 /*
518  * __lock_freelocker
519  *	Remove a locker its family from the hash table.
520  *
521  * This must be called without the locker bucket locked.
522  *
523  * PUBLIC: int __lock_freelocker  __P((DB_LOCKTAB *, DB_LOCKER *));
524  */
525 int
__lock_freelocker(lt,sh_locker)526 __lock_freelocker(lt, sh_locker)
527 	DB_LOCKTAB *lt;
528 	DB_LOCKER *sh_locker;
529 {
530 	DB_LOCKREGION *region;
531 	ENV *env;
532 	int ret;
533 
534 	region = lt->reginfo.primary;
535 	env = lt->env;
536 
537 	if (sh_locker == NULL)
538 		return (0);
539 
540 	LOCK_LOCKERS(env, region);
541 	ret = __lock_freelocker_int(lt, region, sh_locker, 1);
542 	UNLOCK_LOCKERS(env, region);
543 
544 	return (ret);
545 }
546 
547 /*
548  * __lock_familyremove
549  *	Remove a locker from its family.
550  *
551  * This must be called without the locker bucket locked.
552  *
553  * PUBLIC: int __lock_familyremove  __P((DB_LOCKTAB *, DB_LOCKER *));
554  */
555 int
__lock_familyremove(lt,sh_locker)556 __lock_familyremove(lt, sh_locker)
557 	DB_LOCKTAB *lt;
558 	DB_LOCKER *sh_locker;
559 {
560 	DB_LOCKREGION *region;
561 	ENV *env;
562 	int ret;
563 
564 	region = lt->reginfo.primary;
565 	env = lt->env;
566 
567 	LOCK_LOCKERS(env, region);
568 	ret = __lock_freelocker_int(lt, region, sh_locker, 0);
569 	UNLOCK_LOCKERS(env, region);
570 
571 	return (ret);
572 }
573