diff options
Diffstat (limited to 'db2/log')
-rw-r--r-- | db2/log/log.c | 194 | ||||
-rw-r--r-- | db2/log/log_archive.c | 123 | ||||
-rw-r--r-- | db2/log/log_auto.c | 21 | ||||
-rw-r--r-- | db2/log/log_findckp.c | 32 | ||||
-rw-r--r-- | db2/log/log_get.c | 54 | ||||
-rw-r--r-- | db2/log/log_put.c | 162 | ||||
-rw-r--r-- | db2/log/log_rec.c | 198 | ||||
-rw-r--r-- | db2/log/log_register.c | 76 |
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(®info, 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, ®info.path)) != 0) + return (ret); reginfo.file = DB_DEFAULT_LOG_FILE; ret = __db_runlink(®info, 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); |