summary refs log tree commit diff
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);