#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_put.c 8.8 (Berkeley) 7/26/94";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/db/btree/bt_put.c,v 1.9 2009/03/28 05:45:29 delphij Exp $");
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "btree.h"
static EPG *bt_fast(BTREE *, const DBT *, const DBT *, int *);
int
__bt_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
{
BTREE *t;
DBT tkey, tdata;
EPG *e;
PAGE *h;
indx_t idx, nxtindex;
pgno_t pg;
u_int32_t nbytes, tmp;
int dflags, exact, status;
char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
t = dbp->internal;
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
if (F_ISSET(t, B_RDONLY)) {
errno = EPERM;
return (RET_ERROR);
}
switch (flags) {
case 0:
case R_NOOVERWRITE:
break;
case R_CURSOR:
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor,
CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
break;
default:
errno = EINVAL;
return (RET_ERROR);
}
dflags = 0;
if (key->size + data->size > t->bt_ovflsize) {
if (key->size > t->bt_ovflsize) {
storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR)
return (RET_ERROR);
tkey.data = kb;
tkey.size = NOVFLSIZE;
memmove(kb, &pg, sizeof(pgno_t));
tmp = key->size;
memmove(kb + sizeof(pgno_t),
&tmp, sizeof(u_int32_t));
dflags |= P_BIGKEY;
key = &tkey;
}
if (key->size + data->size > t->bt_ovflsize) {
if (__ovfl_put(t, data, &pg) == RET_ERROR)
return (RET_ERROR);
tdata.data = db;
tdata.size = NOVFLSIZE;
memmove(db, &pg, sizeof(pgno_t));
tmp = data->size;
memmove(db + sizeof(pgno_t),
&tmp, sizeof(u_int32_t));
dflags |= P_BIGDATA;
data = &tdata;
}
if (key->size + data->size > t->bt_ovflsize)
goto storekey;
}
if (flags == R_CURSOR) {
if ((h = mpool_get(t->bt_mp, t->bt_cursor.pg.pgno, 0)) == NULL)
return (RET_ERROR);
idx = t->bt_cursor.pg.index;
goto delete;
}
if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
if ((e = __bt_search(t, key, &exact)) == NULL)
return (RET_ERROR);
h = e->page;
idx = e->index;
switch (flags) {
case R_NOOVERWRITE:
if (!exact)
break;
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
default:
if (!exact || !F_ISSET(t, B_NODUPS))
break;
delete: if (__bt_dleaf(t, key, h, idx) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
break;
}
nbytes = NBLEAFDBT(key->size, data->size);
if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
if ((status = __bt_split(t, h, key,
data, dflags, nbytes, idx)) != RET_SUCCESS)
return (status);
goto success;
}
if (idx < (nxtindex = NEXTINDEX(h)))
memmove(h->linp + idx + 1, h->linp + idx,
(nxtindex - idx) * sizeof(indx_t));
h->lower += sizeof(indx_t);
h->linp[idx] = h->upper -= nbytes;
dest = (char *)h + h->upper;
WR_BLEAF(dest, key, data, dflags);
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index >= idx)
++t->bt_cursor.pg.index;
if (t->bt_order == NOT) {
if (h->nextpg == P_INVALID) {
if (idx == NEXTINDEX(h) - 1) {
t->bt_order = FORWARD;
t->bt_last.index = idx;
t->bt_last.pgno = h->pgno;
}
} else if (h->prevpg == P_INVALID) {
if (idx == 0) {
t->bt_order = BACK;
t->bt_last.index = 0;
t->bt_last.pgno = h->pgno;
}
}
}
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
success:
if (flags == R_SETCURSOR)
__bt_setcur(t, e->page->pgno, e->index);
F_SET(t, B_MODIFIED);
return (RET_SUCCESS);
}
#ifdef STATISTICS
u_long bt_cache_hit, bt_cache_miss;
#endif
static EPG *
bt_fast(BTREE *t, const DBT *key, const DBT *data, int *exactp)
{
PAGE *h;
u_int32_t nbytes;
int cmp;
if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
t->bt_order = NOT;
return (NULL);
}
t->bt_cur.page = h;
t->bt_cur.index = t->bt_last.index;
nbytes = NBLEAFDBT(key->size, data->size);
if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t))
goto miss;
if (t->bt_order == FORWARD) {
if (t->bt_cur.page->nextpg != P_INVALID)
goto miss;
if (t->bt_cur.index != NEXTINDEX(h) - 1)
goto miss;
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
goto miss;
t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
} else {
if (t->bt_cur.page->prevpg != P_INVALID)
goto miss;
if (t->bt_cur.index != 0)
goto miss;
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
goto miss;
t->bt_last.index = 0;
}
*exactp = cmp == 0;
#ifdef STATISTICS
++bt_cache_hit;
#endif
return (&t->bt_cur);
miss:
#ifdef STATISTICS
++bt_cache_miss;
#endif
t->bt_order = NOT;
mpool_put(t->bt_mp, h, 0);
return (NULL);
}