📄 dbreg_util.c
字号:
* __dbreg_fid_to_fname -- * Traverse the shared-memory region looking for the entry that * matches the passed file unique id. Returns 0 on success; -1 on error. * * PUBLIC: int __dbreg_fid_to_fname __P((DB_LOG *, u_int8_t *, int, FNAME **)); */int__dbreg_fid_to_fname(dblp, fid, have_lock, fnamep) DB_LOG *dblp; u_int8_t *fid; int have_lock; FNAME **fnamep;{ DB_ENV *dbenv; FNAME *fnp; LOG *lp; int ret; dbenv = dblp->dbenv; lp = dblp->reginfo.primary; ret = -1; if (!have_lock) MUTEX_LOCK(dbenv, &lp->fq_mutex); for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { if (memcmp(fnp->ufid, fid, DB_FILE_ID_LEN) == 0) { *fnamep = fnp; ret = 0; break; } } if (!have_lock) MUTEX_UNLOCK(dbenv, &lp->fq_mutex); return (ret);}/* * __dbreg_get_name * * Interface to get name of registered files. This is mainly diagnostic * and the name passed could be transient unless there is something * ensuring that the file cannot be closed. * * PUBLIC: int __dbreg_get_name __P((DB_ENV *, u_int8_t *, char **)); */int__dbreg_get_name(dbenv, fid, namep) DB_ENV *dbenv; u_int8_t *fid; char **namep;{ DB_LOG *dblp; FNAME *fname; dblp = dbenv->lg_handle; if (dblp != NULL && __dbreg_fid_to_fname(dblp, fid, 0, &fname) == 0) { *namep = R_ADDR(&dblp->reginfo, fname->name_off); return (0); } return (-1);}/* * __dbreg_do_open -- * Open files referenced in the log. This is the part of the open that * is not protected by the thread mutex. * PUBLIC: int __dbreg_do_open __P((DB_ENV *, DB_TXN *, DB_LOG *, u_int8_t *, * PUBLIC: char *, DBTYPE, int32_t, db_pgno_t, void *, u_int32_t)); */int__dbreg_do_open(dbenv, txn, lp, uid, name, ftype, ndx, meta_pgno, info, id) DB_ENV *dbenv; DB_TXN *txn; DB_LOG *lp; u_int8_t *uid; char *name; DBTYPE ftype; int32_t ndx; db_pgno_t meta_pgno; void *info; u_int32_t id;{ DB *dbp; int ret; u_int32_t cstat; if ((ret = db_create(&dbp, lp->dbenv, 0)) != 0) return (ret); /* * We can open files under a number of different scenarios. * First, we can open a file during a normal txn_abort, if that file * was opened and closed during the transaction (as is the master * database of a sub-database). * Second, we might be aborting a transaction in XA and not have * it open in the process that is actually doing the abort. * Third, we might be in recovery. * In case 3, there is no locking, so there is no issue. * In cases 1 and 2, we are guaranteed to already hold any locks * that we need, since we're still in the same transaction, so by * setting DB_AM_RECOVER, we guarantee that we don't log and that * we don't try to acquire locks on behalf of a different locker id. */ F_SET(dbp, DB_AM_RECOVER); if (meta_pgno != PGNO_BASE_MD) { memcpy(dbp->fileid, uid, DB_FILE_ID_LEN); dbp->meta_pgno = meta_pgno; } dbp->type = ftype; if ((ret = __db_dbopen(dbp, txn, name, NULL, DB_ODDFILESIZE, __db_omode("rw----"), meta_pgno)) == 0) { /* * Verify that we are opening the same file that we were * referring to when we wrote this log record. */ if ((meta_pgno != PGNO_BASE_MD && __dbreg_check_master(dbenv, uid, name) != 0) || memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0) cstat = TXN_IGNORE; else cstat = TXN_EXPECTED; /* Assign the specific dbreg id to this dbp. */ if ((ret = __dbreg_assign_id(dbp, ndx)) != 0) goto err; /* * If we successfully opened this file, then we need to * convey that information to the txnlist so that we * know how to handle the subtransaction that created * the file system object. */ if (id != TXN_INVALID) { if ((ret = __db_txnlist_update(dbenv, info, id, cstat, NULL)) == TXN_NOTFOUND) ret = __db_txnlist_add(dbenv, info, id, cstat, NULL); else if (ret > 0) ret = 0; }err: if (cstat == TXN_IGNORE) goto not_right; return (ret); } else { /* Record that the open failed in the txnlist. */ if (id != TXN_INVALID && (ret = __db_txnlist_update(dbenv, info, id, TXN_UNEXPECTED, NULL)) == TXN_NOTFOUND) ret = __db_txnlist_add(dbenv, info, id, TXN_UNEXPECTED, NULL); }not_right: (void)dbp->close(dbp, 0); /* Add this file as deleted. */ (void)__dbreg_add_dbentry(dbenv, lp, NULL, ndx); return (ENOENT);}static int__dbreg_check_master(dbenv, uid, name) DB_ENV *dbenv; u_int8_t *uid; char *name;{ DB *dbp; int ret; ret = 0; if ((ret = db_create(&dbp, dbenv, 0)) != 0) return (ret); dbp->type = DB_BTREE; F_SET(dbp, DB_AM_RECOVER); ret = __db_dbopen(dbp, NULL, name, NULL, 0, __db_omode("rw----"), PGNO_BASE_MD); if (ret == 0 && memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0) ret = EINVAL; (void)dbp->close(dbp, 0); return (ret);}/* * __dbreg_lazy_id -- * When a replication client gets upgraded to being a replication master, * it may have database handles open that have not been assigned an ID, but * which have become legal to use for logging. * * This function lazily allocates a new ID for such a function, in a * new transaction created for the purpose. We need to do this in a new * transaction because we definitely wish to commit the dbreg_register, but * at this point we have no way of knowing whether the log record that incited * us to call this will be part of a committed transaction. * * PUBLIC: int __dbreg_lazy_id __P((DB *)); */int__dbreg_lazy_id(dbp) DB *dbp;{ DB_ENV *dbenv; DB_TXN *txn; int ret; dbenv = dbp->dbenv; DB_ASSERT(F_ISSET(dbenv, DB_ENV_REP_MASTER)); if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0) return (ret); if ((ret = __dbreg_new_id(dbp, txn)) != 0) { (void)txn->abort(txn); return (ret); } return (txn->commit(txn, DB_TXN_NOSYNC));}/* * __dbreg_push_id and __dbreg_pop_id -- * Dbreg ids from closed files are kept on a stack in shared memory * for recycling. (We want to reuse them as much as possible because each * process keeps open files in an array by ID.) Push them to the stack and * pop them from it, managing memory as appropriate. * * The stack is protected by the fq_mutex, and in both functions we assume * that this is already locked. * * PUBLIC: int __dbreg_push_id __P((DB_ENV *, int32_t)); * PUBLIC: int __dbreg_pop_id __P((DB_ENV *, int32_t *)); */int__dbreg_push_id(dbenv, id) DB_ENV *dbenv; int32_t id;{ DB_LOG *dblp; LOG *lp; int32_t *stack, *newstack; int ret; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; if (lp->free_fid_stack != INVALID_ROFF) stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack); else stack = NULL; /* Check if we have room on the stack. */ if (lp->free_fids_alloced <= lp->free_fids + 1) { R_LOCK(dbenv, &dblp->reginfo); if ((ret = __db_shalloc(dblp->reginfo.addr, (lp->free_fids_alloced + 20) * sizeof(u_int32_t), 0, &newstack)) != 0) { R_UNLOCK(dbenv, &dblp->reginfo); return (ret); } memcpy(newstack, stack, lp->free_fids_alloced * sizeof(u_int32_t)); lp->free_fid_stack = R_OFFSET(&dblp->reginfo, newstack); lp->free_fids_alloced += 20; if (stack != NULL) __db_shalloc_free(dblp->reginfo.addr, stack); stack = newstack; R_UNLOCK(dbenv, &dblp->reginfo); } DB_ASSERT(stack != NULL); stack[lp->free_fids++] = id; return (0);}int__dbreg_pop_id(dbenv, id) DB_ENV *dbenv; int32_t *id;{ DB_LOG *dblp; LOG *lp; int32_t *stack; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; /* Do we have anything to pop? */ if (lp->free_fid_stack != INVALID_ROFF && lp->free_fids > 0) { stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack); *id = stack[--lp->free_fids]; } else *id = DB_LOGFILEID_INVALID; return (0);}/* * __dbreg_pluck_id -- * Remove a particular dbreg id from the stack of free ids. This is * used when we open a file, as in recovery, with a specific ID that might * be on the stack. * * Returns success whether or not the particular id was found, and like * push and pop, assumes that the fq_mutex is locked. * * PUBLIC: int __dbreg_pluck_id __P((DB_ENV *, int32_t)); */int__dbreg_pluck_id(dbenv, id) DB_ENV *dbenv; int32_t id;{ DB_LOG *dblp; LOG *lp; int32_t *stack; int i; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; /* Do we have anything to look at? */ if (lp->free_fid_stack != INVALID_ROFF) { stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack); for (i = 0; i < lp->free_fids; i++) if (id == stack[i]) { /* * Found it. Overwrite it with the top * id (which may harmlessly be itself), * and shorten the stack by one. */ stack[i] = stack[lp->free_fids - 1]; lp->free_fids--; return (0); } } return (0);}#ifdef DEBUG/* * __dbreg_print_dblist -- * Display the list of files. * * PUBLIC: void __dbreg_print_dblist __P((DB_ENV *)); */void__dbreg_print_dblist(dbenv) DB_ENV *dbenv;{ DB *dbp; DB_LOG *dblp; FNAME *fnp; LOG *lp; int del, first; char *name; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; MUTEX_LOCK(dbenv, &lp->fq_mutex); for (first = 1, fnp = SH_TAILQ_FIRST(&lp->fq, __fname); fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { if (first) { first = 0; __db_err(dbenv, "ID\t\t\tName\tType\tPgno\tTxnid\tDBP-info"); } if (fnp->name_off == INVALID_ROFF) name = ""; else name = R_ADDR(&dblp->reginfo, fnp->name_off); dbp = fnp->id >= dblp->dbentry_cnt ? NULL : dblp->dbentry[fnp->id].dbp; del = fnp->id >= dblp->dbentry_cnt ? 0 : dblp->dbentry[fnp->id].deleted; __db_err(dbenv, "%ld\t%s\t\t\t%s\t%lu\t%lx\t%s %d %lx %lx", (long)fnp->id, name, __db_dbtype_to_string(fnp->s_type), (u_long)fnp->meta_pgno, (u_long)fnp->create_txnid, dbp == NULL ? "No DBP" : "DBP", del, P_TO_ULONG(dbp), dbp == NULL ? 0 : dbp->flags); } MUTEX_UNLOCK(dbenv, &lp->fq_mutex);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -