1N/A/*-
1N/A * See the file LICENSE for redistribution information.
1N/A *
1N/A * Copyright (c) 1996, 1997, 1998
1N/A * Sleepycat Software. All rights reserved.
1N/A */
1N/A#include "config.h"
1N/A
1N/A#ifndef lint
1N/Astatic const char sccsid[] = "@(#)log_register.c 10.22 (Sleepycat) 9/27/98";
1N/A#endif /* not lint */
1N/A
1N/A#ifndef NO_SYSTEM_INCLUDES
1N/A#include <sys/types.h>
1N/A
1N/A#include <errno.h>
1N/A#include <string.h>
1N/A#endif
1N/A
1N/A#include "db_int.h"
1N/A#include "shqueue.h"
1N/A#include "log.h"
1N/A#include "common_ext.h"
1N/A
1N/A/*
1N/A * log_register --
1N/A * Register a file name.
1N/A */
1N/Aint
1N/Alog_register(dblp, dbp, name, type, idp)
1N/A DB_LOG *dblp;
1N/A DB *dbp;
1N/A const char *name;
1N/A DBTYPE type;
1N/A u_int32_t *idp;
1N/A{
1N/A DBT fid_dbt, r_name;
1N/A DB_LSN r_unused;
1N/A FNAME *fnp, *reuse_fnp;
1N/A size_t len;
1N/A u_int32_t maxid;
1N/A int inserted, ret;
1N/A char *fullname;
1N/A void *namep;
1N/A
1N/A inserted = 0;
1N/A fullname = NULL;
1N/A fnp = namep = reuse_fnp = NULL;
1N/A
1N/A LOG_PANIC_CHECK(dblp);
1N/A
1N/A /* Check the arguments. */
1N/A if (type != DB_BTREE && type != DB_HASH && type != DB_RECNO) {
1N/A __db_err(dblp->dbenv, "log_register: unknown DB file type");
1N/A return (EINVAL);
1N/A }
1N/A
1N/A /* Get the log file id. */
1N/A if ((ret = __db_appname(dblp->dbenv,
1N/A DB_APP_DATA, NULL, name, 0, NULL, &fullname)) != 0)
1N/A return (ret);
1N/A
1N/A LOCK_LOGREGION(dblp);
1N/A
1N/A /*
1N/A * See if we've already got this file in the log, finding the
1N/A * (maximum+1) in-use file id and some available file id (if we
1N/A * find an available fid, we'll use it, else we'll have to allocate
1N/A * one after the maximum that we found).
1N/A */
1N/A for (maxid = 0, fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
1N/A fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
1N/A if (fnp->ref == 0) { /* Entry is not in use. */
1N/A if (reuse_fnp == NULL)
1N/A reuse_fnp = fnp;
1N/A continue;
1N/A }
1N/A if (!memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN)) {
1N/A ++fnp->ref;
1N/A goto found;
1N/A }
1N/A if (maxid <= fnp->id)
1N/A maxid = fnp->id + 1;
1N/A }
1N/A
1N/A /* Fill in fnp structure. */
1N/A
1N/A if (reuse_fnp != NULL) /* Reuse existing one. */
1N/A fnp = reuse_fnp;
1N/A else if ((ret = __db_shalloc(dblp->addr, sizeof(FNAME), 0, &fnp)) != 0)
1N/A goto err;
1N/A else /* Allocate a new one. */
1N/A fnp->id = maxid;
1N/A
1N/A fnp->ref = 1;
1N/A fnp->s_type = type;
1N/A memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN);
1N/A
1N/A len = strlen(name) + 1;
1N/A if ((ret = __db_shalloc(dblp->addr, len, 0, &namep)) != 0)
1N/A goto err;
1N/A fnp->name_off = R_OFFSET(dblp, namep);
1N/A memcpy(namep, name, len);
1N/A
1N/A /* Only do the insert if we allocated a new fnp. */
1N/A if (reuse_fnp == NULL)
1N/A SH_TAILQ_INSERT_HEAD(&dblp->lp->fq, fnp, q, __fname);
1N/A inserted = 1;
1N/A
1N/Afound: /* Log the registry. */
1N/A if (!F_ISSET(dblp, DBC_RECOVER)) {
1N/A r_name.data = (void *)name; /* XXX: Yuck! */
1N/A r_name.size = strlen(name) + 1;
1N/A memset(&fid_dbt, 0, sizeof(fid_dbt));
1N/A fid_dbt.data = dbp->fileid;
1N/A fid_dbt.size = DB_FILE_ID_LEN;
1N/A if ((ret = __log_register_log(dblp, NULL, &r_unused,
1N/A 0, LOG_OPEN, &r_name, &fid_dbt, fnp->id, type)) != 0)
1N/A goto err;
1N/A if ((ret = __log_add_logid(dblp, dbp, name, fnp->id)) != 0)
1N/A goto err;
1N/A }
1N/A
1N/A if (0) {
1N/Aerr: /*
1N/A * XXX
1N/A * We should grow the region.
1N/A */
1N/A if (inserted)
1N/A SH_TAILQ_REMOVE(&dblp->lp->fq, fnp, q, __fname);
1N/A if (namep != NULL)
1N/A __db_shalloc_free(dblp->addr, namep);
1N/A if (fnp != NULL)
1N/A __db_shalloc_free(dblp->addr, fnp);
1N/A }
1N/A
1N/A if (idp != NULL)
1N/A *idp = fnp->id;
1N/A UNLOCK_LOGREGION(dblp);
1N/A
1N/A if (fullname != NULL)
1N/A __os_freestr(fullname);
1N/A
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * log_unregister --
1N/A * Discard a registered file name.
1N/A */
1N/Aint
1N/Alog_unregister(dblp, fid)
1N/A DB_LOG *dblp;
1N/A u_int32_t fid;
1N/A{
1N/A DBT fid_dbt, r_name;
1N/A DB_LSN r_unused;
1N/A FNAME *fnp;
1N/A int ret;
1N/A
1N/A LOG_PANIC_CHECK(dblp);
1N/A
1N/A ret = 0;
1N/A LOCK_LOGREGION(dblp);
1N/A
1N/A /* Find the entry in the log. */
1N/A for (fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
1N/A fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname))
1N/A if (fid == fnp->id)
1N/A break;
1N/A if (fnp == NULL) {
1N/A __db_err(dblp->dbenv, "log_unregister: non-existent file id");
1N/A ret = EINVAL;
1N/A goto ret1;
1N/A }
1N/A
1N/A /* Unlog the registry. */
1N/A if (!F_ISSET(dblp, DBC_RECOVER)) {
1N/A memset(&r_name, 0, sizeof(r_name));
1N/A r_name.data = R_ADDR(dblp, fnp->name_off);
1N/A r_name.size = strlen(r_name.data) + 1;
1N/A memset(&fid_dbt, 0, sizeof(fid_dbt));
1N/A fid_dbt.data = fnp->ufid;
1N/A fid_dbt.size = DB_FILE_ID_LEN;
1N/A if ((ret = __log_register_log(dblp, NULL, &r_unused,
1N/A 0, LOG_CLOSE, &r_name, &fid_dbt, fid, fnp->s_type)) != 0)
1N/A goto ret1;
1N/A }
1N/A
1N/A /*
1N/A * If more than 1 reference, just decrement the reference and return.
1N/A * Otherwise, free the name.
1N/A */
1N/A --fnp->ref;
1N/A if (fnp->ref == 0)
1N/A __db_shalloc_free(dblp->addr, R_ADDR(dblp, fnp->name_off));
1N/A
1N/A /*
1N/A * Remove from the process local table. If this operation is taking
1N/A * place during recovery, then the logid was never added to the table,
1N/A * so do not remove it.
1N/A */
1N/A if (!F_ISSET(dblp, DBC_RECOVER))
1N/A __log_rem_logid(dblp, fid);
1N/A
1N/Aret1: UNLOCK_LOGREGION(dblp);
1N/A return (ret);
1N/A}