📄 dbreg_util.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1997-2002 * Sleepycat Software. All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: dbreg_util.c,v 11.22 2002/09/10 02:43:10 bostic Exp $";#endif /* not lint */#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <string.h>#endif#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_am.h"#include "dbinc/log.h"#include "dbinc/txn.h"static int __dbreg_check_master __P((DB_ENV *, u_int8_t *, char *));/* * __dbreg_add_dbentry -- * Adds a DB entry to the dbreg DB entry table. * * PUBLIC: int __dbreg_add_dbentry __P((DB_ENV *, DB_LOG *, DB *, int32_t)); */int__dbreg_add_dbentry(dbenv, dblp, dbp, ndx) DB_ENV *dbenv; DB_LOG *dblp; DB *dbp; int32_t ndx;{ int32_t i; int ret; ret = 0; MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); /* * Check if we need to grow the table. Note, ndx is 0-based (the * index into the DB entry table) an dbentry_cnt is 1-based, the * number of available slots. */ if (dblp->dbentry_cnt <= ndx) { if ((ret = __os_realloc(dbenv, (ndx + DB_GROW_SIZE) * sizeof(DB_ENTRY), &dblp->dbentry)) != 0) goto err; /* Initialize the new entries. */ for (i = dblp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) { dblp->dbentry[i].dbp = NULL; dblp->dbentry[i].deleted = 0; } dblp->dbentry_cnt = i; } DB_ASSERT(dblp->dbentry[ndx].dbp == NULL); dblp->dbentry[ndx].deleted = dbp == NULL; dblp->dbentry[ndx].dbp = dbp;err: MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); return (ret);}/* * __dbreg_rem_dbentry * Remove an entry from the DB entry table. * * PUBLIC: void __dbreg_rem_dbentry __P((DB_LOG *, int32_t)); */void__dbreg_rem_dbentry(dblp, ndx) DB_LOG *dblp; int32_t ndx;{ MUTEX_THREAD_LOCK(dblp->dbenv, dblp->mutexp); dblp->dbentry[ndx].dbp = NULL; dblp->dbentry[ndx].deleted = 0; MUTEX_THREAD_UNLOCK(dblp->dbenv, dblp->mutexp);}/* * __dbreg_open_files -- * Put a LOG_CHECKPOINT log record for each open database. * * PUBLIC: int __dbreg_open_files __P((DB_ENV *)); */int__dbreg_open_files(dbenv) DB_ENV *dbenv;{ DB_LOG *dblp; DB_LSN r_unused; DBT *dbtp, fid_dbt, t; FNAME *fnp; LOG *lp; int ret; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; ret = 0; MUTEX_LOCK(dbenv, &lp->fq_mutex); for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { if (fnp->name_off == INVALID_ROFF) dbtp = NULL; else { memset(&t, 0, sizeof(t)); t.data = R_ADDR(&dblp->reginfo, fnp->name_off); t.size = (u_int32_t)strlen(t.data) + 1; dbtp = &t; } memset(&fid_dbt, 0, sizeof(fid_dbt)); fid_dbt.data = fnp->ufid; fid_dbt.size = DB_FILE_ID_LEN; /* * Output LOG_CHECKPOINT records which will be * processed during the OPENFILES pass of recovery. * At the end of recovery we want to output the * files that were open so that a future recovery * run will have the correct files open during * a backward pass. For this we output LOG_RCLOSE * records so that the files will be closed on * the forward pass. */ if ((ret = __dbreg_register_log(dbenv, NULL, &r_unused, 0, F_ISSET(dblp, DBLOG_RECOVER) ? LOG_RCLOSE : LOG_CHECKPOINT, dbtp, &fid_dbt, fnp->id, fnp->s_type, fnp->meta_pgno, TXN_INVALID)) != 0) break; } MUTEX_UNLOCK(dbenv, &lp->fq_mutex); return (ret);}/* * __dbreg_close_files -- * Close files that were opened by the recovery daemon. We sync the * file, unless its mpf pointer has been NULLed by a db_remove or * db_rename. We may not have flushed the log_register record that * closes the file. * * PUBLIC: int __dbreg_close_files __P((DB_ENV *)); */int__dbreg_close_files(dbenv) DB_ENV *dbenv;{ DB_LOG *dblp; DB *dbp; int ret, t_ret; int32_t i; /* If we haven't initialized logging, we have nothing to do. */ if (!LOGGING_ON(dbenv)) return (0); dblp = dbenv->lg_handle; ret = 0; MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); for (i = 0; i < dblp->dbentry_cnt; i++) { /* We only want to close dbps that recovery opened. */ if ((dbp = dblp->dbentry[i].dbp) != NULL && F_ISSET(dbp, DB_AM_RECOVER)) { /* * It's unsafe to call DB->close while holding the * thread lock, because we'll call __dbreg_rem_dbentry * and grab it again. * * Just drop it. Since dbreg ids go monotonically * upward, concurrent opens should be safe, and the * user should have no business closing files while * we're in this loop anyway--we're in the process of * making all outstanding dbps invalid. */ MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); if ((t_ret = dbp->close(dbp, dbp->mpf == NULL ? DB_NOSYNC : 0)) != 0 && ret == 0) ret = t_ret; MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); } dblp->dbentry[i].deleted = 0; dblp->dbentry[i].dbp = NULL; } MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); return (ret);}/* * __dbreg_nofiles -- * Check that there are no open files in the process local table. * Returns 0 if there are no files and EINVAL if there are any. * * PUBLIC: int __dbreg_nofiles __P((DB_ENV *)); */int__dbreg_nofiles(dbenv) DB_ENV *dbenv;{ DB *dbp; DB_LOG *dblp; int ret; int32_t i; /* If we haven't initialized logging, we have nothing to do. */ if (!LOGGING_ON(dbenv)) return (0); dblp = dbenv->lg_handle; ret = 0; MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); for (i = 0; i < dblp->dbentry_cnt; i++) { if ((dbp = dblp->dbentry[i].dbp) != NULL && !F_ISSET(dbp, DB_AM_RECOVER)) { ret = EINVAL; break; } } MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); return (ret);}/* * __dbreg_id_to_db -- * Return the DB corresponding to the specified dbreg id. * * PUBLIC: int __dbreg_id_to_db __P((DB_ENV *, DB_TXN *, DB **, int32_t, int)); */int__dbreg_id_to_db(dbenv, txn, dbpp, ndx, inc) DB_ENV *dbenv; DB_TXN *txn; DB **dbpp; int32_t ndx; int inc;{ return (__dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, 1));}/* * __dbreg_id_to_db_int -- * Return the DB corresponding to the specified dbreg id. The internal * version takes a final parameter that indicates whether we should attempt * to open the file if no mapping is found. During recovery, the recovery * routines all want to try to open the file (and this is called from * __dbreg_id_to_db), however, if we have a multi-process environment where * some processes may not have the files open (e.g., XA), then we also get * called from __dbreg_assign_id and it's OK if there is no mapping. * * PUBLIC: int __dbreg_id_to_db_int __P((DB_ENV *, * PUBLIC: DB_TXN *, DB **, int32_t, int, int)); */int__dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen) DB_ENV *dbenv; DB_TXN *txn; DB **dbpp; int32_t ndx; int inc, tryopen;{ DB_LOG *dblp; FNAME *fname; int ret; char *name; ret = 0; dblp = dbenv->lg_handle; COMPQUIET(inc, 0); MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); /* * Under XA, a process different than the one issuing DB operations * may abort a transaction. In this case, the "recovery" routines * are run by a process that does not necessarily have the file open, * so we we must open the file explicitly. */ if (ndx >= dblp->dbentry_cnt || (!dblp->dbentry[ndx].deleted && dblp->dbentry[ndx].dbp == NULL)) { if (!tryopen || F_ISSET(dblp, DBLOG_RECOVER)) { ret = ENOENT; goto err; } /* * __dbreg_id_to_fname acquires the region's fq_mutex, * which we can't safely acquire while we hold the thread lock. * We no longer need it anyway--the dbentry table didn't * have what we needed. */ MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); if (__dbreg_id_to_fname(dblp, ndx, 0, &fname) != 0) /* * With transactional opens, we may actually have * closed this file in the transaction in which * case this will fail too. Then it's up to the * caller to reopen the file. */ return (ENOENT); /* * Note that we're relying on fname not to change, even * though we released the mutex that protects it (fq_mutex) * inside __dbreg_id_to_fname. This should be a safe * assumption, because the other process that has the file * open shouldn't be closing it while we're trying to abort. */ name = R_ADDR(&dblp->reginfo, fname->name_off); /* * At this point, we are not holding the thread lock, so exit * directly instead of going through the exit code at the * bottom. If the __dbreg_do_open succeeded, then we don't need * to do any of the remaining error checking at the end of this * routine. * XXX I am sending a NULL txnlist and 0 txnid which may be * completely broken ;( */ if ((ret = __dbreg_do_open(dbenv, txn, dblp, fname->ufid, name, fname->s_type, ndx, fname->meta_pgno, NULL, 0)) != 0) return (ret); *dbpp = dblp->dbentry[ndx].dbp; return (0); } /* * Return DB_DELETED if the file has been deleted (it's not an error). */ if (dblp->dbentry[ndx].deleted) { ret = DB_DELETED; goto err; } /* It's an error if we don't have a corresponding writeable DB. */ if ((*dbpp = dblp->dbentry[ndx].dbp) == NULL) ret = ENOENT;err: MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); return (ret);}/* * __dbreg_id_to_fname -- * Traverse the shared-memory region looking for the entry that * matches the passed dbreg id. Returns 0 on success; -1 on error. * * PUBLIC: int __dbreg_id_to_fname __P((DB_LOG *, int32_t, int, FNAME **)); */int__dbreg_id_to_fname(dblp, lid, have_lock, fnamep) DB_LOG *dblp; int32_t lid; 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 (fnp->id == lid) { *fnamep = fnp; ret = 0; break; } } if (!have_lock) MUTEX_UNLOCK(dbenv, &lp->fq_mutex); return (ret);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -