#include "config.h"
#ifndef lint
static const char sccsid[] = "@(#)hash_rec.c 10.22 (Sleepycat) 10/21/98";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#endif
#include "db_int.h"
#include "shqueue.h"
#include "db_page.h"
#include "hash.h"
#include "btree.h"
#include "log.h"
#include "common_ext.h"
int
__ham_insdel_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_insdel_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
PAGE *pagep;
u_int32_t op;
int cmp_n, cmp_p, getmeta, ret;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_insdel_print);
REC_INTRO(__ham_insdel_read);
hcp = (HASH_CURSOR *)dbc->internal;
ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
goto done;
} else if ((ret = memp_fget(mpf, &argp->pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
GET_META(file_dbp, hcp, ret);
if (ret != 0)
goto out;
getmeta = 1;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
op = OPCODE_OF(argp->opcode);
if ((op == DELPAIR && cmp_n == 0 && !redo) ||
(op == PUTPAIR && cmp_p == 0 && redo)) {
if (op != DELPAIR ||
argp->ndx == (u_int32_t)H_NUMPAIRS(pagep)) {
__ham_putitem(pagep, &argp->key,
!redo || PAIR_ISKEYBIG(argp->opcode) ?
H_OFFPAGE : H_KEYDATA);
__ham_putitem(pagep, &argp->data,
!redo || PAIR_ISDATABIG(argp->opcode) ?
H_OFFPAGE : H_KEYDATA);
} else
(void) __ham_reputpair(pagep, hcp->hdr->pagesize,
argp->ndx, &argp->key, &argp->data);
LSN(pagep) = redo ? *lsnp : argp->pagelsn;
if ((ret = __ham_put_page(file_dbp, pagep, 1)) != 0)
goto out;
} else if ((op == DELPAIR && cmp_p == 0 && redo)
|| (op == PUTPAIR && cmp_n == 0 && !redo)) {
__ham_dpair(file_dbp, pagep, argp->ndx);
LSN(pagep) = redo ? *lsnp : argp->pagelsn;
if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
goto out;
} else
if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
goto out;
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}
int
__ham_newpage_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_newpage_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
PAGE *pagep;
int cmp_n, cmp_p, change, getmeta, ret;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_newpage_print);
REC_INTRO(__ham_newpage_read);
hcp = (HASH_CURSOR *)dbc->internal;
ret = memp_fget(mpf, &argp->new_pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
ret = 0;
goto ppage;
} else if ((ret = memp_fget(mpf, &argp->new_pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
if (ret != 0)
goto out;
getmeta = 1;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
change = 0;
if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
(cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
P_INIT(pagep, file_dbp->pgsize, argp->new_pgno,
argp->prev_pgno, argp->next_pgno, 0, P_HASH);
change = 1;
} else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
(cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
change = 1;
}
if (!change) {
if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
goto out;
} else {
LSN(pagep) = redo ? *lsnp : argp->pagelsn;
if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
goto out;
}
ppage: if (argp->prev_pgno != PGNO_INVALID) {
ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
ret = 0;
goto npage;
} else if ((ret =
memp_fget(mpf, &argp->prev_pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
change = 0;
if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
(cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
pagep->next_pgno = argp->new_pgno;
change = 1;
} else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
(cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
pagep->next_pgno = argp->next_pgno;
change = 1;
}
if (!change) {
if ((ret =
__ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
goto out;
} else {
LSN(pagep) = redo ? *lsnp : argp->prevlsn;
if ((ret =
__ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
goto out;
}
}
npage: if (argp->next_pgno != PGNO_INVALID) {
ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
goto done;
} else if ((ret =
memp_fget(mpf, &argp->next_pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
change = 0;
if ((cmp_p == 0 && redo && argp->opcode == PUTOVFL) ||
(cmp_n == 0 && !redo && argp->opcode == DELOVFL)) {
pagep->prev_pgno = argp->new_pgno;
change = 1;
} else if ((cmp_p == 0 && redo && argp->opcode == DELOVFL) ||
(cmp_n == 0 && !redo && argp->opcode == PUTOVFL)) {
pagep->prev_pgno = argp->prev_pgno;
change = 1;
}
if (!change) {
if ((ret =
__ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
goto out;
} else {
LSN(pagep) = redo ? *lsnp : argp->nextlsn;
if ((ret =
__ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
goto out;
}
}
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}
int
__ham_replace_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_replace_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
DBT dbt;
PAGE *pagep;
int32_t grow;
int change, cmp_n, cmp_p, getmeta, ret;
u_int8_t *hk;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_replace_print);
REC_INTRO(__ham_replace_read);
hcp = (HASH_CURSOR *)dbc->internal;
ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
goto done;
} else if ((ret = memp_fget(mpf, &argp->pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
if (ret != 0)
goto out;
getmeta = 1;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
if (cmp_p == 0 && redo) {
change = 1;
dbt.data = argp->newitem.data;
dbt.size = argp->newitem.size;
grow = argp->newitem.size - argp->olditem.size;
LSN(pagep) = *lsnp;
} else if (cmp_n == 0 && !redo) {
change = 1;
dbt.data = argp->olditem.data;
dbt.size = argp->olditem.size;
grow = argp->olditem.size - argp->newitem.size;
LSN(pagep) = argp->pagelsn;
} else {
change = 0;
grow = 0;
}
if (change) {
__ham_onpage_replace(pagep,
file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt);
if (argp->makedup) {
hk = P_ENTRY(pagep, argp->ndx);
if (redo)
HPAGE_PTYPE(hk) = H_DUPLICATE;
else
HPAGE_PTYPE(hk) = H_KEYDATA;
}
}
if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
goto out;
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}
int
__ham_newpgno_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_newpgno_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
PAGE *pagep;
int change, cmp_n, cmp_p, getmeta, ret;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_newpgno_print);
REC_INTRO(__ham_newpgno_read);
hcp = (HASH_CURSOR *)dbc->internal;
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
if (ret != 0)
goto out;
getmeta = 1;
cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
change = 0;
if ((cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) ||
(cmp_n == 0 && !redo && argp->opcode == DELPGNO)) {
hcp->hdr->last_freed = argp->free_pgno;
if (redo && argp->old_pgno != 0)
hcp->hdr->spares[hcp->hdr->ovfl_point]++;
change = 1;
} else if (cmp_p == 0 && redo && argp->opcode == DELPGNO) {
hcp->hdr->last_freed = argp->pgno;
change = 1;
} else if (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO) {
if (argp->old_pgno == 0)
hcp->hdr->last_freed = argp->pgno;
else {
hcp->hdr->spares[hcp->hdr->ovfl_point]--;
hcp->hdr->last_freed = 0;
}
change = 1;
}
if (change) {
hcp->hdr->lsn = redo ? *lsnp : argp->metalsn;
F_SET(hcp, H_DIRTY);
}
ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
goto done;
} else if ((ret = memp_fget(mpf, &argp->pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
change = 0;
if (cmp_p == 0 && redo && argp->opcode == ALLOCPGNO) {
P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
PGNO_INVALID, 0, argp->new_type);
change = 1;
} else if (cmp_n == 0 && !redo && argp->opcode == DELPGNO) {
P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
argp->old_pgno, 0, argp->old_type);
change = 1;
} else if ((cmp_p == 0 && redo && argp->opcode == DELPGNO) ||
(cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO)) {
NEXT_PGNO(pagep) = argp->free_pgno;
TYPE(pagep) = P_INVALID;
change = 1;
}
if (change)
LSN(pagep) = redo ? *lsnp : argp->pagelsn;
if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
goto out;
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}
int
__ham_splitmeta_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_splitmeta_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
int change, cmp_n, cmp_p, getmeta, ret;
u_int32_t pow;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_splitmeta_print);
REC_INTRO(__ham_splitmeta_read);
hcp = (HASH_CURSOR *)dbc->internal;
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
if (ret != 0)
goto out;
getmeta = 1;
cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
change = 0;
if (cmp_p == 0 && redo) {
hcp->hdr->max_bucket = argp->bucket + 1;
pow = __db_log2(hcp->hdr->max_bucket + 1);
if (pow > hcp->hdr->ovfl_point) {
hcp->hdr->spares[pow] =
hcp->hdr->spares[hcp->hdr->ovfl_point];
hcp->hdr->ovfl_point = pow;
}
if (hcp->hdr->max_bucket > hcp->hdr->high_mask) {
hcp->hdr->low_mask = hcp->hdr->high_mask;
hcp->hdr->high_mask =
hcp->hdr->max_bucket | hcp->hdr->low_mask;
}
change = 1;
} else if (cmp_n == 0 && !redo) {
hcp->hdr->max_bucket = argp->bucket;
hcp->hdr->ovfl_point = argp->ovflpoint;
hcp->hdr->spares[hcp->hdr->ovfl_point] = argp->spares;
pow = 1 << __db_log2(hcp->hdr->max_bucket + 1);
hcp->hdr->high_mask = pow - 1;
hcp->hdr->low_mask = (pow >> 1) - 1;
change = 1;
}
if (change) {
hcp->hdr->lsn = redo ? *lsnp : argp->metalsn;
F_SET(hcp, H_DIRTY);
}
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}
int
__ham_splitdata_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_splitdata_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
PAGE *pagep;
int change, cmp_n, cmp_p, getmeta, ret;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_splitdata_print);
REC_INTRO(__ham_splitdata_read);
hcp = (HASH_CURSOR *)dbc->internal;
ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
goto done;
} else if ((ret = memp_fget(mpf, &argp->pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
if (ret != 0)
goto out;
getmeta = 1;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
change = 0;
if (cmp_p == 0 && redo) {
if (argp->opcode == SPLITNEW)
memcpy(pagep, argp->pageimage.data,
argp->pageimage.size);
LSN(pagep) = *lsnp;
change = 1;
} else if (cmp_n == 0 && !redo) {
if (argp->opcode == SPLITOLD) {
memcpy(pagep, argp->pageimage.data,
argp->pageimage.size);
} else
P_INIT(pagep, file_dbp->pgsize, argp->pgno,
PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
LSN(pagep) = argp->pagelsn;
change = 1;
}
if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
goto out;
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}
int
__ham_ovfl_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_ovfl_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
PAGE *pagep;
db_pgno_t max_pgno, pgno;
int cmp_n, cmp_p, getmeta, ret;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_ovfl_print);
REC_INTRO(__ham_ovfl_read);
hcp = (HASH_CURSOR *)dbc->internal;
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
if (ret != 0)
goto out;
getmeta = 1;
cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
if (cmp_p == 0 && redo) {
hcp->hdr->last_freed = argp->start_pgno;
hcp->hdr->spares[argp->ovflpoint] += argp->npages;
hcp->hdr->lsn = *lsnp;
F_SET(hcp, H_DIRTY);
} else if (cmp_n == 0 && !redo) {
hcp->hdr->last_freed = argp->free_pgno;
hcp->hdr->spares[argp->ovflpoint] -= argp->npages;
hcp->hdr->lsn = argp->metalsn;
F_SET(hcp, H_DIRTY);
}
max_pgno = argp->start_pgno + argp->npages - 1;
ret = 0;
for (pgno = argp->start_pgno; pgno <= max_pgno; pgno++) {
if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) != 0) {
if (!redo) {
ret = 0;
continue;
}
if ((ret = memp_fget(mpf,
&pgno, DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
}
if (redo && log_compare((const DB_LSN *)lsnp,
(const DB_LSN *)&LSN(pagep)) > 0) {
P_INIT(pagep, file_dbp->pgsize, pgno, PGNO_INVALID,
pgno == max_pgno ? argp->free_pgno : pgno + 1,
0, P_HASH);
LSN(pagep) = *lsnp;
ret = __ham_put_page(file_dbp, pagep, 1);
} else if (!redo) {
ZERO_LSN(pagep->lsn);
ret = __ham_put_page(file_dbp, pagep, 1);
} else
ret = __ham_put_page(file_dbp, pagep, 0);
if (ret)
goto out;
}
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}
int
__ham_copypage_recover(logp, dbtp, lsnp, redo, info)
DB_LOG *logp;
DBT *dbtp;
DB_LSN *lsnp;
int redo;
void *info;
{
__ham_copypage_args *argp;
DB *file_dbp;
DBC *dbc;
HASH_CURSOR *hcp;
DB_MPOOLFILE *mpf;
PAGE *pagep;
int cmp_n, cmp_p, getmeta, modified, ret;
getmeta = 0;
hcp = NULL;
REC_PRINT(__ham_copypage_print);
REC_INTRO(__ham_copypage_read);
hcp = (HASH_CURSOR *)dbc->internal;
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
if (ret != 0)
goto out;
getmeta = 1;
modified = 0;
ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
ret = 0;
goto donext;
} else if ((ret = memp_fget(mpf, &argp->pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
if (cmp_p == 0 && redo) {
memcpy(pagep, argp->page.data, argp->page.size);
LSN(pagep) = *lsnp;
modified = 1;
} else if (cmp_n == 0 && !redo) {
P_INIT(pagep, hcp->hdr->pagesize, argp->pgno, PGNO_INVALID,
argp->next_pgno, 0, P_HASH);
LSN(pagep) = argp->pagelsn;
modified = 1;
}
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
donext: ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
ret = 0;
goto do_nn;
} else if ((ret = memp_fget(mpf, &argp->next_pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
cmp_n = log_compare(lsnp, &LSN(pagep));
if (cmp_n == 0 && !redo) {
memcpy(pagep, argp->page.data, argp->page.size);
modified = 1;
}
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
do_nn: if (argp->nnext_pgno == PGNO_INVALID)
goto done;
ret = memp_fget(mpf, &argp->nnext_pgno, 0, &pagep);
if (ret != 0)
if (!redo) {
goto done;
} else if ((ret = memp_fget(mpf, &argp->nnext_pgno,
DB_MPOOL_CREATE, &pagep)) != 0)
goto out;
cmp_n = log_compare(lsnp, &LSN(pagep));
cmp_p = log_compare(&LSN(pagep), &argp->nnextlsn);
if (cmp_p == 0 && redo) {
PREV_PGNO(pagep) = argp->pgno;
LSN(pagep) = *lsnp;
modified = 1;
} else if (cmp_n == 0 && !redo) {
PREV_PGNO(pagep) = argp->next_pgno;
LSN(pagep) = argp->nnextlsn;
modified = 1;
}
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
goto out;
done: *lsnp = argp->prev_lsn;
ret = 0;
out: if (getmeta)
RELEASE_META(file_dbp, hcp);
REC_CLOSE;
}