#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/btree.h"
#include "dbinc/heap.h"
#include "dbinc/lock.h"
#include "dbinc/mp.h"
static int __heap_bulk __P((DBC *, DBT *, u_int32_t));
static int __heap_getpage __P((DBC *, u_int32_t, u_int8_t *));
static int __heapc_close __P((DBC *, db_pgno_t, int *));
static int __heapc_del __P((DBC *, u_int32_t));
static int __heapc_destroy __P((DBC *));
static int __heapc_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
static int __heapc_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
static int __heapc_reloc __P((DBC *, DBT *, DBT *));
static int __heapc_reloc_partial __P((DBC *, DBT *, DBT *));
static int __heapc_split __P((DBC *, DBT *, DBT *, int));
#undef ACQUIRE
#define ACQUIRE(dbc, mode, lpgno, lock, fpgno, pagep, flags, mflags, ret) do { \
DB_MPOOLFILE *__mpf = (dbc)->dbp->mpf; \
if ((pagep) != NULL) { \
ret = __memp_fput(__mpf, \
(dbc)->thread_info, pagep, dbc->priority); \
pagep = NULL; \
} \
if ((ret) == 0 && STD_LOCKING(dbc)) \
ret = __db_lget(dbc, \
LOCK_ISSET(lock) ? LCK_COUPLE : 0, \
lpgno, mode, flags, &(lock)); \
if ((ret) == 0) \
ret = __memp_fget(__mpf, &(fpgno), \
(dbc)->thread_info, (dbc)->txn, mflags, &(pagep)); \
} while (0)
#undef ACQUIRE_CUR
#define ACQUIRE_CUR(dbc, mode, p, flags, mflags, ret) do { \
HEAP_CURSOR *__cp = (HEAP_CURSOR *)(dbc)->internal; \
if (p != __cp->pgno) \
__cp->pgno = PGNO_INVALID; \
ACQUIRE(dbc, mode, p, __cp->lock, p, __cp->page, flags, mflags, ret); \
if ((ret) == 0) { \
__cp->pgno = p; \
__cp->lock_mode = (mode); \
} \
} while (0)
#undef DISCARD
#define DISCARD(dbc, pagep, lock, tlock, ret) do { \
DB_MPOOLFILE *__mpf = (dbc)->dbp->mpf; \
int __t_ret; \
__t_ret = 0; \
if ((pagep) != NULL) { \
__t_ret = __memp_fput(__mpf, \
(dbc)->thread_info, pagep, dbc->priority); \
pagep = NULL; \
} \
if (__t_ret != 0 && (ret) == 0) \
ret = __t_ret; \
if (tlock == 1) \
__t_ret = __TLPUT((dbc), lock); \
else \
__t_ret = __LPUT((dbc), lock); \
if (__t_ret != 0 && (ret) == 0) \
ret = __t_ret; \
} while (0)
int
__heapc_init(dbc)
DBC *dbc;
{
ENV *env;
int ret;
env = dbc->env;
if (dbc->internal == NULL)
if ((ret = __os_calloc(
env, 1, sizeof(HEAP_CURSOR), &dbc->internal)) != 0)
return (ret);
dbc->close = dbc->c_close = __dbc_close_pp;
dbc->cmp = __dbc_cmp_pp;
dbc->count = dbc->c_count = __dbc_count_pp;
dbc->del = dbc->c_del = __dbc_del_pp;
dbc->dup = dbc->c_dup = __dbc_dup_pp;
dbc->get = dbc->c_get = __dbc_get_pp;
dbc->pget = dbc->c_pget = __dbc_pget_pp;
dbc->put = dbc->c_put = __dbc_put_pp;
dbc->am_bulk = __heap_bulk;
dbc->am_close = __heapc_close;
dbc->am_del = __heapc_del;
dbc->am_destroy = __heapc_destroy;
dbc->am_get = __heapc_get;
dbc->am_put = __heapc_put;
dbc->am_writelock = NULL;
return (0);
}
static int
__heap_bulk(dbc, data, flags)
DBC *dbc;
DBT *data;
u_int32_t flags;
{
DB *dbp;
DB_HEAP_RID prev_rid, rid;
DBT sdata;
HEAP_CURSOR *cp;
HEAPHDR *hdr;
HEAPSPLITHDR *shdr;
PAGE *pg;
db_lockmode_t lock_type;
int is_key, ret;
int32_t *offp;
u_int32_t data_size, key_size, needed, space;
u_int8_t *dbuf, *np;
ret = 0;
dbp = dbc->dbp;
cp = (HEAP_CURSOR *)dbc->internal;
hdr = NULL;
shdr = NULL;
if (F_ISSET(dbc, DBC_RMW))
lock_type = DB_LOCK_WRITE;
else
lock_type = DB_LOCK_READ;
dbuf = data->data;
np = dbuf;
space = data->ulen;
space -= sizeof(*offp);
offp = (int32_t *)((u_int8_t *)dbuf + data->ulen);
offp--;
key_size = DB_ALIGN(DB_HEAP_RID_SZ, sizeof(u_int32_t));
data_size = 0;
is_key = LF_ISSET(DB_MULTIPLE_KEY) ? 1 : 0;
next_pg:
rid.indx = cp->indx;
rid.pgno = cp->pgno;
pg = cp->page;
do {
if (HEAP_OFFSETTBL(dbp, pg)[rid.indx] == 0)
continue;
hdr = (HEAPHDR *)P_ENTRY(dbp, pg, rid.indx);
if (F_ISSET(hdr, HEAP_RECSPLIT) &&
!F_ISSET(hdr, HEAP_RECFIRST))
continue;
needed = 0;
if (is_key)
needed = 2 * sizeof(*offp) + key_size;
if (F_ISSET(hdr, HEAP_RECSPLIT)) {
shdr = (HEAPSPLITHDR *)hdr;
data_size = DB_ALIGN(shdr->tsize, sizeof(u_int32_t));
} else
data_size = DB_ALIGN(hdr->size, sizeof(u_int32_t));
needed += 2 * sizeof(*offp) + data_size;
if (needed > space) {
if (np == dbuf || F_ISSET(dbc, DBC_FROM_DB_GET)) {
data->size = (u_int32_t)DB_ALIGN(
needed + data->ulen - space, 1024);
return (DB_BUFFER_SMALL);
}
break;
}
if (is_key) {
memcpy(np, &rid, key_size);
*offp-- = (int32_t)(np - dbuf);
*offp-- = (int32_t)DB_HEAP_RID_SZ;
np += key_size;
}
if (F_ISSET(hdr, HEAP_RECSPLIT)) {
memset(&sdata, 0, sizeof(DBT));
sdata.data = np;
sdata.size = sdata.ulen = shdr->tsize;
sdata.flags = DB_DBT_USERMEM;
cp->pgno = rid.pgno;
cp->indx = rid.indx;
if ((ret = __heapc_gsplit(
dbc, &sdata, NULL, NULL)) != 0)
return (ret);
} else {
memcpy(np,
(u_int8_t *)hdr + sizeof(HEAPHDR), hdr->size);
}
*offp-- = (int32_t)(np - dbuf);
if (F_ISSET(hdr, HEAP_RECSPLIT))
*offp-- = (int32_t)shdr->tsize;
else
*offp-- = (int32_t)hdr->size;
np += data_size;
space -= needed;
prev_rid = rid;
DB_ASSERT(dbp->env, (void *)np <= (void *)offp);
} while (++rid.indx < NUM_ENT(pg));
if (rid.indx >= NUM_ENT(pg)) {
rid.pgno++;
ACQUIRE_CUR(dbc, lock_type, rid.pgno, 0, 0, ret);
if (ret == 0) {
cp->indx = 0;
goto next_pg;
} else if (ret != DB_PAGE_NOTFOUND)
return (ret);
}
DB_ASSERT(dbp->env, (ret == 0 || ret == DB_PAGE_NOTFOUND));
cp->indx = prev_rid.indx;
cp->pgno = prev_rid.pgno;
*offp = -1;
return (0);
}
static int
__heapc_close(dbc, root_pgno, rmroot)
DBC *dbc;
db_pgno_t root_pgno;
int *rmroot;
{
DB_MPOOLFILE *mpf;
HEAP_CURSOR *cp;
int ret;
COMPQUIET(root_pgno, 0);
COMPQUIET(rmroot, 0);
cp = (HEAP_CURSOR *)dbc->internal;
mpf = dbc->dbp->mpf;
ret = 0;
DISCARD(dbc, cp->page, cp->lock, 1, ret);
if (ret == 0 && !LOCK_ISSET(cp->lock))
cp->lock_mode = DB_LOCK_NG;
return (ret);
}
static int
__heapc_del(dbc, flags)
DBC *dbc;
u_int32_t flags;
{
DB *dbp;
DB_HEAP_RID next_rid, orig_rid;
DB_MPOOLFILE *mpf;
DBT hdr_dbt, log_dbt;
HEAP *h;
HEAPHDR *hdr;
HEAPPG *rpage;
HEAP_CURSOR *cp;
db_pgno_t region_pgno;
int oldspacebits, ret, spacebits, t_ret;
u_int16_t data_size, size;
dbp = dbc->dbp;
mpf = dbp->mpf;
h = dbp->heap_internal;
cp = (HEAP_CURSOR *)dbc->internal;
rpage = NULL;
COMPQUIET(flags, 0);
orig_rid.pgno = cp->pgno;
orig_rid.indx = cp->indx;
DB_ASSERT(dbp->env, cp->page == NULL);
start: if (STD_LOCKING(dbc) && (ret = __db_lget(dbc,
LCK_COUPLE, cp->pgno, DB_LOCK_WRITE, 0, &cp->lock)) != 0)
return (ret);
if ((ret = __memp_fget(mpf, &cp->pgno,
dbc->thread_info, dbc->txn, DB_MPOOL_DIRTY, &cp->page)) != 0)
return (ret);
HEAP_CALCSPACEBITS(dbp, HEAP_FREESPACE(dbp, cp->page), oldspacebits);
hdr = (HEAPHDR *)P_ENTRY(dbp, cp->page, cp->indx);
data_size = DB_ALIGN(hdr->size, sizeof(u_int32_t));
size = data_size + HEAP_HDRSIZE(hdr);
if (size < sizeof(HEAPSPLITHDR))
size = sizeof(HEAPSPLITHDR);
if (F_ISSET(hdr, HEAP_RECSPLIT) && !F_ISSET(hdr, HEAP_RECLAST)) {
next_rid.pgno = F_ISSET(hdr, HEAP_RECLAST) ?
PGNO_INVALID : ((HEAPSPLITHDR *)hdr)->nextpg;
next_rid.indx = F_ISSET(hdr, HEAP_RECLAST) ?
PGNO_INVALID : ((HEAPSPLITHDR *)hdr)->nextindx;
} else {
next_rid.pgno = PGNO_INVALID;
next_rid.indx = 0;
}
if (DBC_LOGGING(dbc)) {
hdr_dbt.data = hdr;
hdr_dbt.size = HEAP_HDRSIZE(hdr);
log_dbt.data = (u_int8_t *)hdr + hdr_dbt.size;
log_dbt.size = data_size;
if ((ret = __heap_addrem_log(dbp, dbc->txn, &LSN(cp->page),
0, DB_REM_HEAP, cp->pgno, (u_int32_t)cp->indx,
size, &hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_ditem(dbc, cp->page, cp->indx, size)) != 0)
goto err;
region_pgno = HEAP_REGION_PGNO(dbp, cp->pgno);
if (region_pgno < h->curregion)
h->curregion = region_pgno;
HEAP_CALCSPACEBITS(dbp, HEAP_FREESPACE(dbp, cp->page), spacebits);
if (spacebits != oldspacebits) {
if ((ret = __memp_fget(mpf, ®ion_pgno,
dbc->thread_info, NULL, DB_MPOOL_DIRTY, &rpage)) != 0)
goto err;
HEAP_SETSPACE(dbp, rpage,
cp->pgno - region_pgno - 1, spacebits);
}
err: DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
if (rpage != NULL && (t_ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority)) != 0 && ret == 0)
ret = t_ret;
rpage = NULL;
if ((t_ret = __memp_fput(mpf,
dbc->thread_info, cp->page, dbc->priority)) != 0 && ret == 0)
ret = t_ret;
cp->page = NULL;
if (ret == 0 && next_rid.pgno != PGNO_INVALID) {
cp->pgno = next_rid.pgno;
cp->indx = next_rid.indx;
goto start;
}
cp->pgno = orig_rid.pgno;
cp->indx = orig_rid.indx;
return (ret);
}
int
__heap_ditem(dbc, pagep, indx, nbytes)
DBC *dbc;
PAGE *pagep;
u_int32_t indx, nbytes;
{
DB *dbp;
db_indx_t first, i, max, off, *offtbl, span;
u_int8_t *src, *dest;
dbp = dbc->dbp;
DB_ASSERT(dbp->env, TYPE(pagep) == P_HEAP);
DB_ASSERT(dbp->env, nbytes == DB_ALIGN(nbytes, sizeof(u_int32_t)));
DB_ASSERT(dbp->env, nbytes >= sizeof(HEAPSPLITHDR));
offtbl = (db_indx_t *)HEAP_OFFSETTBL(dbp, pagep);
off = offtbl[indx];
max = HEAP_HIGHINDX(pagep);
first = HOFFSET(pagep);
for (i = 0; i <= max; i++) {
if (offtbl[i] < off && offtbl[i] != 0)
offtbl[i] += nbytes;
}
offtbl[indx] = 0;
src = (u_int8_t *)(pagep) + first;
dest = src + nbytes;
span = off - first;
memmove(dest, src, span);
#ifdef DIAGNOSTIC
memset(src, CLEAR_BYTE, nbytes);
#endif
NUM_ENT(pagep)--;
HOFFSET(pagep) += nbytes;
if (indx < HEAP_FREEINDX(pagep))
HEAP_FREEINDX(pagep) = indx;
while (HEAP_HIGHINDX(pagep) > 0 && offtbl[HEAP_HIGHINDX(pagep)] == 0)
HEAP_HIGHINDX(pagep)--;
if (NUM_ENT(pagep) == 0)
HEAP_FREEINDX(pagep) = 0;
else if (HEAP_FREEINDX(pagep) > HEAP_HIGHINDX(pagep) + 1)
HEAP_FREEINDX(pagep) = HEAP_HIGHINDX(pagep) + 1;
return (0);
}
static int
__heapc_destroy(dbc)
DBC *dbc;
{
HEAP_CURSOR *cp;
cp = (HEAP_CURSOR *)dbc->internal;
__os_free(dbc->env, cp);
dbc->internal = NULL;
return (0);
}
static int
__heapc_get(dbc, key, data, flags, pgnop)
DBC *dbc;
DBT *key;
DBT *data;
u_int32_t flags;
db_pgno_t *pgnop;
{
DB *dbp;
DB_HEAP_RID rid;
DB_MPOOLFILE *mpf;
DB_LOCK meta_lock;
DBT tmp_val;
HEAP *h;
HEAPHDR *hdr;
HEAPMETA *meta;
HEAPPG *dpage;
HEAP_CURSOR *cp;
db_lockmode_t lock_type;
db_pgno_t pgno;
int cmp, f_indx, found, getpage, indx, ret;
dbp = dbc->dbp;
mpf = dbp->mpf;
h = dbp->heap_internal;
cp = (HEAP_CURSOR *)dbc->internal;
LOCK_INIT(meta_lock);
COMPQUIET(pgnop, NULL);
if (F_ISSET(key, DB_DBT_USERMEM) && key->ulen < DB_HEAP_RID_SZ) {
key->size = DB_HEAP_RID_SZ;
return (DB_BUFFER_SMALL);
}
if (F_ISSET(dbc, DBC_RMW))
lock_type = DB_LOCK_WRITE;
else
lock_type = DB_LOCK_READ;
ret = 0;
found = getpage = FALSE;
meta = NULL;
dpage = NULL;
switch (flags) {
case DB_CURRENT:
ACQUIRE_CUR(dbc, lock_type, cp->pgno, 0, 0, ret);
if (ret != 0) {
if (ret == DB_PAGE_NOTFOUND)
ret = DB_NOTFOUND;
goto err;
}
if (HEAP_OFFSETTBL(dbp, cp->page)[cp->indx] == 0) {
ret = DB_NOTFOUND;
goto err;
}
dpage = (HEAPPG *)cp->page;
hdr = (HEAPHDR *)P_ENTRY(dbp, dpage, cp->indx);
if (F_ISSET(hdr, HEAP_RECSPLIT) &&
!F_ISSET(hdr, HEAP_RECFIRST)) {
ret = DB_NOTFOUND;
goto err;
}
break;
case DB_FIRST:
first: pgno = FIRST_HEAP_DPAGE;
while (!found) {
ACQUIRE_CUR(dbc, lock_type, pgno, 0, 0, ret);
if (ret != 0 ) {
if (ret == DB_PAGE_NOTFOUND)
ret = DB_NOTFOUND;
goto err;
}
dpage = (HEAPPG *)cp->page;
if (TYPE(dpage) == P_HEAP && NUM_ENT(dpage) != 0) {
for (indx = 0;
indx <= HEAP_HIGHINDX(dpage); indx++) {
if (HEAP_OFFSETTBL(
dbp, dpage)[indx] == 0)
continue;
hdr = (HEAPHDR *)P_ENTRY(
dbp, dpage, indx);
if (!F_ISSET(hdr, HEAP_RECSPLIT) ||
F_ISSET(hdr, HEAP_RECFIRST)) {
found = TRUE;
cp->pgno = pgno;
cp->indx = indx;
break;
}
}
if (!found)
pgno++;
} else
pgno++;
}
break;
case DB_LAST:
last: pgno = PGNO_BASE_MD;
ACQUIRE(dbc, DB_LOCK_READ,
pgno, meta_lock, pgno, meta, 0, 0, ret);
if (ret != 0)
goto err;
pgno = meta->dbmeta.last_pgno;
DISCARD(dbc, meta, meta_lock, 1, ret);
if (ret != 0)
goto err;
while (!found) {
if (pgno < FIRST_HEAP_DPAGE) {
ret = DB_NOTFOUND;
goto err;
}
ACQUIRE_CUR(dbc, lock_type, pgno, 0, 0, ret);
if (ret != 0)
goto err;
dpage = (HEAPPG *)cp->page;
if (TYPE(dpage) == P_HEAP && NUM_ENT(dpage) != 0) {
for (indx = HEAP_HIGHINDX(dpage);
indx >= 0; indx--) {
if (HEAP_OFFSETTBL(
dbp, dpage)[indx] == 0)
continue;
hdr = (HEAPHDR *)P_ENTRY(
dbp, dpage, indx);
if (!F_ISSET(hdr, HEAP_RECSPLIT) ||
F_ISSET(hdr, HEAP_RECFIRST)) {
found = TRUE;
cp->pgno = pgno;
cp->indx = indx;
break;
}
}
if (!found)
pgno--;
} else
pgno--;
}
break;
case DB_NEXT_NODUP:
case DB_NEXT:
if (dbc->internal->pgno == PGNO_INVALID)
goto first;
ACQUIRE_CUR(dbc, lock_type, cp->pgno, 0, 0, ret);
if (ret != 0)
goto err;
dpage = (HEAPPG *)cp->page;
if (cp->indx >= HEAP_HIGHINDX(dpage))
getpage = TRUE;
while (!found) {
if (getpage) {
pgno = cp->pgno + 1;
ACQUIRE_CUR(dbc, lock_type, pgno, 0, 0, ret);
if (ret != 0) {
if (ret == DB_PAGE_NOTFOUND)
ret = DB_NOTFOUND;
goto err;
}
dpage = (HEAPPG *)cp->page;
if (TYPE(dpage) != P_HEAP ||
(TYPE(dpage) == P_HEAP &&
NUM_ENT(dpage) == 0))
continue;
cp->indx = -1;
getpage = FALSE;
}
cp->indx++;
for (indx=cp->indx;
indx <= HEAP_HIGHINDX(dpage); indx++) {
if (HEAP_OFFSETTBL(dbp, dpage)[indx] == 0)
continue;
hdr = (HEAPHDR *)P_ENTRY(dbp, dpage, indx);
if (!F_ISSET(hdr, HEAP_RECSPLIT) ||
F_ISSET(hdr, HEAP_RECFIRST)) {
found = TRUE;
cp->indx = indx;
break;
}
}
if (!found)
getpage = TRUE;
}
break;
case DB_PREV_NODUP:
case DB_PREV:
if (dbc->internal->pgno == PGNO_INVALID)
goto last;
ACQUIRE_CUR(dbc, lock_type, cp->pgno, 0, 0, ret);
if (ret != 0)
goto err;
dpage = (HEAPPG *)cp->page;
for (f_indx=0; (f_indx <= HEAP_HIGHINDX(dpage)) &&
(HEAP_OFFSETTBL(dbp, dpage)[f_indx] == 0); f_indx++) ;
if (cp->indx == 0 || cp->indx <= f_indx) {
if (cp->pgno == FIRST_HEAP_DPAGE) {
ret = DB_NOTFOUND;
goto err;
}
getpage = TRUE;
}
while (!found) {
if (getpage) {
pgno = cp->pgno - 1;
if (pgno < FIRST_HEAP_DPAGE) {
ret = DB_NOTFOUND;
goto err;
}
ACQUIRE_CUR(dbc, lock_type, pgno, 0, 0, ret);
if (ret != 0)
goto err;
dpage = (HEAPPG *)cp->page;
if (TYPE(dpage) != P_HEAP ||
(TYPE(dpage) == P_HEAP &&
NUM_ENT(dpage) == 0))
continue;
cp->indx = HEAP_HIGHINDX(dpage) + 1;
getpage = FALSE;
}
cp->indx--;
for (indx=cp->indx;
indx >= 0; indx--) {
if (HEAP_OFFSETTBL(dbp, dpage)[indx] == 0)
continue;
hdr = (HEAPHDR *)P_ENTRY(dbp, dpage, indx);
if (!F_ISSET(hdr, HEAP_RECSPLIT) ||
F_ISSET(hdr, HEAP_RECFIRST)) {
found = TRUE;
cp->indx = indx;
break;
}
}
if (!found)
getpage = TRUE;
}
break;
case DB_GET_BOTH_RANGE:
case DB_GET_BOTH:
case DB_SET_RANGE:
case DB_SET:
pgno = ((DB_HEAP_RID *)key->data)->pgno;
indx = ((DB_HEAP_RID *)key->data)->indx;
if (pgno == PGNO_BASE_MD ||
pgno == HEAP_REGION_PGNO(dbp, pgno)) {
ret = DB_NOTFOUND;
goto err;
}
ACQUIRE_CUR(dbc, lock_type, pgno, 0, 0, ret);
if (ret != 0) {
if (ret == DB_PAGE_NOTFOUND)
ret = DB_NOTFOUND;
goto err;
}
dpage = (HEAPPG *)cp->page;
if ((indx > HEAP_HIGHINDX(dpage)) ||
(HEAP_OFFSETTBL(dbp, dpage)[indx] == 0)) {
DISCARD(dbc, cp->page, cp->lock, 0, ret);
ret = DB_NOTFOUND;
goto err;
}
hdr = (HEAPHDR *)P_ENTRY(dbp, dpage, indx);
if (F_ISSET(hdr, HEAP_RECSPLIT) &&
!F_ISSET(hdr, HEAP_RECFIRST)) {
DISCARD(dbc, cp->page, cp->lock, 0, ret);
ret = DB_NOTFOUND;
goto err;
}
cp->pgno = pgno;
cp->indx = indx;
if (flags == DB_GET_BOTH || flags == DB_GET_BOTH_RANGE) {
memset(&tmp_val, 0, sizeof(DBT));
if (F_ISSET(hdr, HEAP_RECSPLIT)) {
tmp_val.flags = DB_DBT_MALLOC;
if ((ret = __heapc_gsplit(
dbc, &tmp_val, NULL, 0)) != 0)
goto err;
} else {
tmp_val.data =
(void *)((u_int8_t *)hdr + sizeof(HEAPHDR));
tmp_val.size = hdr->size;
}
cmp = __bam_defcmp(dbp, &tmp_val, data);
if (F_ISSET(&tmp_val, DB_DBT_MALLOC))
__os_ufree(dbp->env, tmp_val.data);
if (cmp != 0) {
ret = DB_NOTFOUND;
goto err;
}
}
break;
case DB_NEXT_DUP:
case DB_PREV_DUP:
ret = DB_NOTFOUND;
goto err;
default:
ret = __db_unknown_flag(dbp->env, "__heap_get", flags);
goto err;
}
err: if (ret == 0 ) {
if (key != NULL) {
rid.pgno = cp->pgno;
rid.indx = cp->indx;
ret = __db_retcopy(dbp->env, key, &rid,
DB_HEAP_RID_SZ, &dbc->rkey->data, &dbc->rkey->ulen);
F_SET(key, DB_DBT_ISSET);
}
} else {
if (meta != NULL)
(void)__memp_fput(mpf,
dbc->thread_info, meta, dbc->priority);
if (LOCK_ISSET(meta_lock))
(void)__LPUT(dbc, meta_lock);
if (LOCK_ISSET(cp->lock))
(void)__LPUT(dbc, cp->lock);
}
DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
return (ret);
}
#undef IS_FIRST
#define IS_FIRST (last_rid.pgno == PGNO_INVALID)
static int
__heapc_reloc_partial(dbc, key, data)
DBC *dbc;
DBT *key;
DBT *data;
{
DB *dbp;
DBT hdr_dbt, log_dbt, t_data, t_key;
DB_HEAP_RID last_rid, next_rid;
HEAPHDR *old_hdr;
HEAPSPLITHDR new_hdr;
HEAP_CURSOR *cp;
int add_bytes, ret;
u_int32_t buflen, data_size, dlen, doff, left, old_size;
u_int32_t remaining, size;
u_int8_t *buf, *olddata;
dbp = dbc->dbp;
cp = (HEAP_CURSOR *)dbc->internal;
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
memset(&hdr_dbt, 0, sizeof(DBT));
memset(&log_dbt, 0, sizeof(DBT));
buf = NULL;
COMPQUIET(key, NULL);
DB_ASSERT(dbp->env, F_ISSET(data, DB_DBT_PARTIAL));
if (F_ISSET(old_hdr, HEAP_RECSPLIT))
old_size = ((HEAPSPLITHDR *)old_hdr)->tsize;
else
old_size = old_hdr->size;
doff = data->doff;
if (old_size < doff) {
dlen = data->dlen;
data_size = doff + data->size;
} else {
if (old_size - doff < data->dlen)
dlen = old_size - doff;
else
dlen = data->dlen;
data_size = old_size - dlen + data->size;
}
buflen = 0;
buf = NULL;
last_rid.pgno = PGNO_INVALID;
last_rid.indx = 0;
add_bytes = 1;
left = data_size;
memset(&t_data, 0, sizeof(DBT));
remaining = 0;
for (;;) {
if (F_ISSET(old_hdr, HEAP_RECSPLIT)) {
next_rid.pgno = ((HEAPSPLITHDR *)old_hdr)->nextpg;
next_rid.indx = ((HEAPSPLITHDR *)old_hdr)->nextindx;
} else {
next_rid.pgno = PGNO_INVALID;
next_rid.indx = 0;
}
if (doff >= old_hdr->size)
if (F_ISSET(old_hdr, HEAP_RECLAST) ||
!F_ISSET(old_hdr, HEAP_RECSPLIT)) {
data_size = doff + data->size;
} else {
data_size = old_hdr->size;
}
else if (doff + dlen > old_hdr->size)
data_size = doff + (add_bytes ? data->size : 0);
else
data_size = old_hdr->size -
dlen + (add_bytes ? data->size : 0);
data_size += remaining;
if (data_size > buflen) {
if (__os_realloc(dbp->env, data_size, &buf) != 0)
return (ENOMEM);
buflen = data_size;
}
t_data.data = buf;
buf += remaining;
remaining = 0;
olddata = (u_int8_t *)old_hdr + HEAP_HDRSIZE(old_hdr);
if (doff >= old_hdr->size) {
memcpy(buf, olddata, old_hdr->size);
doff -= old_hdr->size;
if (F_ISSET(old_hdr, HEAP_RECLAST) ||
!F_ISSET(old_hdr, HEAP_RECSPLIT)) {
buf += old_hdr->size;
memset(buf, '\0', doff);
buf += doff;
memcpy(buf, data->data, data->size);
}
} else {
memcpy(buf, olddata, doff);
buf += doff;
olddata += doff;
if (add_bytes) {
memcpy(buf, data->data, data->size);
buf += data->size;
add_bytes = 0;
}
if (doff + dlen < old_hdr->size) {
olddata += dlen;
memcpy(buf,
olddata, old_hdr->size - doff - dlen);
dlen = 0;
} else
dlen = doff + dlen - old_hdr->size;
doff = 0;
}
buf = t_data.data;
old_size = DB_ALIGN(
old_hdr->size + HEAP_HDRSIZE(old_hdr), sizeof(u_int32_t));
if (old_size < sizeof(HEAPSPLITHDR))
old_size = sizeof(HEAPSPLITHDR);
if (DBC_LOGGING(dbc)) {
hdr_dbt.data = old_hdr;
hdr_dbt.size = HEAP_HDRSIZE(old_hdr);
log_dbt.data = (u_int8_t *)old_hdr + hdr_dbt.size;
log_dbt.size = DB_ALIGN(
old_hdr->size, sizeof(u_int32_t));
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_REM_HEAP, cp->pgno,
(u_int32_t)cp->indx, old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_ditem(
dbc, cp->page, cp->indx, old_size)) != 0)
goto err;
if (left == 0)
goto next_pg;
if (data_size == 0 && !IS_FIRST) {
ACQUIRE_CUR(dbc, DB_LOCK_WRITE,
last_rid.pgno, 0, DB_MPOOL_DIRTY, ret);
if (ret != 0)
goto err;
cp->indx = last_rid.indx;
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
if (DBC_LOGGING(dbc)) {
old_size = DB_ALIGN(old_hdr->size +
HEAP_HDRSIZE(old_hdr), sizeof(u_int32_t));
hdr_dbt.data = old_hdr;
hdr_dbt.size = HEAP_HDRSIZE(old_hdr);
log_dbt.data =
(u_int8_t *)old_hdr + hdr_dbt.size;
log_dbt.size = DB_ALIGN(
old_hdr->size, sizeof(u_int32_t));
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_REM_HEAP, cp->pgno,
(u_int32_t)cp->indx, old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
((HEAPSPLITHDR *)old_hdr)->nextpg = next_rid.pgno;
((HEAPSPLITHDR *)old_hdr)->nextindx = next_rid.indx;
if (DBC_LOGGING(dbc)) {
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_ADD_HEAP, cp->pgno,
(u_int32_t)cp->indx, old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
DISCARD(dbc, cp->page, cp->lock, 1, ret);
goto next_pg;
}
memset(&new_hdr, 0, sizeof(HEAPSPLITHDR));
new_hdr.std_hdr.flags = HEAP_RECSPLIT;
new_hdr.nextpg = next_rid.pgno;
new_hdr.nextindx = next_rid.indx;
size = HEAP_FREESPACE(dbp, cp->page);
if (NUM_ENT(cp->page) == 0 ||
cp->indx > HEAP_HIGHINDX(cp->page))
size -= sizeof(db_indx_t);
size = DB_ALIGN(
size - sizeof(u_int32_t) + 1, sizeof(u_int32_t));
DB_ASSERT(dbp->env, size >= sizeof(HEAPSPLITHDR));
new_hdr.std_hdr.size = (u_int16_t)
(size - sizeof(HEAPSPLITHDR));
if (new_hdr.std_hdr.size > data_size)
new_hdr.std_hdr.size = data_size;
if (new_hdr.std_hdr.size >= left) {
new_hdr.std_hdr.size = left;
new_hdr.std_hdr.flags |= HEAP_RECLAST;
new_hdr.nextpg = PGNO_INVALID;
new_hdr.nextindx = 0;
}
if (IS_FIRST) {
new_hdr.std_hdr.flags |= HEAP_RECFIRST;
new_hdr.tsize = left;
}
t_data.size = new_hdr.std_hdr.size;
hdr_dbt.data = &new_hdr;
hdr_dbt.size = sizeof(HEAPSPLITHDR);
if (DBC_LOGGING(dbc)) {
if ((ret = __heap_addrem_log(dbp,
dbc->txn, &LSN(cp->page), 0,
DB_ADD_HEAP, cp->pgno, (u_int32_t)cp->indx,
size, &hdr_dbt, &t_data, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_pitem(dbc,
(PAGE *)cp->page, cp->indx, size, &hdr_dbt, &t_data)) != 0)
goto err;
left -= new_hdr.std_hdr.size;
if (new_hdr.std_hdr.size < data_size) {
remaining = data_size - new_hdr.std_hdr.size;
memmove(buf, buf + new_hdr.std_hdr.size, remaining);
}
next_pg: last_rid.pgno = cp->pgno;
last_rid.indx = cp->indx;
if (next_rid.pgno != PGNO_INVALID) {
ACQUIRE_CUR(dbc, DB_LOCK_WRITE,
next_rid.pgno, 0, DB_MPOOL_DIRTY, ret);
if (ret != 0)
goto err;
cp->indx = next_rid.indx;
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
DB_ASSERT(dbp->env,
HEAP_HIGHINDX(cp->page) <= cp->indx);
DB_ASSERT(dbp->env, F_ISSET(old_hdr, HEAP_RECSPLIT));
} else {
DISCARD(dbc, cp->page, cp->lock, 1, ret);
if (ret != 0)
goto err;
break;
}
}
if (left > 0) {
memset(&t_key, 0, sizeof(DBT));
t_key.size = t_key.ulen = sizeof(DB_HEAP_RID);
t_key.data = &next_rid;
t_key.flags = DB_DBT_USERMEM;
t_data.size = left;
if ((ret = __heapc_split(dbc, &t_key, &t_data, 0)) != 0)
goto err;
ACQUIRE_CUR(dbc,
DB_LOCK_WRITE, last_rid.pgno, 0, DB_MPOOL_DIRTY, ret);
if (ret != 0)
goto err;
cp->indx = last_rid.indx;
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
if (DBC_LOGGING(dbc)) {
old_size = DB_ALIGN(old_hdr->size +
HEAP_HDRSIZE(old_hdr), sizeof(u_int32_t));
hdr_dbt.data = old_hdr;
hdr_dbt.size = HEAP_HDRSIZE(old_hdr);
log_dbt.data = (u_int8_t *)old_hdr + hdr_dbt.size;
log_dbt.size = DB_ALIGN(
old_hdr->size, sizeof(u_int32_t));
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_REM_HEAP, cp->pgno,
(u_int32_t)cp->indx, old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
((HEAPSPLITHDR *)old_hdr)->nextpg = next_rid.pgno;
((HEAPSPLITHDR *)old_hdr)->nextindx = next_rid.indx;
if (DBC_LOGGING(dbc)) {
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_ADD_HEAP, cp->pgno,
(u_int32_t)cp->indx, old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
DISCARD(dbc, cp->page, cp->lock, 1, ret);
}
err: DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
if (buf != NULL)
__os_free(dbp->env, buf);
return (ret);
}
static int
__heapc_reloc(dbc, key, data)
DBC *dbc;
DBT *key;
DBT *data;
{
DB *dbp;
DBT hdr_dbt, log_dbt, t_data, t_key;
DB_HEAP_RID last_rid, next_rid;
HEAPHDR *old_hdr;
HEAPSPLITHDR new_hdr;
HEAP_CURSOR *cp;
int is_first, ret;
u_int32_t left, old_size, size;
dbp = dbc->dbp;
cp = (HEAP_CURSOR *)dbc->internal;
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
memset(&hdr_dbt, 0, sizeof(DBT));
memset(&log_dbt, 0, sizeof(DBT));
COMPQUIET(key, NULL);
is_first = 1;
left = data->size;
memset(&t_data, 0, sizeof(DBT));
t_data.data = data->data;
for (;;) {
if (F_ISSET(old_hdr, HEAP_RECSPLIT)) {
next_rid.pgno = ((HEAPSPLITHDR *)old_hdr)->nextpg;
next_rid.indx = ((HEAPSPLITHDR *)old_hdr)->nextindx;
} else {
next_rid.pgno = PGNO_INVALID;
next_rid.indx = 0;
}
old_size = DB_ALIGN(
old_hdr->size + HEAP_HDRSIZE(old_hdr), sizeof(u_int32_t));
if (old_size < sizeof(HEAPSPLITHDR))
old_size = sizeof(HEAPSPLITHDR);
if (DBC_LOGGING(dbc)) {
hdr_dbt.data = old_hdr;
hdr_dbt.size = HEAP_HDRSIZE(old_hdr);
log_dbt.data = (u_int8_t *)old_hdr + hdr_dbt.size;
log_dbt.size = DB_ALIGN(
old_hdr->size, sizeof(u_int32_t));
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_REM_HEAP, cp->pgno,
(u_int32_t)cp->indx, old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_ditem(
dbc, cp->page, cp->indx, old_size)) != 0)
goto err;
if (left == 0)
goto next_pg;
memset(&new_hdr, 0, sizeof(HEAPSPLITHDR));
new_hdr.std_hdr.flags = HEAP_RECSPLIT;
new_hdr.nextpg = next_rid.pgno;
new_hdr.nextindx = next_rid.indx;
size = HEAP_FREESPACE(dbp, cp->page);
if (NUM_ENT(cp->page) == 0 ||
cp->indx > HEAP_HIGHINDX(cp->page))
size -= sizeof(db_indx_t);
size = DB_ALIGN(
size - sizeof(u_int32_t) + 1, sizeof(u_int32_t));
DB_ASSERT(dbp->env, size >= sizeof(HEAPSPLITHDR));
new_hdr.std_hdr.size =
(u_int16_t)(size - sizeof(HEAPSPLITHDR));
if (new_hdr.std_hdr.size >= left) {
new_hdr.std_hdr.size = left;
new_hdr.std_hdr.flags |= HEAP_RECLAST;
new_hdr.nextpg = PGNO_INVALID;
new_hdr.nextindx = 0;
}
if (is_first) {
new_hdr.std_hdr.flags |= HEAP_RECFIRST;
new_hdr.tsize = left;
is_first = 0;
}
t_data.size = new_hdr.std_hdr.size;
hdr_dbt.data = &new_hdr;
hdr_dbt.size = sizeof(HEAPSPLITHDR);
if (DBC_LOGGING(dbc)) {
if ((ret = __heap_addrem_log(dbp,
dbc->txn, &LSN(cp->page), 0,
DB_ADD_HEAP, cp->pgno, (u_int32_t)cp->indx,
size, &hdr_dbt, &t_data, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_pitem(dbc,
(PAGE *)cp->page, cp->indx, size, &hdr_dbt, &t_data)) != 0)
goto err;
left -= new_hdr.std_hdr.size;
t_data.data = (u_int8_t *)(t_data.data) + new_hdr.std_hdr.size;
next_pg: if (next_rid.pgno != PGNO_INVALID) {
ACQUIRE_CUR(dbc, DB_LOCK_WRITE,
next_rid.pgno, 0, DB_MPOOL_DIRTY, ret);
if (ret != 0)
goto err;
cp->indx = next_rid.indx;
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
} else {
last_rid.pgno = cp->pgno;
last_rid.indx = cp->indx;
DISCARD(dbc, cp->page, cp->lock, 1, ret);
if (ret != 0)
goto err;
break;
}
}
if (left > 0) {
memset(&t_key, 0, sizeof(DBT));
t_key.size = t_key.ulen = sizeof(DB_HEAP_RID);
t_key.data = &next_rid;
t_key.flags = DB_DBT_USERMEM;
t_data.size = left;
if ((ret = __heapc_split(dbc, &t_key, &t_data, 0)) != 0)
goto err;
ACQUIRE_CUR(dbc,
DB_LOCK_WRITE, last_rid.pgno, 0, DB_MPOOL_DIRTY, ret);
if (ret != 0)
goto err;
cp->indx = last_rid.indx;
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
if (DBC_LOGGING(dbc)) {
old_size = DB_ALIGN(old_hdr->size +
HEAP_HDRSIZE(old_hdr), sizeof(u_int32_t));
hdr_dbt.data = old_hdr;
hdr_dbt.size = HEAP_HDRSIZE(old_hdr);
log_dbt.data = (u_int8_t *)old_hdr + hdr_dbt.size;
log_dbt.size = DB_ALIGN(
old_hdr->size, sizeof(u_int32_t));
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_REM_HEAP, cp->pgno,
(u_int32_t)cp->indx, old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
((HEAPSPLITHDR *)old_hdr)->nextpg = next_rid.pgno;
((HEAPSPLITHDR *)old_hdr)->nextindx = next_rid.indx;
if (DBC_LOGGING(dbc)) {
if ((ret = __heap_addrem_log(dbp, dbc->txn,
&LSN(cp->page), 0, DB_ADD_HEAP, cp->pgno,
(u_int32_t)cp->indx,old_size,
&hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
DISCARD(dbc, cp->page, cp->lock, 1, ret);
}
err: DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
return (ret);
}
static int
__heapc_put(dbc, key, data, flags, pgnop)
DBC *dbc;
DBT *key;
DBT *data;
u_int32_t flags;
db_pgno_t *pgnop;
{
DB *dbp;
DBT hdr_dbt, log_dbt, new_data;
DB_MPOOLFILE *mpf;
HEAPHDR hdr, *old_hdr;
HEAP_CURSOR *cp;
PAGE *rpage;
db_pgno_t region_pgno;
int oldspace, ret, space, t_ret;
u_int32_t data_size, dlen, new_size, old_flags, old_size, tot_size;
u_int8_t *buf, *olddata, *src, *dest;
dbp = dbc->dbp;
mpf = dbp->mpf;
cp = (HEAP_CURSOR *)dbc->internal;
rpage = NULL;
buf = dest = src = NULL;
dlen = 0;
if (flags != DB_CURRENT) {
old_flags = dbc->flags;
F_SET(dbc, DBC_RMW);
ret = __heapc_get(dbc, key, data, DB_SET, pgnop);
F_CLR(key, DB_DBT_ISSET);
dbc->flags = old_flags;
DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
if (ret != 0)
return (ret);
else if (flags == DB_NOOVERWRITE)
return (DB_KEYEXIST);
if ((ret = __memp_dirty(mpf, &cp->page,
dbc->thread_info, dbc->txn, dbc->priority, 0)) != 0)
return (ret);
} else {
if (STD_LOCKING(dbc) && cp->lock_mode != DB_LOCK_WRITE &&
(ret = __db_lget(dbc,
LCK_COUPLE, cp->pgno, DB_LOCK_WRITE, 0, &cp->lock)) != 0)
return (ret);
if ((ret = __memp_fget(mpf, &cp->pgno, dbc->thread_info,
dbc->txn, DB_MPOOL_DIRTY, &cp->page)) != 0)
return (ret);
}
HEAP_CALCSPACEBITS(dbp, HEAP_FREESPACE(dbp, cp->page), oldspace);
old_hdr = (HEAPHDR *)(P_ENTRY(dbp, cp->page, cp->indx));
old_size =
DB_ALIGN(old_hdr->size + HEAP_HDRSIZE(old_hdr), sizeof(u_int32_t));
if (old_size < sizeof(HEAPSPLITHDR))
old_size = sizeof(HEAPSPLITHDR);
if (F_ISSET(data, DB_DBT_PARTIAL)) {
if (F_ISSET(old_hdr, HEAP_RECSPLIT))
tot_size = ((HEAPSPLITHDR *)old_hdr)->tsize;
else
tot_size = old_hdr->size;
if (tot_size < data->doff) {
dlen = data->dlen;
data_size = data->doff + data->size;
} else {
if (tot_size - data->doff < data->dlen)
dlen = tot_size - data->doff;
else
dlen = data->dlen;
data_size = tot_size - dlen + data->size;
}
} else
data_size = data->size;
new_size = DB_ALIGN(data_size + sizeof(HEAPHDR), sizeof(u_int32_t));
if (new_size < sizeof(HEAPSPLITHDR))
new_size = sizeof(HEAPSPLITHDR);
if (F_ISSET(old_hdr, HEAP_RECSPLIT) ||
(new_size > old_size &&
new_size - old_size > HEAP_FREESPACE(dbp, cp->page))) {
if (F_ISSET(data, DB_DBT_PARTIAL))
return (__heapc_reloc_partial(dbc, key, data));
else
return (__heapc_reloc(dbc, key, data));
}
memset(&new_data, 0, sizeof(DBT));
new_data.size = data_size;
if (F_ISSET(data, DB_DBT_PARTIAL)) {
if ((ret = __os_malloc(dbp->env, data_size, &buf)) != 0)
goto err;
new_data.data = buf;
olddata = (u_int8_t *)old_hdr + sizeof(HEAPHDR);
if (data->doff > old_hdr->size) {
memcpy(buf, olddata, old_hdr->size);
buf += old_hdr->size;
memset(buf, '\0', data->doff - old_hdr->size);
buf += data->doff - old_hdr->size;
} else {
memcpy(buf, olddata, data->doff);
buf += data->doff;
}
memcpy(buf, data->data, data->size);
buf += data->size;
if (data->doff < old_hdr->size) {
olddata += data->doff + data->dlen;
memcpy(buf,
olddata, old_hdr->size - data->doff - data->dlen);
}
} else {
new_data.data = data->data;
}
memset(&hdr, 0, sizeof(HEAPHDR));
hdr.size = data_size;
if (DBC_LOGGING(dbc)) {
hdr_dbt.data = old_hdr;
hdr_dbt.size = HEAP_HDRSIZE(old_hdr);
log_dbt.data = (u_int8_t *)old_hdr + hdr_dbt.size;
log_dbt.size = DB_ALIGN(old_hdr->size, sizeof(u_int32_t));
if ((ret = __heap_addrem_log(dbp, dbc->txn, &LSN(cp->page),
0, DB_REM_HEAP, cp->pgno, (u_int32_t)cp->indx,
old_size, &hdr_dbt, &log_dbt, &LSN(cp->page))) != 0)
goto err;
hdr_dbt.data = &hdr;
hdr_dbt.size = HEAP_HDRSIZE(&hdr);
if ((ret = __heap_addrem_log(dbp, dbc->txn, &LSN(cp->page),
0, DB_ADD_HEAP, cp->pgno, (u_int32_t)cp->indx,
new_size, &hdr_dbt, &new_data, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_ditem(dbc, cp->page, cp->indx, old_size)) != 0)
goto err;
hdr_dbt.data = &hdr;
hdr_dbt.size = HEAP_HDRSIZE(&hdr);
if ((ret = __heap_pitem(dbc,
(PAGE *)cp->page, cp->indx, new_size, &hdr_dbt, &new_data)) != 0)
goto err;
HEAP_CALCSPACEBITS(dbp, HEAP_FREESPACE(dbp, cp->page), space);
if (space != oldspace) {
region_pgno = HEAP_REGION_PGNO(dbp, cp->pgno);
if ((ret = __memp_fget(mpf, ®ion_pgno,
dbc->thread_info, NULL, DB_MPOOL_DIRTY, &rpage)) != 0)
goto err;
HEAP_SETSPACE(dbp, rpage, cp->pgno - region_pgno - 1, space);
}
err: DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
if (rpage != NULL && (t_ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority)) != 0 && ret == 0)
ret = t_ret;
if (F_ISSET(data, DB_DBT_PARTIAL))
__os_free(dbp->env, new_data.data);
if (ret != 0 && LOCK_ISSET(cp->lock))
(void)__TLPUT(dbc, cp->lock);
return (ret);
}
static int
__heap_getpage(dbc, size, avail)
DBC *dbc;
u_int32_t size;
u_int8_t *avail;
{
DB *dbp;
DBMETA *meta;
DB_LOCK meta_lock;
DB_LSN meta_lsn;
DB_MPOOLFILE *mpf;
HEAP *h;
HEAPPG *rpage;
HEAP_CURSOR *cp;
db_pgno_t data_pgno, *lkd_pgs, meta_pgno, region_pgno, start_region;
int i, lk_mode, max, p, ret, space, start, t_ret;
LOCK_INIT(meta_lock);
dbp = dbc->dbp;
mpf = dbp->mpf;
cp = (HEAP_CURSOR *)dbc->internal;
h = dbp->heap_internal;
start_region = region_pgno = h->curregion;
max = HEAP_REGION_SIZE(dbp);
i = ret = t_ret = 0;
lkd_pgs = NULL;
HEAP_CALCSPACEBITS(dbp, size, space);
lk_mode = DB_MPOOL_TRY;
find: while ((ret = __memp_fget(mpf, ®ion_pgno,
dbc->thread_info, NULL, lk_mode, &rpage)) != 0 ||
TYPE(rpage) != P_IHEAP) {
if (ret == DB_LOCK_NOTGRANTED)
goto next_region;
if (ret != 0 && ret != DB_PAGE_NOTFOUND)
return (ret);
if (ret == 0 && (ret = __memp_fput(
mpf, dbc->thread_info, rpage, dbc->priority)) != 0)
return (ret);
if ((ret = __heap_create_region(dbc, region_pgno)) != 0)
return (ret);
}
start = h->curpgindx;
if (region_pgno + max > h->maxpgno)
max = h->maxpgno - region_pgno;
for (; i < max; i++) {
p = start + i;
if (p >= max)
p -= max;
if ((*avail = HEAP_SPACE(dbp, rpage, p)) > space)
continue;
data_pgno = region_pgno + p + 1;
ACQUIRE_CUR(dbc,
DB_LOCK_WRITE, data_pgno, DB_LOCK_NOWAIT, 0, ret);
if (ret == 0 || ret == DB_PAGE_NOTFOUND)
break;
else if (ret == DB_LOCK_NOTGRANTED || ret == DB_LOCK_DEADLOCK) {
ret = 0;
continue;
} else
goto err;
}
if (i < max && data_pgno > rpage->high_pgno) {
if ((ret = __memp_dirty(mpf,
&rpage, dbc->thread_info, NULL, dbc->priority, 0)) != 0)
goto err;
if (data_pgno > rpage->high_pgno)
rpage->high_pgno = data_pgno;
}
if ((ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority)) != 0) {
DISCARD(dbc, cp->page, cp->lock, 0, t_ret);
goto err;
}
rpage = NULL;
if (i >= max) {
next_region: region_pgno += HEAP_REGION_SIZE(dbp) + 1;
if (region_pgno > h->maxpgno)
region_pgno = FIRST_HEAP_RPAGE;
if (region_pgno == start_region) {
if (lk_mode == DB_MPOOL_TRY) {
lk_mode = 0;
} else {
ret = DB_HEAP_FULL;
goto err;
}
}
h->curregion = region_pgno;
h->curpgindx = 0;
i = 0;
goto find;
}
if (cp->pgno == PGNO_INVALID || PGNO(cp->page) == PGNO_INVALID) {
meta_pgno = PGNO_BASE_MD;
if ((ret = __db_lget(dbc, LCK_ALWAYS, meta_pgno,
DB_LOCK_WRITE, DB_LOCK_NOWAIT, &meta_lock)) != 0) {
p = cp->page != NULL;
DISCARD(dbc, cp->page, cp->lock, 0, t_ret);
if (t_ret != 0 ||
(ret != DB_LOCK_NOTGRANTED &&
ret != DB_LOCK_DEADLOCK))
goto pg_err;
if ((ret = __db_lget(dbc, LCK_ALWAYS, meta_pgno,
DB_LOCK_WRITE, 0, &meta_lock)) != 0)
goto pg_err;
ACQUIRE_CUR(dbc, DB_LOCK_WRITE,
data_pgno, 0, DB_MPOOL_CREATE, ret);
if (ret != 0) {
pg_err: if (p != 0) {
ACQUIRE_CUR(dbc, DB_LOCK_WRITE,
data_pgno, 0, 0, t_ret);
if (t_ret == 0 &&
PGNO(cp->page) == PGNO_INVALID) {
(void)__memp_fput(mpf,
dbc->thread_info,
cp->page, dbc->priority);
(void)__memp_fget(mpf,
&data_pgno,
dbc->thread_info, dbc->txn,
DB_MPOOL_FREE, &cp->page);
}
(void)__LPUT(dbc, cp->lock);
}
(void)__LPUT(dbc, meta_lock);
goto err;
}
if (PGNO(cp->page) != PGNO_INVALID) {
if ((ret = __LPUT(dbc, meta_lock)) != 0)
goto err;
goto check;
}
}
ret = __memp_fget(mpf, ®ion_pgno,
dbc->thread_info, NULL, DB_MPOOL_TRY, &rpage);
if (ret == DB_LOCK_NOTGRANTED)
ret = 0;
else if (ret != 0) {
if ((t_ret = __LPUT(dbc, meta_lock)) != 0)
ret = t_ret;
if (ret != DB_PAGE_NOTFOUND)
goto err;
DISCARD(dbc, cp->page, cp->lock, 0, t_ret);
goto find;
} else
ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority);
rpage = NULL;
if (ret != 0)
goto meta_unlock;
if ((ret = __memp_fget(mpf, &meta_pgno,
dbc->thread_info, dbc->txn, DB_MPOOL_DIRTY, &meta)) != 0)
goto err;
if (DBC_LOGGING(dbc))
ret = __heap_pg_alloc_log(dbp,
dbc->txn, &LSN(meta), 0, &LSN(meta), meta_pgno,
data_pgno, (u_int32_t)P_HEAP, meta->last_pgno);
else
LSN_NOT_LOGGED(LSN(meta));
if (ret == 0 && data_pgno > meta->last_pgno)
meta->last_pgno = data_pgno;
meta_lsn = LSN(meta);
if ((t_ret = __memp_fput(mpf,
dbc->thread_info, meta, dbc->priority)) != 0 && ret == 0)
ret = t_ret;
meta = NULL;
if (ret != 0)
goto meta_unlock;
if (cp->pgno == PGNO_INVALID) {
cp->pgno = data_pgno;
if ((ret = __memp_fget(mpf, &cp->pgno,
dbc->thread_info, dbc->txn,
DB_MPOOL_CREATE | DB_MPOOL_DIRTY, &cp->page)) != 0)
goto meta_unlock;
DB_ASSERT(dbp->env, cp->pgno == data_pgno);
} else if ((ret = __memp_dirty(mpf, &cp->page,
dbc->thread_info, dbc->txn, dbc->priority, 0)) != 0) {
DISCARD(dbc, cp->page, cp->lock, 0, t_ret);
goto meta_unlock;
}
P_INIT(cp->page,
dbp->pgsize, cp->pgno, P_INVALID, P_INVALID, 0, P_HEAP);
LSN(cp->page) = meta_lsn;
meta_unlock: if ((t_ret = __TLPUT(dbc, meta_lock)) != 0 && ret == 0)
ret = t_ret;
if (ret != 0)
goto err;
} else {
check: if (size + sizeof(db_indx_t) > HEAP_FREESPACE(dbp, cp->page)) {
DISCARD(dbc, cp->page, cp->lock, 0, ret);
if (ret != 0)
goto err;
i++;
goto find;
}
if ((ret = __memp_dirty(mpf, &cp->page,
dbc->thread_info, dbc->txn, dbc->priority, 0)) != 0) {
DISCARD(dbc, cp->page, cp->lock, 0, t_ret);
goto err;
}
}
h->curpgindx = data_pgno - region_pgno - 1;
err: DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
if (rpage != NULL && (t_ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
int
__heap_append(dbc, key, data)
DBC *dbc;
DBT *data, *key;
{
DB *dbp;
DBT tmp_dbt;
DB_HEAP_RID rid;
DB_MPOOLFILE *mpf;
HEAPPG *rpage;
HEAPHDR hdr;
HEAP_CURSOR *cp;
db_indx_t indx;
db_pgno_t region_pgno;
int ret, space, t_ret;
u_int8_t avail;
u_int32_t data_size;
dbp = dbc->dbp;
mpf = dbp->mpf;
ret = t_ret = 0;
rpage = NULL;
cp = (HEAP_CURSOR *)dbc->internal;
if (F_ISSET(data, DB_DBT_PARTIAL))
data_size = DB_ALIGN(data->doff +
data->size + sizeof(HEAPHDR), sizeof(u_int32_t));
else
data_size = DB_ALIGN(
data->size + sizeof(HEAPHDR), sizeof(u_int32_t));
if (data_size >= HEAP_MAXDATASIZE(dbp))
return (__heapc_split(dbc, key, data, 1));
else if (data_size < sizeof(HEAPSPLITHDR))
data_size = sizeof(HEAPSPLITHDR);
if ((ret = __heap_getpage(dbc, data_size, &avail)) != 0)
goto err;
indx = HEAP_FREEINDX(cp->page);
memset(&hdr, 0, sizeof(HEAPHDR));
hdr.size = data->size;
if (F_ISSET(data, DB_DBT_PARTIAL))
hdr.size += data->doff;
tmp_dbt.data = &hdr;
tmp_dbt.size = sizeof(HEAPHDR);
if (DBC_LOGGING(dbc)) {
if ((ret = __heap_addrem_log(dbp, dbc->txn, &LSN(cp->page),
0, DB_ADD_HEAP, cp->pgno, (u_int32_t)indx,
data_size, &tmp_dbt, data, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_pitem(
dbc, (PAGE *)cp->page, indx, data_size, &tmp_dbt, data)) != 0)
goto err;
rid.pgno = cp->pgno;
rid.indx = indx;
cp->indx = indx;
HEAP_CALCSPACEBITS(dbp, HEAP_FREESPACE(dbp, cp->page), space);
if (space != avail) {
region_pgno = HEAP_REGION_PGNO(dbp, cp->pgno);
if ((ret = __memp_fget(mpf, ®ion_pgno,
dbc->thread_info, NULL, DB_MPOOL_DIRTY, &rpage)) != 0)
goto err;
HEAP_SETSPACE(dbp, rpage, cp->pgno - region_pgno - 1, space);
}
err: DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
if (rpage != NULL && (t_ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority)) != 0 && ret == 0)
ret = t_ret;
if (cp->page != NULL) {
DISCARD(dbc, cp->page, cp->lock, 1, t_ret);
if (ret == 0)
ret = t_ret;
}
if (ret == 0 && key != NULL)
ret = __db_retcopy(dbp->env, key,
&rid, DB_HEAP_RID_SZ, &dbc->rkey->data, &dbc->rkey->ulen);
return (ret);
}
static int
__heapc_split(dbc, key, data, is_first)
DBC *dbc;
DBT *key, *data;
int is_first;
{
DB *dbp;
DBT hdr_dbt, t_data;
DB_HEAP_RID rid;
DB_MPOOLFILE *mpf;
HEAPPG *rpage;
HEAPSPLITHDR hdrs;
HEAP_CURSOR *cp;
db_indx_t indx;
db_pgno_t region_pgno;
int ret, spacebits, t_ret;
u_int32_t buflen, doff, left, size;
u_int8_t availbits, *buf;
dbp = dbc->dbp;
mpf = dbp->mpf;
cp = (HEAP_CURSOR *)dbc->internal;
memset(&hdrs, 0, sizeof(HEAPSPLITHDR));
memset(&t_data, 0, sizeof(DBT));
hdrs.std_hdr.flags = HEAP_RECSPLIT | HEAP_RECLAST;
doff = data->doff;
rpage = NULL;
ret = t_ret = 0;
indx = 0;
buf = NULL;
buflen = 0;
t_data.data = (u_int8_t *)data->data + data->size;
left = data->size;
if (F_ISSET(data, DB_DBT_PARTIAL)) {
left += data->doff;
}
hdrs.tsize = left;
while (left > 0) {
size = DB_ALIGN(left + sizeof(HEAPSPLITHDR), sizeof(u_int32_t));
if (size < sizeof(HEAPSPLITHDR))
size = sizeof(HEAPSPLITHDR);
if (size > HEAP_MAXDATASIZE(dbp))
size = DB_ALIGN(dbp->pgsize / 3, sizeof(u_int32_t));
else
hdrs.std_hdr.flags |= HEAP_RECFIRST;
if ((ret = __heap_getpage(dbc, size, &availbits)) != 0)
return (ret);
if (F_ISSET(&(hdrs.std_hdr), HEAP_RECFIRST)) {
hdrs.std_hdr.size = left;
if (!is_first)
F_CLR(&(hdrs.std_hdr), HEAP_RECFIRST);
} else {
size = HEAP_FREESPACE(dbp, cp->page);
if (NUM_ENT(cp->page) == 0 ||
HEAP_FREEINDX(cp->page) > HEAP_HIGHINDX(cp->page))
size -= sizeof(db_indx_t);
size = DB_ALIGN(
size - sizeof(u_int32_t) + 1, sizeof(u_int32_t));
DB_ASSERT(dbp->env, size >= sizeof(HEAPSPLITHDR));
hdrs.std_hdr.size =
(u_int16_t)(size - sizeof(HEAPSPLITHDR));
}
t_data.data = (u_int8_t *)(t_data.data) - hdrs.std_hdr.size;
DB_ASSERT(dbp->env, (F_ISSET(data, DB_DBT_PARTIAL) ||
t_data.data >= data->data));
t_data.size = hdrs.std_hdr.size;
if (F_ISSET(data, DB_DBT_PARTIAL) &&
t_data.size > left - doff) {
if (buflen < t_data.size) {
if (__os_realloc(
dbp->env, t_data.size, &buf) != 0)
return (ENOMEM);
buflen = t_data.size;
}
t_data.data = buf;
memset(buf, '\0', t_data.size - left + doff);
buf += t_data.size - left + doff;
memcpy(buf, data->data, left - doff);
doff -= t_data.size - left + doff;
buf = t_data.data;
}
hdr_dbt.data = &hdrs;
hdr_dbt.size = sizeof(HEAPSPLITHDR);
indx = HEAP_FREEINDX(cp->page);
if (DBC_LOGGING(dbc)) {
if ((ret = __heap_addrem_log(dbp,
dbc->txn, &LSN(cp->page), 0,
DB_ADD_HEAP, cp->pgno, (u_int32_t)indx,
size, &hdr_dbt, &t_data, &LSN(cp->page))) != 0)
goto err;
} else
LSN_NOT_LOGGED(LSN(cp->page));
if ((ret = __heap_pitem(dbc,
(PAGE *)cp->page, indx, size, &hdr_dbt, &t_data)) != 0)
goto err;
F_CLR(&(hdrs.std_hdr), HEAP_RECLAST);
left -= hdrs.std_hdr.size;
hdrs.nextpg = cp->pgno;
hdrs.nextindx = indx;
HEAP_CALCSPACEBITS(dbp,
HEAP_FREESPACE(dbp, cp->page), spacebits);
if (spacebits != availbits) {
region_pgno = HEAP_REGION_PGNO(dbp, cp->pgno);
if ((ret = __memp_fget(mpf, ®ion_pgno,
dbc->thread_info,
NULL, DB_MPOOL_DIRTY, &rpage)) != 0)
goto err;
HEAP_SETSPACE(dbp,
rpage, cp->pgno - region_pgno - 1, spacebits);
ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority);
rpage = NULL;
if (ret != 0)
goto err;
}
}
rid.pgno = cp->pgno;
rid.indx = indx;
cp->indx = indx;
err: if (rpage != NULL && (t_ret = __memp_fput(mpf,
dbc->thread_info, rpage, dbc->priority)) != 0 && ret == 0)
ret = t_ret;
if (cp->page != NULL) {
DISCARD(dbc, cp->page, cp->lock, 1, t_ret);
if (ret == 0)
ret = t_ret;
}
if (buf != NULL)
__os_free(dbp->env, buf);
if (ret == 0 && key != NULL)
ret = __db_retcopy(dbp->env, key,
&rid, DB_HEAP_RID_SZ, &dbc->rkey->data, &dbc->rkey->ulen);
DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
return (ret);
}
int
__heap_pitem(dbc, pagep, indx, nbytes, hdr, data)
DBC *dbc;
PAGE *pagep;
u_int32_t indx;
u_int32_t nbytes;
DBT *hdr, *data;
{
DB *dbp;
u_int8_t *buf;
dbp = dbc->dbp;
DB_ASSERT(dbp->env, TYPE(pagep) == P_HEAP);
DB_ASSERT(dbp->env, IS_DIRTY(pagep));
DB_ASSERT(dbp->env, nbytes == DB_ALIGN(nbytes, sizeof(u_int32_t)));
DB_ASSERT(dbp->env, DB_ALIGN(((HEAPHDR *)hdr->data)->size,
sizeof(u_int32_t)) >= data->size);
DB_ASSERT(dbp->env, nbytes >= hdr->size + data->size);
HEAP_OFFSETTBL(dbp, pagep)[indx] = HOFFSET(pagep) - nbytes;
buf = P_ENTRY(dbp, pagep, indx);
DB_ASSERT(dbp->env, buf > (u_int8_t*)&HEAP_OFFSETTBL(dbp, pagep)[indx]);
if (hdr != NULL) {
memcpy(buf, hdr->data, hdr->size);
buf += hdr->size;
}
if (F_ISSET(data, DB_DBT_PARTIAL)) {
memset(buf, 0, data->doff);
buf += data->doff;
}
memcpy(buf, data->data, data->size);
if (indx > HEAP_HIGHINDX(pagep)) {
if (NUM_ENT(pagep) == 0)
HEAP_FREEINDX(pagep) = 0;
else if (HEAP_FREEINDX(pagep) >= indx) {
if (indx > (u_int32_t)HEAP_HIGHINDX(pagep) + 1)
HEAP_FREEINDX(pagep) = HEAP_HIGHINDX(pagep) + 1;
else
HEAP_FREEINDX(pagep) = indx + 1;
}
while (++HEAP_HIGHINDX(pagep) < indx)
HEAP_OFFSETTBL(dbp,pagep)[HEAP_HIGHINDX(pagep)] = 0;
} else {
for (; indx <= HEAP_HIGHINDX(pagep); indx++)
if (HEAP_OFFSETTBL(dbp, pagep)[indx] == 0)
break;
HEAP_FREEINDX(pagep) = indx;
}
HOFFSET(pagep) -= nbytes;
NUM_ENT(pagep)++;
return (0);
}
int
__heapc_dup(orig_dbc, new_dbc)
DBC *orig_dbc, *new_dbc;
{
HEAP_CURSOR *orig, *new;
orig = (HEAP_CURSOR *)orig_dbc->internal;
new = (HEAP_CURSOR *)new_dbc->internal;
new->flags = orig->flags;
return (0);
}
int
__heapc_gsplit(dbc, dbt, bpp, bpsz)
DBC *dbc;
DBT *dbt;
void **bpp;
u_int32_t *bpsz;
{
DB *dbp;
DB_MPOOLFILE *mpf;
DB_HEAP_RID rid;
DB_LOCK data_lock;
HEAP_CURSOR *cp;
ENV *env;
HEAPPG *dpage;
HEAPSPLITHDR *hdr;
db_indx_t bytes;
u_int32_t curoff, needed, start, tlen;
u_int8_t *p, *src;
int putpage, ret, t_ret;
LOCK_INIT(data_lock);
dbp = dbc->dbp;
env = dbp->env;
mpf = dbp->mpf;
cp = (HEAP_CURSOR *)dbc->internal;
putpage = FALSE;
ret = 0;
DB_ASSERT(env, cp->page != NULL);
rid.pgno = cp->pgno;
rid.indx = cp->indx;
dpage = cp->page;
hdr = (HEAPSPLITHDR *)P_ENTRY(dbp, dpage, rid.indx);
DB_ASSERT(env, hdr->tsize != 0);
tlen = hdr->tsize;
if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
start = dbt->doff;
if (start > tlen)
needed = 0;
else if (dbt->dlen > tlen - start)
needed = tlen - start;
else
needed = dbt->dlen;
} else {
start = 0;
needed = tlen;
}
if (needed == 0) {
dbt->size = 0;
return (0);
}
if (F_ISSET(dbt, DB_DBT_USERCOPY))
goto skip_alloc;
if (F_ISSET(dbt, DB_DBT_USERMEM)) {
if (needed > dbt->ulen) {
dbt->size = needed;
return (DB_BUFFER_SMALL);
}
} else if (F_ISSET(dbt, DB_DBT_MALLOC)) {
if ((ret = __os_umalloc(env, needed, &dbt->data)) != 0)
return (ret);
} else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
if ((ret = __os_urealloc(env, needed, &dbt->data)) != 0)
return (ret);
} else if (bpsz != NULL && (*bpsz == 0 || *bpsz < needed)) {
if ((ret = __os_realloc(env, needed, bpp)) != 0)
return (ret);
*bpsz = needed;
dbt->data = *bpp;
} else if (bpp != NULL)
dbt->data = *bpp;
else {
DB_ASSERT(env,
F_ISSET(dbt,
DB_DBT_USERMEM | DB_DBT_MALLOC | DB_DBT_REALLOC) ||
bpsz != NULL || bpp != NULL);
return (DB_BUFFER_SMALL);
}
skip_alloc:
curoff = 0;
dbt->size = needed;
for (p = dbt->data; needed > 0;) {
if (curoff + hdr->std_hdr.size >= start) {
bytes = hdr->std_hdr.size;
src = (u_int8_t *)hdr +
P_TO_UINT16(sizeof(HEAPSPLITHDR));
if (start > curoff) {
src += start - curoff;
bytes -= start - curoff;
}
if (bytes > needed)
bytes = needed;
if (F_ISSET(dbt, DB_DBT_USERCOPY)) {
if ((ret = env->dbt_usercopy(
dbt, dbt->size - needed,
src, bytes, DB_USERCOPY_SETDATA)) != 0) {
if (putpage)
(void)__memp_fput(
mpf, dbc->thread_info,
dpage, dbp->priority);
return (ret);
}
} else
memcpy(p, src, bytes);
p += bytes;
needed -= bytes;
}
curoff += hdr->std_hdr.size;
if (!F_ISSET((HEAPHDR *)hdr, HEAP_RECLAST)) {
rid.pgno = hdr->nextpg;
rid.indx = hdr->nextindx;
if (putpage) {
if ((ret = __memp_fput(mpf, dbc->thread_info,
dpage, dbp->priority) ) != 0)
goto err;
dpage = NULL;
if ((ret = __TLPUT(dbc, data_lock)) != 0)
goto err;
}
if ((ret = __db_lget(dbc, 0, rid.pgno,
DB_LOCK_READ, 0, &data_lock)) != 0)
goto err;
if ((ret = __memp_fget(mpf, &rid.pgno,
dbc->thread_info, dbc->txn, 0, &dpage)) != 0)
goto err;
hdr = (HEAPSPLITHDR *)P_ENTRY(dbp, dpage, rid.indx);
putpage = TRUE;
if (F_ISSET((HEAPHDR *)hdr, HEAP_RECLAST) &&
!F_ISSET(dbt, DB_DBT_PARTIAL) &&
(hdr->std_hdr.size != needed)) {
__db_errx(env, DB_STR_A("1167",
"Incorrect record size in header: %s: rid %lu.%lu",
"%s %lu %lu"), dbc->dbp->fname,
(u_long)(cp->pgno), (u_long)(cp->indx));
ret = __env_panic(env, DB_RUNRECOVERY);
goto err;
}
}
}
err: DB_ASSERT(dbp->env, ret != DB_PAGE_NOTFOUND);
if (putpage && dpage != NULL && (t_ret = __memp_fput(mpf,
dbc->thread_info, dpage, dbp->priority)) != 0 && ret == 0)
ret = t_ret;
if ((t_ret = __TLPUT(dbc, data_lock)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
int
__heapc_refresh(dbc)
DBC *dbc;
{
HEAP_CURSOR *cp;
cp = (HEAP_CURSOR *)dbc->internal;
LOCK_INIT(cp->lock);
cp->lock_mode = DB_LOCK_NG;
cp->flags = 0;
return (0);
}