aboutsummaryrefslogtreecommitdiff
path: root/db2/log
diff options
context:
space:
mode:
Diffstat (limited to 'db2/log')
-rw-r--r--db2/log/log.c194
-rw-r--r--db2/log/log_archive.c123
-rw-r--r--db2/log/log_auto.c21
-rw-r--r--db2/log/log_findckp.c32
-rw-r--r--db2/log/log_get.c54
-rw-r--r--db2/log/log_put.c162
-rw-r--r--db2/log/log_rec.c198
-rw-r--r--db2/log/log_register.c76
8 files changed, 526 insertions, 334 deletions
diff --git a/db2/log/log.c b/db2/log/log.c
index d642c9f9ef..ad15f16aef 100644
--- a/db2/log/log.c
+++ b/db2/log/log.c
@@ -7,13 +7,14 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)log.c 10.54 (Sleepycat) 5/31/98";
+static const char sccsid[] = "@(#)log.c 10.63 (Sleepycat) 10/10/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <errno.h>
+#include <shqueue.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -23,6 +24,7 @@ static const char sccsid[] = "@(#)log.c 10.54 (Sleepycat) 5/31/98";
#include "shqueue.h"
#include "log.h"
#include "db_dispatch.h"
+#include "txn.h"
#include "txn_auto.h"
#include "common_ext.h"
@@ -54,13 +56,11 @@ log_open(path, flags, mode, dbenv, lpp)
return (ret);
/* Create and initialize the DB_LOG structure. */
- if ((dblp = (DB_LOG *)__db_calloc(1, sizeof(DB_LOG))) == NULL)
- return (ENOMEM);
+ if ((ret = __os_calloc(1, sizeof(DB_LOG), &dblp)) != 0)
+ return (ret);
- if (path != NULL && (dblp->dir = __db_strdup(path)) == NULL) {
- ret = ENOMEM;
+ if (path != NULL && (ret = __os_strdup(path, &dblp->dir)) != 0)
goto err;
- }
dblp->dbenv = dbenv;
dblp->lfd = -1;
@@ -80,7 +80,7 @@ log_open(path, flags, mode, dbenv, lpp)
if (path == NULL)
dblp->reginfo.path = NULL;
else
- if ((dblp->reginfo.path = __db_strdup(path)) == NULL)
+ if ((ret = __os_strdup(path, &dblp->reginfo.path)) != 0)
goto err;
dblp->reginfo.file = DB_DEFAULT_LOG_FILE;
dblp->reginfo.mode = mode;
@@ -122,7 +122,7 @@ log_open(path, flags, mode, dbenv, lpp)
if ((ret = __db_shalloc(dblp->addr,
sizeof(db_mutex_t), MUTEX_ALIGNMENT, &dblp->mutexp)) != 0)
goto err;
- (void)__db_mutex_init(dblp->mutexp, -1);
+ (void)__db_mutex_init(dblp->mutexp, 0);
}
/*
@@ -148,14 +148,28 @@ err: if (dblp->reginfo.addr != NULL) {
}
if (dblp->reginfo.path != NULL)
- FREES(dblp->reginfo.path);
+ __os_freestr(dblp->reginfo.path);
if (dblp->dir != NULL)
- FREES(dblp->dir);
- FREE(dblp, sizeof(*dblp));
+ __os_freestr(dblp->dir);
+ __os_free(dblp, sizeof(*dblp));
return (ret);
}
/*
+ * __log_panic --
+ * Panic a log.
+ *
+ * PUBLIC: void __log_panic __P((DB_ENV *));
+ */
+void
+__log_panic(dbenv)
+ DB_ENV *dbenv;
+{
+ if (dbenv->lg_info != NULL)
+ dbenv->lg_info->lp->rlayout.panic = 1;
+}
+
+/*
* __log_recover --
* Recover a log.
*/
@@ -212,12 +226,12 @@ __log_recover(dblp)
}
/*
- * We know where the end of the log is. Since that record is on disk,
- * it's also the last-synced LSN.
+ * We now know where the end of the log is. Set the first LSN that
+ * we want to return to an application and the LSN of the last known
+ * record on disk.
*/
- lp->lsn = lsn;
+ lp->lsn = lp->s_lsn = lsn;
lp->lsn.offset += dblp->c_len;
- lp->s_lsn = lp->lsn;
/* Set up the current buffer information, too. */
lp->len = dblp->c_len;
@@ -250,13 +264,23 @@ __log_recover(dblp)
}
}
}
+ /*
+ * Reset the cursor lsn to the beginning of the log, so that an
+ * initial call to DB_NEXT does the right thing.
+ */
+ ZERO_LSN(dblp->c_lsn);
/* If we never find a checkpoint, that's okay, just 0 it out. */
if (!found_checkpoint)
ZERO_LSN(lp->chkpt_lsn);
+ /*
+ * !!!
+ * The test suite explicitly looks for this string -- don't change
+ * it here unless you also change it there.
+ */
__db_err(dblp->dbenv,
- "Recovering the log: last valid LSN: file: %lu offset %lu",
+ "Finding last valid log LSN: file: %lu offset %lu",
(u_long)lp->lsn.file, (u_long)lp->lsn.offset);
return (0);
@@ -275,14 +299,15 @@ __log_find(dblp, find_first, valp)
DB_LOG *dblp;
int find_first, *valp;
{
- int cnt, fcnt, logval, ret;
+ u_int32_t clv, logval;
+ int cnt, fcnt, ret;
const char *dir;
char **names, *p, *q;
*valp = 0;
/* Find the directory name. */
- if ((ret = __log_name(dblp, 1, &p)) != 0)
+ if ((ret = __log_name(dblp, 1, &p, NULL, 0)) != 0)
return (ret);
if ((q = __db_rpath(p)) == NULL)
dir = PATH_DOT;
@@ -292,8 +317,8 @@ __log_find(dblp, find_first, valp)
}
/* Get the list of file names. */
- ret = __db_dirlist(dir, &names, &fcnt);
- FREES(p);
+ ret = __os_dirlist(dir, &names, &fcnt);
+ __os_freestr(p);
if (ret != 0) {
__db_err(dblp->dbenv, "%s: %s", dir, strerror(ret));
return (ret);
@@ -302,29 +327,31 @@ __log_find(dblp, find_first, valp)
/*
* Search for a valid log file name, return a value of 0 on
* failure.
+ *
+ * XXX
+ * Assumes that atoi(3) returns a 32-bit number.
*/
- for (cnt = fcnt, logval = 0; --cnt >= 0;)
- if (strncmp(names[cnt], "log.", sizeof("log.") - 1) == 0) {
- logval = atoi(names[cnt] + 4);
- if (logval != 0 &&
- __log_valid(dblp, dblp->lp, logval) == 0)
- break;
- }
+ for (cnt = fcnt, clv = logval = 0; --cnt >= 0;) {
+ if (strncmp(names[cnt], LFPREFIX, sizeof(LFPREFIX) - 1) != 0)
+ continue;
+
+ clv = atoi(names[cnt] + (sizeof(LFPREFIX) - 1));
+ if (find_first) {
+ if (logval != 0 && clv > logval)
+ continue;
+ } else
+ if (logval != 0 && clv < logval)
+ continue;
+
+ if (__log_valid(dblp, clv, 1) == 0)
+ logval = clv;
+ }
- /* Discard the list. */
- __db_dirfree(names, fcnt);
-
- /* We have a valid log file, find either the first or last one. */
- if (find_first) {
- for (; logval > 0; --logval)
- if (__log_valid(dblp, dblp->lp, logval - 1) != 0)
- break;
- } else
- for (; logval < MAXLFNAME; ++logval)
- if (__log_valid(dblp, dblp->lp, logval + 1) != 0)
- break;
*valp = logval;
+ /* Discard the list. */
+ __os_dirfree(names, fcnt);
+
return (0);
}
@@ -332,62 +359,68 @@ __log_find(dblp, find_first, valp)
* log_valid --
* Validate a log file.
*
- * PUBLIC: int __log_valid __P((DB_LOG *, LOG *, int));
+ * PUBLIC: int __log_valid __P((DB_LOG *, u_int32_t, int));
*/
int
-__log_valid(dblp, lp, cnt)
+__log_valid(dblp, number, set_persist)
DB_LOG *dblp;
- LOG *lp;
- int cnt;
+ u_int32_t number;
+ int set_persist;
{
LOGP persist;
ssize_t nw;
+ char *fname;
int fd, ret;
- char *p;
- if ((ret = __log_name(dblp, cnt, &p)) != 0)
+ /* Try to open the log file. */
+ if ((ret = __log_name(dblp,
+ number, &fname, &fd, DB_RDONLY | DB_SEQUENTIAL)) != 0) {
+ __os_freestr(fname);
return (ret);
+ }
- fd = -1;
- if ((ret = __db_open(p,
- DB_RDONLY | DB_SEQUENTIAL,
- DB_RDONLY | DB_SEQUENTIAL, 0, &fd)) != 0 ||
- (ret = __db_seek(fd, 0, 0, sizeof(HDR), 0, SEEK_SET)) != 0 ||
- (ret = __db_read(fd, &persist, sizeof(LOGP), &nw)) != 0 ||
+ /* Try to read the header. */
+ if ((ret = __os_seek(fd, 0, 0, sizeof(HDR), 0, SEEK_SET)) != 0 ||
+ (ret = __os_read(fd, &persist, sizeof(LOGP), &nw)) != 0 ||
nw != sizeof(LOGP)) {
if (ret == 0)
ret = EIO;
- if (fd != -1) {
- (void)__db_close(fd);
- __db_err(dblp->dbenv,
- "Ignoring log file: %s: %s", p, strerror(ret));
- }
+
+ (void)__os_close(fd);
+
+ __db_err(dblp->dbenv,
+ "Ignoring log file: %s: %s", fname, strerror(ret));
goto err;
}
- (void)__db_close(fd);
+ (void)__os_close(fd);
+ /* Validate the header. */
if (persist.magic != DB_LOGMAGIC) {
__db_err(dblp->dbenv,
"Ignoring log file: %s: magic number %lx, not %lx",
- p, (u_long)persist.magic, (u_long)DB_LOGMAGIC);
+ fname, (u_long)persist.magic, (u_long)DB_LOGMAGIC);
ret = EINVAL;
goto err;
}
if (persist.version < DB_LOGOLDVER || persist.version > DB_LOGVERSION) {
__db_err(dblp->dbenv,
"Ignoring log file: %s: unsupported log version %lu",
- p, (u_long)persist.version);
+ fname, (u_long)persist.version);
ret = EINVAL;
goto err;
}
- if (lp != NULL) {
- lp->persist.lg_max = persist.lg_max;
- lp->persist.mode = persist.mode;
+ /*
+ * If we're going to use this log file, set the region's persistent
+ * information based on the headers.
+ */
+ if (set_persist) {
+ dblp->lp->persist.lg_max = persist.lg_max;
+ dblp->lp->persist.mode = persist.mode;
}
ret = 0;
-err: FREES(p);
+err: __os_freestr(fname);
return (ret);
}
@@ -401,6 +434,11 @@ log_close(dblp)
{
int ret, t_ret;
+ LOG_PANIC_CHECK(dblp);
+
+ /* We may have opened files as part of XA; if so, close them. */
+ __log_close_files(dblp);
+
/* Discard the per-thread pointer. */
if (dblp->mutexp != NULL) {
LOCK_LOGREGION(dblp);
@@ -412,21 +450,22 @@ log_close(dblp)
ret = __db_rdetach(&dblp->reginfo);
/* Close open files, release allocated memory. */
- if (dblp->lfd != -1 && (t_ret = __db_close(dblp->lfd)) != 0 && ret == 0)
+ if (dblp->lfd != -1 && (t_ret = __os_close(dblp->lfd)) != 0 && ret == 0)
ret = t_ret;
if (dblp->c_dbt.data != NULL)
- FREE(dblp->c_dbt.data, dblp->c_dbt.ulen);
+ __os_free(dblp->c_dbt.data, dblp->c_dbt.ulen);
if (dblp->c_fd != -1 &&
- (t_ret = __db_close(dblp->c_fd)) != 0 && ret == 0)
+ (t_ret = __os_close(dblp->c_fd)) != 0 && ret == 0)
ret = t_ret;
if (dblp->dbentry != NULL)
- FREE(dblp->dbentry, (dblp->dbentry_cnt * sizeof(DB_ENTRY)));
+ __os_free(dblp->dbentry,
+ (dblp->dbentry_cnt * sizeof(DB_ENTRY)));
if (dblp->dir != NULL)
- FREES(dblp->dir);
+ __os_freestr(dblp->dir);
if (dblp->reginfo.path != NULL)
- FREES(dblp->reginfo.path);
- FREE(dblp, sizeof(*dblp));
+ __os_freestr(dblp->reginfo.path);
+ __os_free(dblp, sizeof(*dblp));
return (ret);
}
@@ -447,12 +486,12 @@ log_unlink(path, force, dbenv)
memset(&reginfo, 0, sizeof(reginfo));
reginfo.dbenv = dbenv;
reginfo.appname = DB_APP_LOG;
- if (path != NULL && (reginfo.path = __db_strdup(path)) == NULL)
- return (ENOMEM);
+ if (path != NULL && (ret = __os_strdup(path, &reginfo.path)) != 0)
+ return (ret);
reginfo.file = DB_DEFAULT_LOG_FILE;
ret = __db_runlink(&reginfo, force);
if (reginfo.path != NULL)
- FREES(reginfo.path);
+ __os_freestr(reginfo.path);
return (ret);
}
@@ -467,14 +506,15 @@ log_stat(dblp, gspp, db_malloc)
void *(*db_malloc) __P((size_t));
{
LOG *lp;
+ int ret;
*gspp = NULL;
lp = dblp->lp;
- if ((*gspp = db_malloc == NULL ?
- (DB_LOG_STAT *)__db_malloc(sizeof(**gspp)) :
- (DB_LOG_STAT *)db_malloc(sizeof(**gspp))) == NULL)
- return (ENOMEM);
+ LOG_PANIC_CHECK(dblp);
+
+ if ((ret = __os_malloc(sizeof(**gspp), db_malloc, gspp)) != 0)
+ return (ret);
/* Copy out the global statistics. */
LOCK_LOGREGION(dblp);
diff --git a/db2/log/log_archive.c b/db2/log/log_archive.c
index 7db0cc3e36..9f3b24d8e3 100644
--- a/db2/log/log_archive.c
+++ b/db2/log/log_archive.c
@@ -8,7 +8,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)log_archive.c 10.37 (Sleepycat) 5/3/98";
+static const char sccsid[] = "@(#)log_archive.c 10.44 (Sleepycat) 10/9/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -49,8 +49,11 @@ log_archive(dblp, listp, flags, db_malloc)
int array_size, n, ret;
char **array, **arrayp, *name, *p, *pref, buf[MAXPATHLEN];
+ name = NULL;
COMPQUIET(fnum, 0);
+ LOG_PANIC_CHECK(dblp);
+
#define OKFLAGS (DB_ARCH_ABS | DB_ARCH_DATA | DB_ARCH_LOG)
if (flags != 0) {
if ((ret =
@@ -84,7 +87,7 @@ log_archive(dblp, listp, flags, db_malloc)
if ((ret = log_get(dblp, &stable_lsn, &rec, DB_LAST)) != 0)
return (ret);
if (F_ISSET(dblp, DB_AM_THREAD))
- __db_free(rec.data);
+ __os_free(rec.data, rec.size);
fnum = stable_lsn.file;
break;
case 0:
@@ -106,40 +109,40 @@ log_archive(dblp, listp, flags, db_malloc)
#define LIST_INCREMENT 64
/* Get some initial space. */
- if ((array =
- (char **)__db_malloc(sizeof(char *) * (array_size = 10))) == NULL)
- return (ENOMEM);
+ array_size = 10;
+ if ((ret = __os_malloc(sizeof(char *) * array_size, NULL, &array)) != 0)
+ return (ret);
array[0] = NULL;
/* Build an array of the file names. */
for (n = 0; fnum > 0; --fnum) {
- if ((ret = __log_name(dblp, fnum, &name)) != 0)
+ if ((ret = __log_name(dblp, fnum, &name, NULL, 0)) != 0)
goto err;
- if (__db_exists(name, NULL) != 0)
+ if (__os_exists(name, NULL) != 0) {
+ __os_freestr(name);
+ name = NULL;
break;
+ }
if (n >= array_size - 1) {
array_size += LIST_INCREMENT;
- if ((array = (char **)__db_realloc(array,
- sizeof(char *) * array_size)) == NULL) {
- ret = ENOMEM;
+ if ((ret = __os_realloc(&array,
+ sizeof(char *) * array_size)) != 0)
goto err;
- }
}
if (LF_ISSET(DB_ARCH_ABS)) {
if ((ret = __absname(pref, name, &array[n])) != 0)
goto err;
- FREES(name);
+ __os_freestr(name);
} else if ((p = __db_rpath(name)) != NULL) {
- if ((array[n] = (char *)__db_strdup(p + 1)) == NULL) {
- ret = ENOMEM;
+ if ((ret = __os_strdup(p + 1, &array[n])) != 0)
goto err;
- }
- FREES(name);
+ __os_freestr(name);
} else
array[n] = name;
+ name = NULL;
array[++n] = NULL;
}
@@ -162,9 +165,11 @@ log_archive(dblp, listp, flags, db_malloc)
err: if (array != NULL) {
for (arrayp = array; *arrayp != NULL; ++arrayp)
- FREES(*arrayp);
- __db_free(array);
+ __os_freestr(*arrayp);
+ __os_free(array, sizeof(char *) * array_size);
}
+ if (name != NULL)
+ __os_freestr(name);
return (ret);
}
@@ -186,9 +191,9 @@ __build_data(dblp, pref, listp, db_malloc)
char **array, **arrayp, *p, *real_name;
/* Get some initial space. */
- if ((array =
- (char **)__db_malloc(sizeof(char *) * (array_size = 10))) == NULL)
- return (ENOMEM);
+ array_size = 10;
+ if ((ret = __os_malloc(sizeof(char *) * array_size, NULL, &array)) != 0)
+ return (ret);
array[0] = NULL;
memset(&rec, 0, sizeof(rec));
@@ -205,7 +210,7 @@ __build_data(dblp, pref, listp, db_malloc)
memcpy(&rectype, rec.data, sizeof(rectype));
if (rectype != DB_log_register) {
if (F_ISSET(dblp, DB_AM_THREAD)) {
- __db_free(rec.data);
+ __os_free(rec.data, rec.size);
rec.data = NULL;
}
continue;
@@ -219,25 +224,22 @@ __build_data(dblp, pref, listp, db_malloc)
if (n >= array_size - 1) {
array_size += LIST_INCREMENT;
- if ((array = (char **)__db_realloc(array,
- sizeof(char *) * array_size)) == NULL) {
- ret = ENOMEM;
+ if ((ret = __os_realloc(&array,
+ sizeof(char *) * array_size)) != 0)
goto lg_free;
- }
}
- if ((array[n] = (char *)__db_strdup(argp->name.data)) == NULL) {
- ret = ENOMEM;
+ if ((ret = __os_strdup(argp->name.data, &array[n])) != 0) {
lg_free: if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL)
- __db_free(rec.data);
+ __os_free(rec.data, rec.size);
goto err1;
}
array[++n] = NULL;
- __db_free(argp);
+ __os_free(argp, 0);
if (F_ISSET(dblp, DB_AM_THREAD)) {
- __db_free(rec.data);
+ __os_free(rec.data, rec.size);
rec.data = NULL;
}
}
@@ -268,7 +270,7 @@ lg_free: if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL)
}
for (++nxt; nxt < n &&
strcmp(array[last], array[nxt]) == 0; ++nxt) {
- FREES(array[nxt]);
+ __os_freestr(array[nxt]);
array[nxt] = NULL;
}
@@ -278,25 +280,25 @@ lg_free: if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL)
goto err2;
/* If the file doesn't exist, ignore it. */
- if (__db_exists(real_name, NULL) != 0) {
- FREES(real_name);
- FREES(array[last]);
+ if (__os_exists(real_name, NULL) != 0) {
+ __os_freestr(real_name);
+ __os_freestr(array[last]);
array[last] = NULL;
continue;
}
/* Rework the name as requested by the user. */
- FREES(array[last]);
+ __os_freestr(array[last]);
array[last] = NULL;
if (pref != NULL) {
ret = __absname(pref, real_name, &array[last]);
- FREES(real_name);
+ __os_freestr(real_name);
if (ret != 0)
goto err2;
} else if ((p = __db_rpath(real_name)) != NULL) {
- array[last] = (char *)__db_strdup(p + 1);
- FREES(real_name);
- if (array[last] == NULL)
+ ret = __os_strdup(p + 1, &array[last]);
+ __os_freestr(real_name);
+ if (ret != 0)
goto err2;
} else
array[last] = real_name;
@@ -320,13 +322,13 @@ err2: /*
*/
if (array != NULL)
for (; nxt < n; ++nxt)
- FREES(array[nxt]);
+ __os_freestr(array[nxt]);
/* FALLTHROUGH */
err1: if (array != NULL) {
for (arrayp = array; *arrayp != NULL; ++arrayp)
- FREES(*arrayp);
- __db_free(array);
+ __os_freestr(*arrayp);
+ __os_free(array, array_size * sizeof(char *));
}
return (ret);
}
@@ -340,17 +342,17 @@ __absname(pref, name, newnamep)
char *pref, *name, **newnamep;
{
size_t l_pref, l_name;
- int isabspath;
+ int isabspath, ret;
char *newname;
l_name = strlen(name);
- isabspath = __db_abspath(name);
+ isabspath = __os_abspath(name);
l_pref = isabspath ? 0 : strlen(pref);
/* Malloc space for concatenating the two. */
- if ((*newnamep =
- newname = (char *)__db_malloc(l_pref + l_name + 2)) == NULL)
- return (ENOMEM);
+ if ((ret = __os_malloc(l_pref + l_name + 2, NULL, &newname)) != 0)
+ return (ret);
+ *newnamep = newname;
/* Build the name. If `name' is an absolute path, ignore any prefix. */
if (!isabspath) {
@@ -369,11 +371,12 @@ __absname(pref, name, newnamep)
* If the user has their own malloc routine, use it.
*/
static int
-__usermem(listp, cmpfunc)
+__usermem(listp, db_malloc)
char ***listp;
- void *(*cmpfunc) __P((size_t));
+ void *(*db_malloc) __P((size_t));
{
size_t len;
+ int ret;
char **array, **arrayp, **orig, *strp;
/* Find out how much space we need. */
@@ -381,18 +384,10 @@ __usermem(listp, cmpfunc)
len += sizeof(char *) + strlen(*orig) + 1;
len += sizeof(char *);
- /*
- * Allocate it and set up the pointers.
- *
- * XXX
- * Don't simplify this expression, SunOS compilers don't like it.
- */
- if (cmpfunc == NULL)
- array = (char **)__db_malloc(len);
- else
- array = (char **)cmpfunc(len);
- if (array == NULL)
- return (ENOMEM);
+ /* Allocate it and set up the pointers. */
+ if ((ret = __os_malloc(len, db_malloc, &array)) != 0)
+ return (ret);
+
strp = (char *)(array + (orig - *listp) + 1);
/* Copy the original information into the new memory. */
@@ -402,13 +397,13 @@ __usermem(listp, cmpfunc)
*arrayp = strp;
strp += len + 1;
- FREES(*orig);
+ __os_freestr(*orig);
}
/* NULL-terminate the list. */
*arrayp = NULL;
- __db_free(*listp);
+ __os_free(*listp, 0);
*listp = array;
return (0);
diff --git a/db2/log/log_auto.c b/db2/log/log_auto.c
index b17b1ffb2f..92e682661c 100644
--- a/db2/log/log_auto.c
+++ b/db2/log/log_auto.c
@@ -10,7 +10,6 @@
#endif
#include "db_int.h"
-#include "shqueue.h"
#include "db_page.h"
#include "db_dispatch.h"
#include "log.h"
@@ -43,8 +42,7 @@ int __log_register_log(logp, txnid, ret_lsnp, flags,
rectype = DB_log_register;
txn_num = txnid == NULL ? 0 : txnid->txnid;
if (txnid == NULL) {
- null_lsn.file = 0;
- null_lsn.offset = 0;
+ ZERO_LSN(null_lsn);
lsnp = &null_lsn;
} else
lsnp = &txnid->last_lsn;
@@ -54,8 +52,8 @@ int __log_register_log(logp, txnid, ret_lsnp, flags,
+ sizeof(u_int32_t) + (uid == NULL ? 0 : uid->size)
+ sizeof(id)
+ sizeof(ftype);
- if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
- return (ENOMEM);
+ if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
bp = logrec.data;
memcpy(bp, &rectype, sizeof(rectype));
@@ -97,7 +95,7 @@ int __log_register_log(logp, txnid, ret_lsnp, flags,
ret = __log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
if (txnid != NULL)
txnid->last_lsn = *ret_lsnp;
- __db_free(logrec.data);
+ __os_free(logrec.data, 0);
return (ret);
}
@@ -155,7 +153,7 @@ __log_register_print(notused1, dbtp, lsnp, notused2, notused3)
printf("\tid: %lu\n", (u_long)argp->id);
printf("\tftype: 0x%lx\n", (u_long)argp->ftype);
printf("\n");
- __db_free(argp);
+ __os_free(argp, 0);
return (0);
}
@@ -169,11 +167,12 @@ __log_register_read(recbuf, argpp)
{
__log_register_args *argp;
u_int8_t *bp;
+ int ret;
- argp = (__log_register_args *)__db_malloc(sizeof(__log_register_args) +
- sizeof(DB_TXN));
- if (argp == NULL)
- return (ENOMEM);
+ ret = __os_malloc(sizeof(__log_register_args) +
+ sizeof(DB_TXN), NULL, &argp);
+ if (ret != 0)
+ return (ret);
argp->txnid = (DB_TXN *)&argp[1];
bp = recbuf;
memcpy(&argp->type, bp, sizeof(argp->type));
diff --git a/db2/log/log_findckp.c b/db2/log/log_findckp.c
index 1f717b49e7..ab13c8380e 100644
--- a/db2/log/log_findckp.c
+++ b/db2/log/log_findckp.c
@@ -8,7 +8,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)log_findckp.c 10.15 (Sleepycat) 4/26/98";
+static const char sccsid[] = "@(#)log_findckp.c 10.17 (Sleepycat) 9/17/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -28,7 +28,10 @@ static const char sccsid[] = "@(#)log_findckp.c 10.15 (Sleepycat) 4/26/98";
* __log_findckp --
*
* Looks for the most recent checkpoint that occurs before the most recent
- * checkpoint LSN. This is the point from which recovery can start and the
+ * checkpoint LSN, subject to the constraint that there must be at least two
+ * checkpoints. The reason you need two checkpoints is that you might have
+ * crashed during the most recent one and may not have a copy of all the
+ * open files. This is the point from which recovery can start and the
* point up to which archival/truncation can take place. Checkpoints in
* the log look like:
*
@@ -56,7 +59,7 @@ __log_findckp(lp, lsnp)
DB_LSN *lsnp;
{
DBT data;
- DB_LSN ckp_lsn, last_ckp, next_lsn;
+ DB_LSN ckp_lsn, final_ckp, last_ckp, next_lsn;
__txn_ckp_args *ckp_args;
int ret, verbose;
@@ -77,16 +80,17 @@ __log_findckp(lp, lsnp)
return (ret);
}
+ final_ckp = last_ckp;
next_lsn = last_ckp;
do {
if (F_ISSET(lp, DB_AM_THREAD))
- __db_free(data.data);
+ __os_free(data.data, data.size);
if ((ret = log_get(lp, &next_lsn, &data, DB_SET)) != 0)
return (ret);
if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
if (F_ISSET(lp, DB_AM_THREAD))
- __db_free(data.data);
+ __os_free(data.data, data.size);
return (ret);
}
if (IS_ZERO_LSN(ckp_lsn))
@@ -103,12 +107,19 @@ __log_findckp(lp, lsnp)
}
last_ckp = next_lsn;
next_lsn = ckp_args->last_ckp;
- __db_free(ckp_args);
+ __os_free(ckp_args, sizeof(*ckp_args));
+
+ /*
+ * Keep looping until either you 1) run out of checkpoints,
+ * 2) you've found a checkpoint before the most recent
+ * checkpoint's LSN and you have at least 2 checkpoints.
+ */
} while (!IS_ZERO_LSN(next_lsn) &&
- log_compare(&last_ckp, &ckp_lsn) > 0);
+ (log_compare(&last_ckp, &ckp_lsn) > 0 ||
+ log_compare(&final_ckp, &last_ckp) == 0));
if (F_ISSET(lp, DB_AM_THREAD))
- __db_free(data.data);
+ __os_free(data.data, data.size);
/*
* At this point, either, next_lsn is ZERO or ckp_lsn is the
@@ -117,11 +128,12 @@ __log_findckp(lp, lsnp)
* next_lsn must be 0 and we need to roll forward from the
* beginning of the log.
*/
- if (log_compare(&last_ckp, &ckp_lsn) > 0) {
+ if (log_compare(&last_ckp, &ckp_lsn) > 0 ||
+ log_compare(&final_ckp, &last_ckp) == 0) {
get_first: if ((ret = log_get(lp, &last_ckp, &data, DB_FIRST)) != 0)
return (ret);
if (F_ISSET(lp, DB_AM_THREAD))
- __db_free(data.data);
+ __os_free(data.data, data.size);
}
*lsnp = last_ckp;
diff --git a/db2/log/log_get.c b/db2/log/log_get.c
index 84ddca1c73..de81519a7c 100644
--- a/db2/log/log_get.c
+++ b/db2/log/log_get.c
@@ -7,7 +7,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)log_get.c 10.32 (Sleepycat) 5/6/98";
+static const char sccsid[] = "@(#)log_get.c 10.38 (Sleepycat) 10/3/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -38,26 +38,16 @@ log_get(dblp, alsn, dbt, flags)
{
int ret;
+ LOG_PANIC_CHECK(dblp);
+
/* Validate arguments. */
-#define OKFLAGS (DB_CHECKPOINT | \
- DB_CURRENT | DB_FIRST | DB_LAST | DB_NEXT | DB_PREV | DB_SET)
- if ((ret = __db_fchk(dblp->dbenv, "log_get", flags, OKFLAGS)) != 0)
- return (ret);
- switch (flags) {
- case DB_CHECKPOINT:
- case DB_CURRENT:
- case DB_FIRST:
- case DB_LAST:
- case DB_NEXT:
- case DB_PREV:
- case DB_SET:
- break;
- default:
+ if (flags != DB_CHECKPOINT && flags != DB_CURRENT &&
+ flags != DB_FIRST && flags != DB_LAST &&
+ flags != DB_NEXT && flags != DB_PREV && flags != DB_SET)
return (__db_ferr(dblp->dbenv, "log_get", 1));
- }
if (F_ISSET(dblp, DB_AM_THREAD)) {
- if (LF_ISSET(DB_NEXT | DB_PREV | DB_CURRENT))
+ if (flags == DB_NEXT || flags == DB_PREV || flags == DB_CURRENT)
return (__db_ferr(dblp->dbenv, "log_get", 1));
if (!F_ISSET(dbt, DB_DBT_USERMEM | DB_DBT_MALLOC))
return (__db_ferr(dblp->dbenv, "threaded data", 1));
@@ -156,7 +146,7 @@ __log_get(dblp, alsn, dbt, flags, silent)
/* If at start-of-file, move to the previous file. */
if (nlsn.offset == 0) {
if (nlsn.file == 1 ||
- __log_valid(dblp, NULL, nlsn.file - 1) != 0)
+ __log_valid(dblp, nlsn.file - 1, 0) != 0)
return (DB_NOTFOUND);
--nlsn.file;
@@ -183,7 +173,7 @@ retry:
/* If we've switched files, discard the current fd. */
if (dblp->c_lsn.file != nlsn.file && dblp->c_fd != -1) {
- (void)__db_close(dblp->c_fd);
+ (void)__os_close(dblp->c_fd);
dblp->c_fd = -1;
}
@@ -203,24 +193,22 @@ retry:
/* Acquire a file descriptor. */
if (dblp->c_fd == -1) {
- if ((ret = __log_name(dblp, nlsn.file, &np)) != 0)
- goto err1;
- if ((ret = __db_open(np, DB_RDONLY | DB_SEQUENTIAL,
- DB_RDONLY | DB_SEQUENTIAL, 0, &dblp->c_fd)) != 0) {
+ if ((ret = __log_name(dblp, nlsn.file,
+ &np, &dblp->c_fd, DB_RDONLY | DB_SEQUENTIAL)) != 0) {
fail = np;
goto err1;
}
- __db_free(np);
+ __os_freestr(np);
np = NULL;
}
/* Seek to the header offset and read the header. */
if ((ret =
- __db_seek(dblp->c_fd, 0, 0, nlsn.offset, 0, SEEK_SET)) != 0) {
+ __os_seek(dblp->c_fd, 0, 0, nlsn.offset, 0, SEEK_SET)) != 0) {
fail = "seek";
goto err1;
}
- if ((ret = __db_read(dblp->c_fd, &hdr, sizeof(HDR), &nr)) != 0) {
+ if ((ret = __os_read(dblp->c_fd, &hdr, sizeof(HDR), &nr)) != 0) {
fail = "read";
goto err1;
}
@@ -276,10 +264,8 @@ retry:
* We're calling malloc(3) with a region locked. This isn't
* a good idea.
*/
- if ((tbuf = (char *)__db_malloc(len)) == NULL) {
- ret = ENOMEM;
+ if ((ret = __os_malloc(len, NULL, &tbuf)) != 0)
goto err1;
- }
/*
* Read the record into the buffer. If read returns a short count,
@@ -287,7 +273,7 @@ retry:
* buffer. Note, the information may be garbage if we're in recovery,
* so don't read past the end of the buffer's memory.
*/
- if ((ret = __db_read(dblp->c_fd, tbuf, len, &nr)) != 0) {
+ if ((ret = __os_read(dblp->c_fd, tbuf, len, &nr)) != 0) {
fail = "read";
goto err1;
}
@@ -305,7 +291,7 @@ retry:
if ((ret = __db_retcopy(dbt, tbuf, len,
&dblp->c_dbt.data, &dblp->c_dbt.ulen, NULL)) != 0)
goto err1;
- __db_free(tbuf);
+ __os_free(tbuf, 0);
tbuf = NULL;
cksum: if (hdr.cksum != __ham_func4(dbt->data, dbt->size)) {
@@ -329,7 +315,7 @@ corrupt:/*
ret = EIO;
fail = "read";
- err1: if (!silent) {
+err1: if (!silent) {
if (fail == NULL)
__db_err(dblp->dbenv, "log_get: %s", strerror(ret));
else
@@ -337,8 +323,8 @@ corrupt:/*
"log_get: %s: %s", fail, strerror(ret));
}
err2: if (np != NULL)
- __db_free(np);
+ __os_freestr(np);
if (tbuf != NULL)
- __db_free(tbuf);
+ __os_free(tbuf, 0);
return (ret);
}
diff --git a/db2/log/log_put.c b/db2/log/log_put.c
index 5ef2294af5..86de6b0d1d 100644
--- a/db2/log/log_put.c
+++ b/db2/log/log_put.c
@@ -7,13 +7,14 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)log_put.c 10.35 (Sleepycat) 5/6/98";
+static const char sccsid[] = "@(#)log_put.c 10.44 (Sleepycat) 11/3/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <errno.h>
+#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
@@ -24,6 +25,7 @@ static const char sccsid[] = "@(#)log_put.c 10.35 (Sleepycat) 5/6/98";
#include "db_page.h"
#include "log.h"
#include "hash.h"
+#include "clib_ext.h"
#include "common_ext.h"
static int __log_fill __P((DB_LOG *, DB_LSN *, void *, u_int32_t));
@@ -45,22 +47,12 @@ log_put(dblp, lsn, dbt, flags)
{
int ret;
+ LOG_PANIC_CHECK(dblp);
+
/* Validate arguments. */
-#define OKFLAGS (DB_CHECKPOINT | DB_FLUSH | DB_CURLSN)
- if (flags != 0) {
- if ((ret =
- __db_fchk(dblp->dbenv, "log_put", flags, OKFLAGS)) != 0)
- return (ret);
- switch (flags) {
- case DB_CHECKPOINT:
- case DB_CURLSN:
- case DB_FLUSH:
- case 0:
- break;
- default:
- return (__db_ferr(dblp->dbenv, "log_put", 1));
- }
- }
+ if (flags != 0 && flags != DB_CHECKPOINT &&
+ flags != DB_CURLSN && flags != DB_FLUSH)
+ return (__db_ferr(dblp->dbenv, "log_put", 0));
LOCK_LOGREGION(dblp);
ret = __log_put(dblp, lsn, dbt, flags);
@@ -95,7 +87,7 @@ __log_put(dblp, lsn, dbt, flags)
* the information. Currently used by the transaction manager
* to avoid writing TXN_begin records.
*/
- if (LF_ISSET(DB_CURLSN)) {
+ if (flags == DB_CURLSN) {
lsn->file = lp->lsn.file;
lsn->offset = lp->lsn.offset;
return (0);
@@ -165,6 +157,8 @@ __log_put(dblp, lsn, dbt, flags)
for (fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
+ if (fnp->ref == 0) /* Entry not in use. */
+ continue;
memset(&t, 0, sizeof(t));
t.data = R_ADDR(dblp, fnp->name_off);
t.size = strlen(t.data) + 1;
@@ -248,6 +242,8 @@ log_flush(dblp, lsn)
{
int ret;
+ LOG_PANIC_CHECK(dblp);
+
LOCK_LOGREGION(dblp);
ret = __log_flush(dblp, lsn);
UNLOCK_LOGREGION(dblp);
@@ -304,8 +300,7 @@ __log_flush(dblp, lsn)
* buffer's starting LSN.
*/
current = 0;
- if (lp->b_off != 0 &&
- lsn->file >= lp->f_lsn.file && lsn->offset >= lp->f_lsn.offset) {
+ if (lp->b_off != 0 && log_compare(lsn, &lp->f_lsn) >= 0) {
if ((ret = __log_write(dblp, lp->buf, lp->b_off)) != 0)
return (ret);
@@ -322,8 +317,10 @@ __log_flush(dblp, lsn)
return (ret);
/* Sync all writes to disk. */
- if ((ret = __db_fsync(dblp->lfd)) != 0)
+ if ((ret = __os_fsync(dblp->lfd)) != 0) {
+ __db_panic(dblp->dbenv, ret);
return (ret);
+ }
++lp->stat.st_scount;
/*
@@ -331,9 +328,16 @@ __log_flush(dblp, lsn)
* the current buffer was flushed, we know the LSN of the first byte
* of the buffer is on disk, otherwise, we only know that the LSN of
* the record before the one beginning the current buffer is on disk.
+ *
+ * XXX
+ * Check to make sure that the saved lsn isn't 0 before we go making
+ * this change. If DB_CHECKPOINT was called before we actually wrote
+ * something, you can end up here without ever having written anything
+ * to a log file, and decrementing either s_lsn.file or s_lsn.offset
+ * will cause much sadness later on.
*/
lp->s_lsn = lp->f_lsn;
- if (!current) {
+ if (!current && lp->s_lsn.file != 0) {
if (lp->s_lsn.offset == 0) {
--lp->s_lsn.file;
lp->s_lsn.offset = lp->persist.lg_max;
@@ -431,10 +435,11 @@ __log_write(dblp, addr, len)
* Seek to the offset in the file (someone may have written it
* since we last did).
*/
- if ((ret = __db_seek(dblp->lfd, 0, 0, lp->w_off, 0, SEEK_SET)) != 0)
- return (ret);
- if ((ret = __db_write(dblp->lfd, addr, len, &nw)) != 0)
+ if ((ret = __os_seek(dblp->lfd, 0, 0, lp->w_off, 0, SEEK_SET)) != 0 ||
+ (ret = __os_write(dblp->lfd, addr, len, &nw)) != 0) {
+ __db_panic(dblp->dbenv, ret);
return (ret);
+ }
if (nw != (int32_t)len)
return (EIO);
@@ -467,21 +472,23 @@ log_file(dblp, lsn, namep, len)
size_t len;
{
int ret;
- char *p;
+ char *name;
+
+ LOG_PANIC_CHECK(dblp);
LOCK_LOGREGION(dblp);
- ret = __log_name(dblp, lsn->file, &p);
+ ret = __log_name(dblp, lsn->file, &name, NULL, 0);
UNLOCK_LOGREGION(dblp);
if (ret != 0)
return (ret);
/* Check to make sure there's enough room and copy the name. */
- if (len < strlen(p) + 1) {
+ if (len < strlen(name) + 1) {
*namep = '\0';
return (ENOMEM);
}
- (void)strcpy(namep, p);
- __db_free(p);
+ (void)strcpy(namep, name);
+ __os_freestr(name);
return (0);
}
@@ -495,43 +502,102 @@ __log_newfd(dblp)
DB_LOG *dblp;
{
int ret;
- char *p;
+ char *name;
/* Close any previous file descriptor. */
if (dblp->lfd != -1) {
- (void)__db_close(dblp->lfd);
+ (void)__os_close(dblp->lfd);
dblp->lfd = -1;
}
/* Get the path of the new file and open it. */
dblp->lfname = dblp->lp->lsn.file;
- if ((ret = __log_name(dblp, dblp->lfname, &p)) != 0)
- return (ret);
- if ((ret = __db_open(p,
- DB_CREATE | DB_SEQUENTIAL,
- DB_CREATE | DB_SEQUENTIAL,
- dblp->lp->persist.mode, &dblp->lfd)) != 0)
- __db_err(dblp->dbenv,
- "log_put: %s: %s", p, strerror(ret));
- FREES(p);
+ if ((ret = __log_name(dblp,
+ dblp->lfname, &name, &dblp->lfd, DB_CREATE | DB_SEQUENTIAL)) != 0)
+ __db_err(dblp->dbenv, "log_put: %s: %s", name, strerror(ret));
+
+ __os_freestr(name);
return (ret);
}
/*
* __log_name --
- * Return the log name for a particular file.
+ * Return the log name for a particular file, and optionally open it.
*
- * PUBLIC: int __log_name __P((DB_LOG *, int, char **));
+ * PUBLIC: int __log_name __P((DB_LOG *, u_int32_t, char **, int *, u_int32_t));
*/
int
-__log_name(dblp, filenumber, namep)
+__log_name(dblp, filenumber, namep, fdp, flags)
DB_LOG *dblp;
+ u_int32_t filenumber, flags;
char **namep;
- int filenumber;
+ int *fdp;
{
- char name[sizeof(LFNAME) + 10];
+ int ret;
+ char *oname;
+ char old[sizeof(LFPREFIX) + 5 + 20], new[sizeof(LFPREFIX) + 10 + 20];
+
+ /*
+ * !!!
+ * The semantics of this routine are bizarre.
+ *
+ * The reason for all of this is that we need a place where we can
+ * intercept requests for log files, and, if appropriate, check for
+ * both the old-style and new-style log file names. The trick is
+ * that all callers of this routine that are opening the log file
+ * read-only want to use an old-style file name if they can't find
+ * a match using a new-style name. The only down-side is that some
+ * callers may check for the old-style when they really don't need
+ * to, but that shouldn't mess up anything, and we only check for
+ * the old-style name when we've already failed to find a new-style
+ * one.
+ *
+ * Create a new-style file name, and if we're not going to open the
+ * file, return regardless.
+ */
+ (void)snprintf(new, sizeof(new), LFNAME, filenumber);
+ if ((ret = __db_appname(dblp->dbenv,
+ DB_APP_LOG, dblp->dir, new, 0, NULL, namep)) != 0 || fdp == NULL)
+ return (ret);
- (void)snprintf(name, sizeof(name), LFNAME, filenumber);
- return (__db_appname(dblp->dbenv,
- DB_APP_LOG, dblp->dir, name, 0, NULL, namep));
+ /* Open the new-style file -- if we succeed, we're done. */
+ if ((ret = __db_open(*namep,
+ flags, flags, dblp->lp->persist.mode, fdp)) == 0)
+ return (0);
+
+ /*
+ * The open failed... if the DB_RDONLY flag isn't set, we're done,
+ * the caller isn't interested in old-style files.
+ */
+ if (!LF_ISSET(DB_RDONLY))
+ return (ret);
+
+ /* Create an old-style file name. */
+ (void)snprintf(old, sizeof(old), LFNAME_V1, filenumber);
+ if ((ret = __db_appname(dblp->dbenv,
+ DB_APP_LOG, dblp->dir, old, 0, NULL, &oname)) != 0)
+ goto err;
+
+ /*
+ * Open the old-style file -- if we succeed, we're done. Free the
+ * space allocated for the new-style name and return the old-style
+ * name to the caller.
+ */
+ if ((ret = __db_open(oname,
+ flags, flags, dblp->lp->persist.mode, fdp)) == 0) {
+ __os_freestr(*namep);
+ *namep = oname;
+ return (0);
+ }
+
+ /*
+ * Couldn't find either style of name -- return the new-style name
+ * for the caller's error message. If it's an old-style name that's
+ * actually missing we're going to confuse the user with the error
+ * message, but that implies that not only were we looking for an
+ * old-style name, but we expected it to exist and we weren't just
+ * looking for any log file. That's not a likely error.
+ */
+err: __os_freestr(oname);
+ return (ret);
}
diff --git a/db2/log/log_rec.c b/db2/log/log_rec.c
index 5deac46298..8895150be1 100644
--- a/db2/log/log_rec.c
+++ b/db2/log/log_rec.c
@@ -40,7 +40,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)log_rec.c 10.20 (Sleepycat) 4/28/98";
+static const char sccsid[] = "@(#)log_rec.c 10.26 (Sleepycat) 10/21/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -56,8 +56,10 @@ static const char sccsid[] = "@(#)log_rec.c 10.20 (Sleepycat) 4/28/98";
#include "db_dispatch.h"
#include "common_ext.h"
-static int __log_open_file __P((DB_LOG *,
+static int __log_do_open __P((DB_LOG *,
u_int8_t *, char *, DBTYPE, u_int32_t));
+static int __log_lid_to_fname __P((DB_LOG *, u_int32_t, FNAME **));
+static int __log_open_file __P((DB_LOG *, __log_register_args *));
/*
* PUBLIC: int __log_register_recover
@@ -80,7 +82,7 @@ __log_register_recover(logp, dbtp, lsnp, redo, info)
COMPQUIET(info, NULL);
COMPQUIET(lsnp, NULL);
- F_SET(logp, DB_AM_RECOVER);
+ F_SET(logp, DBC_RECOVER);
if ((ret = __log_register_read(dbtp->data, &argp)) != 0)
goto out;
@@ -95,13 +97,11 @@ __log_register_recover(logp, dbtp, lsnp, redo, info)
* If we are redoing an open or undoing a close, then we need
* to open a file.
*/
- ret = __log_open_file(logp,
- argp->uid.data, argp->name.data, argp->ftype, argp->id);
+ ret = __log_open_file(logp, argp);
if (ret == ENOENT) {
if (redo == TXN_OPENFILES)
- __db_err(logp->dbenv,
- "warning: file %s not found",
- argp->name.data);
+ __db_err(logp->dbenv, "warning: %s: %s",
+ argp->name.data, strerror(ENOENT));
ret = 0;
}
} else if (argp->opcode != LOG_CHECKPOINT) {
@@ -109,26 +109,42 @@ __log_register_recover(logp, dbtp, lsnp, redo, info)
* If we are redoing a close or undoing an open, then we need
* to close the file.
*
- * If the file is deleted, then we can just ignore this close.
- * Otherwise, we'd better have a valid dbp that we should either
- * close or whose reference count should be decremented.
+ * If the file is deleted, then we can just ignore this close.
+ * Otherwise, we should usually have a valid dbp we should
+ * close or whose reference count should be decremented.
+ * However, if we shut down without closing a file, we
+ * may, in fact, not have the file open, and that's OK.
*/
LOCK_LOGTHREAD(logp);
- if (logp->dbentry[argp->id].dbp == NULL) {
- if (!logp->dbentry[argp->id].deleted)
- ret = EINVAL;
- } else if (--logp->dbentry[argp->id].refcount == 0) {
- F_SET(logp->dbentry[argp->id].dbp, DB_AM_RECOVER);
+ if (logp->dbentry[argp->id].dbp != NULL &&
+ --logp->dbentry[argp->id].refcount == 0) {
ret = logp->dbentry[argp->id].dbp->close(
logp->dbentry[argp->id].dbp, 0);
logp->dbentry[argp->id].dbp = NULL;
}
UNLOCK_LOGTHREAD(logp);
+ } else if (redo == TXN_UNDO &&
+ (argp->id >= logp->dbentry_cnt ||
+ (!logp->dbentry[argp->id].deleted &&
+ logp->dbentry[argp->id].dbp == NULL))) {
+ /*
+ * It's a checkpoint and we are rolling backward. It
+ * is possible that the system was shut down and thus
+ * ended with a stable checkpoint; this file was never
+ * closed and has therefore not been reopened yet. If
+ * so, we need to try to open it.
+ */
+ ret = __log_open_file(logp, argp);
+ if (ret == ENOENT) {
+ __db_err(logp->dbenv, "warning: %s: %s",
+ argp->name.data, strerror(ENOENT));
+ ret = 0;
+ }
}
-out: F_CLR(logp, DB_AM_RECOVER);
+out: F_CLR(logp, DBC_RECOVER);
if (argp != NULL)
- __db_free(argp);
+ __os_free(argp, 0);
return (ret);
}
@@ -140,34 +156,49 @@ out: F_CLR(logp, DB_AM_RECOVER);
* Returns 0 on success, non-zero on error.
*/
static int
-__log_open_file(lp, uid, name, ftype, ndx)
+__log_open_file(lp, argp)
DB_LOG *lp;
- u_int8_t *uid;
- char *name;
- DBTYPE ftype;
- u_int32_t ndx;
+ __log_register_args *argp;
{
- DB *dbp;
- int ret;
-
LOCK_LOGTHREAD(lp);
- if (ndx < lp->dbentry_cnt &&
- (lp->dbentry[ndx].deleted == 1 || lp->dbentry[ndx].dbp != NULL)) {
- lp->dbentry[ndx].refcount++;
+ if (argp->id < lp->dbentry_cnt &&
+ (lp->dbentry[argp->id].deleted == 1 ||
+ lp->dbentry[argp->id].dbp != NULL)) {
+ if (argp->opcode != LOG_CHECKPOINT)
+ lp->dbentry[argp->id].refcount++;
UNLOCK_LOGTHREAD(lp);
return (0);
}
UNLOCK_LOGTHREAD(lp);
+ return (__log_do_open(lp,
+ argp->uid.data, argp->name.data, argp->ftype, argp->id));
+}
+
+/*
+ * __log_do_open --
+ * Open files referenced in the log. This is the part of the open that
+ * is not protected by the thread mutex.
+ */
+
+static int
+__log_do_open(lp, uid, name, ftype, ndx)
+ DB_LOG *lp;
+ u_int8_t *uid;
+ char *name;
+ DBTYPE ftype;
+ u_int32_t ndx;
+{
+ DB *dbp;
+ int ret;
- /* Need to open file. */
dbp = NULL;
if ((ret = db_open(name, ftype, 0, 0, lp->dbenv, NULL, &dbp)) == 0) {
/*
* Verify that we are opening the same file that we were
* referring to when we wrote this log record.
*/
- if (memcmp(uid, dbp->lock.fileid, DB_FILE_ID_LEN) != 0) {
+ if (memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0) {
(void)dbp->close(dbp, 0);
dbp = NULL;
ret = ENOENT;
@@ -181,10 +212,9 @@ __log_open_file(lp, uid, name, ftype, ndx)
}
/*
- * This function returns:
- * 0 SUCCESS (the entry was not previously set and is now set or the
- * entry was previously set and we just inced the ref count.
- * >0 on system error (returns errno value).
+ * __log_add_logid --
+ * Adds a DB entry to the log's DB entry table.
+ *
* PUBLIC: int __log_add_logid __P((DB_LOG *, DB *, u_int32_t));
*/
int
@@ -193,43 +223,30 @@ __log_add_logid(logp, dbp, ndx)
DB *dbp;
u_int32_t ndx;
{
- DB_ENTRY *temp_entryp;
u_int32_t i;
int ret;
ret = 0;
LOCK_LOGTHREAD(logp);
+
/*
- * Check if we need to grow the table.
+ * 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 (logp->dbentry_cnt <= ndx) {
- if (logp->dbentry_cnt == 0) {
- logp->dbentry = (DB_ENTRY *)
- __db_malloc(DB_GROW_SIZE * sizeof(DB_ENTRY));
- if (logp->dbentry == NULL) {
- ret = ENOMEM;
- goto err;
- }
- } else {
- temp_entryp = (DB_ENTRY *)__db_realloc(logp->dbentry,
- (DB_GROW_SIZE + logp->dbentry_cnt) *
- sizeof(DB_ENTRY));
- if (temp_entryp == NULL) {
- ret = ENOMEM;
- goto err;
- }
- logp->dbentry = temp_entryp;
+ if ((ret = __os_realloc(&logp->dbentry,
+ (ndx + DB_GROW_SIZE) * sizeof(DB_ENTRY))) != 0)
+ goto err;
- }
/* Initialize the new entries. */
- for (i = logp->dbentry_cnt;
- i < logp->dbentry_cnt + DB_GROW_SIZE; i++) {
+ for (i = logp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) {
logp->dbentry[i].dbp = NULL;
logp->dbentry[i].deleted = 0;
}
- logp->dbentry_cnt += DB_GROW_SIZE;
+ logp->dbentry_cnt = i;
}
if (logp->dbentry[ndx].deleted == 0 && logp->dbentry[ndx].dbp == NULL) {
@@ -257,11 +274,47 @@ __db_fileid_to_db(logp, dbpp, ndx)
u_int32_t ndx;
{
int ret;
+ char *name;
+ FNAME *fname;
ret = 0;
LOCK_LOGTHREAD(logp);
/*
+ * Under XA, a process different than the one issuing DB
+ * operations may abort a transaction. In this case,
+ * recovery routines are run by a process that does not
+ * necessarily have the file open. In this case, we must
+ * open the file explicitly.
+ */
+ if (ndx >= logp->dbentry_cnt ||
+ (!logp->dbentry[ndx].deleted && logp->dbentry[ndx].dbp == NULL)) {
+ if (__log_lid_to_fname(logp, ndx, &fname) != 0) {
+ /* Couldn't find entry; this is a fatal error. */
+ ret = EINVAL;
+ goto err;
+ }
+ name = R_ADDR(logp, fname->name_off);
+ /*
+ * __log_do_open is called without protection of the
+ * log thread lock.
+ */
+ UNLOCK_LOGTHREAD(logp);
+ /*
+ * 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 __log_do_open succeeded, then
+ * we don't need to do any of the remaining error checking
+ * at the end of this routine.
+ */
+ if ((ret = __log_do_open(logp,
+ fname->ufid, name, fname->s_type, ndx)) != 0)
+ return (ret);
+ *dbpp = logp->dbentry[ndx].dbp;
+ return (0);
+ }
+
+ /*
* Return DB_DELETED if the file has been deleted
* (it's not an error).
*/
@@ -294,8 +347,12 @@ __log_close_files(logp)
LOCK_LOGTHREAD(logp);
for (i = 0; i < logp->dbentry_cnt; i++)
- if (logp->dbentry[i].dbp)
+ if (logp->dbentry[i].dbp) {
logp->dbentry[i].dbp->close(logp->dbentry[i].dbp, 0);
+ logp->dbentry[i].dbp = NULL;
+ logp->dbentry[i].deleted = 0;
+ }
+ F_CLR(logp, DBC_RECOVER);
UNLOCK_LOGTHREAD(logp);
}
@@ -314,3 +371,28 @@ __log_rem_logid(logp, ndx)
}
UNLOCK_LOGTHREAD(logp);
}
+
+/*
+ * __log_lid_to_fname --
+ * Traverse the shared-memory region looking for the entry that
+ * matches the passed log fileid. Returns 0 on success; -1 on error.
+ */
+static int
+__log_lid_to_fname(dblp, lid, fnamep)
+ DB_LOG *dblp;
+ u_int32_t lid;
+ FNAME **fnamep;
+{
+ FNAME *fnp;
+
+ for (fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
+ fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
+ if (fnp->ref == 0) /* Entry not in use. */
+ continue;
+ if (fnp->id == lid) {
+ *fnamep = fnp;
+ return (0);
+ }
+ }
+ return (-1);
+}
diff --git a/db2/log/log_register.c b/db2/log/log_register.c
index a6fc4c1b3b..22264e3291 100644
--- a/db2/log/log_register.c
+++ b/db2/log/log_register.c
@@ -7,7 +7,7 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)log_register.c 10.18 (Sleepycat) 5/3/98";
+static const char sccsid[] = "@(#)log_register.c 10.22 (Sleepycat) 9/27/98";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -36,17 +36,18 @@ log_register(dblp, dbp, name, type, idp)
{
DBT fid_dbt, r_name;
DB_LSN r_unused;
- FNAME *fnp;
+ FNAME *fnp, *reuse_fnp;
size_t len;
- u_int32_t fid;
+ u_int32_t maxid;
int inserted, ret;
char *fullname;
void *namep;
- fid = 0;
inserted = 0;
fullname = NULL;
- fnp = namep = NULL;
+ fnp = namep = reuse_fnp = NULL;
+
+ LOG_PANIC_CHECK(dblp);
/* Check the arguments. */
if (type != DB_BTREE && type != DB_HASH && type != DB_RECNO) {
@@ -63,26 +64,37 @@ log_register(dblp, dbp, name, type, idp)
/*
* See if we've already got this file in the log, finding the
- * next-to-lowest file id currently in use as we do it.
+ * (maximum+1) in-use file id and some available file id (if we
+ * find an available fid, we'll use it, else we'll have to allocate
+ * one after the maximum that we found).
*/
- for (fid = 1, fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
+ for (maxid = 0, fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
- if (fid <= fnp->id)
- fid = fnp->id + 1;
- if (!memcmp(dbp->lock.fileid, fnp->ufid, DB_FILE_ID_LEN)) {
+ if (fnp->ref == 0) { /* Entry is not in use. */
+ if (reuse_fnp == NULL)
+ reuse_fnp = fnp;
+ continue;
+ }
+ if (!memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN)) {
++fnp->ref;
- fid = fnp->id;
goto found;
}
+ if (maxid <= fnp->id)
+ maxid = fnp->id + 1;
}
- /* Allocate a new file name structure. */
- if ((ret = __db_shalloc(dblp->addr, sizeof(FNAME), 0, &fnp)) != 0)
+ /* Fill in fnp structure. */
+
+ if (reuse_fnp != NULL) /* Reuse existing one. */
+ fnp = reuse_fnp;
+ else if ((ret = __db_shalloc(dblp->addr, sizeof(FNAME), 0, &fnp)) != 0)
goto err;
+ else /* Allocate a new one. */
+ fnp->id = maxid;
+
fnp->ref = 1;
- fnp->id = fid;
fnp->s_type = type;
- memcpy(fnp->ufid, dbp->lock.fileid, DB_FILE_ID_LEN);
+ memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN);
len = strlen(name) + 1;
if ((ret = __db_shalloc(dblp->addr, len, 0, &namep)) != 0)
@@ -90,20 +102,22 @@ log_register(dblp, dbp, name, type, idp)
fnp->name_off = R_OFFSET(dblp, namep);
memcpy(namep, name, len);
- SH_TAILQ_INSERT_HEAD(&dblp->lp->fq, fnp, q, __fname);
+ /* Only do the insert if we allocated a new fnp. */
+ if (reuse_fnp == NULL)
+ SH_TAILQ_INSERT_HEAD(&dblp->lp->fq, fnp, q, __fname);
inserted = 1;
found: /* Log the registry. */
- if (!F_ISSET(dblp, DB_AM_RECOVER)) {
+ if (!F_ISSET(dblp, DBC_RECOVER)) {
r_name.data = (void *)name; /* XXX: Yuck! */
r_name.size = strlen(name) + 1;
memset(&fid_dbt, 0, sizeof(fid_dbt));
- fid_dbt.data = dbp->lock.fileid;
+ fid_dbt.data = dbp->fileid;
fid_dbt.size = DB_FILE_ID_LEN;
if ((ret = __log_register_log(dblp, NULL, &r_unused,
- 0, LOG_OPEN, &r_name, &fid_dbt, fid, type)) != 0)
+ 0, LOG_OPEN, &r_name, &fid_dbt, fnp->id, type)) != 0)
goto err;
- if ((ret = __log_add_logid(dblp, dbp, fid)) != 0)
+ if ((ret = __log_add_logid(dblp, dbp, fnp->id)) != 0)
goto err;
}
@@ -120,13 +134,13 @@ err: /*
__db_shalloc_free(dblp->addr, fnp);
}
+ if (idp != NULL)
+ *idp = fnp->id;
UNLOCK_LOGREGION(dblp);
if (fullname != NULL)
- FREES(fullname);
+ __os_freestr(fullname);
- if (idp != NULL)
- *idp = fid;
return (ret);
}
@@ -144,6 +158,8 @@ log_unregister(dblp, fid)
FNAME *fnp;
int ret;
+ LOG_PANIC_CHECK(dblp);
+
ret = 0;
LOCK_LOGREGION(dblp);
@@ -159,7 +175,7 @@ log_unregister(dblp, fid)
}
/* Unlog the registry. */
- if (!F_ISSET(dblp, DB_AM_RECOVER)) {
+ if (!F_ISSET(dblp, DBC_RECOVER)) {
memset(&r_name, 0, sizeof(r_name));
r_name.data = R_ADDR(dblp, fnp->name_off);
r_name.size = strlen(r_name.data) + 1;
@@ -173,22 +189,18 @@ log_unregister(dblp, fid)
/*
* If more than 1 reference, just decrement the reference and return.
- * Otherwise, free the unique file information, name and structure.
+ * Otherwise, free the name.
*/
- if (fnp->ref > 1)
- --fnp->ref;
- else {
+ --fnp->ref;
+ if (fnp->ref == 0)
__db_shalloc_free(dblp->addr, R_ADDR(dblp, fnp->name_off));
- SH_TAILQ_REMOVE(&dblp->lp->fq, fnp, q, __fname);
- __db_shalloc_free(dblp->addr, fnp);
- }
/*
* Remove from the process local table. If this operation is taking
* place during recovery, then the logid was never added to the table,
* so do not remove it.
*/
- if (!F_ISSET(dblp, DB_AM_RECOVER))
+ if (!F_ISSET(dblp, DBC_RECOVER))
__log_rem_logid(dblp, fid);
ret1: UNLOCK_LOGREGION(dblp);