summaryrefslogtreecommitdiff
path: root/db/qam
diff options
context:
space:
mode:
authorjbj <devnull@localhost>2001-03-21 18:33:35 +0000
committerjbj <devnull@localhost>2001-03-21 18:33:35 +0000
commit731946f4b90eb1173452dd30f1296dd825155d82 (patch)
tree67535f54ecb7e5463c06e62044e4efd84ae0291d /db/qam
parent7ed904da030dc4640ff9bce8458ba07cc09d830d (diff)
downloadrpm-731946f4b90eb1173452dd30f1296dd825155d82.tar.gz
rpm-731946f4b90eb1173452dd30f1296dd825155d82.tar.bz2
rpm-731946f4b90eb1173452dd30f1296dd825155d82.zip
Initial revision
CVS patchset: 4644 CVS date: 2001/03/21 18:33:35
Diffstat (limited to 'db/qam')
-rw-r--r--db/qam/qam.c1357
-rw-r--r--db/qam/qam.src124
-rw-r--r--db/qam/qam_auto.c1282
-rw-r--r--db/qam/qam_conv.c83
-rw-r--r--db/qam/qam_files.c503
-rw-r--r--db/qam/qam_method.c472
-rw-r--r--db/qam/qam_open.c268
-rw-r--r--db/qam/qam_rec.c732
-rw-r--r--db/qam/qam_stat.c201
-rw-r--r--db/qam/qam_upgrade.c111
-rw-r--r--db/qam/qam_verify.c194
11 files changed, 5327 insertions, 0 deletions
diff --git a/db/qam/qam.c b/db/qam/qam.c
new file mode 100644
index 000000000..0c9f45304
--- /dev/null
+++ b/db/qam/qam.c
@@ -0,0 +1,1357 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam.c,v 11.72 2001/01/16 20:10:55 ubell Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_shash.h"
+#include "db_am.h"
+#include "mp.h"
+#include "lock.h"
+#include "log.h"
+#include "btree.h"
+#include "qam.h"
+
+static int __qam_c_close __P((DBC *, db_pgno_t, int *));
+static int __qam_c_del __P((DBC *));
+static int __qam_c_destroy __P((DBC *));
+static int __qam_c_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
+static int __qam_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
+static int __qam_getno __P((DB *, const DBT *, db_recno_t *));
+
+/*
+ * __qam_position --
+ * Position a queued access method cursor at a record. This returns
+ * the page locked. *exactp will be set if the record is valid.
+ * PUBLIC: int __qam_position
+ * PUBLIC: __P((DBC *, db_recno_t *, qam_position_mode, int *));
+ */
+int
+__qam_position(dbc, recnop, mode, exactp)
+ DBC *dbc; /* open cursor */
+ db_recno_t *recnop; /* pointer to recno to find */
+ qam_position_mode mode;/* locking: read or write */
+ int *exactp; /* indicate if it was found */
+{
+ QUEUE_CURSOR *cp;
+ DB *dbp;
+ QAMDATA *qp;
+ db_pgno_t pg;
+ int ret;
+
+ dbp = dbc->dbp;
+ cp = (QUEUE_CURSOR *)dbc->internal;
+
+ /* Fetch the page for this recno. */
+ pg = QAM_RECNO_PAGE(dbp, *recnop);
+
+ if ((ret = __db_lget(dbc, 0, pg, mode == QAM_READ ?
+ DB_LOCK_READ : DB_LOCK_WRITE, 0, &cp->lock)) != 0)
+ return (ret);
+ cp->page = NULL;
+ *exactp = 0;
+ if ((ret = __qam_fget(dbp, &pg,
+ mode == QAM_WRITE ? DB_MPOOL_CREATE : 0,
+ &cp->page)) != 0) {
+ /* We did not fetch it, we can release the lock. */
+ (void)__LPUT(dbc, cp->lock);
+ cp->lock.off = LOCK_INVALID;
+ if (mode != QAM_WRITE && (ret == EINVAL || ret == ENOENT))
+ return (0);
+ return (ret);
+ }
+ cp->pgno = pg;
+ cp->indx = QAM_RECNO_INDEX(dbp, pg, *recnop);
+
+ if (PGNO(cp->page) == 0) {
+ if (F_ISSET(dbp, DB_AM_RDONLY)) {
+ *exactp = 0;
+ return (0);
+ }
+ PGNO(cp->page) = pg;
+ TYPE(cp->page) = P_QAMDATA;
+ }
+
+ qp = QAM_GET_RECORD(dbp, cp->page, cp->indx);
+ *exactp = F_ISSET(qp, QAM_VALID);
+
+ return (ret);
+}
+
+/*
+ * __qam_pitem --
+ * Put an item on a queue page. Copy the data to the page and set the
+ * VALID and SET bits. If logging and the record was previously set,
+ * log that data, otherwise just log the new data.
+ *
+ * pagep must be write locked
+ *
+ * PUBLIC: int __qam_pitem
+ * PUBLIC: __P((DBC *, QPAGE *, u_int32_t, db_recno_t, DBT *));
+ */
+int
+__qam_pitem(dbc, pagep, indx, recno, data)
+ DBC *dbc;
+ QPAGE *pagep;
+ u_int32_t indx;
+ db_recno_t recno;
+ DBT *data;
+{
+ DB *dbp;
+ DBT olddata, pdata, *datap;
+ QAMDATA *qp;
+ QUEUE *t;
+ u_int32_t size;
+ u_int8_t *dest, *p;
+ int alloced, ret;
+
+ alloced = ret = 0;
+
+ dbp = dbc->dbp;
+ t = (QUEUE *)dbp->q_internal;
+
+ if (data->size > t->re_len)
+ goto len_err;
+
+ qp = QAM_GET_RECORD(dbp, pagep, indx);
+
+ p = qp->data;
+ size = data->size;
+ datap = data;
+ if (F_ISSET(data, DB_DBT_PARTIAL)) {
+ if (data->doff + data->dlen > t->re_len) {
+ alloced = data->dlen;
+ goto len_err;
+ }
+ if (data->size != data->dlen) {
+len_err: __db_err(dbp->dbenv,
+ "Length improper for fixed length record %lu",
+ (u_long)(alloced ? alloced : data->size));
+ return (EINVAL);
+ }
+ if (data->size == t->re_len)
+ goto no_partial;
+
+ /*
+ * If we are logging, then we have to build the record
+ * first, otherwise, we can simply drop the change
+ * directly on the page. After this clause, make
+ * sure that datap and p are set up correctly so that
+ * copying datap into p does the right thing.
+ *
+ * Note, I am changing this so that if the existing
+ * record is not valid, we create a complete record
+ * to log so that both this and the recovery code is simpler.
+ */
+
+ if (DB_LOGGING(dbc) || !F_ISSET(qp, QAM_VALID)) {
+ datap = &pdata;
+ memset(datap, 0, sizeof(*datap));
+
+ if ((ret = __os_malloc(dbp->dbenv,
+ t->re_len, NULL, &datap->data)) != 0)
+ return (ret);
+ alloced = 1;
+ datap->size = t->re_len;
+
+ /*
+ * Construct the record if it's valid, otherwise set it
+ * all to the pad character.
+ */
+ dest = datap->data;
+ if (F_ISSET(qp, QAM_VALID))
+ memcpy(dest, p, t->re_len);
+ else
+ memset(dest, t->re_pad, t->re_len);
+
+ dest += data->doff;
+ memcpy(dest, data->data, data->size);
+ } else {
+ datap = data;
+ p += data->doff;
+ }
+ }
+
+no_partial:
+ if (DB_LOGGING(dbc)) {
+ olddata.size = 0;
+ if (F_ISSET(qp, QAM_SET)) {
+ olddata.data = qp->data;
+ olddata.size = t->re_len;
+ }
+ if ((ret = __qam_add_log(dbp->dbenv, dbc->txn, &LSN(pagep),
+ 0, dbp->log_fileid, &LSN(pagep), pagep->pgno,
+ indx, recno, datap, qp->flags,
+ olddata.size == 0 ? NULL : &olddata)) != 0)
+ goto err;
+ }
+
+ F_SET(qp, QAM_VALID | QAM_SET);
+ memcpy(p, datap->data, datap->size);
+ if (!F_ISSET(data, DB_DBT_PARTIAL))
+ memset(p + datap->size, t->re_pad, t->re_len - datap->size);
+
+err: if (alloced)
+ __os_free(datap->data, t->re_len);
+
+ return (ret);
+}
+/*
+ * __qam_c_put
+ * Cursor put for queued access method.
+ * BEFORE and AFTER cannot be specified.
+ */
+static int
+__qam_c_put(dbc, key, data, flags, pgnop)
+ DBC *dbc;
+ DBT *key, *data;
+ u_int32_t flags;
+ db_pgno_t *pgnop;
+{
+ QUEUE_CURSOR *cp;
+ DB *dbp;
+ DB_LOCK lock;
+ QMETA *meta;
+ db_pgno_t pg;
+ db_recno_t new_cur, new_first;
+ u_int32_t opcode;
+ int exact, ret, t_ret;
+
+ COMPQUIET(key, NULL);
+
+ dbp = dbc->dbp;
+ if (pgnop != NULL)
+ *pgnop = PGNO_INVALID;
+
+ cp = (QUEUE_CURSOR *)dbc->internal;
+
+ /* Write lock the record. */
+ if ((ret = __db_lget(dbc,
+ 0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
+ return (ret);
+
+ if ((ret = __qam_position(dbc,
+ &cp->recno, QAM_WRITE, &exact)) != 0) {
+ /* We could not get the page, we can release the record lock. */
+ __LPUT(dbc, lock);
+ return (ret);
+ }
+
+ if (exact && flags == DB_NOOVERWRITE) {
+ ret = __TLPUT(dbc, lock);
+ /* Doing record locking, release the page lock */
+ if ((t_ret = __LPUT(dbc, cp->lock)) == 0)
+ cp->lock.off = LOCK_INVALID;
+ else
+ if (ret == 0)
+ ret = t_ret;
+ if ((t_ret =
+ __qam_fput(dbp, cp->pgno, cp->page, 0)) != 0 && ret == 0)
+ ret = t_ret;
+ cp->page = NULL;
+ return (ret == 0 ? DB_KEYEXIST : ret);
+ }
+
+ /* Put the item on the page. */
+ ret = __qam_pitem(dbc, (QPAGE *)cp->page, cp->indx, cp->recno, data);
+
+ /* Doing record locking, release the page lock */
+ if ((t_ret = __LPUT(dbc, cp->lock)) != 0 && ret == 0)
+ ret = t_ret;
+ if ((t_ret =
+ __qam_fput(dbp, cp->pgno, cp->page, DB_MPOOL_DIRTY)) && ret == 0)
+ ret = t_ret;
+ cp->page = NULL;
+ cp->lock = lock;
+ cp->lock_mode = DB_LOCK_WRITE;
+ if (ret != 0)
+ return (ret);
+
+ /* We may need to reset the head or tail of the queue. */
+ pg = ((QUEUE *)dbp->q_internal)->q_meta;
+ if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ return (ret);
+ if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) {
+ /* We did not fetch it, we can release the lock. */
+ (void)__LPUT(dbc, lock);
+ return (ret);
+ }
+
+ opcode = 0;
+ new_cur = new_first = 0;
+
+ /*
+ * If the put address is outside the queue, adjust the head and
+ * tail of the queue. If the order is inverted we move
+ * the one which is closer. The first case is when the
+ * queue is empty, move first and current to where the new
+ * insert is.
+ */
+
+ if (meta->first_recno == meta->cur_recno) {
+ new_first = cp->recno;
+ new_cur = cp->recno + 1;
+ if (new_cur == RECNO_OOB)
+ new_cur++;
+ opcode |= QAM_SETFIRST;
+ opcode |= QAM_SETCUR;
+ } else {
+ if (QAM_BEFORE_FIRST(meta, cp->recno) &&
+ (meta->first_recno <= meta->cur_recno ||
+ meta->first_recno - cp->recno < cp->recno - meta->cur_recno)) {
+ new_first = cp->recno;
+ opcode |= QAM_SETFIRST;
+ }
+
+ if (meta->cur_recno == cp->recno ||
+ (QAM_AFTER_CURRENT(meta, cp->recno) &&
+ (meta->first_recno <= meta->cur_recno ||
+ cp->recno - meta->cur_recno <= meta->first_recno - cp->recno))) {
+ new_cur = cp->recno + 1;
+ if (new_cur == RECNO_OOB)
+ new_cur++;
+ opcode |= QAM_SETCUR;
+ }
+ }
+
+ if (opcode != 0 && DB_LOGGING(dbc)) {
+ ret = __qam_mvptr_log(dbp->dbenv, dbc->txn, &meta->dbmeta.lsn,
+ 0, opcode, dbp->log_fileid, meta->first_recno, new_first,
+ meta->cur_recno, new_cur, &meta->dbmeta.lsn);
+ }
+
+ if (opcode & QAM_SETCUR)
+ meta->cur_recno = new_cur;
+ if (opcode & QAM_SETFIRST)
+ meta->first_recno = new_first;
+
+ if ((t_ret =
+ memp_fput(dbp->mpf, meta, opcode != 0 ? DB_MPOOL_DIRTY : 0)) != 0 &&
+ ret == 0)
+ ret = t_ret;
+
+ /* Don't hold the meta page long term. */
+ if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
+ ret = t_ret;
+ return (ret);
+}
+
+/*
+ * __qam_put --
+ * Add a record to the queue.
+ * If we are doing anything but appending, just call qam_c_put to do the
+ * work. Otherwise we fast path things here.
+ *
+ * PUBLIC: int __qam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
+ */
+int
+__qam_put(dbp, txn, key, data, flags)
+ DB *dbp;
+ DB_TXN *txn;
+ DBT *key, *data;
+ u_int32_t flags;
+{
+ QUEUE_CURSOR *cp;
+ DBC *dbc;
+ DB_LOCK lock;
+ QMETA *meta;
+ QPAGE *page;
+ QUEUE *qp;
+ db_pgno_t pg;
+ db_recno_t recno;
+ int ret, t_ret;
+
+ PANIC_CHECK(dbp->dbenv);
+ DB_CHECK_TXN(dbp, txn);
+
+ /* Allocate a cursor. */
+ if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
+ return (ret);
+
+ DEBUG_LWRITE(dbc, dbc->txn, "qam_put", key, data, flags);
+
+ cp = (QUEUE_CURSOR *)dbc->internal;
+
+ /* Check for invalid flags. */
+ if ((ret = __db_putchk(dbp,
+ key, data, flags, F_ISSET(dbp, DB_AM_RDONLY), 0)) != 0)
+ goto done;
+
+ /* If not appending, then just call the cursor routine */
+ if (flags != DB_APPEND) {
+ if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0)
+ goto done;
+
+ ret = __qam_c_put(dbc, NULL, data, flags, NULL);
+ goto done;
+ }
+
+ /* Write lock the meta page. */
+ pg = ((QUEUE *)dbp->q_internal)->q_meta;
+ if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ goto done;
+ if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) {
+ /* We did not fetch it, we can release the lock. */
+ (void)__LPUT(dbc, lock);
+ goto done;
+ }
+
+ /* Record that we are going to allocate a record. */
+ if (DB_LOGGING(dbc)) {
+ __qam_inc_log(dbp->dbenv,
+ dbc->txn, &meta->dbmeta.lsn,
+ 0, dbp->log_fileid, &meta->dbmeta.lsn);
+ }
+
+ /* Get the next record number. */
+ recno = meta->cur_recno;
+ meta->cur_recno++;
+ if (meta->cur_recno == RECNO_OOB)
+ meta->cur_recno++;
+ if (meta->cur_recno == meta->first_recno) {
+ meta->cur_recno--;
+ if (meta->cur_recno == RECNO_OOB)
+ meta->cur_recno--;
+ (void)__LPUT(dbc, lock);
+ ret = EFBIG;
+ goto err;
+ }
+
+ if (QAM_BEFORE_FIRST(meta, recno))
+ meta->first_recno = recno;
+
+ /* Lock the record and release meta page lock. */
+ if ((ret = __db_lget(dbc,
+ 1, recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
+ goto err;
+
+ /*
+ * The application may modify the data based on the selected record
+ * number.
+ */
+ if (flags == DB_APPEND && dbc->dbp->db_append_recno != NULL &&
+ (ret = dbc->dbp->db_append_recno(dbc->dbp, data, recno)) != 0) {
+ (void)__LPUT(dbc, lock);
+ goto err;
+ }
+
+ cp->lock = lock;
+ cp->lock_mode = DB_LOCK_WRITE;
+
+ pg = QAM_RECNO_PAGE(dbp, recno);
+
+ /* Fetch and write lock the data page. */
+ if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ goto err;
+ if ((ret = __qam_fget(dbp, &pg, DB_MPOOL_CREATE, &page)) != 0) {
+ /* We did not fetch it, we can release the lock. */
+ (void)__LPUT(dbc, lock);
+ goto err;
+ }
+
+ /* See if this is a new page. */
+ if (page->pgno == 0) {
+ page->pgno = pg;
+ page->type = P_QAMDATA;
+ }
+
+ /* Put the item on the page and log it. */
+ ret = __qam_pitem(dbc, page,
+ QAM_RECNO_INDEX(dbp, pg, recno), recno, data);
+
+ /* Doing record locking, release the page lock */
+ if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
+ ret = t_ret;
+
+ if ((t_ret
+ = __qam_fput(dbp, pg, page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
+ ret = t_ret;
+
+ /* Return the record number to the user. */
+ if (ret == 0)
+ ret = __db_retcopy(dbp, key,
+ &recno, sizeof(recno), &dbc->rkey.data, &dbc->rkey.ulen);
+
+ /* See if we are leaving the extent. */
+ qp = (QUEUE *) dbp->q_internal;
+ if (qp->page_ext != 0
+ && (recno % (qp->page_ext * qp->rec_page) == 0
+ || recno == UINT32_T_MAX)) {
+ if ((ret =
+ __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ goto err;
+ if (!QAM_AFTER_CURRENT(meta, recno))
+ ret = __qam_fclose(dbp, pg);
+ (void)__LPUT(dbc, lock);
+ }
+
+err:
+ /* Release the meta page. */
+ if ((t_ret
+ = memp_fput(dbp->mpf, meta, DB_MPOOL_DIRTY)) != 0 && ret == 0)
+ ret = t_ret;
+
+done:
+ /* Discard the cursor. */
+ if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret);
+}
+
+/*
+ * __qam_c_del --
+ * Qam cursor->am_del function
+ */
+static int
+__qam_c_del(dbc)
+ DBC *dbc;
+{
+ QUEUE_CURSOR *cp;
+ DB *dbp;
+ DBT data;
+ DB_LOCK lock;
+ PAGE *pagep;
+ QAMDATA *qp;
+ QMETA *meta;
+ db_pgno_t pg;
+ int exact, ret, t_ret;
+
+ dbp = dbc->dbp;
+ cp = (QUEUE_CURSOR *)dbc->internal;
+
+ pg = ((QUEUE *)dbp->q_internal)->q_meta;
+ if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_READ, 0, &lock)) != 0)
+ return (ret);
+ if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) {
+ /* We did not fetch it, we can release the lock. */
+ (void)__LPUT(dbc, lock);
+ return (ret);
+ }
+
+ if (QAM_NOT_VALID(meta, cp->recno))
+ ret = DB_NOTFOUND;
+
+ /* Don't hold the meta page long term. */
+ if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
+ ret = t_ret;
+ if ((t_ret = memp_fput(dbp->mpf, meta, 0)) != 0 && ret == 0)
+ ret = t_ret;
+
+ if (ret != 0)
+ return (ret);
+
+ if ((ret = __db_lget(dbc,
+ 0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
+ return (ret);
+
+ cp->lock_mode = DB_LOCK_WRITE;
+ /* Find the record ; delete only deletes exact matches. */
+ if ((ret = __qam_position(dbc,
+ &cp->recno, QAM_WRITE, &exact)) != 0) {
+ cp->lock = lock;
+ return (ret);
+ }
+ if (!exact) {
+ ret = DB_NOTFOUND;
+ goto err1;
+ }
+
+ pagep = cp->page;
+ qp = QAM_GET_RECORD(dbp, pagep, cp->indx);
+
+ if (DB_LOGGING(dbc)) {
+ if (((QUEUE *)dbp->q_internal)->page_ext == 0
+ || ((QUEUE *)dbp->q_internal)->re_len == 0) {
+ if ((ret =
+ __qam_del_log(dbp->dbenv,
+ dbc->txn, &LSN(pagep), 0,
+ dbp->log_fileid, &LSN(pagep),
+ pagep->pgno, cp->indx, cp->recno)) != 0)
+ goto err1;
+ } else {
+ data.size = ((QUEUE *)dbp->q_internal)->re_len;
+ data.data = qp->data;
+ if ((ret =
+ __qam_delext_log(dbp->dbenv, dbc->txn,
+ &LSN(pagep), 0, dbp->log_fileid, &LSN(pagep),
+ pagep->pgno, cp->indx, cp->recno, &data)) != 0)
+ goto err1;
+ }
+ }
+
+ F_CLR(qp, QAM_VALID);
+
+err1:
+ if ((t_ret = __qam_fput(
+ dbp, cp->pgno, cp->page, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0)
+ return (ret ? ret : t_ret);
+ cp->page = NULL;
+ /* Doing record locking, release the page lock */
+ if ((t_ret = __LPUT(dbc, cp->lock)) != 0) {
+ cp->lock = lock;
+ return (ret ? ret : t_ret);
+ }
+ cp->lock = lock;
+ return (ret);
+}
+
+/*
+ * __qam_delete --
+ * Queue db->del function.
+ *
+ * PUBLIC: int __qam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
+ */
+int
+__qam_delete(dbp, txn, key, flags)
+ DB *dbp;
+ DB_TXN *txn;
+ DBT *key;
+ u_int32_t flags;
+{
+ QUEUE_CURSOR *cp;
+ DBC *dbc;
+ int ret, t_ret;
+
+ PANIC_CHECK(dbp->dbenv);
+ DB_CHECK_TXN(dbp, txn);
+
+ /* Check for invalid flags. */
+ if ((ret =
+ __db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0)
+ return (ret);
+
+ /* Acquire a cursor. */
+ if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
+ return (ret);
+
+ DEBUG_LWRITE(dbc, txn, "qam_delete", key, NULL, flags);
+
+ cp = (QUEUE_CURSOR *)dbc->internal;
+ if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0)
+ goto err;
+
+ ret = __qam_c_del(dbc);
+
+ /* Release the cursor. */
+err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret);
+}
+
+#ifdef DEBUG_WOP
+#define QDEBUG
+#endif
+
+/*
+ * __qam_c_get --
+ * Queue cursor->c_get function.
+ */
+static int
+__qam_c_get(dbc, key, data, flags, pgnop)
+ DBC *dbc;
+ DBT *key, *data;
+ u_int32_t flags;
+ db_pgno_t *pgnop;
+{
+ DB *dbp;
+ DB_LOCK lock, pglock, metalock, save_lock;
+ DBT tmp;
+ PAGE *pg;
+ QAMDATA *qp;
+ QMETA *meta;
+ QUEUE *t;
+ QUEUE_CURSOR *cp;
+ db_indx_t save_indx;
+ db_lockmode_t lock_mode;
+ db_pgno_t metapno, save_page;
+ db_recno_t current, first, save_recno;
+ qam_position_mode mode;
+ u_int32_t rec_extent;
+ int exact, is_first, locked, ret, t_ret, wait, with_delete;
+ int put_mode, meta_dirty, retrying, skip_again, wrapped;
+
+ cp = (QUEUE_CURSOR *)dbc->internal;
+ dbp = dbc->dbp;
+
+ PANIC_CHECK(dbp->dbenv);
+
+ wait = 0;
+ with_delete = 0;
+ retrying = 0;
+ rec_extent = 0;
+ lock_mode = DB_LOCK_READ;
+ mode = QAM_READ;
+ put_mode = 0;
+ t_ret = 0;
+ *pgnop = 0;
+ pg = NULL;
+ skip_again = 0;
+
+ if (F_ISSET(dbc, DBC_RMW)) {
+ lock_mode = DB_LOCK_WRITE;
+ mode = QAM_WRITE;
+ }
+
+ if (flags == DB_CONSUME_WAIT) {
+ wait = 1;
+ flags = DB_CONSUME;
+ }
+ if (flags == DB_CONSUME) {
+ DB_CHECK_TXN(dbp, dbc->txn);
+ with_delete = 1;
+ flags = DB_FIRST;
+ lock_mode = DB_LOCK_WRITE;
+ mode = QAM_CONSUME;
+ }
+
+ DEBUG_LREAD(dbc, dbc->txn, "qam_c_get",
+ flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags);
+
+ is_first = 0;
+
+ t = (QUEUE *)dbp->q_internal;
+ /* get the meta page */
+ metapno = t->q_meta;
+ if ((ret = __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0)
+ return (ret);
+ locked = 1;
+ if ((ret = memp_fget(dbp->mpf, &metapno, 0, &meta)) != 0) {
+ /* We did not fetch it, we can release the lock. */
+ (void)__LPUT(dbc, metalock);
+ return (ret);
+ }
+
+ first = 0;
+
+ /* Make lint and friends happy. */
+ meta_dirty = 0;
+
+ /* Release any previous lock if not in a transaction. */
+ if (cp->lock.off != LOCK_INVALID) {
+ (void)__TLPUT(dbc, cp->lock);
+ cp->lock.off = LOCK_INVALID;
+ }
+
+retry: /* Update the record number. */
+ switch (flags) {
+ case DB_CURRENT:
+ break;
+ case DB_NEXT_DUP:
+ ret = DB_NOTFOUND;
+ goto err;
+ /* NOTREACHED */
+ case DB_NEXT:
+ case DB_NEXT_NODUP:
+ if (cp->recno != RECNO_OOB) {
+ ++cp->recno;
+ /* Wrap around, skipping zero. */
+ if (cp->recno == RECNO_OOB)
+ cp->recno++;
+ break;
+ }
+ /* FALLTHROUGH */
+ case DB_FIRST:
+ flags = DB_NEXT;
+ is_first = 1;
+
+ /* get the first record number */
+ cp->recno = first = meta->first_recno;
+
+ break;
+ case DB_PREV:
+ case DB_PREV_NODUP:
+ if (cp->recno != RECNO_OOB) {
+ if (QAM_BEFORE_FIRST(meta, cp->recno)
+ || cp->recno == meta->first_recno) {
+ ret = DB_NOTFOUND;
+ goto err;
+ }
+ --cp->recno;
+ /* Wrap around, skipping zero. */
+ if (cp->recno == RECNO_OOB)
+ --cp->recno;
+ break;
+ }
+ /* FALLTHROUGH */
+ case DB_LAST:
+ if (meta->first_recno == meta->cur_recno) {
+ ret = DB_NOTFOUND;
+ goto err;
+ }
+ cp->recno = meta->cur_recno - 1;
+ if (cp->recno == RECNO_OOB)
+ cp->recno--;
+ break;
+ case DB_GET_BOTH:
+ case DB_SET:
+ case DB_SET_RANGE:
+ if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0)
+ goto err;
+ break;
+ default:
+ ret = __db_unknown_flag(dbp->dbenv, "__qam_c_get", flags);
+ goto err;
+ }
+
+ /*
+ * Check to see if we are out of data. Current points to
+ * the first free slot.
+ */
+ if (cp->recno == meta->cur_recno ||
+ QAM_AFTER_CURRENT(meta, cp->recno)) {
+ ret = DB_NOTFOUND;
+ pg = NULL;
+ if (wait) {
+ flags = DB_FIRST;
+ /*
+ * If first is not set, then we skipped a
+ * locked record, go back and find it.
+ * If we find a locked record again
+ * wait for it.
+ */
+ if (first == 0) {
+ retrying = 1;
+ goto retry;
+ }
+ if (CDB_LOCKING(dbp->dbenv)) {
+ if ((ret = lock_get(dbp->dbenv, dbc->locker,
+ DB_LOCK_SWITCH, &dbc->lock_dbt,
+ DB_LOCK_WAIT, &dbc->mylock)) != 0)
+ goto err;
+ if ((ret = lock_get(dbp->dbenv, dbc->locker,
+ DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE,
+ &dbc->mylock)) != 0)
+ goto err;
+ goto retry;
+ }
+ /*
+ * Wait for someone to update the meta page.
+ * This will probably mean there is something
+ * in the queue. We then go back up and
+ * try again.
+ */
+ if (locked == 0) {
+ if ((ret = __db_lget( dbc,
+ 0, metapno, lock_mode, 0, &metalock)) != 0)
+ goto err;
+ locked = 1;
+ if (cp->recno != RECNO_OOB &&
+ !QAM_AFTER_CURRENT(meta, cp->recno))
+ goto retry;
+ }
+ if ((ret = __db_lget(dbc, 0, metapno,
+ DB_LOCK_WAIT, DB_LOCK_SWITCH, &metalock)) != 0)
+ goto err;
+ if ((ret = lock_get(dbp->dbenv, dbc->locker,
+ DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE,
+ &metalock)) != 0)
+ goto err;
+ locked = 1;
+ goto retry;
+ }
+
+ goto err;
+ }
+
+ /* Don't hold the meta page long term. */
+ if (locked) {
+ if ((ret = __LPUT(dbc, metalock)) != 0)
+ goto err;
+ locked = 0;
+ }
+
+ /* Lock the record. */
+ if ((ret = __db_lget(dbc, 0, cp->recno, lock_mode,
+ (with_delete && !retrying) ?
+ DB_LOCK_NOWAIT | DB_LOCK_RECORD : DB_LOCK_RECORD,
+ &lock)) == DB_LOCK_NOTGRANTED && with_delete) {
+#ifdef QDEBUG
+ __db_logmsg(dbp->dbenv,
+ dbc->txn, "Queue S", 0, "%x %d %d %d",
+ dbc->locker, cp->recno, first, meta->first_recno);
+#endif
+ first = 0;
+ goto retry;
+ }
+
+ if (ret != 0)
+ goto err;
+
+ /*
+ * In the DB_FIRST or DB_LAST cases we must wait and then start over
+ * since the first/last may have moved while we slept.
+ * We release our locks and try again.
+ */
+ if ((!with_delete && is_first) || flags == DB_LAST) {
+ if ((ret =
+ __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0)
+ goto err;
+ if (cp->recno !=
+ (is_first ? meta->first_recno : (meta->cur_recno - 1))) {
+ __LPUT(dbc, lock);
+ if (is_first)
+ flags = DB_FIRST;
+ locked = 1;
+ goto retry;
+ }
+ /* Don't hold the meta page long term. */
+ if ((ret = __LPUT(dbc, metalock)) != 0)
+ goto err;
+ }
+
+ /* Position the cursor on the record. */
+ if ((ret = __qam_position(dbc, &cp->recno, mode, &exact)) != 0) {
+ /* We cannot get the page, release the record lock. */
+ (void)__LPUT(dbc, lock);
+ goto err;
+ }
+
+ pg = cp->page;
+ pglock = cp->lock;
+ cp->lock = lock;
+ cp->lock_mode = lock_mode;
+
+ if (!exact) {
+ if (flags == DB_NEXT || flags == DB_NEXT_NODUP
+ || flags == DB_PREV || flags == DB_PREV_NODUP
+ || flags == DB_LAST) {
+ /* Release locks and try again. */
+ if (pg != NULL)
+ (void)__qam_fput(dbp, cp->pgno, pg, 0);
+ cp->page = pg = NULL;
+ (void)__LPUT(dbc, pglock);
+ (void)__LPUT(dbc, cp->lock);
+ if (flags == DB_LAST)
+ flags = DB_PREV;
+ if (!with_delete)
+ is_first = 0;
+ retrying = 0;
+ goto retry;
+ }
+ /* this is for the SET and SET_RANGE cases */
+ ret = DB_KEYEMPTY;
+ goto err1;
+ }
+
+ /* Return the key if the user didn't give us one. */
+ if (key != NULL && flags != DB_SET && flags != DB_GET_BOTH &&
+ (ret = __db_retcopy(dbp, key, &cp->recno, sizeof(cp->recno),
+ &dbc->rkey.data, &dbc->rkey.ulen)) != 0)
+ goto err1;
+
+ if (key != NULL)
+ F_SET(key, DB_DBT_ISSET);
+
+ qp = QAM_GET_RECORD(dbp, pg, cp->indx);
+
+ /* Return the data item. */
+ if (flags == DB_GET_BOTH) {
+ /*
+ * Need to compare
+ */
+ tmp.data = qp->data;
+ tmp.size = t->re_len;
+ if ((ret = __bam_defcmp(dbp, data, &tmp)) != 0) {
+ ret = DB_NOTFOUND;
+ goto err1;
+ }
+ }
+ if (data != NULL && (ret = __db_retcopy(dbp, data,
+ qp->data, t->re_len, &dbc->rdata.data, &dbc->rdata.ulen)) != 0)
+ goto err1;
+
+ if (data != NULL)
+ F_SET(data, DB_DBT_ISSET);
+
+ /* Finally, if we are doing DB_CONSUME mark the record. */
+ if (with_delete) {
+ if (DB_LOGGING(dbc)) {
+ if (t->page_ext == 0 || t->re_len == 0) {
+ if ((ret = __qam_del_log(dbp->dbenv, dbc->txn,
+ &LSN(pg), 0, dbp->log_fileid, &LSN(pg),
+ pg->pgno, cp->indx, cp->recno)) != 0)
+ goto err1;
+ } else {
+ tmp.data = qp->data;
+ tmp.size = t->re_len;
+ if ((ret =
+ __qam_delext_log(dbp->dbenv, dbc->txn,
+ &LSN(pg), 0, dbp->log_fileid, &LSN(pg),
+ pg->pgno, cp->indx, cp->recno, &tmp)) != 0)
+ goto err1;
+ }
+ }
+
+ F_CLR(qp, QAM_VALID);
+ put_mode = DB_MPOOL_DIRTY;
+
+ if ((ret = __LPUT(dbc, pglock)) != 0)
+ goto err;
+
+ /*
+ * Now we need to update the metapage
+ * first pointer. If we have deleted
+ * the record that is pointed to by
+ * first_recno then we move it as far
+ * forward as we can without blocking.
+ * The metapage lock must be held for
+ * the whole scan otherwise someone could
+ * do a random insert behind where we are
+ * looking.
+ */
+
+ if (locked == 0 && (ret = __db_lget(
+ dbc, 0, metapno, lock_mode, 0, &metalock)) != 0)
+ goto err1;
+ locked = 1;
+#ifdef QDEBUG
+ __db_logmsg(dbp->dbenv,
+ dbc->txn, "Queue D", 0, "%x %d %d %d",
+ dbc->locker, cp->recno, first, meta->first_recno);
+#endif
+ /*
+ * See if we deleted the "first" record. If
+ * first is zero then we skipped something,
+ * see if first_recno has been move passed
+ * that to the record that we deleted.
+ */
+ if (first == 0)
+ first = cp->recno;
+ if (first != meta->first_recno)
+ goto done;
+
+ save_page = cp->pgno;
+ save_indx = cp->indx;
+ save_recno = cp->recno;
+ save_lock = cp->lock;
+
+ /*
+ * If we skipped some deleted records, we need to
+ * reposition on the first one. Get a lock
+ * in case someone is trying to put it back.
+ */
+ if (first != cp->recno) {
+ ret = __db_lget(dbc, 0, first, DB_LOCK_READ,
+ DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock);
+ if (ret == DB_LOCK_NOTGRANTED) {
+ ret = 0;
+ goto done;
+ }
+ if (ret != 0)
+ goto err1;
+ if ((ret =
+ __qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0)
+ goto err1;
+ cp->page = NULL;
+ put_mode = 0;
+ if ((ret = __qam_position(dbc,
+ &first, QAM_READ, &exact)) != 0 || exact != 0) {
+ (void)__LPUT(dbc, lock);
+ goto err1;
+ }
+ if ((ret =__LPUT(dbc, lock)) != 0)
+ goto err1;
+ if ((ret = __LPUT(dbc, cp->lock)) != 0)
+ goto err1;
+ }
+
+ current = meta->cur_recno;
+ wrapped = 0;
+ if (first > current)
+ wrapped = 1;
+ rec_extent = meta->page_ext * meta->rec_page;
+
+ /* Loop until we find a record or hit current */
+ for (;;) {
+ /*
+ * Check to see if we are moving off the extent
+ * and remove the extent.
+ * If we are moving off a page we need to
+ * get rid of the buffer.
+ * Wait for the lagging readers to move off the
+ * page.
+ */
+ if (rec_extent != 0
+ && ((exact = first % rec_extent == 0)
+ || first % meta->rec_page == 0
+ || first == UINT32_T_MAX)) {
+ if (exact == 1 && (ret = __db_lget(dbc,
+ 0, cp->pgno, DB_LOCK_WRITE, 0, &cp->lock)) != 0)
+ break;
+
+#ifdef QDEBUG
+ __db_logmsg(dbp->dbenv,
+ dbc->txn, "Queue R", 0, "%x %d %d %d",
+ dbc->locker, cp->pgno, first, meta->first_recno);
+#endif
+ put_mode |= DB_MPOOL_DISCARD;
+ if ((ret = __qam_fput(dbp,
+ cp->pgno, cp->page, put_mode)) != 0)
+ break;
+ cp->page = NULL;
+
+ if (exact == 1) {
+ ret = __qam_fremove(dbp, cp->pgno);
+ t_ret = __LPUT(dbc, cp->lock);
+ }
+ if (ret != 0)
+ break;
+ if (t_ret != 0) {
+ ret = t_ret;
+ break;
+ }
+ } else if ((ret =
+ __qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0)
+ break;
+ cp->page = NULL;
+ first++;
+ if (first == RECNO_OOB) {
+ wrapped = 0;
+ first++;
+ }
+
+ /*
+ * LOOP EXIT when we come move to the current
+ * pointer.
+ */
+ if (!wrapped && first >= current)
+ break;
+
+ ret = __db_lget(dbc, 0, first, DB_LOCK_READ,
+ DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock);
+ if (ret == DB_LOCK_NOTGRANTED) {
+ ret = 0;
+ break;
+ }
+ if (ret != 0)
+ break;
+
+ if ((ret = __qam_position(dbc,
+ &first, QAM_READ, &exact)) != 0) {
+ (void)__LPUT(dbc, lock);
+ break;
+ }
+ put_mode = 0;
+ if ((ret =__LPUT(dbc, lock)) != 0
+ || (ret = __LPUT(dbc, cp->lock)) != 0 ||exact) {
+ if ((t_ret = __qam_fput(dbp, cp->pgno,
+ cp->page, put_mode)) != 0 && ret == 0)
+ ret = t_ret;
+ cp->page = NULL;
+ break;
+ }
+ }
+
+ cp->pgno = save_page;
+ cp->indx = save_indx;
+ cp->recno = save_recno;
+ cp->lock = save_lock;
+
+ /*
+ * We have advanced as far as we can.
+ * Advance first_recno to this point.
+ */
+ if (meta->first_recno != first) {
+#ifdef QDEBUG
+ __db_logmsg(dbp->dbenv, dbc->txn, "Queue M",
+ 0, "%x %d %d %d", dbc->locker, cp->recno,
+ first, meta->first_recno);
+#endif
+ if (DB_LOGGING(dbc))
+ if ((ret =
+ __qam_incfirst_log(dbp->dbenv,
+ dbc->txn, &meta->dbmeta.lsn, 0,
+ dbp->log_fileid, cp->recno)) != 0)
+ goto err;
+ meta->first_recno = first;
+ meta_dirty = 1;
+ }
+ }
+
+done:
+err1: if (cp->page != NULL) {
+ t_ret = __qam_fput(dbp, cp->pgno, cp->page, put_mode);
+
+ if (!ret)
+ ret = t_ret;
+ /* Doing record locking, release the page lock */
+ t_ret = __LPUT(dbc, pglock);
+ cp->page = NULL;
+ }
+
+err: if (!ret)
+ ret = t_ret;
+ if (meta) {
+
+ /* release the meta page */
+ t_ret = memp_fput(
+ dbp->mpf, meta, meta_dirty ? DB_MPOOL_DIRTY : 0);
+
+ if (!ret)
+ ret = t_ret;
+
+ /* Don't hold the meta page long term. */
+ if (locked)
+ t_ret = __LPUT(dbc, metalock);
+ }
+ DB_ASSERT(metalock.off == LOCK_INVALID);
+
+ /*
+ * There is no need to keep the record locked if we are
+ * not in a transaction.
+ */
+ if (t_ret == 0)
+ t_ret = __TLPUT(dbc, cp->lock);
+
+ return (ret ? ret : t_ret);
+}
+
+/*
+ * __qam_c_close --
+ * Close down the cursor from a single use.
+ */
+static int
+__qam_c_close(dbc, root_pgno, rmroot)
+ DBC *dbc;
+ db_pgno_t root_pgno;
+ int *rmroot;
+{
+ QUEUE_CURSOR *cp;
+
+ COMPQUIET(root_pgno, 0);
+ COMPQUIET(rmroot, NULL);
+
+ cp = (QUEUE_CURSOR *)dbc->internal;
+
+ /* Discard any locks not acquired inside of a transaction. */
+ if (cp->lock.off != LOCK_INVALID) {
+ (void)__TLPUT(dbc, cp->lock);
+ cp->lock.off = LOCK_INVALID;
+ }
+
+ cp->page = NULL;
+ cp->pgno = PGNO_INVALID;
+ cp->indx = 0;
+ cp->lock.off = LOCK_INVALID;
+ cp->lock_mode = DB_LOCK_NG;
+ cp->recno = RECNO_OOB;
+ cp->flags = 0;
+
+ return (0);
+}
+
+/*
+ * __qam_c_dup --
+ * Duplicate a queue cursor, such that the new one holds appropriate
+ * locks for the position of the original.
+ *
+ * PUBLIC: int __qam_c_dup __P((DBC *, DBC *));
+ */
+int
+__qam_c_dup(orig_dbc, new_dbc)
+ DBC *orig_dbc, *new_dbc;
+{
+ QUEUE_CURSOR *orig, *new;
+
+ orig = (QUEUE_CURSOR *)orig_dbc->internal;
+ new = (QUEUE_CURSOR *)new_dbc->internal;
+
+ new->recno = orig->recno;
+
+ /* reget the long term lock if we are not in a xact */
+ if (orig_dbc->txn != NULL ||
+ !STD_LOCKING(orig_dbc) || orig->lock.off == LOCK_INVALID)
+ return (0);
+
+ return (__db_lget(new_dbc,
+ 0, new->recno, new->lock_mode, DB_LOCK_RECORD, &new->lock));
+}
+
+/*
+ * __qam_c_init
+ *
+ * PUBLIC: int __qam_c_init __P((DBC *));
+ */
+int
+__qam_c_init(dbc)
+ DBC *dbc;
+{
+ QUEUE_CURSOR *cp;
+ DB *dbp;
+ int ret;
+
+ dbp = dbc->dbp;
+
+ /* Allocate the internal structure. */
+ cp = (QUEUE_CURSOR *)dbc->internal;
+ if (cp == NULL) {
+ if ((ret =
+ __os_calloc(dbp->dbenv, 1, sizeof(QUEUE_CURSOR), &cp)) != 0)
+ return (ret);
+ dbc->internal = (DBC_INTERNAL *)cp;
+ }
+
+ /* Initialize methods. */
+ dbc->c_close = __db_c_close;
+ dbc->c_count = __db_c_count;
+ dbc->c_del = __db_c_del;
+ dbc->c_dup = __db_c_dup;
+ dbc->c_get = __db_c_get;
+ dbc->c_put = __db_c_put;
+ dbc->c_am_close = __qam_c_close;
+ dbc->c_am_del = __qam_c_del;
+ dbc->c_am_destroy = __qam_c_destroy;
+ dbc->c_am_get = __qam_c_get;
+ dbc->c_am_put = __qam_c_put;
+ dbc->c_am_writelock = NULL;
+
+ return (0);
+}
+
+/*
+ * __qam_c_destroy --
+ * Close a single cursor -- internal version.
+ */
+static int
+__qam_c_destroy(dbc)
+ DBC *dbc;
+{
+ /* Discard the structures. */
+ __os_free(dbc->internal, sizeof(QUEUE_CURSOR));
+
+ return (0);
+}
+
+/*
+ * __qam_getno --
+ * Check the user's record number.
+ */
+static int
+__qam_getno(dbp, key, rep)
+ DB *dbp;
+ const DBT *key;
+ db_recno_t *rep;
+{
+ if ((*rep = *(db_recno_t *)key->data) == 0) {
+ __db_err(dbp->dbenv, "illegal record number of 0");
+ return (EINVAL);
+ }
+ return (0);
+}
diff --git a/db/qam/qam.src b/db/qam/qam.src
new file mode 100644
index 000000000..507d7a652
--- /dev/null
+++ b/db/qam/qam.src
@@ -0,0 +1,124 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ *
+ * $Id: qam.src,v 11.15 2001/01/16 20:10:55 ubell Exp $
+ */
+
+PREFIX qam
+
+INCLUDE #include "db_config.h"
+INCLUDE
+INCLUDE #ifndef NO_SYSTEM_INCLUDES
+INCLUDE #include <sys/types.h>
+INCLUDE
+INCLUDE #include <ctype.h>
+INCLUDE #include <errno.h>
+INCLUDE #include <string.h>
+INCLUDE #endif
+INCLUDE
+INCLUDE #include "db_int.h"
+INCLUDE #include "db_page.h"
+INCLUDE #include "db_dispatch.h"
+INCLUDE #include "db_am.h"
+INCLUDE #include "qam.h"
+INCLUDE #include "txn.h"
+INCLUDE
+
+/*
+ * inc
+ * Used when we increment a record number. These do not actually
+ * tell you what record number you got, just that you incremented
+ * the record number. These operations are never undone.
+ */
+BEGIN inc 76
+ARG fileid int32_t ld
+POINTER lsn DB_LSN * lu
+END
+
+/*
+ * incfirst
+ * Used when we increment first_recno.
+ */
+BEGIN incfirst 77
+ARG fileid int32_t ld
+ARG recno db_recno_t lu
+END
+
+/*
+ * mvptr
+ * Used when we change one or both of cur_recno and first_recno.
+ */
+BEGIN mvptr 78
+ARG opcode u_int32_t lu
+ARG fileid int32_t ld
+ARG old_first db_recno_t lu
+ARG new_first db_recno_t lu
+ARG old_cur db_recno_t lu
+ARG new_cur db_recno_t lu
+POINTER metalsn DB_LSN * lu
+END
+
+/*
+ * del
+ * Used when we delete a record.
+ * recno is the record that is being deleted.
+ */
+BEGIN del 79
+ARG fileid int32_t ld
+POINTER lsn DB_LSN * lu
+ARG pgno db_pgno_t lu
+ARG indx u_int32_t lu
+ARG recno db_recno_t lu
+END
+
+/*
+ * add
+ * Used when we put a record on a page.
+ * recno is the record being added.
+ * data is the record itself.
+ */
+BEGIN add 80
+ARG fileid int32_t ld
+POINTER lsn DB_LSN * lu
+ARG pgno db_pgno_t lu
+ARG indx u_int32_t lu
+ARG recno db_recno_t lu
+DBT data DBT s
+ARG vflag u_int32_t lu
+DBT olddata DBT s
+END
+
+/*
+ * delete
+ * Used when we remove a Queue extent file.
+ */
+BEGIN delete 81
+DBT name DBT s
+POINTER lsn DB_LSN * lu
+END
+
+/*
+ * rename
+ * Used when we rename a Queue extent file.
+ */
+BEGIN rename 82
+DBT name DBT s
+DBT newname DBT s
+END
+
+/*
+ * delext
+ * Used when we delete a record in extent based queue.
+ * recno is the record that is being deleted.
+ */
+BEGIN delext 83
+ARG fileid int32_t ld
+POINTER lsn DB_LSN * lu
+ARG pgno db_pgno_t lu
+ARG indx u_int32_t lu
+ARG recno db_recno_t lu
+DBT data DBT s
+END
diff --git a/db/qam/qam_auto.c b/db/qam/qam_auto.c
new file mode 100644
index 000000000..cfdba3195
--- /dev/null
+++ b/db/qam/qam_auto.c
@@ -0,0 +1,1282 @@
+/* Do not edit: automatically built by gen_rec.awk. */
+#include "db_config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_dispatch.h"
+#include "db_am.h"
+#include "qam.h"
+#include "txn.h"
+
+int
+__qam_inc_log(dbenv, txnid, ret_lsnp, flags,
+ fileid, lsn)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ int32_t fileid;
+ DB_LSN * lsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_inc;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(*lsn);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_inc_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_inc_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_inc_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_inc: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %ld\n", (long)argp->fileid);
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_inc_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_inc_args **argpp;
+{
+ __qam_inc_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_inc_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_incfirst_log(dbenv, txnid, ret_lsnp, flags,
+ fileid, recno)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ int32_t fileid;
+ db_recno_t recno;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_incfirst;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(recno);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &recno, sizeof(recno));
+ bp += sizeof(recno);
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_incfirst_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_incfirst_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_incfirst_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_incfirst: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %ld\n", (long)argp->fileid);
+ printf("\trecno: %lu\n", (u_long)argp->recno);
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_incfirst_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_incfirst_args **argpp;
+{
+ __qam_incfirst_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_incfirst_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->recno, bp, sizeof(argp->recno));
+ bp += sizeof(argp->recno);
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_mvptr_log(dbenv, txnid, ret_lsnp, flags,
+ opcode, fileid, old_first, new_first, old_cur, new_cur,
+ metalsn)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ u_int32_t opcode;
+ int32_t fileid;
+ db_recno_t old_first;
+ db_recno_t new_first;
+ db_recno_t old_cur;
+ db_recno_t new_cur;
+ DB_LSN * metalsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_mvptr;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(opcode)
+ + sizeof(fileid)
+ + sizeof(old_first)
+ + sizeof(new_first)
+ + sizeof(old_cur)
+ + sizeof(new_cur)
+ + sizeof(*metalsn);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &opcode, sizeof(opcode));
+ bp += sizeof(opcode);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &old_first, sizeof(old_first));
+ bp += sizeof(old_first);
+ memcpy(bp, &new_first, sizeof(new_first));
+ bp += sizeof(new_first);
+ memcpy(bp, &old_cur, sizeof(old_cur));
+ bp += sizeof(old_cur);
+ memcpy(bp, &new_cur, sizeof(new_cur));
+ bp += sizeof(new_cur);
+ if (metalsn != NULL)
+ memcpy(bp, metalsn, sizeof(*metalsn));
+ else
+ memset(bp, 0, sizeof(*metalsn));
+ bp += sizeof(*metalsn);
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_mvptr_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_mvptr_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_mvptr_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_mvptr: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\topcode: %lu\n", (u_long)argp->opcode);
+ printf("\tfileid: %ld\n", (long)argp->fileid);
+ printf("\told_first: %lu\n", (u_long)argp->old_first);
+ printf("\tnew_first: %lu\n", (u_long)argp->new_first);
+ printf("\told_cur: %lu\n", (u_long)argp->old_cur);
+ printf("\tnew_cur: %lu\n", (u_long)argp->new_cur);
+ printf("\tmetalsn: [%lu][%lu]\n",
+ (u_long)argp->metalsn.file, (u_long)argp->metalsn.offset);
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_mvptr_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_mvptr_args **argpp;
+{
+ __qam_mvptr_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_mvptr_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->opcode, bp, sizeof(argp->opcode));
+ bp += sizeof(argp->opcode);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->old_first, bp, sizeof(argp->old_first));
+ bp += sizeof(argp->old_first);
+ memcpy(&argp->new_first, bp, sizeof(argp->new_first));
+ bp += sizeof(argp->new_first);
+ memcpy(&argp->old_cur, bp, sizeof(argp->old_cur));
+ bp += sizeof(argp->old_cur);
+ memcpy(&argp->new_cur, bp, sizeof(argp->new_cur));
+ bp += sizeof(argp->new_cur);
+ memcpy(&argp->metalsn, bp, sizeof(argp->metalsn));
+ bp += sizeof(argp->metalsn);
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_del_log(dbenv, txnid, ret_lsnp, flags,
+ fileid, lsn, pgno, indx, recno)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ int32_t fileid;
+ DB_LSN * lsn;
+ db_pgno_t pgno;
+ u_int32_t indx;
+ db_recno_t recno;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_del;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(*lsn)
+ + sizeof(pgno)
+ + sizeof(indx)
+ + sizeof(recno);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ memcpy(bp, &indx, sizeof(indx));
+ bp += sizeof(indx);
+ memcpy(bp, &recno, sizeof(recno));
+ bp += sizeof(recno);
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_del_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_del_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_del_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_del: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %ld\n", (long)argp->fileid);
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tindx: %lu\n", (u_long)argp->indx);
+ printf("\trecno: %lu\n", (u_long)argp->recno);
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_del_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_del_args **argpp;
+{
+ __qam_del_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_del_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->indx, bp, sizeof(argp->indx));
+ bp += sizeof(argp->indx);
+ memcpy(&argp->recno, bp, sizeof(argp->recno));
+ bp += sizeof(argp->recno);
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_add_log(dbenv, txnid, ret_lsnp, flags,
+ fileid, lsn, pgno, indx, recno, data,
+ vflag, olddata)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ int32_t fileid;
+ DB_LSN * lsn;
+ db_pgno_t pgno;
+ u_int32_t indx;
+ db_recno_t recno;
+ const DBT *data;
+ u_int32_t vflag;
+ const DBT *olddata;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_add;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(*lsn)
+ + sizeof(pgno)
+ + sizeof(indx)
+ + sizeof(recno)
+ + sizeof(u_int32_t) + (data == NULL ? 0 : data->size)
+ + sizeof(vflag)
+ + sizeof(u_int32_t) + (olddata == NULL ? 0 : olddata->size);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ memcpy(bp, &indx, sizeof(indx));
+ bp += sizeof(indx);
+ memcpy(bp, &recno, sizeof(recno));
+ bp += sizeof(recno);
+ if (data == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &data->size, sizeof(data->size));
+ bp += sizeof(data->size);
+ memcpy(bp, data->data, data->size);
+ bp += data->size;
+ }
+ memcpy(bp, &vflag, sizeof(vflag));
+ bp += sizeof(vflag);
+ if (olddata == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &olddata->size, sizeof(olddata->size));
+ bp += sizeof(olddata->size);
+ memcpy(bp, olddata->data, olddata->size);
+ bp += olddata->size;
+ }
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_add_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_add_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_add_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_add: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %ld\n", (long)argp->fileid);
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tindx: %lu\n", (u_long)argp->indx);
+ printf("\trecno: %lu\n", (u_long)argp->recno);
+ printf("\tdata: ");
+ for (i = 0; i < argp->data.size; i++) {
+ ch = ((u_int8_t *)argp->data.data)[i];
+ if (isprint(ch) || ch == 0xa)
+ putchar(ch);
+ else
+ printf("%#x ", ch);
+ }
+ printf("\n");
+ printf("\tvflag: %lu\n", (u_long)argp->vflag);
+ printf("\tolddata: ");
+ for (i = 0; i < argp->olddata.size; i++) {
+ ch = ((u_int8_t *)argp->olddata.data)[i];
+ if (isprint(ch) || ch == 0xa)
+ putchar(ch);
+ else
+ printf("%#x ", ch);
+ }
+ printf("\n");
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_add_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_add_args **argpp;
+{
+ __qam_add_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_add_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->indx, bp, sizeof(argp->indx));
+ bp += sizeof(argp->indx);
+ memcpy(&argp->recno, bp, sizeof(argp->recno));
+ bp += sizeof(argp->recno);
+ memset(&argp->data, 0, sizeof(argp->data));
+ memcpy(&argp->data.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->data.data = bp;
+ bp += argp->data.size;
+ memcpy(&argp->vflag, bp, sizeof(argp->vflag));
+ bp += sizeof(argp->vflag);
+ memset(&argp->olddata, 0, sizeof(argp->olddata));
+ memcpy(&argp->olddata.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->olddata.data = bp;
+ bp += argp->olddata.size;
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_delete_log(dbenv, txnid, ret_lsnp, flags,
+ name, lsn)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ const DBT *name;
+ DB_LSN * lsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_delete;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(u_int32_t) + (name == NULL ? 0 : name->size)
+ + sizeof(*lsn);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ if (name == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &name->size, sizeof(name->size));
+ bp += sizeof(name->size);
+ memcpy(bp, name->data, name->size);
+ bp += name->size;
+ }
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_delete_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_delete_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_delete_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_delete: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tname: ");
+ for (i = 0; i < argp->name.size; i++) {
+ ch = ((u_int8_t *)argp->name.data)[i];
+ if (isprint(ch) || ch == 0xa)
+ putchar(ch);
+ else
+ printf("%#x ", ch);
+ }
+ printf("\n");
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_delete_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_delete_args **argpp;
+{
+ __qam_delete_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_delete_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memset(&argp->name, 0, sizeof(argp->name));
+ memcpy(&argp->name.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->name.data = bp;
+ bp += argp->name.size;
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_rename_log(dbenv, txnid, ret_lsnp, flags,
+ name, newname)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ const DBT *name;
+ const DBT *newname;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_rename;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(u_int32_t) + (name == NULL ? 0 : name->size)
+ + sizeof(u_int32_t) + (newname == NULL ? 0 : newname->size);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ if (name == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &name->size, sizeof(name->size));
+ bp += sizeof(name->size);
+ memcpy(bp, name->data, name->size);
+ bp += name->size;
+ }
+ if (newname == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &newname->size, sizeof(newname->size));
+ bp += sizeof(newname->size);
+ memcpy(bp, newname->data, newname->size);
+ bp += newname->size;
+ }
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_rename_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_rename_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_rename_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_rename: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tname: ");
+ for (i = 0; i < argp->name.size; i++) {
+ ch = ((u_int8_t *)argp->name.data)[i];
+ if (isprint(ch) || ch == 0xa)
+ putchar(ch);
+ else
+ printf("%#x ", ch);
+ }
+ printf("\n");
+ printf("\tnewname: ");
+ for (i = 0; i < argp->newname.size; i++) {
+ ch = ((u_int8_t *)argp->newname.data)[i];
+ if (isprint(ch) || ch == 0xa)
+ putchar(ch);
+ else
+ printf("%#x ", ch);
+ }
+ printf("\n");
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_rename_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_rename_args **argpp;
+{
+ __qam_rename_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_rename_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memset(&argp->name, 0, sizeof(argp->name));
+ memcpy(&argp->name.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->name.data = bp;
+ bp += argp->name.size;
+ memset(&argp->newname, 0, sizeof(argp->newname));
+ memcpy(&argp->newname.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->newname.data = bp;
+ bp += argp->newname.size;
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_delext_log(dbenv, txnid, ret_lsnp, flags,
+ fileid, lsn, pgno, indx, recno, data)
+ DB_ENV *dbenv;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ int32_t fileid;
+ DB_LSN * lsn;
+ db_pgno_t pgno;
+ u_int32_t indx;
+ db_recno_t recno;
+ const DBT *data;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_qam_delext;
+ if (txnid != NULL &&
+ TAILQ_FIRST(&txnid->kids) != NULL &&
+ (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)
+ return (ret);
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ ZERO_LSN(null_lsn);
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(*lsn)
+ + sizeof(pgno)
+ + sizeof(indx)
+ + sizeof(recno)
+ + sizeof(u_int32_t) + (data == NULL ? 0 : data->size);
+ if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)
+ return (ret);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ memcpy(bp, &indx, sizeof(indx));
+ bp += sizeof(indx);
+ memcpy(bp, &recno, sizeof(recno));
+ bp += sizeof(recno);
+ if (data == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &data->size, sizeof(data->size));
+ bp += sizeof(data->size);
+ memcpy(bp, data->data, data->size);
+ bp += data->size;
+ }
+ DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size);
+ ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ __os_free(logrec.data, logrec.size);
+ return (ret);
+}
+
+int
+__qam_delext_print(dbenv, dbtp, lsnp, notused2, notused3)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops notused2;
+ void *notused3;
+{
+ __qam_delext_args *argp;
+ u_int32_t i;
+ u_int ch;
+ int ret;
+
+ i = 0;
+ ch = 0;
+ notused2 = DB_TXN_ABORT;
+ notused3 = NULL;
+
+ if ((ret = __qam_delext_read(dbenv, dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]qam_delext: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %ld\n", (long)argp->fileid);
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tindx: %lu\n", (u_long)argp->indx);
+ printf("\trecno: %lu\n", (u_long)argp->recno);
+ printf("\tdata: ");
+ for (i = 0; i < argp->data.size; i++) {
+ ch = ((u_int8_t *)argp->data.data)[i];
+ if (isprint(ch) || ch == 0xa)
+ putchar(ch);
+ else
+ printf("%#x ", ch);
+ }
+ printf("\n");
+ printf("\n");
+ __os_free(argp, 0);
+ return (0);
+}
+
+int
+__qam_delext_read(dbenv, recbuf, argpp)
+ DB_ENV *dbenv;
+ void *recbuf;
+ __qam_delext_args **argpp;
+{
+ __qam_delext_args *argp;
+ u_int8_t *bp;
+ int ret;
+
+ ret = __os_malloc(dbenv, sizeof(__qam_delext_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));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->indx, bp, sizeof(argp->indx));
+ bp += sizeof(argp->indx);
+ memcpy(&argp->recno, bp, sizeof(argp->recno));
+ bp += sizeof(argp->recno);
+ memset(&argp->data, 0, sizeof(argp->data));
+ memcpy(&argp->data.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->data.data = bp;
+ bp += argp->data.size;
+ *argpp = argp;
+ return (0);
+}
+
+int
+__qam_init_print(dbenv)
+ DB_ENV *dbenv;
+{
+ int ret;
+
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_inc_print, DB_qam_inc)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_incfirst_print, DB_qam_incfirst)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_mvptr_print, DB_qam_mvptr)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_del_print, DB_qam_del)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_add_print, DB_qam_add)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_delete_print, DB_qam_delete)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_rename_print, DB_qam_rename)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_delext_print, DB_qam_delext)) != 0)
+ return (ret);
+ return (0);
+}
+
+int
+__qam_init_recover(dbenv)
+ DB_ENV *dbenv;
+{
+ int ret;
+
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_inc_recover, DB_qam_inc)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_incfirst_recover, DB_qam_incfirst)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_mvptr_recover, DB_qam_mvptr)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_del_recover, DB_qam_del)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_add_recover, DB_qam_add)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_delete_recover, DB_qam_delete)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_rename_recover, DB_qam_rename)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __qam_delext_recover, DB_qam_delext)) != 0)
+ return (ret);
+ return (0);
+}
+
diff --git a/db/qam/qam_conv.c b/db/qam/qam_conv.c
new file mode 100644
index 000000000..2eb1c7227
--- /dev/null
+++ b/db/qam/qam_conv.c
@@ -0,0 +1,83 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_conv.c,v 11.6 2000/11/16 23:40:57 ubell Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "qam.h"
+#include "db_swap.h"
+#include "db_am.h"
+
+/*
+ * __qam_mswap --
+ * Swap the bytes on the queue metadata page.
+ *
+ * PUBLIC: int __qam_mswap __P((PAGE *));
+ */
+int
+__qam_mswap(pg)
+ PAGE *pg;
+{
+ u_int8_t *p;
+
+ __db_metaswap(pg);
+
+ p = (u_int8_t *)pg + sizeof(DBMETA);
+
+ SWAP32(p); /* first_recno */
+ SWAP32(p); /* cur_recno */
+ SWAP32(p); /* re_len */
+ SWAP32(p); /* re_pad */
+ SWAP32(p); /* rec_page */
+ SWAP32(p); /* page_ext */
+
+ return (0);
+}
+
+/*
+ * __qam_pgin_out --
+ * Convert host-specific page layout to/from the host-independent format
+ * stored on disk.
+ * We only need to fix up a few fields in the header
+ *
+ * PUBLIC: int __qam_pgin_out __P((DB_ENV *, db_pgno_t, void *, DBT *));
+ */
+int
+__qam_pgin_out(dbenv, pg, pp, cookie)
+ DB_ENV *dbenv;
+ db_pgno_t pg;
+ void *pp;
+ DBT *cookie;
+{
+ DB_PGINFO *pginfo;
+ QPAGE *h;
+
+ COMPQUIET(pg, 0);
+ COMPQUIET(dbenv, NULL);
+ pginfo = (DB_PGINFO *)cookie->data;
+ if (!pginfo->needswap)
+ return (0);
+
+ h = pp;
+ if (h->type == P_QAMMETA)
+ return (__qam_mswap(pp));
+
+ M_32_SWAP(h->lsn.file);
+ M_32_SWAP(h->lsn.offset);
+ M_32_SWAP(h->pgno);
+
+ return (0);
+}
diff --git a/db/qam/qam_files.c b/db/qam/qam_files.c
new file mode 100644
index 000000000..e53a3bf24
--- /dev/null
+++ b/db/qam/qam_files.c
@@ -0,0 +1,503 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_files.c,v 1.16 2001/01/19 18:01:59 bostic Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_shash.h"
+#include "db_am.h"
+#include "lock.h"
+#include "btree.h"
+#include "qam.h"
+#include "mp.h"
+
+/*
+ * __qam_fprobe -- calcluate and open extent
+ *
+ * Calculate which extent the page is in, open and create
+ * if necessary.
+ *
+ * PUBLIC: int __qam_fprobe __P((DB *, db_pgno_t, void *, qam_probe_mode, int));
+ */
+
+int
+__qam_fprobe(dbp, pgno, addrp, mode, flags)
+ DB *dbp;
+ db_pgno_t pgno;
+ void *addrp;
+ qam_probe_mode mode;
+ int flags;
+{
+ DB_ENV *dbenv;
+ DB_MPOOLFILE *mpf;
+ MPFARRAY *array;
+ QUEUE *qp;
+ u_int32_t extid, maxext;
+ char buf[256];
+ int numext, offset, oldext, openflags, ret;
+
+ qp = (QUEUE *)dbp->q_internal;
+ if (qp->page_ext == 0) {
+ mpf = dbp->mpf;
+ if (mode == QAM_PROBE_GET)
+ return (memp_fget(mpf, &pgno, flags, addrp));
+ return (memp_fput(mpf, addrp, flags));
+ }
+
+ dbenv = dbp->dbenv;
+ mpf = NULL;
+ ret = 0;
+
+ /*
+ * Need to lock long enough to find the mpf or create the file.
+ * The file cannot go away because we must have a record locked
+ * in that file.
+ */
+ MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+ extid = (pgno - 1) / qp->page_ext;
+
+ /* Array1 will always be in use if array2 is in use. */
+ array = &qp->array1;
+ if (array->n_extent == 0) {
+ /* Start with 4 extents */
+ oldext = 0;
+ array->n_extent = 4;
+ array->low_extent = extid;
+ offset = 0;
+ numext = 0;
+ goto alloc;
+ }
+
+ offset = extid - qp->array1.low_extent;
+ if (qp->array2.n_extent != 0 &&
+ abs(offset) > abs(extid - qp->array2.low_extent)) {
+ array = &qp->array2;
+ offset = extid - array->low_extent;
+ }
+
+ /*
+ * Check to see if the requested extent is outside the range of
+ * extents in the array. This is true by defualt if there are
+ * no extents here yet.
+ */
+ if (offset < 0 || (unsigned) offset >= array->n_extent) {
+ oldext = array->n_extent;
+ numext = array->hi_extent - array->low_extent + 1;
+ if (offset < 0
+ && (unsigned) -offset + numext <= array->n_extent) {
+ /* If we can fit this one in, move the array up */
+ memmove(&array->mpfarray[-offset],
+ array->mpfarray, numext
+ * sizeof(array->mpfarray[0]));
+ memset(array->mpfarray, 0, -offset
+ * sizeof(array->mpfarray[0]));
+ offset = 0;
+ } else if ((u_int32_t)offset == array->n_extent &&
+ mode != QAM_PROBE_MPF && array->mpfarray[0].pinref == 0) {
+ /* We can close the bottom extent. */
+ mpf = array->mpfarray[0].mpf;
+ if (mpf != NULL && (ret = memp_fclose(mpf)) != 0)
+ goto err;
+ memmove(&array->mpfarray[0], &array->mpfarray[1],
+ (array->n_extent - 1) * sizeof (array->mpfarray[0]));
+ array->low_extent++;
+ array->hi_extent++;
+ offset--;
+ array->mpfarray[offset].mpf = NULL;
+ array->mpfarray[offset].pinref = 0;
+ } else {
+ /* See if we have wrapped around the queue. */
+ maxext = (u_int32_t) UINT32_T_MAX
+ / (qp->page_ext * qp->rec_page);
+ if ((u_int32_t) abs(offset) >= maxext/2) {
+ array = &qp->array2;
+ DB_ASSERT(array->n_extent == 0);
+ oldext = 0;
+ array->n_extent = 4;
+ array->low_extent = extid;
+ offset = 0;
+ numext = 0;
+ } else {
+ /*
+ * Increase the size to at least include
+ * the new one and double it.
+ */
+ array->n_extent += abs(offset);
+ array->n_extent <<= 2;
+ }
+ alloc:
+ if ((ret = __os_realloc(dbenv,
+ array->n_extent * sizeof(struct __qmpf),
+ NULL, &array->mpfarray)) != 0)
+ goto err;
+
+ if (offset < 0) {
+ offset = -offset;
+ memmove(&array->mpfarray[offset], array->mpfarray,
+ numext * sizeof(array->mpfarray[0]));
+ memset(array->mpfarray, 0,
+ offset * sizeof(array->mpfarray[0]));
+ memset(&array->mpfarray[numext + offset], 0,
+ (array->n_extent - (numext + offset))
+ * sizeof(array->mpfarray[0]));
+ offset = 0;
+ }
+ else
+ memset(&array->mpfarray[oldext], 0,
+ (array->n_extent - oldext) *
+ sizeof(array->mpfarray[0]));
+ }
+ }
+
+ if (extid < array->low_extent)
+ array->low_extent = extid;
+ if (extid > array->hi_extent)
+ array->hi_extent = extid;
+ if (array->mpfarray[offset].mpf == NULL) {
+ snprintf(buf,
+ sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, extid);
+ openflags = DB_EXTENT;
+ if (LF_ISSET(DB_MPOOL_CREATE))
+ openflags |= DB_CREATE;
+ if (F_ISSET(dbp, DB_AM_RDONLY))
+ openflags |= DB_RDONLY;
+ qp->finfo.fileid = NULL;
+ if ((ret = __memp_fopen(dbenv->mp_handle,
+ NULL, buf, openflags, qp->mode, dbp->pgsize,
+ 1, &qp->finfo, &array->mpfarray[offset].mpf)) != 0)
+ goto err;
+ }
+
+ mpf = array->mpfarray[offset].mpf;
+ if (mode == QAM_PROBE_GET)
+ array->mpfarray[offset].pinref++;
+ if (LF_ISSET(DB_MPOOL_CREATE))
+ __memp_clear_unlink(mpf);
+
+err:
+ MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+
+ if (ret == 0) {
+ if (mode == QAM_PROBE_MPF) {
+ *(DB_MPOOLFILE **)addrp = mpf;
+ return (0);
+ }
+ pgno--;
+ pgno %= qp->page_ext;
+ if (mode == QAM_PROBE_GET)
+ return (memp_fget(mpf,
+ &pgno, flags | DB_MPOOL_EXTENT, addrp));
+ ret = memp_fput(mpf, addrp, flags);
+ MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+ array->mpfarray[offset].pinref--;
+ MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+ }
+ return (ret);
+}
+
+/*
+ * __qam_fclose -- close an extent.
+ *
+ * Calculate which extent the page is in and close it.
+ * We assume the mpf entry is present.
+ *
+ * PUBLIC: int __qam_fclose __P((DB *, db_pgno_t));
+ */
+
+int
+__qam_fclose(dbp, pgnoaddr)
+ DB *dbp;
+ db_pgno_t pgnoaddr;
+{
+ DB_ENV *dbenv;
+ DB_MPOOLFILE *mpf;
+ MPFARRAY *array;
+ QUEUE *qp;
+ u_int32_t extid;
+ int offset, ret;
+
+ ret = 0;
+ dbenv = dbp->dbenv;
+ qp = (QUEUE *)dbp->q_internal;
+
+ MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+
+ extid = (pgnoaddr - 1) / qp->page_ext;
+ array = &qp->array1;
+ if (array->low_extent > extid || array->hi_extent < extid)
+ array = &qp->array2;
+ offset = extid - array->low_extent;
+
+ DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent);
+
+ /* If other threads are still using this file, leave it. */
+ if (array->mpfarray[offset].pinref != 0)
+ goto done;
+
+ mpf = array->mpfarray[offset].mpf;
+ array->mpfarray[offset].mpf = NULL;
+ ret = memp_fclose(mpf);
+
+done:
+ MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+ return (ret);
+}
+/*
+ * __qam_fremove -- remove an extent.
+ *
+ * Calculate which extent the page is in and remove it. There is no way
+ * to remove an extent without probing it first and seeing that is is empty
+ * so we assume the mpf entry is present.
+ *
+ * PUBLIC: int __qam_fremove __P((DB *, db_pgno_t));
+ */
+
+int
+__qam_fremove(dbp, pgnoaddr)
+ DB *dbp;
+ db_pgno_t pgnoaddr;
+{
+ DB_ENV *dbenv;
+ DB_MPOOLFILE *mpf;
+ MPFARRAY *array;
+ QUEUE *qp;
+ u_int32_t extid;
+#if CONFIG_TEST
+ char buf[256], *real_name;
+#endif
+ int offset, ret;
+
+ qp = (QUEUE *)dbp->q_internal;
+ dbenv = dbp->dbenv;
+ ret = 0;
+
+ MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+
+ extid = (pgnoaddr - 1) / qp->page_ext;
+ array = &qp->array1;
+ if (array->low_extent > extid || array->hi_extent < extid)
+ array = &qp->array2;
+ offset = extid - array->low_extent;
+
+ DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent);
+
+#if CONFIG_TEST
+ real_name = NULL;
+ /* Find the real name of the file. */
+ snprintf(buf, sizeof(buf),
+ QUEUE_EXTENT, qp->dir, qp->name, extid);
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, buf, 0, NULL, &real_name)) != 0)
+ goto err;
+#endif
+ mpf = array->mpfarray[offset].mpf;
+ array->mpfarray[offset].mpf = NULL;
+ __memp_set_unlink(mpf);
+ if ((ret = memp_fclose(mpf)) != 0)
+ goto err;
+
+ if (offset == 0) {
+ memmove(array->mpfarray, &array->mpfarray[1],
+ (array->hi_extent - array->low_extent)
+ * sizeof(array->mpfarray[0]));
+ array->mpfarray[array->hi_extent - array->low_extent].mpf = NULL;
+ if (array->low_extent != array->hi_extent)
+ array->low_extent++;
+ } else {
+ if (extid == array->hi_extent)
+ array->hi_extent--;
+ }
+
+err:
+ MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+#if CONFIG_TEST
+ if (real_name != NULL)
+ __os_freestr(real_name);
+#endif
+ return (ret);
+}
+
+/*
+ * __qam_sync --
+ * Flush the database cache.
+ *
+ * PUBLIC: int __qam_sync __P((DB *, u_int32_t));
+ */
+int
+__qam_sync(dbp, flags)
+ DB *dbp;
+ u_int32_t flags;
+{
+ DB_ENV *dbenv;
+ DB_MPOOLFILE *mpf;
+ MPFARRAY *array;
+ QUEUE *qp;
+ QUEUE_FILELIST *filelist;
+ struct __qmpf *mpfp;
+ u_int32_t i;
+ int done, ret;
+
+ dbenv = dbp->dbenv;
+
+ PANIC_CHECK(dbenv);
+ DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync");
+
+ if ((ret = __db_syncchk(dbp, flags)) != 0)
+ return (ret);
+
+ /* Read-only trees never need to be sync'd. */
+ if (F_ISSET(dbp, DB_AM_RDONLY))
+ return (0);
+
+ /* If the tree was never backed by a database file, we're done. */
+ if (F_ISSET(dbp, DB_AM_INMEM))
+ return (0);
+
+ /* Flush any dirty pages from the cache to the backing file. */
+ if ((ret = memp_fsync(dbp->mpf)) != 0)
+ return (ret);
+
+ qp = (QUEUE *)dbp->q_internal;
+ if (qp->page_ext == 0)
+ return (0);
+
+ /* We do this for the side effect of opening all active extents. */
+ if ((ret = __qam_gen_filelist(dbp, &filelist)) != 0)
+ return (ret);
+
+ if (filelist == NULL)
+ return (0);
+
+ __os_free(filelist, 0);
+
+ done = 0;
+ qp = (QUEUE *)dbp->q_internal;
+ array = &qp->array1;
+
+ MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+again:
+ mpfp = array->mpfarray;
+ for (i = array->low_extent; i <= array->hi_extent; i++, mpfp++)
+ if ((mpf = mpfp->mpf) != NULL) {
+ if ((ret = memp_fsync(mpf)) != 0)
+ goto err;
+ /*
+ * If we are the only ones with this file open
+ * then close it so it might be removed.
+ */
+ if (mpfp->pinref == 0) {
+ mpfp->mpf = NULL;
+ if ((ret = memp_fclose(mpf)) != 0)
+ goto err;
+ }
+ }
+
+ if (done == 0 && qp->array2.n_extent != 0) {
+ array = &qp->array2;
+ done = 1;
+ goto again;
+ }
+
+err:
+ MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+ return (ret);
+}
+
+/*
+ * __qam_gen_filelist -- generate a list of extent files.
+ * Another thread may close the handle so this should only
+ * be used single threaded or with care.
+ *
+ * PUBLIC: int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **));
+ */
+int
+__qam_gen_filelist(dbp, filelistp)
+ DB *dbp;
+ QUEUE_FILELIST **filelistp;
+{
+ DB_ENV *dbenv;
+ QUEUE *qp;
+ QMETA *meta;
+ db_pgno_t i, last, start, stop;
+ db_recno_t current, first;
+ QUEUE_FILELIST *fp;
+ int ret;
+
+ dbenv = dbp->dbenv;
+ qp = (QUEUE *)dbp->q_internal;
+ *filelistp = NULL;
+ if (qp->page_ext == 0)
+ return (0);
+
+ /* This may happen during metapage recovery. */
+ if (qp->name == NULL)
+ return (0);
+
+ /* Find out the page number of the last page in the database. */
+ i = PGNO_BASE_MD;
+ if ((ret = memp_fget(dbp->mpf, &i, 0, &meta)) != 0) {
+ (void)dbp->close(dbp, 0);
+ return (ret);
+ }
+
+ current = meta->cur_recno;
+ first = meta->first_recno;
+
+ if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0) {
+ (void)dbp->close(dbp, 0);
+ return (ret);
+ }
+
+ last = QAM_RECNO_PAGE(dbp, current);
+ start = QAM_RECNO_PAGE(dbp, first);
+
+ /* Allocate the worst case plus 1 for null termination. */
+ if (last >= start)
+ ret = last - start + 2;
+ else
+ ret = last + (QAM_RECNO_PAGE(dbp, UINT32_T_MAX) - start) + 1;
+ if ((ret = __os_calloc(dbenv,
+ ret, sizeof(QUEUE_FILELIST), filelistp)) != 0)
+ return (ret);
+ fp = *filelistp;
+ i = start;
+ if (last >= start)
+ stop = last;
+ else
+ stop = QAM_RECNO_PAGE(dbp, UINT32_T_MAX);
+again:
+ for (; i <= last; i += qp->page_ext) {
+ if ((ret = __qam_fprobe(dbp,
+ i, &fp->mpf, QAM_PROBE_MPF, 0)) != 0) {
+ if (ret == ENOENT)
+ continue;
+ return (ret);
+ }
+ fp->id = (i - 1) / qp->page_ext;
+ fp++;
+ }
+
+ if (last < start) {
+ i = 1;
+ stop = last;
+ start = 0;
+ goto again;
+ }
+
+ return (0);
+}
diff --git a/db/qam/qam_method.c b/db/qam/qam_method.c
new file mode 100644
index 000000000..1c94f4b8d
--- /dev/null
+++ b/db/qam/qam_method.c
@@ -0,0 +1,472 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_method.c,v 11.17 2001/01/10 04:50:54 ubell Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_int.h"
+#include "db_shash.h"
+#include "db_am.h"
+#include "qam.h"
+#include "db.h"
+#include "mp.h"
+#include "lock.h"
+#include "log.h"
+
+static int __qam_set_extentsize __P((DB *, u_int32_t));
+static int __qam_remove_callback __P((DB *, void *));
+
+struct __qam_cookie {
+ DB_LSN lsn;
+ QUEUE_FILELIST *filelist;
+};
+
+/*
+ * __qam_db_create --
+ * Queue specific initialization of the DB structure.
+ *
+ * PUBLIC: int __qam_db_create __P((DB *));
+ */
+int
+__qam_db_create(dbp)
+ DB *dbp;
+{
+ QUEUE *t;
+ int ret;
+
+ /* Allocate and initialize the private queue structure. */
+ if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(QUEUE), &t)) != 0)
+ return (ret);
+ dbp->q_internal = t;
+ dbp->set_q_extentsize = __qam_set_extentsize;
+
+ t->re_pad = ' ';
+
+ return (0);
+}
+
+/*
+ * __qam_db_close --
+ * Queue specific discard of the DB structure.
+ *
+ * PUBLIC: int __qam_db_close __P((DB *));
+ */
+int
+__qam_db_close(dbp)
+ DB *dbp;
+{
+ DB_MPOOLFILE *mpf;
+ MPFARRAY *array;
+ QUEUE *t;
+ struct __qmpf *mpfp;
+ u_int32_t i;
+ int ret, t_ret;
+
+ ret = 0;
+ t = dbp->q_internal;
+
+ array = &t->array1;
+again:
+ mpfp = array->mpfarray;
+ if (mpfp != NULL) {
+ for (i = array->low_extent;
+ i <= array->hi_extent; i++, mpfp++) {
+ mpf = mpfp->mpf;
+ mpfp->mpf = NULL;
+ if (mpf != NULL &&
+ (t_ret = memp_fclose(mpf)) != 0 && ret == 0)
+ ret = t_ret;
+ }
+ __os_free(array->mpfarray, 0);
+ }
+ if (t->array2.n_extent != 0) {
+ array = &t->array2;
+ array->n_extent = 0;
+ goto again;
+ }
+
+ if (t->path != NULL)
+ __os_free(t->path, 0);
+ __os_free(t, sizeof(QUEUE));
+ dbp->q_internal = NULL;
+
+ return (ret);
+}
+
+static int
+__qam_set_extentsize(dbp, extentsize)
+ DB *dbp;
+ u_int32_t extentsize;
+{
+ DB_ILLEGAL_AFTER_OPEN(dbp, "set_extentsize");
+
+ if (extentsize < 1) {
+ __db_err(dbp->dbenv, "Extent size must be at least 1.");
+ return (EINVAL);
+ }
+
+ ((QUEUE*)dbp->q_internal)->page_ext = extentsize;
+
+ return (0);
+}
+
+/*
+ * __db_prqueue --
+ * Print out a queue
+ *
+ * PUBLIC: int __db_prqueue __P((DB *, u_int32_t));
+ */
+int
+__db_prqueue(dbp, flags)
+ DB *dbp;
+ u_int32_t flags;
+{
+ PAGE *h;
+ QMETA *meta;
+ db_pgno_t first, i, last, pg_ext, stop;
+ int ret;
+
+ /* Find out the page number of the last page in the database. */
+ i = PGNO_BASE_MD;
+ if ((ret = memp_fget(dbp->mpf, &i, 0, &meta)) != 0)
+ return (ret);
+
+ first = QAM_RECNO_PAGE(dbp, meta->first_recno);
+ last = QAM_RECNO_PAGE(dbp, meta->cur_recno);
+
+ if ((ret = __db_prpage(dbp, (PAGE *)meta, flags)) != 0)
+ return (ret);
+ if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0)
+ return (ret);
+
+ i = first;
+ if (first > last)
+ stop = QAM_RECNO_PAGE(dbp, UINT32_T_MAX);
+ else
+ stop = last;
+
+ /* Dump each page. */
+begin:
+ for (; i <= stop; ++i) {
+ if ((ret = __qam_fget(dbp, &i, DB_MPOOL_EXTENT, &h)) != 0) {
+ pg_ext = ((QUEUE *)dbp->q_internal)->page_ext;
+ if (pg_ext == 0) {
+ if (ret == EINVAL && first == last)
+ return (0);
+ return (ret);
+ }
+ if (ret == ENOENT || ret == EINVAL) {
+ i += pg_ext - ((i - 1) % pg_ext) - 1;
+ continue;
+ }
+ return (ret);
+ }
+ (void)__db_prpage(dbp, h, flags);
+ if ((ret = __qam_fput(dbp, i, h, 0)) != 0)
+ return (ret);
+ }
+
+ if (first > last) {
+ i = 1;
+ stop = last;
+ first = last;
+ goto begin;
+ }
+ return (0);
+}
+
+/*
+ * __qam_remove
+ * Remove method for a Queue.
+ *
+ * PUBLIC: int __qam_remove __P((DB *, const char *,
+ * PUBLIC: const char *, DB_LSN *, int (**)(DB *, void*), void **));
+ */
+int
+__qam_remove(dbp, name, subdb, lsnp, callbackp, cookiep)
+ DB *dbp;
+ const char *name, *subdb;
+ DB_LSN *lsnp;
+ int (**callbackp) __P((DB *, void *));
+ void **cookiep;
+{
+ DBT namedbt;
+ DB_ENV *dbenv;
+ DB_LSN lsn;
+ MPFARRAY *ap;
+ QUEUE *qp;
+ int ret;
+ char *backup, buf[256], *real_back, *real_name;
+ QUEUE_FILELIST *filelist, *fp;
+ struct __qam_cookie *qam_cookie;
+
+ dbenv = dbp->dbenv;
+ ret = 0;
+ backup = real_back = real_name = NULL;
+ filelist = NULL;
+
+ PANIC_CHECK(dbenv);
+
+ /*
+ * Subdatabases.
+ */
+ if (subdb != NULL) {
+ __db_err(dbenv,
+ "Queue does not support multiple databases per file.");
+ ret = EINVAL;
+ goto done;
+ }
+
+ qp = (QUEUE *)dbp->q_internal;
+
+ if (qp->page_ext != 0 &&
+ (ret = __qam_gen_filelist(dbp, &filelist)) != 0)
+ goto done;
+
+ if (filelist == NULL)
+ goto done;
+
+ for (fp = filelist; fp->mpf != NULL; fp++) {
+ snprintf(buf,
+ sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, fp->id);
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, buf, 0, NULL, &real_name)) != 0)
+ goto done;
+ if (LOGGING_ON(dbenv)) {
+ memset(&namedbt, 0, sizeof(namedbt));
+ namedbt.data = (char *)buf;
+ namedbt.size = strlen(buf) + 1;
+
+ if ((ret =
+ __qam_delete_log(dbenv, dbp->open_txn,
+ &lsn, DB_FLUSH, &namedbt, lsnp)) != 0) {
+ __db_err(dbenv,
+ "%s: %s", name, db_strerror(ret));
+ goto done;
+ }
+ }
+ (void)__memp_fremove(fp->mpf);
+ if ((ret = memp_fclose(fp->mpf)) != 0)
+ goto done;
+ if (qp->array2.n_extent == 0 || qp->array2.low_extent > fp->id)
+ ap = &qp->array1;
+ else
+ ap = &qp->array2;
+ ap->mpfarray[fp->id - ap->low_extent].mpf = NULL;
+
+ /* Create name for backup file. */
+ if (TXN_ON(dbenv)) {
+ if ((ret = __db_backup_name(dbenv,
+ buf, &backup, lsnp)) != 0)
+ goto done;
+ if ((ret = __db_appname(dbenv, DB_APP_DATA,
+ NULL, backup, 0, NULL, &real_back)) != 0)
+ goto done;
+ if ((ret = __os_rename(dbenv,
+ real_name, real_back)) != 0)
+ goto done;
+ __os_freestr(real_back);
+ real_back = NULL;
+ }
+ else
+ if ((ret = __os_unlink(dbenv, real_name)) != 0)
+ goto done;
+ __os_freestr(real_name);
+ real_name = NULL;
+ }
+ if ((ret= __os_malloc(dbenv,
+ sizeof(struct __qam_cookie), NULL, &qam_cookie)) != 0)
+ goto done;
+ qam_cookie->lsn = *lsnp;
+ qam_cookie->filelist = filelist;
+ *cookiep = qam_cookie;
+ *callbackp = __qam_remove_callback;
+
+done:
+ if (ret != 0 && filelist != NULL)
+ __os_free(filelist, 0);
+ if (real_back != NULL)
+ __os_freestr(real_back);
+ if (real_name != NULL)
+ __os_freestr(real_name);
+ if (backup != NULL)
+ __os_freestr(backup);
+
+ return (ret);
+}
+
+static int
+__qam_remove_callback(dbp, cookie)
+ DB *dbp;
+ void *cookie;
+{
+ DB_ENV *dbenv;
+ DB_LSN *lsnp;
+ QUEUE *qp;
+ QUEUE_FILELIST *filelist, *fp;
+ char *backup, buf[256], *real_back;
+ int ret;
+
+ qp = (QUEUE *)dbp->q_internal;
+ if (qp->page_ext == 0)
+ return (__os_unlink(dbp->dbenv, cookie));
+
+ dbenv = dbp->dbenv;
+ lsnp = &((struct __qam_cookie *)cookie)->lsn;
+ filelist = fp = ((struct __qam_cookie *)cookie)->filelist;
+ real_back = backup = NULL;
+ if ((ret =
+ __db_backup_name(dbenv, qp->name, &backup, lsnp)) != 0)
+ goto err;
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0)
+ goto err;
+ if ((ret = __os_unlink(dbp->dbenv, real_back)) != 0)
+ goto err;
+
+ __os_freestr(backup);
+ __os_freestr(real_back);
+
+ if (fp == NULL)
+ return (0);
+
+ for (; fp->mpf != NULL; fp++) {
+ snprintf(buf,
+ sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, fp->id);
+ real_back = backup = NULL;
+ if ((ret = __db_backup_name(dbenv, buf, &backup, lsnp)) != 0)
+ goto err;
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0)
+ goto err;
+ ret = __os_unlink(dbenv, real_back);
+ __os_freestr(real_back);
+ __os_freestr(backup);
+ }
+ __os_free(filelist, 0);
+ __os_free(cookie, sizeof (struct __qam_cookie));
+
+ return (0);
+
+err:
+ if (backup != NULL)
+ __os_freestr(backup);
+
+ if (real_back != NULL)
+ __os_freestr(real_back);
+
+ return (ret);
+}
+
+/*
+ * __qam_rename
+ * Rename method for Queue.
+ *
+ * PUBLIC: int __qam_rename __P((DB *,
+ * PUBLIC: const char *, const char *, const char *));
+ */
+int
+__qam_rename(dbp, filename, subdb, newname)
+ DB *dbp;
+ const char *filename, *subdb, *newname;
+{
+ DBT namedbt, newnamedbt;
+ DB_ENV *dbenv;
+ DB_LSN newlsn;
+ MPFARRAY *ap;
+ QUEUE *qp;
+ QUEUE_FILELIST *fp, *filelist;
+ char buf[256], nbuf[256], *namep, *real_name, *real_newname;
+ int ret;
+
+ dbenv = dbp->dbenv;
+ ret = 0;
+ real_name = real_newname = NULL;
+ filelist = NULL;
+
+ qp = (QUEUE *)dbp->q_internal;
+
+ if (subdb != NULL) {
+ __db_err(dbenv,
+ "Queue does not support multiple databases per file.");
+ ret = EINVAL;
+ goto err;
+ }
+ if (qp->page_ext != 0 &&
+ (ret = __qam_gen_filelist(dbp, &filelist)) != 0)
+ goto err;
+ if ((namep = __db_rpath(newname)) != NULL)
+ newname = namep + 1;
+
+ for (fp = filelist; fp != NULL && fp->mpf != NULL; fp++) {
+ if ((ret = __memp_fremove(fp->mpf)) != 0)
+ goto err;
+ if ((ret = memp_fclose(fp->mpf)) != 0)
+ goto err;
+ if (qp->array2.n_extent == 0 || qp->array2.low_extent > fp->id)
+ ap = &qp->array1;
+ else
+ ap = &qp->array2;
+ ap->mpfarray[fp->id - ap->low_extent].mpf = NULL;
+ snprintf(buf,
+ sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, fp->id);
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, buf, 0, NULL, &real_name)) != 0)
+ goto err;
+ snprintf(nbuf,
+ sizeof(nbuf), QUEUE_EXTENT, qp->dir, newname, fp->id);
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, nbuf, 0, NULL, &real_newname)) != 0)
+ goto err;
+ if (LOGGING_ON(dbenv)) {
+ memset(&namedbt, 0, sizeof(namedbt));
+ namedbt.data = (char *)buf;
+ namedbt.size = strlen(buf) + 1;
+
+ memset(&newnamedbt, 0, sizeof(namedbt));
+ newnamedbt.data = (char *)nbuf;
+ newnamedbt.size = strlen(nbuf) + 1;
+
+ if ((ret =
+ __qam_rename_log(dbenv,
+ dbp->open_txn, &newlsn, 0,
+ &namedbt, &newnamedbt)) != 0) {
+ __db_err(dbenv, "%s: %s", filename, db_strerror(ret));
+ goto err;
+ }
+
+ if ((ret = __log_filelist_update(dbenv, dbp,
+ dbp->log_fileid, newname, NULL)) != 0)
+ goto err;
+ }
+ if ((ret = __os_rename(dbenv, real_name, real_newname)) != 0)
+ goto err;
+ __os_freestr(real_name);
+ __os_freestr(real_newname);
+ real_name = real_newname = NULL;
+ }
+
+err:
+ if (real_name != NULL)
+ __os_freestr(real_name);
+ if (real_newname != NULL)
+ __os_freestr(real_newname);
+ if (filelist != NULL)
+ __os_free(filelist, 0);
+
+ return (ret);
+}
diff --git a/db/qam/qam_open.c b/db/qam/qam_open.c
new file mode 100644
index 000000000..73346439f
--- /dev/null
+++ b/db/qam/qam_open.c
@@ -0,0 +1,268 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_open.c,v 11.31 2000/12/20 17:59:29 ubell Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_shash.h"
+#include "db_swap.h"
+#include "db_am.h"
+#include "lock.h"
+#include "qam.h"
+
+/*
+ * __qam_open
+ *
+ * PUBLIC: int __qam_open __P((DB *, const char *, db_pgno_t, int, u_int32_t));
+ */
+int
+__qam_open(dbp, name, base_pgno, mode, flags)
+ DB *dbp;
+ const char *name;
+ db_pgno_t base_pgno;
+ int mode;
+ u_int32_t flags;
+{
+ QUEUE *t;
+ DBC *dbc;
+ DB_LOCK metalock;
+ DB_LSN orig_lsn;
+ QMETA *qmeta;
+ int locked;
+ int ret, t_ret;
+
+ ret = 0;
+ locked = 0;
+ t = dbp->q_internal;
+
+ if (name == NULL && t->page_ext != 0) {
+ __db_err(dbp->dbenv,
+ "Extent size may not be specified for in-memory queue database.");
+ return (EINVAL);
+ }
+ /* Initialize the remaining fields/methods of the DB. */
+ dbp->del = __qam_delete;
+ dbp->put = __qam_put;
+ dbp->stat = __qam_stat;
+ dbp->sync = __qam_sync;
+ dbp->db_am_remove = __qam_remove;
+ dbp->db_am_rename = __qam_rename;
+
+ metalock.off = LOCK_INVALID;
+
+ /*
+ * Get a cursor. If DB_CREATE is specified, we may be creating
+ * pages, and to do that safely in CDB we need a write cursor.
+ * In STD_LOCKING mode, we'll synchronize using the meta page
+ * lock instead.
+ */
+ if ((ret = dbp->cursor(dbp, dbp->open_txn,
+ &dbc, LF_ISSET(DB_CREATE) && CDB_LOCKING(dbp->dbenv) ?
+ DB_WRITECURSOR : 0)) != 0)
+ return (ret);
+
+ /* Get, and optionally create the metadata page. */
+ if ((ret =
+ __db_lget(dbc, 0, base_pgno, DB_LOCK_READ, 0, &metalock)) != 0)
+ goto err;
+ if ((ret = memp_fget(
+ dbp->mpf, &base_pgno, DB_MPOOL_CREATE, (PAGE **)&qmeta)) != 0)
+ goto err;
+
+ /*
+ * If the magic number is correct, we're not creating the tree.
+ * Correct any fields that may not be right. Note, all of the
+ * local flags were set by DB->open.
+ */
+again: if (qmeta->dbmeta.magic == DB_QAMMAGIC) {
+ t->re_pad = qmeta->re_pad;
+ t->re_len = qmeta->re_len;
+ t->rec_page = qmeta->rec_page;
+ t->page_ext = qmeta->page_ext;
+
+ (void)memp_fput(dbp->mpf, (PAGE *)qmeta, 0);
+ goto done;
+ }
+
+ /* If we're doing CDB; we now have to get the write lock. */
+ if (CDB_LOCKING(dbp->dbenv)) {
+ DB_ASSERT(LF_ISSET(DB_CREATE));
+ if ((ret = lock_get(dbp->dbenv, dbc->locker, DB_LOCK_UPGRADE,
+ &dbc->lock_dbt, DB_LOCK_WRITE, &dbc->mylock)) != 0)
+ goto err;
+ }
+
+ /*
+ * If we are doing locking, relase the read lock
+ * and get a write lock. We want to avoid deadlock.
+ */
+ if (locked == 0 && STD_LOCKING(dbc)) {
+ if ((ret = __LPUT(dbc, metalock)) != 0)
+ goto err;
+ if ((ret = __db_lget(dbc,
+ 0, base_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0)
+ goto err;
+ locked = 1;
+ goto again;
+ }
+ /* Initialize the tree structure metadata information. */
+ orig_lsn = qmeta->dbmeta.lsn;
+ memset(qmeta, 0, sizeof(QMETA));
+ ZERO_LSN(qmeta->dbmeta.lsn);
+ qmeta->dbmeta.pgno = base_pgno;
+ qmeta->dbmeta.magic = DB_QAMMAGIC;
+ qmeta->dbmeta.version = DB_QAMVERSION;
+ qmeta->dbmeta.pagesize = dbp->pgsize;
+ qmeta->dbmeta.type = P_QAMMETA;
+ qmeta->re_pad = t->re_pad;
+ qmeta->re_len = t->re_len;
+ qmeta->rec_page = CALC_QAM_RECNO_PER_PAGE(dbp);
+ qmeta->cur_recno = 1;
+ qmeta->first_recno = 1;
+ qmeta->page_ext = t->page_ext;
+ t->rec_page = qmeta->rec_page;
+ memcpy(qmeta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN);
+
+ /* Verify that we can fit at least one record per page. */
+ if (QAM_RECNO_PER_PAGE(dbp) < 1) {
+ __db_err(dbp->dbenv,
+ "Record size of %lu too large for page size of %lu",
+ (u_long)t->re_len, (u_long)dbp->pgsize);
+ (void)memp_fput(dbp->mpf, (PAGE *)qmeta, 0);
+ ret = EINVAL;
+ goto err;
+ }
+
+ if ((ret = __db_log_page(dbp,
+ name, &orig_lsn, base_pgno, (PAGE *)qmeta)) != 0)
+ goto err;
+
+ /* Release the metadata page. */
+ if ((ret = memp_fput(dbp->mpf, (PAGE *)qmeta, DB_MPOOL_DIRTY)) != 0)
+ goto err;
+ DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, name);
+
+ /*
+ * Flush the metadata page to disk.
+ *
+ * !!!
+ * It's not useful to return not-yet-flushed here -- convert it to
+ * an error.
+ */
+ if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE) {
+ __db_err(dbp->dbenv, "Flush of metapage failed");
+ ret = EINVAL;
+ }
+ DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name);
+
+done: t->q_meta = base_pgno;
+ t->q_root = base_pgno + 1;
+
+ /* Setup information needed to open extents. */
+ if (t->page_ext != 0) {
+ t->finfo.pgcookie = &t->pgcookie;
+ t->finfo.fileid = NULL;
+ t->finfo.lsn_offset = 0;
+
+ t->pginfo.db_pagesize = dbp->pgsize;
+ t->pginfo.needswap = F_ISSET(dbp, DB_AM_SWAP);
+ t->pgcookie.data = &t->pginfo;
+ t->pgcookie.size = sizeof(DB_PGINFO);
+
+ if ((ret = __os_strdup(dbp->dbenv, name, &t->path)) != 0)
+ goto err;
+ t->dir = t->path;
+ if ((t->name = __db_rpath(t->path)) == NULL) {
+ t->name = t->path;
+ t->dir = PATH_DOT;
+ } else
+ *t->name++ = '\0';
+
+ if (mode == 0)
+ mode = __db_omode("rwrw--");
+ t->mode = mode;
+ }
+
+err:
+DB_TEST_RECOVERY_LABEL
+ /* Don't hold the meta page long term. */
+ (void)__LPUT(dbc, metalock);
+
+ if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret);
+}
+
+/*
+ * __qam_metachk --
+ *
+ * PUBLIC: int __qam_metachk __P((DB *, const char *, QMETA *));
+ */
+int
+__qam_metachk(dbp, name, qmeta)
+ DB *dbp;
+ const char *name;
+ QMETA *qmeta;
+{
+ DB_ENV *dbenv;
+ u_int32_t vers;
+ int ret;
+
+ dbenv = dbp->dbenv;
+
+ /*
+ * At this point, all we know is that the magic number is for a Queue.
+ * Check the version, the database may be out of date.
+ */
+ vers = qmeta->dbmeta.version;
+ if (F_ISSET(dbp, DB_AM_SWAP))
+ M_32_SWAP(vers);
+ switch (vers) {
+ case 1:
+ case 2:
+ __db_err(dbenv,
+ "%s: queue version %lu requires a version upgrade",
+ name, (u_long)vers);
+ return (DB_OLD_VERSION);
+ case 3:
+ break;
+ default:
+ __db_err(dbenv,
+ "%s: unsupported qam version: %lu", name, (u_long)vers);
+ return (EINVAL);
+ }
+
+ /* Swap the page if we need to. */
+ if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __qam_mswap((PAGE *)qmeta)) != 0)
+ return (ret);
+
+ /* Check the type. */
+ if (dbp->type != DB_QUEUE && dbp->type != DB_UNKNOWN)
+ return (EINVAL);
+ dbp->type = DB_QUEUE;
+ DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE);
+
+ /* Set the page size. */
+ dbp->pgsize = qmeta->dbmeta.pagesize;
+
+ /* Copy the file's ID. */
+ memcpy(dbp->fileid, qmeta->dbmeta.uid, DB_FILE_ID_LEN);
+
+ return (0);
+}
diff --git a/db/qam/qam_rec.c b/db/qam/qam_rec.c
new file mode 100644
index 000000000..4d330f586
--- /dev/null
+++ b/db/qam/qam_rec.c
@@ -0,0 +1,732 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_rec.c,v 11.34 2001/01/19 18:01:59 bostic Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_shash.h"
+#include "lock.h"
+#include "db_am.h"
+#include "qam.h"
+#include "log.h"
+
+/*
+ * __qam_inc_recover --
+ * Recovery function for inc.
+ *
+ * PUBLIC: int __qam_inc_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_inc_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_inc_args *argp;
+ DB *file_dbp;
+ DBC *dbc;
+ DB_LOCK lock;
+ DB_MPOOLFILE *mpf;
+ QMETA *meta;
+ db_pgno_t metapg;
+ int cmp_p, modified, ret;
+
+ COMPQUIET(info, NULL);
+ REC_PRINT(__qam_inc_print);
+ REC_INTRO(__qam_inc_read, 1);
+
+ metapg = ((QUEUE *)file_dbp->q_internal)->q_meta;
+
+ if ((ret = __db_lget(dbc,
+ LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ goto done;
+ if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0) {
+ if (DB_REDO(op)) {
+ if ((ret = memp_fget(mpf,
+ &metapg, DB_MPOOL_CREATE, &meta)) != 0) {
+ (void)__LPUT(dbc, lock);
+ goto out;
+ }
+ meta->dbmeta.pgno = metapg;
+ meta->dbmeta.type = P_QAMMETA;
+
+ } else {
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+ (void)__LPUT(dbc, lock);
+ goto out;
+ }
+ }
+
+ modified = 0;
+ cmp_p = log_compare(&LSN(meta), &argp->lsn);
+ CHECK_LSN(op, cmp_p, &LSN(meta), &argp->lsn);
+
+ /*
+ * The cur_recno never goes backwards. It is a point of
+ * contention among appenders. If one fails cur_recno will
+ * most likely be beyond that one when it aborts.
+ * We move it ahead on either an abort or a commit
+ * and make the LSN reflect that fact.
+ */
+ if (cmp_p == 0) {
+ modified = 1;
+ meta->cur_recno++;
+ if (meta->cur_recno == RECNO_OOB)
+ meta->cur_recno++;
+ meta->dbmeta.lsn = *lsnp;
+ }
+ if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)))
+ goto out;
+
+ (void)__LPUT(dbc, lock);
+
+done: *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: REC_CLOSE;
+}
+
+/*
+ * __qam_incfirst_recover --
+ * Recovery function for incfirst.
+ *
+ * PUBLIC: int __qam_incfirst_recover
+ * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_incfirst_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_incfirst_args *argp;
+ DB *file_dbp;
+ DBC *dbc;
+ DB_LOCK lock;
+ DB_MPOOLFILE *mpf;
+ QMETA *meta;
+ QUEUE_CURSOR *cp;
+ db_pgno_t metapg;
+ int exact, modified, ret, rec_ext;
+
+ COMPQUIET(info, NULL);
+ REC_PRINT(__qam_incfirst_print);
+ REC_INTRO(__qam_incfirst_read, 1);
+
+ metapg = ((QUEUE *)file_dbp->q_internal)->q_meta;
+
+ if ((ret = __db_lget(dbc,
+ LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ goto done;
+ if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0) {
+ if (DB_REDO(op)) {
+ if ((ret = memp_fget(mpf,
+ &metapg, DB_MPOOL_CREATE, &meta)) != 0) {
+ (void)__LPUT(dbc, lock);
+ goto out;
+ }
+ meta->dbmeta.pgno = metapg;
+ meta->dbmeta.type = P_QAMMETA;
+ } else {
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+ (void)__LPUT(dbc, lock);
+ goto out;
+ }
+ }
+
+ modified = 0;
+
+ /*
+ * Only move first_recno backwards so we pick up the aborted delete.
+ * When going forward we need to be careful since
+ * we may have bumped over a locked record.
+ */
+ if (DB_UNDO(op)) {
+ if (QAM_BEFORE_FIRST(meta, argp->recno)) {
+ meta->first_recno = argp->recno;
+ modified = 1;
+ }
+ } else {
+ if (log_compare(&LSN(meta), lsnp) < 0) {
+ LSN(meta) = *lsnp;
+ modified = 1;
+ }
+ rec_ext = 0;
+ if (meta->page_ext != 0)
+ rec_ext = meta->page_ext * meta->rec_page;
+ cp = (QUEUE_CURSOR *)dbc->internal;
+ if (meta->first_recno == RECNO_OOB)
+ meta->first_recno++;
+ while (meta->first_recno != meta->cur_recno
+ && !QAM_BEFORE_FIRST(meta, argp->recno + 1)) {
+ if ((ret = __qam_position(dbc,
+ &meta->first_recno, QAM_READ, &exact)) != 0)
+ goto out;
+ if (cp->page != NULL)
+ __qam_fput(file_dbp, cp->pgno, cp->page, 0);
+
+ if (exact == 1)
+ break;
+ if (cp->page != NULL &&
+ rec_ext != 0 && meta->first_recno % rec_ext == 0)
+ if ((ret =
+ __qam_fremove(file_dbp, cp->pgno)) != 0)
+ goto out;
+ meta->first_recno++;
+ if (meta->first_recno == RECNO_OOB)
+ meta->first_recno++;
+ modified = 1;
+ }
+ }
+
+ if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)))
+ goto out;
+
+ (void)__LPUT(dbc, lock);
+
+done: *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: REC_CLOSE;
+}
+
+/*
+ * __qam_mvptr_recover --
+ * Recovery function for mvptr.
+ *
+ * PUBLIC: int __qam_mvptr_recover
+ * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_mvptr_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_mvptr_args *argp;
+ DB *file_dbp;
+ DBC *dbc;
+ DB_LOCK lock;
+ DB_MPOOLFILE *mpf;
+ QMETA *meta;
+ db_pgno_t metapg;
+ int cmp_p, modified, ret;
+
+ COMPQUIET(info, NULL);
+ REC_PRINT(__qam_mvptr_print);
+ REC_INTRO(__qam_mvptr_read, 1);
+
+ metapg = ((QUEUE *)file_dbp->q_internal)->q_meta;
+
+ if ((ret = __db_lget(dbc,
+ LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ goto done;
+ if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0) {
+ if (DB_REDO(op)) {
+ if ((ret = memp_fget(mpf,
+ &metapg, DB_MPOOL_CREATE, &meta)) != 0) {
+ (void)__LPUT(dbc, lock);
+ goto out;
+ }
+ meta->dbmeta.pgno = metapg;
+ meta->dbmeta.type = P_QAMMETA;
+ } else {
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+ (void)__LPUT(dbc, lock);
+ goto out;
+ }
+ }
+
+ modified = 0;
+ cmp_p = log_compare(&meta->dbmeta.lsn, &argp->metalsn);
+
+ /*
+ * We never undo a movement of one of the pointers.
+ * Just move them along regardless of abort/commit.
+ */
+ if (cmp_p == 0) {
+ if (argp->opcode & QAM_SETFIRST)
+ meta->first_recno = argp->new_first;
+
+ if (argp->opcode & QAM_SETCUR)
+ meta->cur_recno = argp->new_cur;
+
+ modified = 1;
+ meta->dbmeta.lsn = *lsnp;
+ }
+
+ if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)))
+ goto out;
+
+ (void)__LPUT(dbc, lock);
+
+done: *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: REC_CLOSE;
+}
+/*
+ * __qam_del_recover --
+ * Recovery function for del.
+ * Non-extent version or if there is no data (zero len).
+ *
+ * PUBLIC: int __qam_del_recover
+ * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_del_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_del_args *argp;
+ DB *file_dbp;
+ DBC *dbc;
+ DB_LOCK lock;
+ DB_MPOOLFILE *mpf;
+ QAMDATA *qp;
+ QMETA *meta;
+ QPAGE *pagep;
+ db_pgno_t metapg;
+ int cmp_n, modified, ret;
+
+ COMPQUIET(info, NULL);
+ REC_PRINT(__qam_del_print);
+ REC_INTRO(__qam_del_read, 1);
+
+ if ((ret = __qam_fget(file_dbp,
+ &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+
+ modified = 0;
+ if (pagep->pgno == PGNO_INVALID) {
+ pagep->pgno = argp->pgno;
+ pagep->type = P_QAMDATA;
+ modified = 1;
+ }
+
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+
+ if (DB_UNDO(op)) {
+ /* make sure first is behind us */
+ metapg = ((QUEUE *)file_dbp->q_internal)->q_meta;
+ if ((ret = __db_lget(dbc,
+ LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ return (ret);
+ if ((ret = memp_fget(file_dbp->mpf, &metapg, 0, &meta)) != 0) {
+ (void)__LPUT(dbc, lock);
+ goto done;
+ }
+ if (meta->first_recno == RECNO_OOB ||
+ (QAM_BEFORE_FIRST(meta, argp->recno)
+ && (meta->first_recno <= meta->cur_recno
+ || meta->first_recno -
+ argp->recno < argp->recno - meta->cur_recno))) {
+ meta->first_recno = argp->recno;
+ (void)memp_fput(file_dbp->mpf, meta, DB_MPOOL_DIRTY);
+ } else
+ (void)memp_fput(file_dbp->mpf, meta, 0);
+ (void)__LPUT(dbc, lock);
+
+ /* Need to undo delete - mark the record as present */
+ qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx);
+ F_SET(qp, QAM_VALID);
+
+ /*
+ * Move the LSN back to this point; do not move it forward.
+ * Only move it back if we're in recovery. If we're in
+ * an abort, because we don't hold a page lock, we could
+ * foul up a concurrent put. Having too late an LSN
+ * is harmless in queue except when we're determining
+ * what we need to roll forward during recovery. [#2588]
+ */
+ if (op == DB_TXN_BACKWARD_ROLL && cmp_n < 0)
+ LSN(pagep) = argp->lsn;
+ modified = 1;
+ } else if (cmp_n > 0 && DB_REDO(op)) {
+ /* Need to redo delete - clear the valid bit */
+ qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx);
+ F_CLR(qp, QAM_VALID);
+ LSN(pagep) = *lsnp;
+ modified = 1;
+ }
+ if ((ret = __qam_fput(file_dbp,
+ argp->pgno, pagep, modified ? DB_MPOOL_DIRTY : 0)))
+ goto out;
+
+done: *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: REC_CLOSE;
+}
+/*
+ * __qam_delext_recover --
+ * Recovery function for del in an extent based queue.
+ *
+ * PUBLIC: int __qam_delext_recover __P((DB_ENV *,
+ * PUBLIC: DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_delext_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_delext_args *argp;
+ DB *file_dbp;
+ DBC *dbc;
+ DB_LOCK lock;
+ DB_MPOOLFILE *mpf;
+ QAMDATA *qp;
+ QMETA *meta;
+ QPAGE *pagep;
+ db_pgno_t metapg;
+ int cmp_n, modified, ret;
+
+ COMPQUIET(info, NULL);
+ REC_PRINT(__qam_delext_print);
+ REC_INTRO(__qam_delext_read, 1);
+
+ if ((ret = __qam_fget(file_dbp,
+ &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+
+ modified = 0;
+ if (pagep->pgno == PGNO_INVALID) {
+ pagep->pgno = argp->pgno;
+ pagep->type = P_QAMDATA;
+ modified = 1;
+ }
+
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+
+ if (DB_UNDO(op)) {
+ /* make sure first is behind us */
+ metapg = ((QUEUE *)file_dbp->q_internal)->q_meta;
+ if ((ret = __db_lget(dbc,
+ LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0)
+ return (ret);
+ if ((ret = memp_fget(file_dbp->mpf, &metapg, 0, &meta)) != 0) {
+ (void)__LPUT(dbc, lock);
+ goto done;
+ }
+ if (meta->first_recno == RECNO_OOB ||
+ (QAM_BEFORE_FIRST(meta, argp->recno)
+ && (meta->first_recno <= meta->cur_recno
+ || meta->first_recno -
+ argp->recno < argp->recno - meta->cur_recno))) {
+ meta->first_recno = argp->recno;
+ (void)memp_fput(file_dbp->mpf, meta, DB_MPOOL_DIRTY);
+ } else
+ (void)memp_fput(file_dbp->mpf, meta, 0);
+ (void)__LPUT(dbc, lock);
+
+ if ((ret = __qam_pitem(dbc, pagep,
+ argp->indx, argp->recno, &argp->data)) != 0)
+ goto done;
+
+ /*
+ * Move the LSN back to this point; do not move it forward.
+ * Only move it back if we're in recovery. If we're in
+ * an abort, because we don't hold a page lock, we could
+ * foul up a concurrent put. Having too late an LSN
+ * is harmless in queue except when we're determining
+ * what we need to roll forward during recovery. [#2588]
+ */
+ if (op == DB_TXN_BACKWARD_ROLL && cmp_n < 0)
+ LSN(pagep) = argp->lsn;
+ modified = 1;
+ } else if (cmp_n > 0 && DB_REDO(op)) {
+ /* Need to redo delete - clear the valid bit */
+ qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx);
+ F_CLR(qp, QAM_VALID);
+ LSN(pagep) = *lsnp;
+ modified = 1;
+ }
+ if ((ret = __qam_fput(file_dbp,
+ argp->pgno, pagep, modified ? DB_MPOOL_DIRTY : 0)))
+ goto out;
+
+done: *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: REC_CLOSE;
+}
+
+/*
+ * __qam_add_recover --
+ * Recovery function for add.
+ *
+ * PUBLIC: int __qam_add_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_add_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_add_args *argp;
+ DB *file_dbp;
+ DBC *dbc;
+ DB_MPOOLFILE *mpf;
+ QAMDATA *qp;
+ QMETA *meta;
+ QPAGE *pagep;
+ db_pgno_t metapg;
+ int cmp_n, modified, ret;
+
+ COMPQUIET(info, NULL);
+ REC_PRINT(__qam_add_print);
+ REC_INTRO(__qam_add_read, 1);
+
+ modified = 0;
+ if ((ret = __qam_fget(file_dbp,
+ &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+
+ if (pagep->pgno == PGNO_INVALID) {
+ pagep->pgno = argp->pgno;
+ pagep->type = P_QAMDATA;
+ modified = 1;
+ }
+
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+
+ if (cmp_n > 0 && DB_REDO(op)) {
+ /* Need to redo add - put the record on page */
+ if ((ret = __qam_pitem(dbc, pagep, argp->indx, argp->recno,
+ &argp->data)) != 0)
+ goto err;
+ LSN(pagep) = *lsnp;
+ modified = 1;
+ /* Make sure first pointer includes this record. */
+ metapg = ((QUEUE *)file_dbp->q_internal)->q_meta;
+ if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0)
+ goto err;
+ if (QAM_BEFORE_FIRST(meta, argp->recno)) {
+ meta->first_recno = argp->recno;
+ if ((ret = memp_fput(mpf, meta, DB_MPOOL_DIRTY)) != 0)
+ goto err;
+ } else
+ if ((ret = memp_fput(mpf, meta, 0)) != 0)
+ goto err;
+
+ } else if (DB_UNDO(op)) {
+ /*
+ * Need to undo add
+ * If this was an overwrite, put old record back.
+ * Otherwise just clear the valid bit
+ */
+ if (argp->olddata.size != 0) {
+ if ((ret = __qam_pitem(dbc, pagep,
+ argp->indx, argp->recno, &argp->olddata)) != 0)
+ goto err;
+
+ if (!(argp->vflag & QAM_VALID)) {
+ qp = QAM_GET_RECORD(
+ file_dbp, pagep, argp->indx);
+ F_CLR(qp, QAM_VALID);
+ }
+ modified = 1;
+ } else {
+ qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx);
+ qp->flags = 0;
+ modified = 1;
+ }
+
+ /*
+ * Move the LSN back to this point; do not move it forward.
+ * Only move it back if we're in recovery. If we're in
+ * an abort, because we don't hold a page lock, we could
+ * foul up a concurrent put. Having too late an LSN
+ * is harmless in queue except when we're determining
+ * what we need to roll forward during recovery. [#2588]
+ */
+ if (op == DB_TXN_BACKWARD_ROLL && cmp_n < 0)
+ LSN(pagep) = argp->lsn;
+ }
+
+err: if ((ret = __qam_fput(file_dbp,
+ argp->pgno, pagep, modified ? DB_MPOOL_DIRTY : 0)))
+ goto out;
+
+done: *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: REC_CLOSE;
+}
+/*
+ * __qam_delete_recover --
+ * Recovery function for delete of an extent.
+ *
+ * PUBLIC: int __qam_delete_recover
+ * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_delete_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_delete_args *argp;
+ int ret;
+ char *backup, *real_back, *real_name;
+
+ COMPQUIET(info, NULL);
+
+ REC_PRINT(__qam_delete_print);
+
+ backup = real_back = real_name = NULL;
+ if ((ret = __qam_delete_read(dbenv, dbtp->data, &argp)) != 0)
+ goto out;
+
+ if (DB_REDO(op)) {
+ /*
+ * On a recovery, as we recreate what was going on, we
+ * recreate the creation of the file. And so, even though
+ * it committed, we need to delete it. Try to delete it,
+ * but it is not an error if that delete fails.
+ */
+ if ((ret = __db_appname(dbenv, DB_APP_DATA,
+ NULL, argp->name.data, 0, NULL, &real_name)) != 0)
+ goto out;
+ if (__os_exists(real_name, NULL) == 0) {
+ if ((ret = __os_unlink(dbenv, real_name)) != 0)
+ goto out;
+ }
+ } else if (DB_UNDO(op)) {
+ /*
+ * Trying to undo. File may or may not have been deleted.
+ * Try to move the backup to the original. If the backup
+ * exists, then this is right. If it doesn't exist, then
+ * nothing will happen and that's OK.
+ */
+ if ((ret = __db_backup_name(dbenv, argp->name.data,
+ &backup, &argp->lsn)) != 0)
+ goto out;
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0)
+ goto out;
+ if ((ret = __db_appname(dbenv, DB_APP_DATA,
+ NULL, argp->name.data, 0, NULL, &real_name)) != 0)
+ goto out;
+ if (__os_exists(real_back, NULL) == 0)
+ if ((ret =
+ __os_rename(dbenv, real_back, real_name)) != 0)
+ goto out;
+ }
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: if (argp != NULL)
+ __os_free(argp, 0);
+ if (backup != NULL)
+ __os_freestr(backup);
+ if (real_back != NULL)
+ __os_freestr(real_back);
+ if (real_name != NULL)
+ __os_freestr(real_name);
+ return (ret);
+}
+/*
+ * __qam_rename_recover --
+ * Recovery function for rename.
+ *
+ * PUBLIC: int __qam_rename_recover
+ * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+ */
+int
+__qam_rename_recover(dbenv, dbtp, lsnp, op, info)
+ DB_ENV *dbenv;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ db_recops op;
+ void *info;
+{
+ __qam_rename_args *argp;
+ char *new_name, *real_name;
+ int ret;
+
+ COMPQUIET(info, NULL);
+
+ REC_PRINT(__qam_rename_print);
+
+ new_name = real_name = NULL;
+
+ if ((ret = __qam_rename_read(dbenv, dbtp->data, &argp)) != 0)
+ goto out;
+
+ if (DB_REDO(op)) {
+ if ((ret = __db_appname(dbenv, DB_APP_DATA,
+ NULL, argp->name.data, 0, NULL, &real_name)) != 0)
+ goto out;
+ if (__os_exists(real_name, NULL) == 0) {
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, argp->newname.data,
+ 0, NULL, &new_name)) != 0)
+ goto out;
+ if ((ret = __os_rename(dbenv,
+ real_name, new_name)) != 0)
+ goto out;
+ }
+ } else {
+ if ((ret = __db_appname(dbenv, DB_APP_DATA,
+ NULL, argp->newname.data, 0, NULL, &new_name)) != 0)
+ goto out;
+ if (__os_exists(new_name, NULL) == 0) {
+ if ((ret = __db_appname(dbenv,
+ DB_APP_DATA, NULL, argp->name.data,
+ 0, NULL, &real_name)) != 0)
+ goto out;
+ if ((ret = __os_rename(dbenv,
+ new_name, real_name)) != 0)
+ goto out;
+ }
+ }
+
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: if (argp != NULL)
+ __os_free(argp, 0);
+
+ if (new_name != NULL)
+ __os_free(new_name, 0);
+
+ if (real_name != NULL)
+ __os_free(real_name, 0);
+
+ return (ret);
+}
diff --git a/db/qam/qam_stat.c b/db/qam/qam_stat.c
new file mode 100644
index 000000000..865f477c1
--- /dev/null
+++ b/db/qam/qam_stat.c
@@ -0,0 +1,201 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_stat.c,v 11.16 2001/01/10 04:50:54 ubell Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_shash.h"
+#include "db_am.h"
+#include "lock.h"
+#include "qam.h"
+
+/*
+ * __qam_stat --
+ * Gather/print the qam statistics
+ *
+ * PUBLIC: int __qam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
+ */
+int
+__qam_stat(dbp, spp, db_malloc, flags)
+ DB *dbp;
+ void *spp;
+ void *(*db_malloc) __P((size_t));
+ u_int32_t flags;
+{
+ QUEUE *t;
+ DBC *dbc;
+ DB_LOCK lock;
+ DB_QUEUE_STAT *sp;
+ PAGE *h;
+ QAMDATA *qp, *ep;
+ QMETA *meta;
+ db_indx_t indx;
+ db_pgno_t first, last, pgno, pg_ext, stop;
+ u_int32_t re_len;
+ int ret, t_ret;
+
+ PANIC_CHECK(dbp->dbenv);
+ DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
+
+ t = dbp->q_internal;
+ sp = NULL;
+ lock.off = LOCK_INVALID;
+
+ /* Check for invalid flags. */
+ if ((ret = __db_statchk(dbp, flags)) != 0)
+ return (ret);
+
+ if (spp == NULL)
+ return (0);
+
+ /* Acquire a cursor. */
+ if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
+ return (ret);
+
+ DEBUG_LWRITE(dbc, NULL, "qam_stat", NULL, NULL, flags);
+
+ /* Allocate and clear the structure. */
+ if ((ret = __os_malloc(dbp->dbenv, sizeof(*sp), db_malloc, &sp)) != 0)
+ goto err;
+ memset(sp, 0, sizeof(*sp));
+
+ re_len = ((QUEUE *)dbp->q_internal)->re_len;
+ if (flags == DB_CACHED_COUNTS) {
+ if ((ret = __db_lget(dbc,
+ 0, t->q_meta, DB_LOCK_READ, 0, &lock)) != 0)
+ goto err;
+ if ((ret =
+ memp_fget(dbp->mpf, &t->q_meta, 0, (PAGE **)&meta)) != 0)
+ goto err;
+ sp->qs_nkeys = meta->dbmeta.key_count;
+ sp->qs_ndata = meta->dbmeta.record_count;
+
+ goto done;
+ }
+
+ /* Determine the last page of the database. */
+ if ((ret = __db_lget(dbc,
+ 0, t->q_meta, DB_LOCK_READ, 0, &lock)) != 0)
+ goto err;
+ if ((ret = memp_fget(dbp->mpf, &t->q_meta, 0, (PAGE **)&meta)) != 0)
+ goto err;
+
+ first = QAM_RECNO_PAGE(dbp, meta->first_recno);
+ last = QAM_RECNO_PAGE(dbp, meta->cur_recno);
+
+ if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0)
+ goto err;
+ (void)__LPUT(dbc, lock);
+
+ pgno = first;
+ if (first > last)
+ stop = QAM_RECNO_PAGE(dbp, UINT32_T_MAX);
+ else
+ stop = last;
+
+ /* Dump each page. */
+ pg_ext = ((QUEUE *)dbp->q_internal)->page_ext;
+begin:
+ /* Walk through the pages and count. */
+ for (; pgno <= stop; ++pgno) {
+ if ((ret =
+ __db_lget(dbc,
+ 0, pgno, DB_LOCK_READ, 0, &lock)) != 0)
+ goto err;
+ ret = __qam_fget(dbp, &pgno, DB_MPOOL_EXTENT, &h);
+ if (ret == ENOENT) {
+ pgno += pg_ext - 1;
+ continue;
+ }
+ if (ret == EINVAL) {
+ pgno += pg_ext - ((pgno - 1) % pg_ext) - 1;
+ continue;
+ }
+ if (ret == EIO && first == last && pg_ext == 0)
+ break;
+ if (ret != 0)
+ goto err;
+
+ ++sp->qs_pages;
+
+ ep = (QAMDATA *)((u_int8_t *)h + dbp->pgsize - re_len);
+ for (indx = 0, qp = QAM_GET_RECORD(dbp, h, indx);
+ qp <= ep;
+ ++indx, qp = QAM_GET_RECORD(dbp, h, indx)) {
+ if (F_ISSET(qp, QAM_VALID))
+ sp->qs_ndata++;
+ else
+ sp->qs_pgfree += re_len;
+ }
+
+ if ((ret = __qam_fput(dbp, pgno, h, 0)) != 0)
+ goto err;
+ (void)__LPUT(dbc, lock);
+ }
+ if (first > last) {
+ pgno = 1;
+ stop = last;
+ first = last;
+ goto begin;
+ }
+
+ /* Get the meta-data page. */
+ if ((ret = __db_lget(dbc,
+ 0, t->q_meta, F_ISSET(dbp, DB_AM_RDONLY) ?
+ DB_LOCK_READ : DB_LOCK_WRITE, 0, &lock)) != 0)
+ goto err;
+ if ((ret = memp_fget(dbp->mpf, &t->q_meta, 0, (PAGE **)&meta)) != 0)
+ goto err;
+
+ /* Get the metadata fields. */
+ sp->qs_magic = meta->dbmeta.magic;
+ sp->qs_version = meta->dbmeta.version;
+ sp->qs_metaflags = meta->dbmeta.flags;
+ sp->qs_pagesize = meta->dbmeta.pagesize;
+ sp->qs_re_len = meta->re_len;
+ sp->qs_re_pad = meta->re_pad;
+ sp->qs_first_recno = meta->first_recno;
+ sp->qs_cur_recno = meta->cur_recno;
+ sp->qs_nkeys = sp->qs_ndata;
+ if (!F_ISSET(dbp, DB_AM_RDONLY))
+ meta->dbmeta.key_count =
+ meta->dbmeta.record_count = sp->qs_ndata;
+
+done:
+ /* Discard the meta-data page. */
+ if ((ret = memp_fput(dbp->mpf,
+ meta, F_ISSET(dbp, DB_AM_RDONLY) ? 0 : DB_MPOOL_DIRTY)) != 0)
+ goto err;
+ (void)__LPUT(dbc, lock);
+
+ *(DB_QUEUE_STAT **)spp = sp;
+ ret = 0;
+
+ if (0) {
+err: if (sp != NULL)
+ __os_free(sp, sizeof(*sp));
+ }
+
+ if (lock.off != LOCK_INVALID)
+ (void)__LPUT(dbc, lock);
+
+ if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret);
+}
diff --git a/db/qam/qam_upgrade.c b/db/qam/qam_upgrade.c
new file mode 100644
index 000000000..f49bfe88d
--- /dev/null
+++ b/db/qam/qam_upgrade.c
@@ -0,0 +1,111 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_upgrade.c,v 11.7 2000/11/30 00:58:44 ubell Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <limits.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_swap.h"
+#include "db_am.h"
+#include "db_upgrade.h"
+
+/*
+ * __qam_31_qammeta --
+ * Upgrade the database from version 1 to version 2.
+ *
+ * PUBLIC: int __qam_31_qammeta __P((DB *, char *, u_int8_t *));
+ */
+int
+__qam_31_qammeta(dbp, real_name, buf)
+ DB *dbp;
+ char *real_name;
+ u_int8_t *buf;
+{
+ QMETA31 *newmeta;
+ QMETA30 *oldmeta;
+
+ COMPQUIET(dbp, NULL);
+ COMPQUIET(real_name, NULL);
+
+ newmeta = (QMETA31 *)buf;
+ oldmeta = (QMETA30 *)buf;
+
+ /*
+ * Copy the fields to their new locations.
+ * They may overlap so start at the bottom and use memmove().
+ */
+ newmeta->rec_page = oldmeta->rec_page;
+ newmeta->re_pad = oldmeta->re_pad;
+ newmeta->re_len = oldmeta->re_len;
+ newmeta->cur_recno = oldmeta->cur_recno;
+ newmeta->first_recno = oldmeta->first_recno;
+ newmeta->start = oldmeta->start;
+ memmove(newmeta->dbmeta.uid,
+ oldmeta->dbmeta.uid, sizeof(oldmeta->dbmeta.uid));
+ newmeta->dbmeta.flags = oldmeta->dbmeta.flags;
+ newmeta->dbmeta.record_count = 0;
+ newmeta->dbmeta.key_count = 0;
+ ZERO_LSN(newmeta->dbmeta.unused3);
+
+ /* Update the version. */
+ newmeta->dbmeta.version = 2;
+
+ return (0);
+}
+
+/*
+ * __qam_32_qammeta --
+ * Upgrade the database from version 2 to version 3.
+ *
+ * PUBLIC: int __qam_32_qammeta __P((DB *, char *, u_int8_t *));
+ */
+int
+__qam_32_qammeta(dbp, real_name, buf)
+ DB *dbp;
+ char *real_name;
+ u_int8_t *buf;
+{
+ QMETA32 *newmeta;
+ QMETA31 *oldmeta;
+
+ COMPQUIET(dbp, NULL);
+ COMPQUIET(real_name, NULL);
+
+ newmeta = (QMETA32 *)buf;
+ oldmeta = (QMETA31 *)buf;
+
+ /*
+ * Copy the fields to their new locations.
+ * We are dropping the first field so move
+ * from the top.
+ */
+ newmeta->first_recno = oldmeta->first_recno;
+ newmeta->cur_recno = oldmeta->cur_recno;
+ newmeta->re_len = oldmeta->re_len;
+ newmeta->re_pad = oldmeta->re_pad;
+ newmeta->rec_page = oldmeta->rec_page;
+ newmeta->page_ext = 0;
+ /* cur_recno now points to the first free slot. */
+ newmeta->cur_recno++;
+ if (newmeta->first_recno == 0)
+ newmeta->first_recno = 1;
+
+ /* Update the version. */
+ newmeta->dbmeta.version = 3;
+
+ return (0);
+}
diff --git a/db/qam/qam_verify.c b/db/qam/qam_verify.c
new file mode 100644
index 000000000..a9a467d67
--- /dev/null
+++ b/db/qam/qam_verify.c
@@ -0,0 +1,194 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1999, 2000
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char revid[] = "$Id: qam_verify.c,v 1.17 2000/12/12 17:39:35 bostic Exp $";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_verify.h"
+#include "qam.h"
+#include "db_ext.h"
+
+/*
+ * __qam_vrfy_meta --
+ * Verify the queue-specific part of a metadata page.
+ *
+ * PUBLIC: int __qam_vrfy_meta __P((DB *, VRFY_DBINFO *, QMETA *,
+ * PUBLIC: db_pgno_t, u_int32_t));
+ */
+int
+__qam_vrfy_meta(dbp, vdp, meta, pgno, flags)
+ DB *dbp;
+ VRFY_DBINFO *vdp;
+ QMETA *meta;
+ db_pgno_t pgno;
+ u_int32_t flags;
+{
+ VRFY_PAGEINFO *pip;
+ int isbad, ret, t_ret;
+
+ if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
+ return (ret);
+ isbad = 0;
+
+ /*
+ * Queue can't be used in subdatabases, so if this isn't set
+ * something very odd is going on.
+ */
+ if (!F_ISSET(pip, VRFY_INCOMPLETE))
+ EPRINT((dbp->dbenv, "Queue databases must be one-per-file."));
+
+ /*
+ * cur_recno/rec_page
+ * Cur_recno may be one beyond the end of the page and
+ * we start numbering from 1.
+ */
+ if (vdp->last_pgno > 0 && meta->cur_recno > 0 &&
+ meta->cur_recno - 1 > meta->rec_page * vdp->last_pgno) {
+ EPRINT((dbp->dbenv,
+ "Current recno %lu references record past last page number %lu",
+ meta->cur_recno, vdp->last_pgno));
+ isbad = 1;
+ }
+
+ /*
+ * re_len: If this is bad, we can't safely verify queue data pages, so
+ * return DB_VERIFY_FATAL
+ */
+ if (ALIGN(meta->re_len + sizeof(QAMDATA) - 1, sizeof(u_int32_t)) *
+ meta->rec_page + sizeof(QPAGE) > dbp->pgsize) {
+ EPRINT((dbp->dbenv,
+ "Queue record length %lu impossibly high for page size and records per page",
+ meta->re_len));
+ ret = DB_VERIFY_FATAL;
+ goto err;
+ } else {
+ vdp->re_len = meta->re_len;
+ vdp->rec_page = meta->rec_page;
+ }
+
+err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
+ ret = t_ret;
+ return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret);
+}
+
+/*
+ * __qam_vrfy_data --
+ * Verify a queue data page.
+ *
+ * PUBLIC: int __qam_vrfy_data __P((DB *, VRFY_DBINFO *, QPAGE *,
+ * PUBLIC: db_pgno_t, u_int32_t));
+ */
+int
+__qam_vrfy_data(dbp, vdp, h, pgno, flags)
+ DB *dbp;
+ VRFY_DBINFO *vdp;
+ QPAGE *h;
+ db_pgno_t pgno;
+ u_int32_t flags;
+{
+ DB fakedb;
+ struct __queue fakeq;
+ QAMDATA *qp;
+ db_recno_t i;
+ u_int8_t qflags;
+
+ /*
+ * Not much to do here, except make sure that flags are reasonable.
+ *
+ * QAM_GET_RECORD assumes a properly initialized q_internal
+ * structure, however, and we don't have one, so we play
+ * some gross games to fake it out.
+ */
+ fakedb.q_internal = &fakeq;
+ fakeq.re_len = vdp->re_len;
+
+ for (i = 0; i < vdp->rec_page; i++) {
+ qp = QAM_GET_RECORD(&fakedb, h, i);
+ if ((u_int8_t *)qp >= (u_int8_t *)h + dbp->pgsize) {
+ EPRINT((dbp->dbenv,
+ "Queue record %lu extends past end of page %lu",
+ i, pgno));
+ return (DB_VERIFY_BAD);
+ }
+
+ qflags = qp->flags;
+ qflags &= !(QAM_VALID | QAM_SET);
+ if (qflags != 0) {
+ EPRINT((dbp->dbenv,
+ "Queue record %lu on page %lu has bad flags",
+ i, pgno));
+ return (DB_VERIFY_BAD);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * __qam_vrfy_structure --
+ * Verify a queue database structure, such as it is.
+ *
+ * PUBLIC: int __qam_vrfy_structure __P((DB *, VRFY_DBINFO *, u_int32_t));
+ */
+int
+__qam_vrfy_structure(dbp, vdp, flags)
+ DB *dbp;
+ VRFY_DBINFO *vdp;
+ u_int32_t flags;
+{
+ VRFY_PAGEINFO *pip;
+ db_pgno_t i;
+ int ret, isbad;
+
+ isbad = 0;
+
+ if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0)
+ return (ret);
+
+ if (pip->type != P_QAMMETA) {
+ EPRINT((dbp->dbenv,
+ "Queue database has no meta page"));
+ isbad = 1;
+ goto err;
+ }
+
+ if ((ret = __db_vrfy_pgset_inc(vdp->pgset, 0)) != 0)
+ goto err;
+
+ for (i = 1; i <= vdp->last_pgno; i++) {
+ /* Send feedback to the application about our progress. */
+ if (!LF_ISSET(DB_SALVAGE))
+ __db_vrfy_struct_feedback(dbp, vdp);
+
+ if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 ||
+ (ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
+ return (ret);
+ if (!F_ISSET(pip, VRFY_IS_ALLZEROES) &&
+ pip->type != P_QAMDATA) {
+ EPRINT((dbp->dbenv,
+ "Queue database page %lu of incorrect type %lu",
+ i, pip->type));
+ isbad = 1;
+ goto err;
+ } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, i)) != 0)
+ goto err;
+ }
+
+err: if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0)
+ return (ret);
+ return (isbad == 1 ? DB_VERIFY_BAD : 0);
+}