📄 lock_id.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. * * $Id: lock_id.c,v 11.146 2004/10/15 16:59:42 bostic Exp $ */#include "db_config.h"#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <string.h>#include <stdlib.h>#endif#include "db_int.h"#include "dbinc/db_shash.h"#include "dbinc/lock.h"#include "dbinc/log.h"/* * __lock_id_pp -- * DB_ENV->lock_id pre/post processing. * * PUBLIC: int __lock_id_pp __P((DB_ENV *, u_int32_t *)); */int__lock_id_pp(dbenv, idp) DB_ENV *dbenv; u_int32_t *idp;{ int rep_check, ret; PANIC_CHECK(dbenv); ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, "DB_ENV->lock_id", DB_INIT_LOCK); rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0; if (rep_check) __env_rep_enter(dbenv); ret = __lock_id(dbenv, idp); if (rep_check) __env_db_rep_exit(dbenv); return (ret);}/* * __lock_id -- * DB_ENV->lock_id. * * PUBLIC: int __lock_id __P((DB_ENV *, u_int32_t *)); */int__lock_id(dbenv, idp) DB_ENV *dbenv; u_int32_t *idp;{ DB_LOCKER *lk; DB_LOCKTAB *lt; DB_LOCKREGION *region; u_int32_t *ids, locker_ndx; int nids, ret; lt = dbenv->lk_handle; region = lt->reginfo.primary; ret = 0; /* * Allocate a new lock id. If we wrap around then we * find the minimum currently in use and make sure we * can stay below that. This code is similar to code * in __txn_begin_int for recovering txn ids. */ LOCKREGION(dbenv, lt); /* * Our current valid range can span the maximum valid value, so check * for it and wrap manually. */ if (region->stat.st_id == DB_LOCK_MAXID && region->stat.st_cur_maxid != DB_LOCK_MAXID) region->stat.st_id = DB_LOCK_INVALIDID; if (region->stat.st_id == region->stat.st_cur_maxid) { if ((ret = __os_malloc(dbenv, sizeof(u_int32_t) * region->stat.st_nlockers, &ids)) != 0) goto err; nids = 0; for (lk = SH_TAILQ_FIRST(®ion->lockers, __db_locker); lk != NULL; lk = SH_TAILQ_NEXT(lk, ulinks, __db_locker)) ids[nids++] = lk->id; region->stat.st_id = DB_LOCK_INVALIDID; region->stat.st_cur_maxid = DB_LOCK_MAXID; if (nids != 0) __db_idspace(ids, nids, ®ion->stat.st_id, ®ion->stat.st_cur_maxid); __os_free(dbenv, ids); } *idp = ++region->stat.st_id; /* Allocate a locker for this id. */ LOCKER_LOCK(lt, region, *idp, locker_ndx); ret = __lock_getlocker(lt, *idp, locker_ndx, 1, &lk);err: UNLOCKREGION(dbenv, lt); return (ret);}/* * __lock_id_free_pp -- * DB_ENV->lock_id_free pre/post processing. * * PUBLIC: int __lock_id_free_pp __P((DB_ENV *, u_int32_t)); */int__lock_id_free_pp(dbenv, id) DB_ENV *dbenv; u_int32_t id;{ int rep_check, ret; PANIC_CHECK(dbenv); ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, "DB_ENV->lock_id_free", DB_INIT_LOCK); rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0; if (rep_check) __env_rep_enter(dbenv); ret = __lock_id_free(dbenv, id); if (rep_check) __env_db_rep_exit(dbenv); return (ret);}/* * __lock_id_free -- * Free a locker id. * * PUBLIC: int __lock_id_free __P((DB_ENV *, u_int32_t)); */int__lock_id_free(dbenv, id) DB_ENV *dbenv; u_int32_t id;{ DB_LOCKER *sh_locker; DB_LOCKTAB *lt; DB_LOCKREGION *region; u_int32_t locker_ndx; int ret; PANIC_CHECK(dbenv); ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, "DB_ENV->lock_id_free", DB_INIT_LOCK); lt = dbenv->lk_handle; region = lt->reginfo.primary; LOCKREGION(dbenv, lt); LOCKER_LOCK(lt, region, id, locker_ndx); if ((ret = __lock_getlocker(lt, id, locker_ndx, 0, &sh_locker)) != 0) goto err; if (sh_locker == NULL) { __db_err(dbenv, "Unknown locker ID: %lx", (u_long)id); ret = EINVAL; goto err; } if (sh_locker->nlocks != 0) { __db_err(dbenv, "Locker still has locks"); ret = EINVAL; goto err; } __lock_freelocker(lt, region, sh_locker, locker_ndx);err: UNLOCKREGION(dbenv, lt); return (ret);}/* * __lock_id_set -- * Set the current locker ID and current maximum unused ID (for * testing purposes only). * * PUBLIC: int __lock_id_set __P((DB_ENV *, u_int32_t, u_int32_t)); */int__lock_id_set(dbenv, cur_id, max_id) DB_ENV *dbenv; u_int32_t cur_id, max_id;{ DB_LOCKTAB *lt; DB_LOCKREGION *region; ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, "lock_id_set", DB_INIT_LOCK); lt = dbenv->lk_handle; region = lt->reginfo.primary; region->stat.st_id = cur_id; region->stat.st_cur_maxid = max_id; return (0);}/* * __lock_getlocker -- * Get a locker in the locker hash table. The create parameter * indicates if the locker should be created if it doesn't exist in * the table. * * This must be called with the locker bucket locked. * * PUBLIC: int __lock_getlocker __P((DB_LOCKTAB *, * PUBLIC: u_int32_t, u_int32_t, int, DB_LOCKER **)); */int__lock_getlocker(lt, locker, indx, create, retp) DB_LOCKTAB *lt; u_int32_t locker, indx; int create; DB_LOCKER **retp;{ DB_ENV *dbenv; DB_LOCKER *sh_locker; DB_LOCKREGION *region; dbenv = lt->dbenv; region = lt->reginfo.primary; HASHLOOKUP(lt->locker_tab, indx, __db_locker, links, locker, sh_locker, __lock_locker_cmp); /* * If we found the locker, then we can just return it. If * we didn't find the locker, then we need to create it. */ if (sh_locker == NULL && create) { /* Create new locker and then insert it into hash table. */ if ((sh_locker = SH_TAILQ_FIRST( ®ion->free_lockers, __db_locker)) == NULL) return (__lock_nomem(dbenv, "locker entries")); SH_TAILQ_REMOVE( ®ion->free_lockers, sh_locker, links, __db_locker); if (++region->stat.st_nlockers > region->stat.st_maxnlockers) region->stat.st_maxnlockers = region->stat.st_nlockers; sh_locker->id = locker; sh_locker->dd_id = 0; sh_locker->master_locker = INVALID_ROFF; sh_locker->parent_locker = INVALID_ROFF; SH_LIST_INIT(&sh_locker->child_locker); sh_locker->flags = 0; SH_LIST_INIT(&sh_locker->heldby); sh_locker->nlocks = 0; sh_locker->nwrites = 0; sh_locker->lk_timeout = 0; LOCK_SET_TIME_INVALID(&sh_locker->tx_expire); LOCK_SET_TIME_INVALID(&sh_locker->lk_expire); HASHINSERT(lt->locker_tab, indx, __db_locker, links, sh_locker); SH_TAILQ_INSERT_HEAD(®ion->lockers, sh_locker, ulinks, __db_locker); } *retp = sh_locker; return (0);}/* * __lock_addfamilylocker * Put a locker entry in for a child transaction. * * PUBLIC: int __lock_addfamilylocker __P((DB_ENV *, u_int32_t, u_int32_t)); */int__lock_addfamilylocker(dbenv, pid, id) DB_ENV *dbenv; u_int32_t pid, id;{ DB_LOCKER *lockerp, *mlockerp; DB_LOCKREGION *region; DB_LOCKTAB *lt; u_int32_t ndx; int ret; lt = dbenv->lk_handle; region = lt->reginfo.primary; LOCKREGION(dbenv, lt); /* get/create the parent locker info */ LOCKER_LOCK(lt, region, pid, ndx); if ((ret = __lock_getlocker(dbenv->lk_handle, pid, ndx, 1, &mlockerp)) != 0) goto err; /* * We assume that only one thread can manipulate * a single transaction family. * Therefore the master locker cannot go away while * we manipulate it, nor can another child in the * family be created at the same time. */ LOCKER_LOCK(lt, region, id, ndx); if ((ret = __lock_getlocker(dbenv->lk_handle, id, ndx, 1, &lockerp)) != 0) goto err; /* Point to our parent. */ lockerp->parent_locker = R_OFFSET(<->reginfo, mlockerp); /* See if this locker is the family master. */ if (mlockerp->master_locker == INVALID_ROFF) lockerp->master_locker = R_OFFSET(<->reginfo, mlockerp); else { lockerp->master_locker = mlockerp->master_locker; mlockerp = R_ADDR(<->reginfo, mlockerp->master_locker); } /* * Link the child at the head of the master's list. * The guess is when looking for deadlock that * the most recent child is the one thats blocked. */ SH_LIST_INSERT_HEAD( &mlockerp->child_locker, lockerp, child_link, __db_locker);err: UNLOCKREGION(dbenv, lt); return (ret);}/* * __lock_freefamilylocker * Remove a locker from the hash table and its family. * * This must be called without the locker bucket locked. * * PUBLIC: int __lock_freefamilylocker __P((DB_LOCKTAB *, u_int32_t)); */int__lock_freefamilylocker(lt, locker) DB_LOCKTAB *lt; u_int32_t locker;{ DB_ENV *dbenv; DB_LOCKER *sh_locker; DB_LOCKREGION *region; u_int32_t indx; int ret; dbenv = lt->dbenv; region = lt->reginfo.primary; LOCKREGION(dbenv, lt); LOCKER_LOCK(lt, region, locker, indx); if ((ret = __lock_getlocker(lt, locker, indx, 0, &sh_locker)) != 0 || sh_locker == NULL) goto err; if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) != NULL) { ret = EINVAL; __db_err(dbenv, "Freeing locker with locks"); goto err; } /* If this is part of a family, we must fix up its links. */ if (sh_locker->master_locker != INVALID_ROFF) SH_LIST_REMOVE(sh_locker, child_link, __db_locker); __lock_freelocker(lt, region, sh_locker, indx);err: UNLOCKREGION(dbenv, lt); return (ret);}/* * __lock_freelocker * Common code for deleting a locker; must be called with the * locker bucket locked. * * PUBLIC: void __lock_freelocker * PUBLIC: __P((DB_LOCKTAB *, DB_LOCKREGION *, DB_LOCKER *, u_int32_t)); */void__lock_freelocker(lt, region, sh_locker, indx) DB_LOCKTAB *lt; DB_LOCKREGION *region; DB_LOCKER *sh_locker; u_int32_t indx;{ HASHREMOVE_EL( lt->locker_tab, indx, __db_locker, links, sh_locker); SH_TAILQ_INSERT_HEAD( ®ion->free_lockers, sh_locker, links, __db_locker); SH_TAILQ_REMOVE(®ion->lockers, sh_locker, ulinks, __db_locker); region->stat.st_nlockers--;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -