#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/btree.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
static int __ram_add __P((DBC *, db_recno_t *, DBT *, u_int32_t, u_int32_t));
static int __ram_source __P((DB *));
static int __ram_sread __P((DBC *, db_recno_t));
static int __ram_update __P((DBC *, db_recno_t, int));
#define CD_SET(cp) { \
if (F_ISSET(cp, C_RENUMBER)) \
F_SET(cp, C_DELETED); \
}
#define CD_CLR(cp) { \
if (F_ISSET(cp, C_RENUMBER)) { \
F_CLR(cp, C_DELETED); \
cp->order = INVALID_ORDER; \
} \
}
#define CD_ISSET(cp) \
(F_ISSET(cp, C_RENUMBER) && F_ISSET(cp, C_DELETED) ? 1 : 0)
#define C_LESSTHAN(cp1, cp2) \
(((cp1)->recno < (cp2)->recno) || \
(((cp1)->recno == (cp2)->recno) && \
((CD_ISSET((cp1)) && CD_ISSET((cp2)) && (cp1)->order < (cp2)->order) || \
(CD_ISSET((cp1)) && !CD_ISSET((cp2))))))
#define C_EQUAL(cp1, cp2) \
((cp1)->recno == (cp2)->recno && CD_ISSET((cp1)) == CD_ISSET((cp2)) && \
(!CD_ISSET((cp1)) || (cp1)->order == (cp2)->order))
#define CURADJ_LOG(dbc) \
(DBC_LOGGING((dbc)) && (dbc)->txn != NULL && (dbc)->txn->parent != NULL)
#define STACK_TO_CURSOR(cp, ret) { \
int __t_ret; \
(cp)->page = (cp)->csp->page; \
(cp)->pgno = (cp)->csp->page->pgno; \
(cp)->indx = (cp)->csp->indx; \
if ((__t_ret = __TLPUT(dbc, (cp)->lock)) != 0 && (ret) == 0) \
ret = __t_ret; \
(cp)->lock = (cp)->csp->lock; \
(cp)->lock_mode = (cp)->csp->lock_mode; \
}
int
__ram_open(dbp, txn, name, base_pgno, flags)
DB *dbp;
DB_TXN *txn;
const char *name;
db_pgno_t base_pgno;
u_int32_t flags;
{
BTREE *t;
DBC *dbc;
int ret, t_ret;
COMPQUIET(name, NULL);
t = dbp->bt_internal;
if ((ret = __bam_read_root(dbp, txn, base_pgno, flags)) != 0)
return (ret);
if (t->re_source != NULL && (ret = __ram_source(dbp)) != 0)
return (ret);
if (F_ISSET(dbp, DB_AM_SNAPSHOT)) {
if ((ret = __db_cursor(dbp, NULL, &dbc, 0)) != 0)
return (ret);
if ((ret = __ram_update(dbc,
DB_MAX_RECORDS, 0)) != 0 && ret == DB_NOTFOUND)
ret = 0;
if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0)
ret = t_ret;
}
return (ret);
}
int
__ram_append(dbc, key, data)
DBC *dbc;
DBT *key, *data;
{
BTREE_CURSOR *cp;
int ret;
cp = (BTREE_CURSOR *)dbc->internal;
ret = __ram_update(dbc, DB_MAX_RECORDS, 0);
if (ret == 0 || ret == DB_NOTFOUND)
ret = __ram_add(dbc, &cp->recno, data, DB_APPEND, 0);
if (ret == 0 && key != NULL)
ret = __db_retcopy(dbc->dbp->dbenv, key, &cp->recno,
sizeof(cp->recno), &dbc->rkey->data, &dbc->rkey->ulen);
return (ret);
}
int
__ramc_del(dbc)
DBC *dbc;
{
BKEYDATA bk;
BTREE *t;
BTREE_CURSOR *cp;
DB *dbp;
DB_LSN lsn;
DBT hdr, data;
int exact, nc, ret, stack, t_ret;
dbp = dbc->dbp;
cp = (BTREE_CURSOR *)dbc->internal;
t = dbp->bt_internal;
stack = 0;
if (CD_ISSET(cp))
return (DB_KEYEMPTY);
if ((ret = __bam_rsearch(dbc, &cp->recno, SR_DELETE, 1, &exact)) != 0)
goto err;
if (!exact) {
ret = DB_NOTFOUND;
goto err;
}
stack = 1;
if ((ret = __memp_dirty(dbp->mpf,
&cp->csp->page, dbc->txn, dbc->priority, 0)) != 0)
goto err;
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
if (B_DISSET(GET_BKEYDATA(dbp, cp->page, cp->indx)->type)) {
ret = DB_KEYEMPTY;
goto err;
}
if (F_ISSET(cp, C_RENUMBER)) {
if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0)
goto err;
if ((ret = __bam_adjust(dbc, -1)) != 0)
goto err;
if ((ret = __ram_ca(dbc, CA_DELETE, &nc)) != 0)
goto err;
if (nc > 0 &&
CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp, dbc->txn,
&lsn, 0, CA_DELETE, cp->root, cp->recno, cp->order)) != 0)
goto err;
if (NUM_ENT(cp->page) == 0 && PGNO(cp->page) != cp->root) {
ret = __bam_dpages(dbc, 0, 0);
stack = 0;
cp->page = NULL;
}
} else {
if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0)
goto err;
B_TSET_DELETED(bk.type, B_KEYDATA);
bk.len = 0;
DB_INIT_DBT(hdr, &bk, SSZA(BKEYDATA, data));
DB_INIT_DBT(data, "", 0);
if ((ret = __db_pitem(dbc,
cp->page, cp->indx, BKEYDATA_SIZE(0), &hdr, &data)) != 0)
goto err;
}
t->re_modified = 1;
err: if (stack && (t_ret = __bam_stkrel(dbc, STK_CLRDBC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
int
__ramc_get(dbc, key, data, flags, pgnop)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
db_pgno_t *pgnop;
{
BTREE_CURSOR *cp;
DB *dbp;
int cmp, exact, ret;
COMPQUIET(pgnop, NULL);
dbp = dbc->dbp;
cp = (BTREE_CURSOR *)dbc->internal;
LF_CLR(DB_MULTIPLE|DB_MULTIPLE_KEY);
retry: switch (flags) {
case DB_CURRENT:
if (CD_ISSET(cp))
return (DB_KEYEMPTY);
break;
case DB_NEXT_DUP:
if (!F_ISSET(dbc, DBC_OPD))
return (DB_NOTFOUND);
case DB_NEXT_NODUP:
case DB_NEXT:
flags = DB_NEXT;
if (CD_ISSET(cp)) {
CD_CLR(cp);
break;
}
if (cp->recno != RECNO_OOB) {
++cp->recno;
break;
}
case DB_FIRST:
flags = DB_NEXT;
cp->recno = 1;
break;
case DB_PREV_DUP:
if (!F_ISSET(dbc, DBC_OPD))
return (DB_NOTFOUND);
case DB_PREV_NODUP:
case DB_PREV:
flags = DB_PREV;
if (cp->recno != RECNO_OOB) {
if (cp->recno == 1) {
ret = DB_NOTFOUND;
goto err;
}
--cp->recno;
break;
}
case DB_LAST:
flags = DB_PREV;
if (((ret = __ram_update(dbc,
DB_MAX_RECORDS, 0)) != 0) && ret != DB_NOTFOUND)
goto err;
if ((ret = __bam_nrecs(dbc, &cp->recno)) != 0)
goto err;
if (cp->recno == 0) {
ret = DB_NOTFOUND;
goto err;
}
break;
case DB_GET_BOTHC:
if (F_ISSET(dbc, DBC_OPD)) {
cp->recno++;
break;
}
ret = DB_NOTFOUND;
goto err;
case DB_GET_BOTH:
case DB_GET_BOTH_RANGE:
if (F_ISSET(dbc, DBC_OPD)) {
cp->recno = 1;
break;
}
case DB_SET:
case DB_SET_RANGE:
if ((ret = __ram_getno(dbc, key, &cp->recno, 0)) != 0)
goto err;
break;
default:
ret = __db_unknown_flag(dbp->dbenv, "__ramc_get", flags);
goto err;
}
if ((flags == DB_NEXT || flags == DB_CURRENT) && ((ret =
__ram_update(dbc, cp->recno, 0)) != 0) && ret != DB_NOTFOUND)
goto err;
for (;; ++cp->recno) {
if ((ret = __bam_rsearch(dbc, &cp->recno,
F_ISSET(dbc, DBC_RMW) ? SR_FIND_WR : SR_FIND,
1, &exact)) != 0)
goto err;
if (!exact) {
ret = DB_NOTFOUND;
goto err;
}
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
if (B_DISSET(GET_BKEYDATA(dbp, cp->page, cp->indx)->type))
switch (flags) {
case DB_NEXT:
case DB_PREV:
(void)__bam_stkrel(dbc, STK_CLRDBC);
goto retry;
case DB_GET_BOTH:
case DB_GET_BOTH_RANGE:
if (F_ISSET(dbc, DBC_OPD)) {
(void)__bam_stkrel(dbc, STK_CLRDBC);
continue;
}
ret = DB_NOTFOUND;
goto err;
default:
ret = DB_KEYEMPTY;
goto err;
}
if (flags == DB_GET_BOTH ||
flags == DB_GET_BOTHC || flags == DB_GET_BOTH_RANGE) {
if ((ret = __bam_cmp(dbp, dbc->txn, data,
cp->page, cp->indx, __bam_defcmp, &cmp)) != 0)
return (ret);
if (cmp == 0)
break;
if (!F_ISSET(dbc, DBC_OPD)) {
ret = DB_NOTFOUND;
goto err;
}
(void)__bam_stkrel(dbc, STK_CLRDBC);
} else
break;
}
if (!F_ISSET(dbc, DBC_OPD) && !F_ISSET(key, DB_DBT_ISSET)) {
ret = __db_retcopy(dbp->dbenv,
key, &cp->recno, sizeof(cp->recno),
&dbc->rkey->data, &dbc->rkey->ulen);
F_SET(key, DB_DBT_ISSET);
}
err: CD_CLR(cp);
return (ret);
}
int
__ramc_put(dbc, key, data, flags, pgnop)
DBC *dbc;
DBT *key, *data;
u_int32_t flags;
db_pgno_t *pgnop;
{
BTREE_CURSOR *cp;
DB *dbp;
DB_ENV *dbenv;
DB_LSN lsn;
u_int32_t iiflags;
int exact, nc, ret, t_ret;
void *arg;
COMPQUIET(pgnop, NULL);
dbp = dbc->dbp;
dbenv = dbp->dbenv;
cp = (BTREE_CURSOR *)dbc->internal;
if (F_ISSET(dbc, DBC_OPD))
switch (flags) {
case DB_KEYFIRST:
cp->recno = 1;
flags = DB_BEFORE;
break;
case DB_KEYLAST:
if ((ret = __ram_add(dbc,
&cp->recno, data, DB_APPEND, 0)) != 0)
return (ret);
if (CURADJ_LOG(dbc) &&
(ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0,
CA_ICURRENT, cp->root, cp->recno, cp->order)) != 0)
return (ret);
return (0);
default:
break;
}
if (flags == DB_KEYFIRST ||
flags == DB_KEYLAST || flags == DB_NOOVERWRITE) {
ret = __ram_getno(dbc, key, &cp->recno, 1);
if (ret == 0 || ret == DB_NOTFOUND)
ret = __ram_add(dbc, &cp->recno, data, flags, 0);
return (ret);
}
if (CD_ISSET(cp))
iiflags = DB_BEFORE;
else
iiflags = flags;
split: if ((ret = __bam_rsearch(dbc, &cp->recno, SR_INSERT, 1, &exact)) != 0)
goto err;
DB_ASSERT(dbenv, exact || CD_ISSET(cp));
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
ret = __bam_iitem(dbc, key, data, iiflags, 0);
t_ret = __bam_stkrel(dbc, STK_CLRDBC);
if (t_ret != 0 && (ret == 0 || ret == DB_NEEDSPLIT))
ret = t_ret;
else if (ret == DB_NEEDSPLIT) {
arg = &cp->recno;
if ((ret = __bam_split(dbc, arg, NULL)) != 0)
goto err;
goto split;
}
if (ret != 0)
goto err;
switch (flags) {
case DB_AFTER:
if ((ret = __ram_ca(dbc, CA_IAFTER, &nc)) != 0)
goto err;
if (iiflags == DB_AFTER)
++cp->recno;
if (nc > 0 && CURADJ_LOG(dbc) &&
(ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0, CA_IAFTER,
cp->root, cp->recno, cp->order)) != 0)
goto err;
break;
case DB_BEFORE:
if ((ret = __ram_ca(dbc, CA_IBEFORE, &nc)) != 0)
goto err;
--cp->recno;
if (nc > 0 && CURADJ_LOG(dbc) &&
(ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0, CA_IBEFORE,
cp->root, cp->recno, cp->order)) != 0)
goto err;
break;
case DB_CURRENT:
if (!CD_ISSET(cp))
break;
if ((ret = __ram_ca(dbc, CA_ICURRENT, &nc)) != 0)
goto err;
if (nc > 0 && CURADJ_LOG(dbc) &&
(ret = __bam_rcuradj_log(dbp, dbc->txn, &lsn, 0,
CA_ICURRENT, cp->root, cp->recno, cp->order)) != 0)
goto err;
break;
default:
break;
}
if (!F_ISSET(dbc, DBC_OPD) &&
(flags == DB_AFTER || flags == DB_BEFORE) && key != NULL)
ret = __db_retcopy(dbenv, key, &cp->recno,
sizeof(cp->recno), &dbc->rkey->data, &dbc->rkey->ulen);
err: CD_CLR(cp);
return (ret);
}
int
__ram_ca(dbc_arg, op, foundp)
DBC *dbc_arg;
ca_recno_arg op;
int *foundp;
{
BTREE_CURSOR *cp, *cp_arg;
DB *dbp, *ldbp;
DB_ENV *dbenv;
DBC *dbc;
db_recno_t recno;
u_int32_t order;
int adjusted, found;
dbp = dbc_arg->dbp;
dbenv = dbp->dbenv;
cp_arg = (BTREE_CURSOR *)dbc_arg->internal;
recno = cp_arg->recno;
DB_ASSERT(dbenv, F_ISSET(cp_arg, C_RENUMBER));
MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
if (op == CA_DELETE) {
FIND_FIRST_DB_MATCH(dbenv, dbp, ldbp);
for (order = 1;
ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
ldbp = TAILQ_NEXT(ldbp, dblistlinks)) {
MUTEX_LOCK(dbenv, dbp->mutex);
TAILQ_FOREACH(dbc, &ldbp->active_queue, links) {
cp = (BTREE_CURSOR *)dbc->internal;
if (cp_arg->root == cp->root &&
recno == cp->recno && CD_ISSET(cp) &&
order <= cp->order &&
!MVCC_SKIP_CURADJ(dbc, cp->root))
order = cp->order + 1;
}
MUTEX_UNLOCK(dbenv, dbp->mutex);
}
} else
order = INVALID_ORDER;
FIND_FIRST_DB_MATCH(dbenv, dbp, ldbp);
for (found = 0;
ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
ldbp = TAILQ_NEXT(ldbp, dblistlinks)) {
MUTEX_LOCK(dbenv, dbp->mutex);
TAILQ_FOREACH(dbc, &ldbp->active_queue, links) {
cp = (BTREE_CURSOR *)dbc->internal;
if (cp_arg->root != cp->root ||
MVCC_SKIP_CURADJ(dbc, cp->root))
continue;
++found;
adjusted = 0;
switch (op) {
case CA_DELETE:
if (recno < cp->recno) {
--cp->recno;
if (recno == cp->recno && CD_ISSET(cp))
cp->order += order;
} else if (recno == cp->recno &&
!CD_ISSET(cp)) {
CD_SET(cp);
cp->order = order;
}
break;
case CA_IBEFORE:
if (C_EQUAL(cp_arg, cp)) {
++cp->recno;
adjusted = 1;
}
goto iafter;
case CA_ICURRENT:
DB_ASSERT(dbenv, CD_ISSET(cp_arg));
if (C_EQUAL(cp_arg, cp)) {
CD_CLR(cp);
break;
}
case CA_IAFTER:
iafter: if (!adjusted && C_LESSTHAN(cp_arg, cp)) {
++cp->recno;
adjusted = 1;
}
if (recno == cp->recno && adjusted)
cp->order -= (cp_arg->order - 1);
break;
}
}
MUTEX_UNLOCK(dbp->dbenv, dbp->mutex);
}
MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
if (foundp != NULL)
*foundp = found;
return (0);
}
int
__ram_getno(dbc, key, rep, can_create)
DBC *dbc;
const DBT *key;
db_recno_t *rep;
int can_create;
{
DB *dbp;
db_recno_t recno;
dbp = dbc->dbp;
if ((recno = *(db_recno_t *)key->data) == 0) {
__db_errx(dbp->dbenv, "illegal record number of 0");
return (EINVAL);
}
if (rep != NULL)
*rep = recno;
return (dbc->dbtype == DB_RECNO ?
__ram_update(dbc, recno, can_create) : 0);
}
static int
__ram_update(dbc, recno, can_create)
DBC *dbc;
db_recno_t recno;
int can_create;
{
BTREE *t;
DB *dbp;
DBT *rdata;
db_recno_t nrecs;
int ret;
dbp = dbc->dbp;
t = dbp->bt_internal;
if (!can_create && t->re_eof)
return (0);
if ((ret = __bam_nrecs(dbc, &nrecs)) != 0)
return (ret);
if (!t->re_eof && recno > nrecs) {
if ((ret = __ram_sread(dbc, recno)) != 0 && ret != DB_NOTFOUND)
return (ret);
if ((ret = __bam_nrecs(dbc, &nrecs)) != 0)
return (ret);
}
if (!can_create || recno <= nrecs + 1)
return (0);
rdata = &dbc->my_rdata;
rdata->flags = 0;
rdata->size = 0;
while (recno > ++nrecs)
if ((ret = __ram_add(dbc,
&nrecs, rdata, 0, BI_DELETED)) != 0)
return (ret);
return (0);
}
static int
__ram_source(dbp)
DB *dbp;
{
DB_ENV *dbenv;
BTREE *t;
char *source;
int ret;
dbenv = dbp->dbenv;
t = dbp->bt_internal;
if ((ret = __db_appname(dbenv,
DB_APP_DATA, t->re_source, 0, NULL, &source)) != 0)
return (ret);
__os_free(dbenv, t->re_source);
t->re_source = source;
if ((t->re_fp = fopen(t->re_source, "rb")) == NULL) {
ret = __os_get_errno();
__db_err(dbenv, ret, "%s", t->re_source);
return (ret);
}
t->re_eof = 0;
return (0);
}
int
__ram_writeback(dbp)
DB *dbp;
{
BTREE *t;
DB_ENV *dbenv;
DBC *dbc;
DBT key, data;
FILE *fp;
db_recno_t keyno;
int ret, t_ret;
u_int8_t delim, *pad;
t = dbp->bt_internal;
dbenv = dbp->dbenv;
fp = NULL;
pad = NULL;
if (!t->re_modified)
return (0);
if (t->re_source == NULL) {
t->re_modified = 0;
return (0);
}
memset(&key, 0, sizeof(key));
key.size = sizeof(db_recno_t);
key.data = &keyno;
memset(&data, 0, sizeof(data));
F_SET(&data, DB_DBT_REALLOC);
if ((ret = __db_cursor(dbp, NULL, &dbc, 0)) != 0)
return (ret);
if ((ret =
__ram_update(dbc, DB_MAX_RECORDS, 0)) != 0 && ret != DB_NOTFOUND)
goto err;
if (t->re_fp != NULL) {
if (fclose(t->re_fp) != 0) {
ret = __os_get_errno();
__db_err(dbenv, ret, "%s", t->re_source);
goto err;
}
t->re_fp = NULL;
}
if ((fp = fopen(t->re_source, "wb")) == NULL) {
ret = __os_get_errno();
__db_err(dbenv, ret, "%s", t->re_source);
goto err;
}
delim = t->re_delim;
for (keyno = 1;; ++keyno) {
switch (ret = __db_get(dbp, NULL, &key, &data, 0)) {
case 0:
if (data.size != 0 &&
fwrite(data.data, 1, data.size, fp) != data.size)
goto write_err;
break;
case DB_KEYEMPTY:
if (F_ISSET(dbp, DB_AM_FIXEDLEN)) {
if (pad == NULL) {
if ((ret = __os_malloc(
dbenv, t->re_len, &pad)) != 0)
goto err;
memset(pad, t->re_pad, t->re_len);
}
if (fwrite(pad, 1, t->re_len, fp) != t->re_len)
goto write_err;
}
break;
case DB_NOTFOUND:
ret = 0;
goto done;
default:
goto err;
}
if (!F_ISSET(dbp, DB_AM_FIXEDLEN) &&
fwrite(&delim, 1, 1, fp) != 1) {
write_err: ret = __os_get_errno();
__db_err(dbenv, ret,
"%s: write failed to backing file", t->re_source);
goto err;
}
}
err:
done:
if (fp != NULL && fclose(fp) != 0) {
t_ret = __os_get_errno();
__db_err(dbenv, t_ret, "%s", t->re_source);
if (ret == 0)
ret = t_ret;
}
if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0)
ret = t_ret;
if (data.data != NULL)
__os_ufree(dbenv, data.data);
if (pad != NULL)
__os_free(dbenv, pad);
if (ret == 0)
t->re_modified = 0;
return (ret);
}
static int
__ram_sread(dbc, top)
DBC *dbc;
db_recno_t top;
{
BTREE *t;
DB *dbp;
DBT data, *rdata;
db_recno_t recno;
size_t len;
int ch, ret, was_modified;
t = dbc->dbp->bt_internal;
dbp = dbc->dbp;
was_modified = t->re_modified;
if ((ret = __bam_nrecs(dbc, &recno)) != 0)
return (ret);
len = F_ISSET(dbp, DB_AM_FIXEDLEN) ? t->re_len : 256;
rdata = &dbc->my_rkey;
if (rdata->ulen < len) {
if ((ret = __os_realloc(
dbp->dbenv, len, &rdata->data)) != 0) {
rdata->ulen = 0;
rdata->data = NULL;
return (ret);
}
rdata->ulen = (u_int32_t)len;
}
memset(&data, 0, sizeof(data));
while (recno < top) {
data.data = rdata->data;
data.size = 0;
if (F_ISSET(dbp, DB_AM_FIXEDLEN))
for (len = t->re_len; len > 0; --len) {
if ((ch = fgetc(t->re_fp)) == EOF) {
if (data.size == 0)
goto eof;
break;
}
((u_int8_t *)data.data)[data.size++] = ch;
}
else
for (;;) {
if ((ch = fgetc(t->re_fp)) == EOF) {
if (data.size == 0)
goto eof;
break;
}
if (ch == t->re_delim)
break;
((u_int8_t *)data.data)[data.size++] = ch;
if (data.size == rdata->ulen) {
if ((ret = __os_realloc(dbp->dbenv,
rdata->ulen *= 2,
&rdata->data)) != 0) {
rdata->ulen = 0;
rdata->data = NULL;
return (ret);
} else
data.data = rdata->data;
}
}
if (t->re_last >= recno) {
++recno;
if ((ret = __ram_add(dbc, &recno, &data, 0, 0)) != 0)
goto err;
}
++t->re_last;
}
if (0) {
eof: t->re_eof = 1;
ret = DB_NOTFOUND;
}
err: if (!was_modified)
t->re_modified = 0;
return (ret);
}
static int
__ram_add(dbc, recnop, data, flags, bi_flags)
DBC *dbc;
db_recno_t *recnop;
DBT *data;
u_int32_t flags, bi_flags;
{
BTREE_CURSOR *cp;
int exact, ret, stack, t_ret;
cp = (BTREE_CURSOR *)dbc->internal;
retry:
if ((ret = __bam_rsearch(dbc, recnop,
SR_INSERT | (flags == DB_APPEND ? SR_APPEND : 0), 1, &exact)) != 0)
return (ret);
stack = 1;
STACK_TO_CURSOR(cp, ret);
if (ret != 0)
goto err;
if (exact && flags == DB_NOOVERWRITE && !CD_ISSET(cp) &&
!B_DISSET(GET_BKEYDATA(dbc->dbp, cp->page, cp->indx)->type)) {
ret = DB_KEYEXIST;
goto err;
}
if (flags == DB_APPEND && dbc->dbp->db_append_recno != NULL &&
(ret = dbc->dbp->db_append_recno(dbc->dbp, data, *recnop)) != 0)
goto err;
switch (ret = __bam_iitem(dbc,
NULL, data, exact ? DB_CURRENT : DB_BEFORE, bi_flags)) {
case 0:
break;
case DB_NEEDSPLIT:
(void)__bam_stkrel(dbc, STK_CLRDBC);
stack = 0;
if ((ret = __bam_split(dbc, recnop, NULL)) != 0)
goto err;
goto retry;
default:
goto err;
}
err: if (stack && (t_ret = __bam_stkrel(dbc, STK_CLRDBC)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}