mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-20 17:51:16 +00:00
Update.
* db2/Makefile (distribute): Remove files which do not exist anymore.
This commit is contained in:
parent
fc37035216
commit
ec239360d1
@ -1,5 +1,8 @@
|
||||
1999-06-13 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* db2/Makefile (distribute): Remove files which do not exist
|
||||
anymore.
|
||||
|
||||
* sysdeps/i386/fpu/bits/mathinline.h: Add __extension__ to signbit
|
||||
definitions to calm down gcc.
|
||||
|
||||
|
@ -45,9 +45,8 @@ distribute = db_int.h config.h compat.h clib/getlong.c btree/btree.src \
|
||||
mp.h mp_ext.h mutex_ext.h os_ext.h queue.h \
|
||||
shqueue.h txn.h txn_auto.h txn_ext.h \
|
||||
os.h os_jump.h xa.h xa_ext.h) \
|
||||
$(addprefix mutex/,x86.gcc uts4_cc.s sparc.gcc parisc.hp \
|
||||
parisc.gcc alpha.gcc alpha.dec README \
|
||||
68020.gcc tsl_parisc.s sco.cc)
|
||||
$(addprefix mutex/,x86.gcc uts4_cc.s sparc.gcc parisc.gcc \
|
||||
README 68020.gcc tsl_parisc.s sco.cc)
|
||||
|
||||
vpath %.c $(subdir-dirs)
|
||||
|
||||
|
@ -1,177 +0,0 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1990, 1993, 1994, 1995, 1996
|
||||
* Keith Bostic. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1990, 1993, 1994, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Mike Olson.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_close.c 10.32 (Sleepycat) 5/6/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "btree.h"
|
||||
|
||||
static void __bam_upstat __P((DB *dbp));
|
||||
|
||||
/*
|
||||
* __bam_close --
|
||||
* Close a btree.
|
||||
*
|
||||
* PUBLIC: int __bam_close __P((DB *));
|
||||
*/
|
||||
int
|
||||
__bam_close(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
BTREE *t;
|
||||
|
||||
DEBUG_LWRITE(dbp, NULL, "bam_close", NULL, NULL, 0);
|
||||
|
||||
t = dbp->internal;
|
||||
|
||||
/* Update tree statistics. */
|
||||
__bam_upstat(dbp);
|
||||
|
||||
/* Free any allocated memory. */
|
||||
if (t->bt_rkey.data)
|
||||
FREE(t->bt_rkey.data, t->bt_rkey.size);
|
||||
if (t->bt_rdata.data)
|
||||
FREE(t->bt_rdata.data, t->bt_rdata.ulen);
|
||||
if (t->bt_sp != t->bt_stack)
|
||||
FREE(t->bt_sp, (t->bt_esp - t->bt_sp) * sizeof(EPG));
|
||||
|
||||
FREE(t, sizeof(BTREE));
|
||||
dbp->internal = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_sync --
|
||||
* Sync the btree to disk.
|
||||
*
|
||||
* PUBLIC: int __bam_sync __P((DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_sync(argdbp, flags)
|
||||
DB *argdbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DB *dbp;
|
||||
int ret;
|
||||
|
||||
DEBUG_LWRITE(argdbp, NULL, "bam_sync", NULL, NULL, flags);
|
||||
|
||||
/* Check for invalid flags. */
|
||||
if ((ret = __db_syncchk(argdbp, flags)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* If it wasn't possible to modify the file, we're done. */
|
||||
if (F_ISSET(argdbp, DB_AM_INMEM | DB_AM_RDONLY))
|
||||
return (0);
|
||||
|
||||
GETHANDLE(argdbp, NULL, &dbp, ret);
|
||||
|
||||
/* Flush any dirty pages from the cache to the backing file. */
|
||||
if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE)
|
||||
ret = 0;
|
||||
|
||||
PUTHANDLE(dbp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_upstat --
|
||||
* Update tree statistics.
|
||||
*/
|
||||
static void
|
||||
__bam_upstat(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
BTREE *t;
|
||||
BTMETA *meta;
|
||||
DB_LOCK metalock;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t flags;
|
||||
|
||||
/*
|
||||
* We use a no-op log call to log the update of the statistics onto the
|
||||
* metadata page. The Db->close call isn't transaction protected to
|
||||
* start with, and I'm not sure what undoing a statistics update means,
|
||||
* anyway.
|
||||
*/
|
||||
if (F_ISSET(dbp, DB_AM_INMEM | DB_AM_RDONLY))
|
||||
return;
|
||||
|
||||
flags = 0;
|
||||
pgno = PGNO_METADATA;
|
||||
|
||||
/* Lock and retrieve the page. */
|
||||
if (__bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &metalock) != 0)
|
||||
return;
|
||||
if (__bam_pget(dbp, (PAGE **)&meta, &pgno, 0) == 0) {
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp) &&
|
||||
__db_noop_log(dbp->dbenv->lg_info, dbp->txn, &LSN(meta), 0,
|
||||
dbp->log_fileid, PGNO_METADATA, &LSN(meta)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Update the statistics. */
|
||||
t = dbp->internal;
|
||||
__bam_add_mstat(&t->lstat, &meta->stat);
|
||||
|
||||
flags = DB_MPOOL_DIRTY;
|
||||
}
|
||||
|
||||
err: (void)memp_fput(dbp->mpf, (PAGE *)meta, flags);
|
||||
(void)__BT_LPUT(dbp, metalock);
|
||||
}
|
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_compare.c 10.9 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)bt_compare.c 10.14 (Sleepycat) 10/9/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -64,93 +64,76 @@ static const char sccsid[] = "@(#)bt_compare.c 10.9 (Sleepycat) 5/6/98";
|
||||
* __bam_cmp --
|
||||
* Compare a key to a given record.
|
||||
*
|
||||
* PUBLIC: int __bam_cmp __P((DB *, const DBT *, EPG *));
|
||||
* PUBLIC: int __bam_cmp __P((DB *, const DBT *,
|
||||
* PUBLIC: PAGE *, u_int32_t, int (*)(const DBT *, const DBT *)));
|
||||
*/
|
||||
int
|
||||
__bam_cmp(dbp, k1, e)
|
||||
__bam_cmp(dbp, dbt, h, indx, func)
|
||||
DB *dbp;
|
||||
const DBT *k1;
|
||||
EPG *e;
|
||||
const DBT *dbt;
|
||||
PAGE *h;
|
||||
u_int32_t indx;
|
||||
int (*func)__P((const DBT *, const DBT *));
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
BKEYDATA *bk;
|
||||
BOVERFLOW *bo;
|
||||
BTREE *t;
|
||||
DBT k2;
|
||||
PAGE *h;
|
||||
|
||||
t = dbp->internal;
|
||||
DBT pg_dbt;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* < 0 if k1 is < record
|
||||
* = 0 if k1 is = record
|
||||
* > 0 if k1 is > record
|
||||
* < 0 if dbt is < page record
|
||||
* = 0 if dbt is = page record
|
||||
* > 0 if dbt is > page record
|
||||
*
|
||||
* The left-most key on internal pages, at any level of the tree, is
|
||||
* guaranteed, by the following code, to be less than any user key.
|
||||
* This saves us from having to update the leftmost key on an internal
|
||||
* page when the user inserts a new key in the tree smaller than
|
||||
* anything we've yet seen.
|
||||
* !!!
|
||||
* We do not clear the pg_dbt DBT even though it's likely to contain
|
||||
* random bits. That should be okay, because the app's comparison
|
||||
* routine had better not be looking at fields other than data/size.
|
||||
* We don't clear it because we go through this path a lot and it's
|
||||
* expensive.
|
||||
*/
|
||||
h = e->page;
|
||||
if (e->indx == 0 &&
|
||||
h->prev_pgno == PGNO_INVALID && TYPE(h) != P_LBTREE)
|
||||
return (1);
|
||||
|
||||
bo = NULL;
|
||||
if (TYPE(h) == P_LBTREE) {
|
||||
bk = GET_BKEYDATA(h, e->indx);
|
||||
if (TYPE(h) == P_LBTREE || TYPE(h) == P_DUPLICATE) {
|
||||
bk = GET_BKEYDATA(h, indx);
|
||||
if (B_TYPE(bk->type) == B_OVERFLOW)
|
||||
bo = (BOVERFLOW *)bk;
|
||||
else {
|
||||
k2.data = bk->data;
|
||||
k2.size = bk->len;
|
||||
pg_dbt.data = bk->data;
|
||||
pg_dbt.size = bk->len;
|
||||
return (func(dbt, &pg_dbt));
|
||||
}
|
||||
} else {
|
||||
bi = GET_BINTERNAL(h, e->indx);
|
||||
/*
|
||||
* The following code guarantees that the left-most key on an
|
||||
* internal page at any level of the btree is less than any
|
||||
* user specified key. This saves us from having to update the
|
||||
* leftmost key on an internal page when the user inserts a new
|
||||
* key in the tree smaller than anything we've seen before.
|
||||
*/
|
||||
if (indx == 0 && h->prev_pgno == PGNO_INVALID)
|
||||
return (1);
|
||||
|
||||
bi = GET_BINTERNAL(h, indx);
|
||||
if (B_TYPE(bi->type) == B_OVERFLOW)
|
||||
bo = (BOVERFLOW *)(bi->data);
|
||||
else {
|
||||
k2.data = bi->data;
|
||||
k2.size = bi->len;
|
||||
pg_dbt.data = bi->data;
|
||||
pg_dbt.size = bi->len;
|
||||
return (func(dbt, &pg_dbt));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overflow.
|
||||
*
|
||||
* XXX
|
||||
* We ignore system errors; the only recoverable one is ENOMEM, and we
|
||||
* don't want to require that comparison routines handle random errors.
|
||||
* We don't want to return a valid comparison, either, so we stop.
|
||||
* We ignore __db_moff() errors, because we have no way of returning
|
||||
* them.
|
||||
*/
|
||||
if (bo != NULL) {
|
||||
/*
|
||||
* If using the default comparison routine, use __db_moff(),
|
||||
* which compares the overflow key a page at a time.
|
||||
*/
|
||||
if (t->bt_compare == __bam_defcmp)
|
||||
return (__db_moff(dbp, k1, bo->pgno));
|
||||
|
||||
/*
|
||||
* Otherwise, we need a contiguous record so we can hand it
|
||||
* to the user's routine.
|
||||
*/
|
||||
memset(&k2, 0, sizeof(k2));
|
||||
if (__db_goff(dbp, &k2, bo->tlen,
|
||||
bo->pgno, &t->bt_rdata.data, &t->bt_rdata.ulen) != 0) {
|
||||
(void)__db_panic(dbp);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Note, we have not cleared the k2 DBT in this path. This should
|
||||
* be okay, because the user's comparison routine had better not be
|
||||
* looking at any fields other than the data/size. We don't clear
|
||||
* it because we go through this path a lot and it's expensive.
|
||||
*/
|
||||
return ((*t->bt_compare)(k1, &k2));
|
||||
(void) __db_moff(dbp,
|
||||
dbt, bo->pgno, bo->tlen, func == __bam_defcmp ? NULL : func, &ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_conv.c 10.6 (Sleepycat) 4/10/98";
|
||||
static const char sccsid[] = "@(#)bt_conv.c 10.7 (Sleepycat) 9/20/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -90,18 +90,5 @@ __bam_mswap(pg)
|
||||
SWAP32(p); /* free */
|
||||
SWAP32(p); /* flags */
|
||||
|
||||
/* Swap the statistics. */
|
||||
p = (u_int8_t *)&((BTMETA *)pg)->stat;
|
||||
SWAP32(p); /* bt_freed */
|
||||
SWAP32(p); /* bt_pfxsaved */
|
||||
SWAP32(p); /* bt_split */
|
||||
SWAP32(p); /* bt_rootsplit */
|
||||
SWAP32(p); /* bt_fastsplit */
|
||||
SWAP32(p); /* bt_added */
|
||||
SWAP32(p); /* bt_deleted */
|
||||
SWAP32(p); /* bt_get */
|
||||
SWAP32(p); /* bt_cache_hit */
|
||||
SWAP32(p); /* bt_cache_miss */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
272
db2/btree/bt_curadj.c
Normal file
272
db2/btree/bt_curadj.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_curadj.c 10.69 (Sleepycat) 12/2/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "btree.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* __bam_cprint --
|
||||
* Display the current cursor list.
|
||||
*
|
||||
* PUBLIC: int __bam_cprint __P((DB *));
|
||||
*/
|
||||
int
|
||||
__bam_cprint(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
CURSOR *cp;
|
||||
DBC *dbc;
|
||||
|
||||
DB_THREAD_LOCK(dbp);
|
||||
for (dbc = TAILQ_FIRST(&dbp->active_queue);
|
||||
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
|
||||
cp = (CURSOR *)dbc->internal;
|
||||
fprintf(stderr,
|
||||
"%#0x->%#0x: page: %lu index: %lu dpage %lu dindex: %lu recno: %lu",
|
||||
(u_int)dbc, (u_int)cp, (u_long)cp->pgno, (u_long)cp->indx,
|
||||
(u_long)cp->dpgno, (u_long)cp->dindx, (u_long)cp->recno);
|
||||
if (F_ISSET(cp, C_DELETED))
|
||||
fprintf(stderr, " (deleted)");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* __bam_ca_delete --
|
||||
* Update the cursors when items are deleted and when already deleted
|
||||
* items are overwritten. Return the number of relevant cursors found.
|
||||
*
|
||||
* PUBLIC: int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int));
|
||||
*/
|
||||
int
|
||||
__bam_ca_delete(dbp, pgno, indx, delete)
|
||||
DB *dbp;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t indx;
|
||||
int delete;
|
||||
{
|
||||
DBC *dbc;
|
||||
CURSOR *cp;
|
||||
int count; /* !!!: Has to contain max number of cursors. */
|
||||
|
||||
/* Recno is responsible for its own adjustments. */
|
||||
if (dbp->type == DB_RECNO)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Adjust the cursors. We don't have to review the cursors for any
|
||||
* thread of control other than the current one, because we have the
|
||||
* page write locked at this point, and any other thread of control
|
||||
* had better be using a different locker ID, meaning only cursors in
|
||||
* our thread of control can be on the page.
|
||||
*
|
||||
* It's possible for multiple cursors within the thread to have write
|
||||
* locks on the same page, but, cursors within a thread must be single
|
||||
* threaded, so all we're locking here is the cursor linked list.
|
||||
*/
|
||||
DB_THREAD_LOCK(dbp);
|
||||
for (count = 0, dbc = TAILQ_FIRST(&dbp->active_queue);
|
||||
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
|
||||
cp = (CURSOR *)dbc->internal;
|
||||
|
||||
if ((cp->pgno == pgno && cp->indx == indx) ||
|
||||
(cp->dpgno == pgno && cp->dindx == indx)) {
|
||||
if (delete)
|
||||
F_SET(cp, C_DELETED);
|
||||
else
|
||||
F_CLR(cp, C_DELETED);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
return (count);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_ca_di --
|
||||
* Adjust the cursors during a delete or insert.
|
||||
*
|
||||
* PUBLIC: void __bam_ca_di __P((DB *, db_pgno_t, u_int32_t, int));
|
||||
*/
|
||||
void
|
||||
__bam_ca_di(dbp, pgno, indx, adjust)
|
||||
DB *dbp;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t indx;
|
||||
int adjust;
|
||||
{
|
||||
CURSOR *cp;
|
||||
DBC *dbc;
|
||||
|
||||
/* Recno is responsible for its own adjustments. */
|
||||
if (dbp->type == DB_RECNO)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Adjust the cursors. See the comment in __bam_ca_delete().
|
||||
*/
|
||||
DB_THREAD_LOCK(dbp);
|
||||
for (dbc = TAILQ_FIRST(&dbp->active_queue);
|
||||
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
|
||||
cp = (CURSOR *)dbc->internal;
|
||||
if (cp->pgno == pgno && cp->indx >= indx)
|
||||
cp->indx += adjust;
|
||||
if (cp->dpgno == pgno && cp->dindx >= indx)
|
||||
cp->dindx += adjust;
|
||||
}
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_ca_dup --
|
||||
* Adjust the cursors when moving items from a leaf page to a duplicates
|
||||
* page.
|
||||
*
|
||||
* PUBLIC: void __bam_ca_dup __P((DB *,
|
||||
* PUBLIC: db_pgno_t, u_int32_t, u_int32_t, db_pgno_t, u_int32_t));
|
||||
*/
|
||||
void
|
||||
__bam_ca_dup(dbp, fpgno, first, fi, tpgno, ti)
|
||||
DB *dbp;
|
||||
db_pgno_t fpgno, tpgno;
|
||||
u_int32_t first, fi, ti;
|
||||
{
|
||||
CURSOR *cp;
|
||||
DBC *dbc;
|
||||
|
||||
/* Recno is responsible for its own adjustments. */
|
||||
if (dbp->type == DB_RECNO)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Adjust the cursors. See the comment in __bam_ca_delete().
|
||||
*/
|
||||
DB_THREAD_LOCK(dbp);
|
||||
for (dbc = TAILQ_FIRST(&dbp->active_queue);
|
||||
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
|
||||
cp = (CURSOR *)dbc->internal;
|
||||
/*
|
||||
* Ignore matching entries that have already been moved,
|
||||
* we move from the same location on the leaf page more
|
||||
* than once.
|
||||
*/
|
||||
if (cp->dpgno == PGNO_INVALID &&
|
||||
cp->pgno == fpgno && cp->indx == fi) {
|
||||
cp->indx = first;
|
||||
cp->dpgno = tpgno;
|
||||
cp->dindx = ti;
|
||||
}
|
||||
}
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_ca_rsplit --
|
||||
* Adjust the cursors when doing reverse splits.
|
||||
*
|
||||
* PUBLIC: void __bam_ca_rsplit __P((DB *, db_pgno_t, db_pgno_t));
|
||||
*/
|
||||
void
|
||||
__bam_ca_rsplit(dbp, fpgno, tpgno)
|
||||
DB *dbp;
|
||||
db_pgno_t fpgno, tpgno;
|
||||
{
|
||||
CURSOR *cp;
|
||||
DBC *dbc;
|
||||
|
||||
/* Recno is responsible for its own adjustments. */
|
||||
if (dbp->type == DB_RECNO)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Adjust the cursors. See the comment in __bam_ca_delete().
|
||||
*/
|
||||
DB_THREAD_LOCK(dbp);
|
||||
for (dbc = TAILQ_FIRST(&dbp->active_queue);
|
||||
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
|
||||
cp = (CURSOR *)dbc->internal;
|
||||
if (cp->pgno == fpgno)
|
||||
cp->pgno = tpgno;
|
||||
}
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_ca_split --
|
||||
* Adjust the cursors when splitting a page.
|
||||
*
|
||||
* PUBLIC: void __bam_ca_split __P((DB *,
|
||||
* PUBLIC: db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
|
||||
*/
|
||||
void
|
||||
__bam_ca_split(dbp, ppgno, lpgno, rpgno, split_indx, cleft)
|
||||
DB *dbp;
|
||||
db_pgno_t ppgno, lpgno, rpgno;
|
||||
u_int32_t split_indx;
|
||||
int cleft;
|
||||
{
|
||||
DBC *dbc;
|
||||
CURSOR *cp;
|
||||
|
||||
/* Recno is responsible for its own adjustments. */
|
||||
if (dbp->type == DB_RECNO)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Adjust the cursors. See the comment in __bam_ca_delete().
|
||||
*
|
||||
* If splitting the page that a cursor was on, the cursor has to be
|
||||
* adjusted to point to the same record as before the split. Most
|
||||
* of the time we don't adjust pointers to the left page, because
|
||||
* we're going to copy its contents back over the original page. If
|
||||
* the cursor is on the right page, it is decremented by the number of
|
||||
* records split to the left page.
|
||||
*/
|
||||
DB_THREAD_LOCK(dbp);
|
||||
for (dbc = TAILQ_FIRST(&dbp->active_queue);
|
||||
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
|
||||
cp = (CURSOR *)dbc->internal;
|
||||
if (cp->pgno == ppgno) {
|
||||
if (cp->indx < split_indx) {
|
||||
if (cleft)
|
||||
cp->pgno = lpgno;
|
||||
} else {
|
||||
cp->pgno = rpgno;
|
||||
cp->indx -= split_indx;
|
||||
}
|
||||
}
|
||||
if (cp->dpgno == ppgno) {
|
||||
if (cp->dindx < split_indx) {
|
||||
if (cleft)
|
||||
cp->dpgno = lpgno;
|
||||
} else {
|
||||
cp->dpgno = rpgno;
|
||||
cp->dindx -= split_indx;
|
||||
}
|
||||
}
|
||||
}
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_delete.c 10.31 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)bt_delete.c 10.43 (Sleepycat) 12/7/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -60,8 +60,6 @@ static const char sccsid[] = "@(#)bt_delete.c 10.31 (Sleepycat) 5/6/98";
|
||||
#include "db_page.h"
|
||||
#include "btree.h"
|
||||
|
||||
static int __bam_dpages __P((DB *, BTREE *));
|
||||
|
||||
/*
|
||||
* __bam_delete --
|
||||
* Delete the items referenced by a key.
|
||||
@ -69,182 +67,67 @@ static int __bam_dpages __P((DB *, BTREE *));
|
||||
* PUBLIC: int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_delete(argdbp, txn, key, flags)
|
||||
DB *argdbp;
|
||||
__bam_delete(dbp, txn, key, flags)
|
||||
DB *dbp;
|
||||
DB_TXN *txn;
|
||||
DBT *key;
|
||||
u_int32_t flags;
|
||||
{
|
||||
BTREE *t;
|
||||
DB *dbp;
|
||||
PAGE *h;
|
||||
db_indx_t cnt, i, indx;
|
||||
int dpage, exact, ret, stack;
|
||||
DBC *dbc;
|
||||
DBT data;
|
||||
u_int32_t f_init, f_next;
|
||||
int ret, t_ret;
|
||||
|
||||
DEBUG_LWRITE(argdbp, txn, "bam_delete", key, NULL, flags);
|
||||
|
||||
stack = 0;
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
/* Check for invalid flags. */
|
||||
if ((ret = __db_delchk(argdbp,
|
||||
key, flags, F_ISSET(argdbp, DB_AM_RDONLY))) != 0)
|
||||
if ((ret =
|
||||
__db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0)
|
||||
return (ret);
|
||||
|
||||
GETHANDLE(argdbp, txn, &dbp, ret);
|
||||
t = dbp->internal;
|
||||
/* Allocate a cursor. */
|
||||
if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Search the tree for the key; delete only deletes exact matches. */
|
||||
if ((ret = __bam_search(dbp, key, S_DELETE, 1, NULL, &exact)) != 0)
|
||||
DEBUG_LWRITE(dbc, txn, "bam_delete", key, NULL, flags);
|
||||
|
||||
/*
|
||||
* Walk a cursor through the key/data pairs, deleting as we go. Set
|
||||
* the DB_DBT_USERMEM flag, as this might be a threaded application
|
||||
* and the flags checking will catch us. We don't actually want the
|
||||
* keys or data, so request a partial of length 0.
|
||||
*/
|
||||
memset(&data, 0, sizeof(data));
|
||||
F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
|
||||
/* If locking, set read-modify-write flag. */
|
||||
f_init = DB_SET;
|
||||
f_next = DB_NEXT_DUP;
|
||||
if (dbp->dbenv != NULL && dbp->dbenv->lk_info != NULL) {
|
||||
f_init |= DB_RMW;
|
||||
f_next |= DB_RMW;
|
||||
}
|
||||
|
||||
/* Walk through the set of key/data pairs, deleting as we go. */
|
||||
if ((ret = dbc->c_get(dbc, key, &data, f_init)) != 0)
|
||||
goto err;
|
||||
stack = 1;
|
||||
h = t->bt_csp->page;
|
||||
indx = t->bt_csp->indx;
|
||||
|
||||
/* Delete the key/data pair, including any on-or-off page duplicates. */
|
||||
for (cnt = 1, i = indx;; ++cnt)
|
||||
if ((i += P_INDX) >= NUM_ENT(h) || h->inp[i] != h->inp[indx])
|
||||
break;
|
||||
for (; cnt > 0; --cnt, ++t->lstat.bt_deleted)
|
||||
if (__bam_ca_delete(dbp, h->pgno, indx, NULL, 1) == 0) {
|
||||
/*
|
||||
* XXX
|
||||
* Delete the key item first, otherwise the duplicate
|
||||
* checks in __bam_ditem() won't work!
|
||||
*/
|
||||
if ((ret = __bam_ditem(dbp, h, indx)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_ditem(dbp, h, indx)) != 0)
|
||||
goto err;
|
||||
} else {
|
||||
B_DSET(GET_BKEYDATA(h, indx + O_INDX)->type);
|
||||
indx += P_INDX;
|
||||
for (;;) {
|
||||
if ((ret = dbc->c_del(dbc, 0)) != 0)
|
||||
goto err;
|
||||
if ((ret = dbc->c_get(dbc, key, &data, f_next)) != 0) {
|
||||
if (ret == DB_NOTFOUND) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* If we're using record numbers, update internal page record counts. */
|
||||
if (F_ISSET(dbp, DB_BT_RECNUM) && (ret = __bam_adjust(dbp, t, -1)) != 0)
|
||||
goto err;
|
||||
|
||||
/* If the page is now empty, delete it. */
|
||||
dpage = NUM_ENT(h) == 0 && h->pgno != PGNO_ROOT;
|
||||
|
||||
__bam_stkrel(dbp);
|
||||
stack = 0;
|
||||
|
||||
ret = dpage ? __bam_dpage(dbp, key) : 0;
|
||||
|
||||
err: if (stack)
|
||||
__bam_stkrel(dbp);
|
||||
PUTHANDLE(dbp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __ram_delete --
|
||||
* Delete the items referenced by a key.
|
||||
*
|
||||
* PUBLIC: int __ram_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__ram_delete(argdbp, txn, key, flags)
|
||||
DB *argdbp;
|
||||
DB_TXN *txn;
|
||||
DBT *key;
|
||||
u_int32_t flags;
|
||||
{
|
||||
BKEYDATA bk;
|
||||
BTREE *t;
|
||||
DB *dbp;
|
||||
DBT hdr, data;
|
||||
PAGE *h;
|
||||
db_indx_t indx;
|
||||
db_recno_t recno;
|
||||
int exact, ret, stack;
|
||||
|
||||
stack = 0;
|
||||
|
||||
/* Check for invalid flags. */
|
||||
if ((ret = __db_delchk(argdbp,
|
||||
key, flags, F_ISSET(argdbp, DB_AM_RDONLY))) != 0)
|
||||
return (ret);
|
||||
|
||||
GETHANDLE(argdbp, txn, &dbp, ret);
|
||||
t = dbp->internal;
|
||||
|
||||
/* Check the user's record number and fill in as necessary. */
|
||||
if ((ret = __ram_getno(argdbp, key, &recno, 0)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Search the tree for the key; delete only deletes exact matches. */
|
||||
if ((ret = __bam_rsearch(dbp, &recno, S_DELETE, 1, &exact)) != 0)
|
||||
goto err;
|
||||
if (!exact) {
|
||||
ret = DB_NOTFOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
h = t->bt_csp->page;
|
||||
indx = t->bt_csp->indx;
|
||||
stack = 1;
|
||||
err: /* Discard the cursor. */
|
||||
if ((t_ret = dbc->c_close(dbc)) != 0 &&
|
||||
(ret == 0 || ret == DB_NOTFOUND))
|
||||
ret = t_ret;
|
||||
|
||||
/* If the record has already been deleted, we couldn't have found it. */
|
||||
if (B_DISSET(GET_BKEYDATA(h, indx)->type)) {
|
||||
ret = DB_KEYEMPTY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're not renumbering records, replace the record with a marker
|
||||
* and return.
|
||||
*/
|
||||
if (!F_ISSET(dbp, DB_RE_RENUMBER)) {
|
||||
if ((ret = __bam_ditem(dbp, h, indx)) != 0)
|
||||
goto err;
|
||||
|
||||
B_TSET(bk.type, B_KEYDATA, 1);
|
||||
bk.len = 0;
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.data = &bk;
|
||||
hdr.size = SSZA(BKEYDATA, data);
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = (char *)"";
|
||||
data.size = 0;
|
||||
if ((ret = __db_pitem(dbp,
|
||||
h, indx, BKEYDATA_SIZE(0), &hdr, &data)) != 0)
|
||||
goto err;
|
||||
|
||||
++t->lstat.bt_deleted;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Delete the item. */
|
||||
if ((ret = __bam_ditem(dbp, h, indx)) != 0)
|
||||
goto err;
|
||||
|
||||
++t->lstat.bt_deleted;
|
||||
if (t->bt_recno != NULL)
|
||||
F_SET(t->bt_recno, RECNO_MODIFIED);
|
||||
|
||||
/* Adjust the counts. */
|
||||
__bam_adjust(dbp, t, -1);
|
||||
|
||||
/* Adjust the cursors. */
|
||||
__ram_ca(dbp, recno, CA_DELETE);
|
||||
|
||||
/*
|
||||
* If the page is now empty, delete it -- we have the whole tree
|
||||
* locked, so there are no preparations to make. Else, release
|
||||
* the pages.
|
||||
*/
|
||||
if (NUM_ENT(h) == 0 && h->pgno != PGNO_ROOT) {
|
||||
stack = 0;
|
||||
ret = __bam_dpages(dbp, t);
|
||||
}
|
||||
|
||||
done:
|
||||
err: if (stack)
|
||||
__bam_stkrel(dbp);
|
||||
|
||||
PUTHANDLE(dbp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -252,20 +135,23 @@ err: if (stack)
|
||||
* __bam_ditem --
|
||||
* Delete one or more entries from a page.
|
||||
*
|
||||
* PUBLIC: int __bam_ditem __P((DB *, PAGE *, u_int32_t));
|
||||
* PUBLIC: int __bam_ditem __P((DBC *, PAGE *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_ditem(dbp, h, indx)
|
||||
DB *dbp;
|
||||
__bam_ditem(dbc, h, indx)
|
||||
DBC *dbc;
|
||||
PAGE *h;
|
||||
u_int32_t indx;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
BKEYDATA *bk;
|
||||
BOVERFLOW *bo;
|
||||
DB *dbp;
|
||||
u_int32_t nbytes;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
switch (TYPE(h)) {
|
||||
case P_IBTREE:
|
||||
bi = GET_BINTERNAL(h, indx);
|
||||
@ -304,7 +190,7 @@ __bam_ditem(dbp, h, indx)
|
||||
*/
|
||||
if (indx + P_INDX < (u_int32_t)NUM_ENT(h) &&
|
||||
h->inp[indx] == h->inp[indx + P_INDX])
|
||||
return (__bam_adjindx(dbp,
|
||||
return (__bam_adjindx(dbc,
|
||||
h, indx, indx + O_INDX, 0));
|
||||
/*
|
||||
* Check for a duplicate before us on the page. It
|
||||
@ -312,7 +198,7 @@ __bam_ditem(dbp, h, indx)
|
||||
* after the data item for the purposes of this one.
|
||||
*/
|
||||
if (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX])
|
||||
return (__bam_adjindx(dbp,
|
||||
return (__bam_adjindx(dbc,
|
||||
h, indx, indx - P_INDX, 0));
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
@ -327,11 +213,11 @@ __bam_ditem(dbp, h, indx)
|
||||
offpage: /* Delete duplicate/offpage chains. */
|
||||
if (B_TYPE(bo->type) == B_DUPLICATE) {
|
||||
if ((ret =
|
||||
__db_ddup(dbp, bo->pgno, __bam_free)) != 0)
|
||||
__db_ddup(dbc, bo->pgno, __bam_free)) != 0)
|
||||
return (ret);
|
||||
} else
|
||||
if ((ret =
|
||||
__db_doff(dbp, bo->pgno, __bam_free)) != 0)
|
||||
__db_doff(dbc, bo->pgno, __bam_free)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
case B_KEYDATA:
|
||||
@ -346,7 +232,7 @@ offpage: /* Delete duplicate/offpage chains. */
|
||||
}
|
||||
|
||||
/* Delete the item. */
|
||||
if ((ret = __db_ditem(dbp, h, indx, nbytes)) != 0)
|
||||
if ((ret = __db_ditem(dbc, h, indx, nbytes)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Mark the page dirty. */
|
||||
@ -357,21 +243,24 @@ offpage: /* Delete duplicate/offpage chains. */
|
||||
* __bam_adjindx --
|
||||
* Adjust an index on the page.
|
||||
*
|
||||
* PUBLIC: int __bam_adjindx __P((DB *, PAGE *, u_int32_t, u_int32_t, int));
|
||||
* PUBLIC: int __bam_adjindx __P((DBC *, PAGE *, u_int32_t, u_int32_t, int));
|
||||
*/
|
||||
int
|
||||
__bam_adjindx(dbp, h, indx, indx_copy, is_insert)
|
||||
DB *dbp;
|
||||
__bam_adjindx(dbc, h, indx, indx_copy, is_insert)
|
||||
DBC *dbc;
|
||||
PAGE *h;
|
||||
u_int32_t indx, indx_copy;
|
||||
int is_insert;
|
||||
{
|
||||
DB *dbp;
|
||||
db_indx_t copy;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp) &&
|
||||
(ret = __bam_adj_log(dbp->dbenv->lg_info, dbp->txn, &LSN(h),
|
||||
if (DB_LOGGING(dbc) &&
|
||||
(ret = __bam_adj_log(dbp->dbenv->lg_info, dbc->txn, &LSN(h),
|
||||
0, dbp->log_fileid, PGNO(h), &LSN(h), indx, indx_copy,
|
||||
(u_int32_t)is_insert)) != 0)
|
||||
return (ret);
|
||||
@ -402,22 +291,24 @@ __bam_adjindx(dbp, h, indx, indx_copy, is_insert)
|
||||
* __bam_dpage --
|
||||
* Delete a page from the tree.
|
||||
*
|
||||
* PUBLIC: int __bam_dpage __P((DB *, const DBT *));
|
||||
* PUBLIC: int __bam_dpage __P((DBC *, const DBT *));
|
||||
*/
|
||||
int
|
||||
__bam_dpage(dbp, key)
|
||||
DB *dbp;
|
||||
__bam_dpage(dbc, key)
|
||||
DBC *dbc;
|
||||
const DBT *key;
|
||||
{
|
||||
BTREE *t;
|
||||
CURSOR *cp;
|
||||
DB *dbp;
|
||||
DB_LOCK lock;
|
||||
PAGE *h;
|
||||
db_pgno_t pgno;
|
||||
int level; /* !!!: has to hold number of tree levels. */
|
||||
int exact, ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
cp = dbc->internal;
|
||||
ret = 0;
|
||||
t = dbp->internal;
|
||||
|
||||
/*
|
||||
* The locking protocol is that we acquire locks by walking down the
|
||||
@ -433,40 +324,40 @@ __bam_dpage(dbp, key)
|
||||
for (level = LEAFLEVEL;; ++level) {
|
||||
/* Acquire a page and its parent, locked. */
|
||||
if ((ret =
|
||||
__bam_search(dbp, key, S_WRPAIR, level, NULL, &exact)) != 0)
|
||||
__bam_search(dbc, key, S_WRPAIR, level, NULL, &exact)) != 0)
|
||||
return (ret);
|
||||
|
||||
/*
|
||||
* If we reach the root or the page isn't going to be empty
|
||||
* when we delete one record, quit.
|
||||
*/
|
||||
h = t->bt_csp[-1].page;
|
||||
h = cp->csp[-1].page;
|
||||
if (h->pgno == PGNO_ROOT || NUM_ENT(h) != 1)
|
||||
break;
|
||||
|
||||
/* Release the two locked pages. */
|
||||
(void)memp_fput(dbp->mpf, t->bt_csp[-1].page, 0);
|
||||
(void)__BT_TLPUT(dbp, t->bt_csp[-1].lock);
|
||||
(void)memp_fput(dbp->mpf, t->bt_csp[0].page, 0);
|
||||
(void)__BT_TLPUT(dbp, t->bt_csp[0].lock);
|
||||
(void)memp_fput(dbp->mpf, cp->csp[-1].page, 0);
|
||||
(void)__BT_TLPUT(dbc, cp->csp[-1].lock);
|
||||
(void)memp_fput(dbp->mpf, cp->csp[0].page, 0);
|
||||
(void)__BT_TLPUT(dbc, cp->csp[0].lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave the stack pointer one after the last entry, we may be about
|
||||
* to push more items on the stack.
|
||||
*/
|
||||
++t->bt_csp;
|
||||
++cp->csp;
|
||||
|
||||
/*
|
||||
* t->bt_csp[-2].page is the top page, which we're not going to delete,
|
||||
* and t->bt_csp[-1].page is the first page we are going to delete.
|
||||
* cp->csp[-2].page is the top page, which we're not going to delete,
|
||||
* and cp->csp[-1].page is the first page we are going to delete.
|
||||
*
|
||||
* Walk down the chain, acquiring the rest of the pages until we've
|
||||
* retrieved the leaf page. If we find any pages that aren't going
|
||||
* to be emptied by the delete, someone else added something while we
|
||||
* were walking the tree, and we discontinue the delete.
|
||||
*/
|
||||
for (h = t->bt_csp[-1].page;;) {
|
||||
for (h = cp->csp[-1].page;;) {
|
||||
if (ISLEAF(h)) {
|
||||
if (NUM_ENT(h) != 0)
|
||||
goto release;
|
||||
@ -482,45 +373,53 @@ __bam_dpage(dbp, key)
|
||||
pgno = TYPE(h) == P_IBTREE ?
|
||||
GET_BINTERNAL(h, 0)->pgno : GET_RINTERNAL(h, 0)->pgno;
|
||||
|
||||
if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &lock)) != 0)
|
||||
if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_WRITE, &lock)) != 0)
|
||||
goto release;
|
||||
if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
|
||||
goto release;
|
||||
BT_STK_PUSH(t, h, 0, lock, ret);
|
||||
if (ret != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
|
||||
goto release;
|
||||
BT_STK_PUSH(cp, h, 0, lock, ret);
|
||||
}
|
||||
|
||||
BT_STK_POP(t);
|
||||
return (__bam_dpages(dbp, t));
|
||||
/* Adjust back to reference the last page on the stack. */
|
||||
BT_STK_POP(cp);
|
||||
|
||||
/* Delete the pages. */
|
||||
return (__bam_dpages(dbc));
|
||||
|
||||
release:
|
||||
/* Adjust back to reference the last page on the stack. */
|
||||
BT_STK_POP(cp);
|
||||
|
||||
/* Discard any locked pages and return. */
|
||||
BT_STK_POP(t);
|
||||
__bam_stkrel(dbp);
|
||||
__bam_stkrel(dbc, 0);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_dpages --
|
||||
* Delete a set of locked pages.
|
||||
*
|
||||
* PUBLIC: int __bam_dpages __P((DBC *));
|
||||
*/
|
||||
static int
|
||||
__bam_dpages(dbp, t)
|
||||
DB *dbp;
|
||||
BTREE *t;
|
||||
int
|
||||
__bam_dpages(dbc)
|
||||
DBC *dbc;
|
||||
{
|
||||
CURSOR *cp;
|
||||
DB *dbp;
|
||||
DBT a, b;
|
||||
DB_LOCK lock;
|
||||
DB_LOCK c_lock, p_lock;
|
||||
EPG *epg;
|
||||
PAGE *h;
|
||||
PAGE *child, *parent;
|
||||
db_indx_t nitems;
|
||||
db_pgno_t pgno;
|
||||
db_recno_t rcnt;
|
||||
int ret;
|
||||
int done, ret;
|
||||
|
||||
COMPQUIET(rcnt, 0);
|
||||
|
||||
epg = t->bt_sp;
|
||||
dbp = dbc->dbp;
|
||||
cp = dbc->internal;
|
||||
epg = cp->sp;
|
||||
|
||||
/*
|
||||
* !!!
|
||||
@ -533,45 +432,107 @@ __bam_dpages(dbp, t)
|
||||
* that we can never again access by walking down the tree. So, before
|
||||
* we unlink the subtree, we relink the leaf page chain.
|
||||
*/
|
||||
if ((ret = __db_relink(dbp, t->bt_csp->page, NULL, 1)) != 0)
|
||||
if ((ret = __db_relink(dbc, DB_REM_PAGE, cp->csp->page, NULL, 1)) != 0)
|
||||
goto release;
|
||||
|
||||
/*
|
||||
* We have the entire stack of deletable pages locked. Start from the
|
||||
* top of the tree and move to the bottom, as it's better to release
|
||||
* the inner pages as soon as possible.
|
||||
* We have the entire stack of deletable pages locked.
|
||||
*
|
||||
* Delete the highest page in the tree's reference to the underlying
|
||||
* stack of pages. Then, release that page, letting the rest of the
|
||||
* tree get back to business.
|
||||
*/
|
||||
if ((ret = __bam_ditem(dbp, epg->page, epg->indx)) != 0)
|
||||
goto release;
|
||||
if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0) {
|
||||
release: (void)__bam_stkrel(dbc, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
pgno = epg->page->pgno;
|
||||
nitems = NUM_ENT(epg->page);
|
||||
|
||||
(void)memp_fput(dbp->mpf, epg->page, 0);
|
||||
(void)__BT_TLPUT(dbc, epg->lock);
|
||||
|
||||
/*
|
||||
* If we just deleted the last or next-to-last item from the root page,
|
||||
* the tree can collapse a level. Write lock the last page referenced
|
||||
* Free the rest of the stack of pages.
|
||||
*
|
||||
* !!!
|
||||
* Don't bother checking for errors. We've unlinked the subtree from
|
||||
* the tree, and there's no possibility of recovery outside of doing
|
||||
* TXN rollback.
|
||||
*/
|
||||
while (++epg <= cp->csp) {
|
||||
/*
|
||||
* Delete page entries so they will be restored as part of
|
||||
* recovery.
|
||||
*/
|
||||
if (NUM_ENT(epg->page) != 0)
|
||||
(void)__bam_ditem(dbc, epg->page, epg->indx);
|
||||
|
||||
(void)__bam_free(dbc, epg->page);
|
||||
(void)__BT_TLPUT(dbc, epg->lock);
|
||||
}
|
||||
BT_STK_CLR(cp);
|
||||
|
||||
/*
|
||||
* Try and collapse the tree a level -- this is only applicable
|
||||
* if we've deleted the next-to-last element from the root page.
|
||||
*
|
||||
* There are two cases when collapsing a tree.
|
||||
*
|
||||
* If we've just deleted the last item from the root page, there is no
|
||||
* further work to be done. The code above has emptied the root page
|
||||
* and freed all pages below it.
|
||||
*/
|
||||
if (pgno != PGNO_ROOT || nitems != 1)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If we just deleted the next-to-last item from the root page, the
|
||||
* tree can collapse one or more levels. While there remains only a
|
||||
* single item on the root page, write lock the last page referenced
|
||||
* by the root page and copy it over the root page. If we can't get a
|
||||
* write lock, that's okay, the tree just remains a level deeper than
|
||||
* we'd like.
|
||||
* write lock, that's okay, the tree just stays deeper than we'd like.
|
||||
*/
|
||||
h = epg->page;
|
||||
if (h->pgno == PGNO_ROOT && NUM_ENT(h) <= 1) {
|
||||
pgno = TYPE(epg->page) == P_IBTREE ?
|
||||
GET_BINTERNAL(epg->page, 0)->pgno :
|
||||
GET_RINTERNAL(epg->page, 0)->pgno;
|
||||
if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &lock)) != 0)
|
||||
goto release;
|
||||
if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
|
||||
goto release;
|
||||
for (done = 0; !done;) {
|
||||
/* Initialize. */
|
||||
parent = child = NULL;
|
||||
p_lock = c_lock = LOCK_INVALID;
|
||||
|
||||
/* Lock the root. */
|
||||
pgno = PGNO_ROOT;
|
||||
if ((ret =
|
||||
__bam_lget(dbc, 0, pgno, DB_LOCK_WRITE, &p_lock)) != 0)
|
||||
goto stop;
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &parent)) != 0)
|
||||
goto stop;
|
||||
|
||||
if (NUM_ENT(parent) != 1 ||
|
||||
(TYPE(parent) != P_IBTREE && TYPE(parent) != P_IRECNO))
|
||||
goto stop;
|
||||
|
||||
pgno = TYPE(parent) == P_IBTREE ?
|
||||
GET_BINTERNAL(parent, 0)->pgno :
|
||||
GET_RINTERNAL(parent, 0)->pgno;
|
||||
|
||||
/* Lock the child page. */
|
||||
if ((ret =
|
||||
__bam_lget(dbc, 0, pgno, DB_LOCK_WRITE, &c_lock)) != 0)
|
||||
goto stop;
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &child)) != 0)
|
||||
goto stop;
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
memset(&a, 0, sizeof(a));
|
||||
a.data = h;
|
||||
a.data = child;
|
||||
a.size = dbp->pgsize;
|
||||
memset(&b, 0, sizeof(b));
|
||||
b.data = P_ENTRY(epg->page, 0);
|
||||
b.data = P_ENTRY(parent, 0);
|
||||
b.size = BINTERNAL_SIZE(((BINTERNAL *)b.data)->len);
|
||||
__bam_rsplit_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
&h->lsn, 0, dbp->log_fileid, h->pgno, &a,
|
||||
RE_NREC(epg->page), &b, &epg->page->lsn);
|
||||
__bam_rsplit_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&child->lsn, 0, dbp->log_fileid, child->pgno, &a,
|
||||
RE_NREC(parent), &b, &parent->lsn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -579,69 +540,50 @@ __bam_dpages(dbp, t)
|
||||
*
|
||||
* One fixup -- if the tree has record numbers and we're not
|
||||
* converting to a leaf page, we have to preserve the total
|
||||
* record count.
|
||||
* record count. Note that we are about to overwrite everything
|
||||
* on the parent, including its LSN. This is actually OK,
|
||||
* because the above log message, which describes this update,
|
||||
* stores its LSN on the child page. When the child is copied
|
||||
* to the parent, the correct LSN is going to copied into
|
||||
* place in the parent.
|
||||
*/
|
||||
if (TYPE(h) == P_IRECNO ||
|
||||
(TYPE(h) == P_IBTREE && F_ISSET(dbp, DB_BT_RECNUM)))
|
||||
rcnt = RE_NREC(epg->page);
|
||||
memcpy(epg->page, h, dbp->pgsize);
|
||||
epg->page->pgno = PGNO_ROOT;
|
||||
if (TYPE(h) == P_IRECNO ||
|
||||
(TYPE(h) == P_IBTREE && F_ISSET(dbp, DB_BT_RECNUM)))
|
||||
RE_NREC_SET(epg->page, rcnt);
|
||||
(void)memp_fset(dbp->mpf, epg->page, DB_MPOOL_DIRTY);
|
||||
COMPQUIET(rcnt, 0);
|
||||
if (TYPE(child) == P_IRECNO ||
|
||||
(TYPE(child) == P_IBTREE && F_ISSET(dbp, DB_BT_RECNUM)))
|
||||
rcnt = RE_NREC(parent);
|
||||
memcpy(parent, child, dbp->pgsize);
|
||||
parent->pgno = PGNO_ROOT;
|
||||
if (TYPE(child) == P_IRECNO ||
|
||||
(TYPE(child) == P_IBTREE && F_ISSET(dbp, DB_BT_RECNUM)))
|
||||
RE_NREC_SET(parent, rcnt);
|
||||
|
||||
/* Mark the pages dirty. */
|
||||
memp_fset(dbp->mpf, parent, DB_MPOOL_DIRTY);
|
||||
memp_fset(dbp->mpf, child, DB_MPOOL_DIRTY);
|
||||
|
||||
/* Adjust the cursors. */
|
||||
__bam_ca_rsplit(dbp, child->pgno, PGNO_ROOT);
|
||||
|
||||
/*
|
||||
* Free the page copied onto the root page and discard its
|
||||
* lock. (The call to __bam_free() discards our reference
|
||||
* to the page.)
|
||||
*
|
||||
* It's possible that the reverse split we're doing involves
|
||||
* pages from the stack of pages we're deleting. Don't free
|
||||
* the page twice.
|
||||
*/
|
||||
if (h->pgno == (epg + 1)->page->pgno)
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
else {
|
||||
(void)__bam_free(dbp, h);
|
||||
++t->lstat.bt_freed;
|
||||
(void)__bam_free(dbc, child);
|
||||
child = NULL;
|
||||
|
||||
if (0) {
|
||||
stop: done = 1;
|
||||
}
|
||||
(void)__BT_TLPUT(dbp, lock);
|
||||
|
||||
/* Adjust the cursors. */
|
||||
__bam_ca_move(dbp, h->pgno, PGNO_ROOT);
|
||||
if (p_lock != LOCK_INVALID)
|
||||
(void)__BT_TLPUT(dbc, p_lock);
|
||||
if (parent != NULL)
|
||||
memp_fput(dbp->mpf, parent, 0);
|
||||
if (c_lock != LOCK_INVALID)
|
||||
(void)__BT_TLPUT(dbc, c_lock);
|
||||
if (child != NULL)
|
||||
memp_fput(dbp->mpf, child, 0);
|
||||
}
|
||||
|
||||
/* Release the top page in the subtree. */
|
||||
(void)memp_fput(dbp->mpf, epg->page, 0);
|
||||
(void)__BT_TLPUT(dbp, epg->lock);
|
||||
|
||||
/*
|
||||
* Free the rest of the pages.
|
||||
*
|
||||
* XXX
|
||||
* Don't bother checking for errors. We've unlinked the subtree from
|
||||
* the tree, and there's no possibility of recovery.
|
||||
*/
|
||||
while (++epg <= t->bt_csp) {
|
||||
/*
|
||||
* XXX
|
||||
* Why do we need to do this? Isn't the page already empty?
|
||||
*/
|
||||
if (NUM_ENT(epg->page) != 0)
|
||||
(void)__bam_ditem(dbp, epg->page, epg->indx);
|
||||
|
||||
(void)__bam_free(dbp, epg->page);
|
||||
(void)__BT_TLPUT(dbp, epg->lock);
|
||||
++t->lstat.bt_freed;
|
||||
}
|
||||
return (0);
|
||||
|
||||
release:
|
||||
/* Discard any remaining pages and return. */
|
||||
for (; epg <= t->bt_csp; ++epg) {
|
||||
(void)memp_fput(dbp->mpf, epg->page, 0);
|
||||
(void)__BT_TLPUT(dbp, epg->lock);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
@ -47,17 +47,9 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_open.c 10.27 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)bt_open.c 10.39 (Sleepycat) 11/21/98";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Implementation of btree access method for 4.4BSD.
|
||||
*
|
||||
* The design here was originally based on that of the btree access method
|
||||
* used in the Postgres database system at UC Berkeley. This implementation
|
||||
* is wholly independent of the Postgres code.
|
||||
*/
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -70,40 +62,34 @@ static const char sccsid[] = "@(#)bt_open.c 10.27 (Sleepycat) 5/6/98";
|
||||
#include "db_page.h"
|
||||
#include "btree.h"
|
||||
|
||||
static int __bam_keyalloc __P((BTREE *));
|
||||
static int __bam_setmeta __P((DB *, BTREE *));
|
||||
|
||||
/*
|
||||
* __bam_open --
|
||||
* Open a btree.
|
||||
*
|
||||
* PUBLIC: int __bam_open __P((DB *, DBTYPE, DB_INFO *));
|
||||
* PUBLIC: int __bam_open __P((DB *, DB_INFO *));
|
||||
*/
|
||||
int
|
||||
__bam_open(dbp, type, dbinfo)
|
||||
__bam_open(dbp, dbinfo)
|
||||
DB *dbp;
|
||||
DBTYPE type;
|
||||
DB_INFO *dbinfo;
|
||||
{
|
||||
BTREE *t;
|
||||
int ret;
|
||||
|
||||
/* Allocate the btree internal structure. */
|
||||
if ((t = (BTREE *)__db_calloc(1, sizeof(BTREE))) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
t->bt_sp = t->bt_csp = t->bt_stack;
|
||||
t->bt_esp = t->bt_stack + sizeof(t->bt_stack) / sizeof(t->bt_stack[0]);
|
||||
|
||||
if ((type == DB_RECNO || F_ISSET(dbp, DB_BT_RECNUM)) &&
|
||||
(ret = __bam_keyalloc(t)) != 0)
|
||||
goto err;
|
||||
/* Allocate and initialize the private btree structure. */
|
||||
if ((ret = __os_calloc(1, sizeof(BTREE), &t)) != 0)
|
||||
return (ret);
|
||||
dbp->internal = t;
|
||||
|
||||
/*
|
||||
* Intention is to make sure all of the user's selections are okay
|
||||
* here and then use them without checking.
|
||||
*/
|
||||
if (dbinfo != NULL) {
|
||||
if (dbinfo == NULL) {
|
||||
t->bt_minkey = DEFMINKEYPAGE;
|
||||
t->bt_compare = __bam_defcmp;
|
||||
t->bt_prefix = __bam_defpfx;
|
||||
} else {
|
||||
/* Minimum number of keys per page. */
|
||||
if (dbinfo->bt_minkey == 0)
|
||||
t->bt_minkey = DEFMINKEYPAGE;
|
||||
@ -126,28 +112,76 @@ __bam_open(dbp, type, dbinfo)
|
||||
* If no comparison, use default comparison. If no comparison
|
||||
* and no prefix, use default prefix. (We can't default the
|
||||
* prefix if the user supplies a comparison routine; shortening
|
||||
* the keys may break their comparison algorithm.)
|
||||
* the keys may break their comparison algorithm. We don't
|
||||
* permit the user to specify a prefix routine if they didn't
|
||||
* also specify a comparison routine, they can't know enough
|
||||
* about our comparison routine to get it right.)
|
||||
*/
|
||||
t->bt_compare = dbinfo->bt_compare == NULL ?
|
||||
__bam_defcmp : dbinfo->bt_compare;
|
||||
t->bt_prefix = dbinfo->bt_prefix == NULL ?
|
||||
(dbinfo->bt_compare == NULL ?
|
||||
__bam_defpfx : NULL) : dbinfo->bt_prefix;
|
||||
} else {
|
||||
t->bt_minkey = DEFMINKEYPAGE;
|
||||
t->bt_compare = __bam_defcmp;
|
||||
t->bt_prefix = __bam_defpfx;
|
||||
if ((t->bt_compare = dbinfo->bt_compare) == NULL) {
|
||||
if (dbinfo->bt_prefix != NULL)
|
||||
goto einval;
|
||||
t->bt_compare = __bam_defcmp;
|
||||
t->bt_prefix = __bam_defpfx;
|
||||
} else
|
||||
t->bt_prefix = dbinfo->bt_prefix;
|
||||
}
|
||||
|
||||
/* Initialize the remaining fields of the DB. */
|
||||
dbp->type = type;
|
||||
dbp->internal = t;
|
||||
dbp->cursor = __bam_cursor;
|
||||
/* Initialize the remaining fields/methods of the DB. */
|
||||
dbp->am_close = __bam_close;
|
||||
dbp->del = __bam_delete;
|
||||
dbp->get = __bam_get;
|
||||
dbp->put = __bam_put;
|
||||
dbp->stat = __bam_stat;
|
||||
dbp->sync = __bam_sync;
|
||||
|
||||
/* Start up the tree. */
|
||||
if ((ret = __bam_read_root(dbp)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Set the overflow page size. */
|
||||
__bam_setovflsize(dbp);
|
||||
|
||||
return (0);
|
||||
|
||||
einval: ret = EINVAL;
|
||||
|
||||
err: __os_free(t, sizeof(BTREE));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_close --
|
||||
* Close a btree.
|
||||
*
|
||||
* PUBLIC: int __bam_close __P((DB *));
|
||||
*/
|
||||
int
|
||||
__bam_close(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
__os_free(dbp->internal, sizeof(BTREE));
|
||||
dbp->internal = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_setovflsize --
|
||||
*
|
||||
* PUBLIC: void __bam_setovflsize __P((DB *));
|
||||
*/
|
||||
void
|
||||
__bam_setovflsize(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
BTREE *t;
|
||||
|
||||
t = dbp->internal;
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Correction for recno, which doesn't know anything about minimum
|
||||
* keys per page.
|
||||
*/
|
||||
if (t->bt_minkey == 0)
|
||||
t->bt_minkey = DEFMINKEYPAGE;
|
||||
|
||||
/*
|
||||
* The btree data structure requires that at least two key/data pairs
|
||||
@ -161,117 +195,42 @@ __bam_open(dbp, type, dbinfo)
|
||||
*/
|
||||
t->bt_ovflsize = (dbp->pgsize - P_OVERHEAD) / (t->bt_minkey * P_INDX)
|
||||
- (BKEYDATA_PSIZE(0) + ALIGN(1, 4));
|
||||
|
||||
/* Create a root page if new tree. */
|
||||
if ((ret = __bam_setmeta(dbp, t)) != 0)
|
||||
goto err;
|
||||
|
||||
return (0);
|
||||
|
||||
einval: ret = EINVAL;
|
||||
|
||||
err: if (t != NULL) {
|
||||
/* If we allocated room for key/data return, discard it. */
|
||||
if (t->bt_rkey.data != NULL)
|
||||
__db_free(t->bt_rkey.data);
|
||||
|
||||
FREE(t, sizeof(BTREE));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_bdup --
|
||||
* Create a BTREE handle for a threaded DB handle.
|
||||
* __bam_read_root --
|
||||
* Check (and optionally create) a tree.
|
||||
*
|
||||
* PUBLIC: int __bam_bdup __P((DB *, DB *));
|
||||
* PUBLIC: int __bam_read_root __P((DB *));
|
||||
*/
|
||||
int
|
||||
__bam_bdup(orig, new)
|
||||
DB *orig, *new;
|
||||
{
|
||||
BTREE *t, *ot;
|
||||
int ret;
|
||||
|
||||
ot = orig->internal;
|
||||
|
||||
if ((t = (BTREE *)__db_calloc(1, sizeof(*t))) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Ignore the cursor queue, only the first DB has attached cursors.
|
||||
*/
|
||||
|
||||
t->bt_sp = t->bt_csp = t->bt_stack;
|
||||
t->bt_esp = t->bt_stack + sizeof(t->bt_stack) / sizeof(t->bt_stack[0]);
|
||||
|
||||
if ((orig->type == DB_RECNO || F_ISSET(orig, DB_BT_RECNUM)) &&
|
||||
(ret = __bam_keyalloc(t)) != 0) {
|
||||
FREE(t, sizeof(*t));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
t->bt_maxkey = ot->bt_maxkey;
|
||||
t->bt_minkey = ot->bt_minkey;
|
||||
t->bt_compare = ot->bt_compare;
|
||||
t->bt_prefix = ot->bt_prefix;
|
||||
t->bt_ovflsize = ot->bt_ovflsize;
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* The entire RECNO structure is shared. If it breaks, the application
|
||||
* was misusing it to start with.
|
||||
*/
|
||||
t->bt_recno = ot->bt_recno;
|
||||
|
||||
new->internal = t;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_keyalloc --
|
||||
* Allocate return memory for recno keys.
|
||||
*/
|
||||
static int
|
||||
__bam_keyalloc(t)
|
||||
BTREE *t;
|
||||
{
|
||||
/*
|
||||
* Recno keys are always the same size, and we don't want to have
|
||||
* to check for space on each return. Allocate it now.
|
||||
*/
|
||||
if ((t->bt_rkey.data = (void *)__db_malloc(sizeof(db_recno_t))) == NULL)
|
||||
return (ENOMEM);
|
||||
t->bt_rkey.ulen = sizeof(db_recno_t);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_setmeta --
|
||||
* Check (and optionally create) a tree.
|
||||
*/
|
||||
static int
|
||||
__bam_setmeta(dbp, t)
|
||||
__bam_read_root(dbp)
|
||||
DB *dbp;
|
||||
BTREE *t;
|
||||
{
|
||||
BTMETA *meta;
|
||||
PAGE *root;
|
||||
BTREE *t;
|
||||
DBC *dbc;
|
||||
DB_LOCK metalock, rootlock;
|
||||
PAGE *root;
|
||||
db_pgno_t pgno;
|
||||
int ret;
|
||||
int ret, t_ret;
|
||||
|
||||
ret = 0;
|
||||
t = dbp->internal;
|
||||
|
||||
/* Get a cursor. */
|
||||
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Get, and optionally create the metadata page. */
|
||||
pgno = PGNO_METADATA;
|
||||
if ((ret =
|
||||
__bam_lget(dbp, 0, PGNO_METADATA, DB_LOCK_WRITE, &metalock)) != 0)
|
||||
return (ret);
|
||||
__bam_lget(dbc, 0, PGNO_METADATA, DB_LOCK_WRITE, &metalock)) != 0)
|
||||
goto err;
|
||||
if ((ret =
|
||||
__bam_pget(dbp, (PAGE **)&meta, &pgno, DB_MPOOL_CREATE)) != 0) {
|
||||
(void)__BT_LPUT(dbp, metalock);
|
||||
return (ret);
|
||||
memp_fget(dbp->mpf, &pgno, DB_MPOOL_CREATE, (PAGE **)&meta)) != 0) {
|
||||
(void)__BT_LPUT(dbc, metalock);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -284,8 +243,8 @@ __bam_setmeta(dbp, t)
|
||||
t->bt_minkey = meta->minkey;
|
||||
|
||||
(void)memp_fput(dbp->mpf, (PAGE *)meta, 0);
|
||||
(void)__BT_LPUT(dbp, metalock);
|
||||
return (0);
|
||||
(void)__BT_LPUT(dbc, metalock);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Initialize the tree structure metadata information. */
|
||||
@ -308,16 +267,16 @@ __bam_setmeta(dbp, t)
|
||||
F_SET(meta, BTM_RECNUM);
|
||||
if (F_ISSET(dbp, DB_RE_RENUMBER))
|
||||
F_SET(meta, BTM_RENUMBER);
|
||||
memcpy(meta->uid, dbp->lock.fileid, DB_FILE_ID_LEN);
|
||||
memcpy(meta->uid, dbp->fileid, DB_FILE_ID_LEN);
|
||||
|
||||
/* Create and initialize a root page. */
|
||||
pgno = PGNO_ROOT;
|
||||
if ((ret =
|
||||
__bam_lget(dbp, 0, PGNO_ROOT, DB_LOCK_WRITE, &rootlock)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __bam_pget(dbp, &root, &pgno, DB_MPOOL_CREATE)) != 0) {
|
||||
(void)__BT_LPUT(dbp, rootlock);
|
||||
return (ret);
|
||||
__bam_lget(dbc, 0, PGNO_ROOT, DB_LOCK_WRITE, &rootlock)) != 0)
|
||||
goto err;
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, DB_MPOOL_CREATE, &root)) != 0) {
|
||||
(void)__BT_LPUT(dbc, rootlock);
|
||||
goto err;
|
||||
}
|
||||
P_INIT(root, dbp->pgsize, PGNO_ROOT, PGNO_INVALID,
|
||||
PGNO_INVALID, 1, dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE);
|
||||
@ -325,9 +284,9 @@ __bam_setmeta(dbp, t)
|
||||
|
||||
/* Release the metadata and root pages. */
|
||||
if ((ret = memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY)) != 0)
|
||||
return (ret);
|
||||
goto err;
|
||||
if ((ret = memp_fput(dbp->mpf, root, DB_MPOOL_DIRTY)) != 0)
|
||||
return (ret);
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Flush the metadata and root pages to disk -- since the user can't
|
||||
@ -341,8 +300,11 @@ __bam_setmeta(dbp, t)
|
||||
ret = EINVAL;
|
||||
|
||||
/* Release the locks. */
|
||||
(void)__BT_LPUT(dbp, metalock);
|
||||
(void)__BT_LPUT(dbp, rootlock);
|
||||
(void)__BT_LPUT(dbc, metalock);
|
||||
(void)__BT_LPUT(dbc, rootlock);
|
||||
|
||||
err:
|
||||
done: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
return (ret);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_page.c 10.12 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)bt_page.c 10.17 (Sleepycat) 1/3/99";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -65,45 +65,47 @@ static const char sccsid[] = "@(#)bt_page.c 10.12 (Sleepycat) 5/6/98";
|
||||
* __bam_new --
|
||||
* Get a new page, preferably from the freelist.
|
||||
*
|
||||
* PUBLIC: int __bam_new __P((DB *, u_int32_t, PAGE **));
|
||||
* PUBLIC: int __bam_new __P((DBC *, u_int32_t, PAGE **));
|
||||
*/
|
||||
int
|
||||
__bam_new(dbp, type, pagepp)
|
||||
DB *dbp;
|
||||
__bam_new(dbc, type, pagepp)
|
||||
DBC *dbc;
|
||||
u_int32_t type;
|
||||
PAGE **pagepp;
|
||||
{
|
||||
BTMETA *meta;
|
||||
DB *dbp;
|
||||
DB_LOCK metalock;
|
||||
PAGE *h;
|
||||
db_pgno_t pgno;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
meta = NULL;
|
||||
h = NULL;
|
||||
metalock = LOCK_INVALID;
|
||||
|
||||
pgno = PGNO_METADATA;
|
||||
if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &metalock)) != 0)
|
||||
if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_WRITE, &metalock)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_pget(dbp, (PAGE **)&meta, &pgno, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0)
|
||||
goto err;
|
||||
|
||||
if (meta->free == PGNO_INVALID) {
|
||||
if ((ret = __bam_pget(dbp, &h, &pgno, DB_MPOOL_NEW)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, DB_MPOOL_NEW, &h)) != 0)
|
||||
goto err;
|
||||
ZERO_LSN(h->lsn);
|
||||
h->pgno = pgno;
|
||||
} else {
|
||||
pgno = meta->free;
|
||||
if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
|
||||
goto err;
|
||||
meta->free = h->next_pgno;
|
||||
}
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if ((ret = __bam_pg_alloc_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if (DB_LOGGING(dbc)) {
|
||||
if ((ret = __bam_pg_alloc_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&meta->lsn, 0, dbp->log_fileid, &meta->lsn, &h->lsn,
|
||||
h->pgno, (u_int32_t)type, meta->free)) != 0)
|
||||
goto err;
|
||||
@ -111,7 +113,7 @@ __bam_new(dbp, type, pagepp)
|
||||
}
|
||||
|
||||
(void)memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY);
|
||||
(void)__BT_TLPUT(dbp, metalock);
|
||||
(void)__BT_TLPUT(dbc, metalock);
|
||||
|
||||
P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, PGNO_INVALID, 0, type);
|
||||
*pagepp = h;
|
||||
@ -122,28 +124,45 @@ err: if (h != NULL)
|
||||
if (meta != NULL)
|
||||
(void)memp_fput(dbp->mpf, meta, 0);
|
||||
if (metalock != LOCK_INVALID)
|
||||
(void)__BT_TLPUT(dbp, metalock);
|
||||
(void)__BT_TLPUT(dbc, metalock);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_lput --
|
||||
* The standard lock put call.
|
||||
*
|
||||
* PUBLIC: int __bam_lput __P((DBC *, DB_LOCK));
|
||||
*/
|
||||
int
|
||||
__bam_lput(dbc, lock)
|
||||
DBC *dbc;
|
||||
DB_LOCK lock;
|
||||
{
|
||||
return (__BT_LPUT(dbc, lock));
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_free --
|
||||
* Add a page to the head of the freelist.
|
||||
*
|
||||
* PUBLIC: int __bam_free __P((DB *, PAGE *));
|
||||
* PUBLIC: int __bam_free __P((DBC *, PAGE *));
|
||||
*/
|
||||
int
|
||||
__bam_free(dbp, h)
|
||||
DB *dbp;
|
||||
__bam_free(dbc, h)
|
||||
DBC *dbc;
|
||||
PAGE *h;
|
||||
{
|
||||
BTMETA *meta;
|
||||
DB *dbp;
|
||||
DBT ldbt;
|
||||
DB_LOCK metalock;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t dirty_flag;
|
||||
int ret, t_ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/*
|
||||
* Retrieve the metadata page and insert the page at the head of
|
||||
* the free list. If either the lock get or page get routines
|
||||
@ -152,23 +171,23 @@ __bam_free(dbp, h)
|
||||
*/
|
||||
dirty_flag = 0;
|
||||
pgno = PGNO_METADATA;
|
||||
if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &metalock)) != 0)
|
||||
if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_WRITE, &metalock)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_pget(dbp, (PAGE **)&meta, &pgno, 0)) != 0) {
|
||||
(void)__BT_TLPUT(dbp, metalock);
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) {
|
||||
(void)__BT_TLPUT(dbc, metalock);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
memset(&ldbt, 0, sizeof(ldbt));
|
||||
ldbt.data = h;
|
||||
ldbt.size = P_OVERHEAD;
|
||||
if ((ret = __bam_pg_free_log(dbp->dbenv->lg_info,
|
||||
dbp->txn, &meta->lsn, 0, dbp->log_fileid, h->pgno,
|
||||
dbc->txn, &meta->lsn, 0, dbp->log_fileid, h->pgno,
|
||||
&meta->lsn, &ldbt, meta->free)) != 0) {
|
||||
(void)memp_fput(dbp->mpf, (PAGE *)meta, 0);
|
||||
(void)__BT_TLPUT(dbp, metalock);
|
||||
(void)__BT_TLPUT(dbc, metalock);
|
||||
return (ret);
|
||||
}
|
||||
LSN(h) = LSN(meta);
|
||||
@ -182,7 +201,7 @@ __bam_free(dbp, h)
|
||||
{ db_pgno_t __pgno; DB_LSN __lsn;
|
||||
__pgno = h->pgno;
|
||||
__lsn = h->lsn;
|
||||
memset(h, 0xff, dbp->pgsize);
|
||||
memset(h, 0xdb, dbp->pgsize);
|
||||
h->pgno = __pgno;
|
||||
h->lsn = __lsn;
|
||||
}
|
||||
@ -194,7 +213,7 @@ __bam_free(dbp, h)
|
||||
|
||||
/* Discard the metadata page. */
|
||||
ret = memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY);
|
||||
if ((t_ret = __BT_TLPUT(dbp, metalock)) != 0)
|
||||
if ((t_ret = __BT_TLPUT(dbc, metalock)) != 0)
|
||||
ret = t_ret;
|
||||
|
||||
/* Discard the caller's page reference. */
|
||||
@ -212,19 +231,21 @@ err: if ((t_ret = memp_fput(dbp->mpf, h, dirty_flag)) != 0 && ret == 0)
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* __bam_lt --
|
||||
* Print out the list of currently held locks.
|
||||
* Print out the list of locks currently held by a cursor.
|
||||
*
|
||||
* PUBLIC: int __bam_lt __P((DB *));
|
||||
* PUBLIC: int __bam_lt __P((DBC *));
|
||||
*/
|
||||
int
|
||||
__bam_lt(dbp)
|
||||
DB *dbp;
|
||||
__bam_lt(dbc)
|
||||
DBC *dbc;
|
||||
{
|
||||
DB *dbp;
|
||||
DB_LOCKREQ req;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
if (F_ISSET(dbp, DB_AM_LOCKING)) {
|
||||
req.op = DB_LOCK_DUMP;
|
||||
lock_vec(dbp->dbenv->lk_info, dbp->locker, 0, &req, 1, NULL);
|
||||
lock_vec(dbp->dbenv->lk_info, dbc->locker, 0, &req, 1, NULL);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -234,27 +255,29 @@ __bam_lt(dbp)
|
||||
* __bam_lget --
|
||||
* The standard lock get call.
|
||||
*
|
||||
* PUBLIC: int __bam_lget __P((DB *, int, db_pgno_t, db_lockmode_t, DB_LOCK *));
|
||||
* PUBLIC: int __bam_lget
|
||||
* PUBLIC: __P((DBC *, int, db_pgno_t, db_lockmode_t, DB_LOCK *));
|
||||
*/
|
||||
int
|
||||
__bam_lget(dbp, do_couple, pgno, mode, lockp)
|
||||
DB *dbp;
|
||||
__bam_lget(dbc, do_couple, pgno, mode, lockp)
|
||||
DBC *dbc;
|
||||
int do_couple;
|
||||
db_pgno_t pgno;
|
||||
db_lockmode_t mode;
|
||||
DB_LOCK *lockp;
|
||||
{
|
||||
DB *dbp;
|
||||
DB_LOCKREQ couple[2];
|
||||
u_int32_t locker;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
if (!F_ISSET(dbp, DB_AM_LOCKING)) {
|
||||
*lockp = LOCK_INVALID;
|
||||
return (0);
|
||||
}
|
||||
|
||||
locker = dbp->txn == NULL ? dbp->locker : dbp->txn->txnid;
|
||||
dbp->lock.pgno = pgno;
|
||||
dbc->lock.pgno = pgno;
|
||||
|
||||
/*
|
||||
* If the object not currently locked, acquire the lock and return,
|
||||
@ -263,54 +286,32 @@ __bam_lget(dbp, do_couple, pgno, mode, lockp)
|
||||
*/
|
||||
if (do_couple) {
|
||||
couple[0].op = DB_LOCK_GET;
|
||||
couple[0].obj = &dbp->lock_dbt;
|
||||
couple[0].obj = &dbc->lock_dbt;
|
||||
couple[0].mode = mode;
|
||||
couple[1].op = DB_LOCK_PUT;
|
||||
couple[1].lock = *lockp;
|
||||
|
||||
ret = lock_vec(dbp->dbenv->lk_info, locker, 0, couple, 2, NULL);
|
||||
if (dbc->txn == NULL)
|
||||
ret = lock_vec(dbp->dbenv->lk_info,
|
||||
dbc->locker, 0, couple, 2, NULL);
|
||||
else
|
||||
ret = lock_tvec(dbp->dbenv->lk_info,
|
||||
dbc->txn, 0, couple, 2, NULL);
|
||||
if (ret != 0) {
|
||||
/* If we fail, discard the lock we held. */
|
||||
__bam_lput(dbp, *lockp);
|
||||
__BT_LPUT(dbc, *lockp);
|
||||
|
||||
return (ret < 0 ? EAGAIN : ret);
|
||||
}
|
||||
*lockp = couple[0].lock;
|
||||
} else {
|
||||
ret = lock_get(dbp->dbenv->lk_info,
|
||||
locker, 0, &dbp->lock_dbt, mode, lockp);
|
||||
if (dbc->txn == NULL)
|
||||
ret = lock_get(dbp->dbenv->lk_info,
|
||||
dbc->locker, 0, &dbc->lock_dbt, mode, lockp);
|
||||
else
|
||||
ret = lock_tget(dbp->dbenv->lk_info,
|
||||
dbc->txn, 0, &dbc->lock_dbt, mode, lockp);
|
||||
return (ret < 0 ? EAGAIN : ret);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_lput --
|
||||
* The standard lock put call.
|
||||
*
|
||||
* PUBLIC: int __bam_lput __P((DB *, DB_LOCK));
|
||||
*/
|
||||
int
|
||||
__bam_lput(dbp, lock)
|
||||
DB *dbp;
|
||||
DB_LOCK lock;
|
||||
{
|
||||
return (__BT_LPUT(dbp, lock));
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_pget --
|
||||
* The standard page get call.
|
||||
*
|
||||
* PUBLIC: int __bam_pget __P((DB *, PAGE **, db_pgno_t *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_pget(dbp, hp, pgnop, mpool_flags)
|
||||
DB *dbp;
|
||||
PAGE **hp;
|
||||
db_pgno_t *pgnop;
|
||||
u_int32_t mpool_flags;
|
||||
{
|
||||
return (memp_fget((dbp)->mpf,
|
||||
pgnop, mpool_flags, hp) == 0 ? 0 : __db_pgerr(dbp, *pgnop));
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_put.c 10.45 (Sleepycat) 5/25/98";
|
||||
static const char sccsid[] = "@(#)bt_put.c 10.54 (Sleepycat) 12/6/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -61,372 +61,23 @@ static const char sccsid[] = "@(#)bt_put.c 10.45 (Sleepycat) 5/25/98";
|
||||
#include "db_page.h"
|
||||
#include "btree.h"
|
||||
|
||||
static int __bam_fixed __P((BTREE *, DBT *));
|
||||
static int __bam_isdeleted __P((DB *, PAGE *, u_int32_t, int *));
|
||||
static int __bam_lookup __P((DB *, DBT *, int *));
|
||||
static int __bam_ndup __P((DB *, PAGE *, u_int32_t));
|
||||
static int __bam_ovput __P((DB *, PAGE *, u_int32_t, DBT *));
|
||||
static int __bam_partial __P((DB *, DBT *, PAGE *, u_int32_t, u_int32_t));
|
||||
static int __bam_fixed __P((DBC *, DBT *));
|
||||
static int __bam_ndup __P((DBC *, PAGE *, u_int32_t));
|
||||
static int __bam_ovput __P((DBC *, PAGE *, u_int32_t, DBT *));
|
||||
static int __bam_partial __P((DBC *,
|
||||
DBT *, PAGE *, u_int32_t, u_int32_t, u_int32_t));
|
||||
static u_int32_t __bam_partsize __P((DBT *, PAGE *, u_int32_t));
|
||||
|
||||
/*
|
||||
* __bam_put --
|
||||
* Add a new key/data pair or replace an existing pair (btree).
|
||||
*
|
||||
* PUBLIC: int __bam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_put(argdbp, txn, key, data, flags)
|
||||
DB *argdbp;
|
||||
DB_TXN *txn;
|
||||
DBT *key, *data;
|
||||
u_int32_t flags;
|
||||
{
|
||||
BTREE *t;
|
||||
CURSOR c;
|
||||
DB *dbp;
|
||||
PAGE *h;
|
||||
db_indx_t indx;
|
||||
u_int32_t iitem_flags, insert_flags;
|
||||
int exact, isdeleted, newkey, ret, stack;
|
||||
|
||||
DEBUG_LWRITE(argdbp, txn, "bam_put", key, data, flags);
|
||||
|
||||
/* Check flags. */
|
||||
if ((ret = __db_putchk(argdbp, key, data, flags,
|
||||
F_ISSET(argdbp, DB_AM_RDONLY), F_ISSET(argdbp, DB_AM_DUP))) != 0)
|
||||
return (ret);
|
||||
|
||||
GETHANDLE(argdbp, txn, &dbp, ret);
|
||||
t = dbp->internal;
|
||||
|
||||
retry: /*
|
||||
* Find the location at which to insert. The call to __bam_lookup
|
||||
* leaves the returned page pinned.
|
||||
*/
|
||||
if ((ret = __bam_lookup(dbp, key, &exact)) != 0) {
|
||||
PUTHANDLE(dbp);
|
||||
return (ret);
|
||||
}
|
||||
h = t->bt_csp->page;
|
||||
indx = t->bt_csp->indx;
|
||||
stack = 1;
|
||||
|
||||
/*
|
||||
* If DB_NOOVERWRITE is set and there's an identical key in the tree,
|
||||
* return an error unless the data item has already been marked for
|
||||
* deletion, or, all the remaining data items have already been marked
|
||||
* for deletion in the case of duplicates. If all the data items have
|
||||
* been marked for deletion, we do a replace, otherwise, it has to be
|
||||
* a set of duplicates, and we simply append a new one to the set.
|
||||
*/
|
||||
isdeleted = 0;
|
||||
if (exact) {
|
||||
if ((ret = __bam_isdeleted(dbp, h, indx, &isdeleted)) != 0)
|
||||
goto err;
|
||||
if (isdeleted)
|
||||
__bam_ca_replace(dbp, h->pgno, indx, REPLACE_SETUP);
|
||||
else
|
||||
if (flags == DB_NOOVERWRITE) {
|
||||
ret = DB_KEYEXIST;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're inserting into the first or last page of the tree,
|
||||
* remember where we did it so we can do fast lookup next time.
|
||||
*
|
||||
* XXX
|
||||
* Does reverse order still work (did it ever!?!?)
|
||||
*/
|
||||
t->bt_lpgno =
|
||||
h->next_pgno == PGNO_INVALID || h->prev_pgno == PGNO_INVALID ?
|
||||
h->pgno : PGNO_INVALID;
|
||||
|
||||
/*
|
||||
* Select the arguments for __bam_iitem() and do the insert. If the
|
||||
* key is an exact match, we're either adding a new duplicate at the
|
||||
* end of the duplicate set, or we're replacing the data item with a
|
||||
* new data item. If the key isn't an exact match, we're inserting
|
||||
* a new key/data pair, before the search location.
|
||||
*/
|
||||
newkey = dbp->type == DB_BTREE && !exact;
|
||||
if (exact) {
|
||||
if (!isdeleted && F_ISSET(dbp, DB_AM_DUP)) {
|
||||
/*
|
||||
* Make sure that we're not looking at a page of
|
||||
* duplicates -- if so, move to the last entry on
|
||||
* that page.
|
||||
*/
|
||||
c.page = h;
|
||||
c.pgno = h->pgno;
|
||||
c.indx = indx;
|
||||
c.dpgno = PGNO_INVALID;
|
||||
c.dindx = 0;
|
||||
if ((ret =
|
||||
__bam_ovfl_chk(dbp, &c, indx + O_INDX, 1)) != 0)
|
||||
goto err;
|
||||
if (c.dpgno != PGNO_INVALID) {
|
||||
/*
|
||||
* XXX
|
||||
* The __bam_ovfl_chk() routine memp_fput() the
|
||||
* current page and acquired a new one, but did
|
||||
* not do anything about the lock we're holding.
|
||||
*/
|
||||
t->bt_csp->page = h = c.page;
|
||||
indx = c.dindx;
|
||||
}
|
||||
insert_flags = DB_AFTER;
|
||||
} else
|
||||
insert_flags = DB_CURRENT;
|
||||
} else
|
||||
insert_flags = DB_BEFORE;
|
||||
|
||||
/*
|
||||
* The pages we're using may be modified by __bam_iitem(), so make
|
||||
* sure we reset the stack.
|
||||
*/
|
||||
iitem_flags = 0;
|
||||
if (newkey)
|
||||
iitem_flags |= BI_NEWKEY;
|
||||
if (isdeleted)
|
||||
iitem_flags |= BI_DOINCR;
|
||||
ret = __bam_iitem(dbp, &h, &indx, key, data, insert_flags, iitem_flags);
|
||||
t->bt_csp->page = h;
|
||||
t->bt_csp->indx = indx;
|
||||
|
||||
switch (ret) {
|
||||
case 0:
|
||||
/* Done. Clean up the cursor. */
|
||||
if (isdeleted)
|
||||
__bam_ca_replace(dbp, h->pgno, indx, REPLACE_SUCCESS);
|
||||
break;
|
||||
case DB_NEEDSPLIT:
|
||||
/*
|
||||
* We have to split the page. Back out the cursor setup,
|
||||
* discard the stack of pages, and do the split.
|
||||
*/
|
||||
if (isdeleted)
|
||||
__bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
|
||||
|
||||
(void)__bam_stkrel(dbp);
|
||||
stack = 0;
|
||||
|
||||
if ((ret = __bam_split(dbp, key)) != 0)
|
||||
break;
|
||||
|
||||
goto retry;
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
if (isdeleted)
|
||||
__bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
|
||||
break;
|
||||
}
|
||||
|
||||
err: if (stack)
|
||||
(void)__bam_stkrel(dbp);
|
||||
|
||||
PUTHANDLE(dbp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_isdeleted --
|
||||
* Return if the only remaining data item for the element has been
|
||||
* deleted.
|
||||
*/
|
||||
static int
|
||||
__bam_isdeleted(dbp, h, indx, isdeletedp)
|
||||
DB *dbp;
|
||||
PAGE *h;
|
||||
u_int32_t indx;
|
||||
int *isdeletedp;
|
||||
{
|
||||
BKEYDATA *bk;
|
||||
db_pgno_t pgno;
|
||||
int ret;
|
||||
|
||||
*isdeletedp = 1;
|
||||
for (;;) {
|
||||
bk = GET_BKEYDATA(h, indx + O_INDX);
|
||||
switch (B_TYPE(bk->type)) {
|
||||
case B_KEYDATA:
|
||||
case B_OVERFLOW:
|
||||
if (!B_DISSET(bk->type)) {
|
||||
*isdeletedp = 0;
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
case B_DUPLICATE:
|
||||
/*
|
||||
* If the data item referencing the off-page duplicates
|
||||
* is flagged as deleted, we're done. Else, we have to
|
||||
* walk the chain of duplicate pages.
|
||||
*/
|
||||
if (B_DISSET(bk->type))
|
||||
return (0);
|
||||
goto dupchk;
|
||||
default:
|
||||
return (__db_pgfmt(dbp, h->pgno));
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no more on-page duplicate items, then every
|
||||
* data item for this key must have been deleted.
|
||||
*/
|
||||
if (indx + P_INDX >= (u_int32_t)NUM_ENT(h))
|
||||
return (0);
|
||||
if (h->inp[indx] != h->inp[indx + P_INDX])
|
||||
return (0);
|
||||
|
||||
/* Check the next item. */
|
||||
indx += P_INDX;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
||||
dupchk: /* Check a chain of duplicate pages. */
|
||||
pgno = ((BOVERFLOW *)bk)->pgno;
|
||||
for (;;) {
|
||||
/* Acquire the next page in the duplicate chain. */
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Check each item for a delete flag. */
|
||||
for (indx = 0; indx < NUM_ENT(h); ++indx)
|
||||
if (!B_DISSET(GET_BKEYDATA(h, indx)->type)) {
|
||||
*isdeletedp = 0;
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* If we reach the end of the duplicate pages, then every
|
||||
* item we reviewed must have been deleted.
|
||||
*/
|
||||
if ((pgno = NEXT_PGNO(h)) == PGNO_INVALID)
|
||||
goto done;
|
||||
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
||||
done: (void)memp_fput(dbp->mpf, h, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_lookup --
|
||||
* Find the right location in the tree for the key.
|
||||
*/
|
||||
static int
|
||||
__bam_lookup(dbp, key, exactp)
|
||||
DB *dbp;
|
||||
DBT *key;
|
||||
int *exactp;
|
||||
{
|
||||
BTREE *t;
|
||||
DB_LOCK lock;
|
||||
EPG e;
|
||||
PAGE *h;
|
||||
db_indx_t indx;
|
||||
int cmp, ret;
|
||||
|
||||
t = dbp->internal;
|
||||
h = NULL;
|
||||
|
||||
/*
|
||||
* Record numbers can't be fast-tracked, we have to lock the entire
|
||||
* tree.
|
||||
*/
|
||||
if (F_ISSET(dbp, DB_BT_RECNUM))
|
||||
goto slow;
|
||||
|
||||
/* Check to see if we've been seeing sorted input. */
|
||||
if (t->bt_lpgno == PGNO_INVALID)
|
||||
goto slow;
|
||||
|
||||
/*
|
||||
* Retrieve the page on which we did the last insert. It's okay if
|
||||
* it doesn't exist, or if it's not the page type we expect, it just
|
||||
* means that the world changed.
|
||||
*/
|
||||
if (__bam_lget(dbp, 0, t->bt_lpgno, DB_LOCK_WRITE, &lock))
|
||||
goto miss;
|
||||
if (__bam_pget(dbp, &h, &t->bt_lpgno, 0)) {
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
goto miss;
|
||||
}
|
||||
if (TYPE(h) != P_LBTREE)
|
||||
goto miss;
|
||||
if (NUM_ENT(h) == 0)
|
||||
goto miss;
|
||||
|
||||
/*
|
||||
* We have to be at the end or beginning of the tree to know that
|
||||
* we're inserting in a sort order. If that's the case and we're
|
||||
* in the right order in comparison to the first/last key/data pair,
|
||||
* we have the right position.
|
||||
*/
|
||||
if (h->next_pgno == PGNO_INVALID) {
|
||||
e.page = h;
|
||||
e.indx = NUM_ENT(h) - P_INDX;
|
||||
if ((cmp = __bam_cmp(dbp, key, &e)) >= 0) {
|
||||
if (cmp > 0)
|
||||
e.indx += P_INDX;
|
||||
goto fast;
|
||||
}
|
||||
}
|
||||
if (h->prev_pgno == PGNO_INVALID) {
|
||||
e.page = h;
|
||||
e.indx = 0;
|
||||
if ((cmp = __bam_cmp(dbp, key, &e)) <= 0) {
|
||||
/*
|
||||
* We're doing a put, so we want to insert as the last
|
||||
* of any set of duplicates.
|
||||
*/
|
||||
if (cmp == 0) {
|
||||
for (indx = 0;
|
||||
indx < (db_indx_t)(NUM_ENT(h) - P_INDX) &&
|
||||
h->inp[indx] == h->inp[indx + P_INDX];
|
||||
indx += P_INDX)
|
||||
;
|
||||
e.indx = indx;
|
||||
}
|
||||
goto fast;
|
||||
}
|
||||
}
|
||||
goto miss;
|
||||
|
||||
/* Set the exact match flag in case we've already inserted this key. */
|
||||
fast: *exactp = cmp == 0;
|
||||
|
||||
/* Enter the entry in the stack. */
|
||||
BT_STK_CLR(t);
|
||||
BT_STK_ENTER(t, e.page, e.indx, lock, ret);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
++t->lstat.bt_cache_hit;
|
||||
return (0);
|
||||
|
||||
miss: ++t->lstat.bt_cache_miss;
|
||||
if (h != NULL) {
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
}
|
||||
|
||||
slow: return (__bam_search(dbp, key, S_INSERT, 1, NULL, exactp));
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_iitem --
|
||||
* Insert an item into the tree.
|
||||
*
|
||||
* PUBLIC: int __bam_iitem __P((DB *,
|
||||
* PUBLIC: int __bam_iitem __P((DBC *,
|
||||
* PUBLIC: PAGE **, db_indx_t *, DBT *, DBT *, u_int32_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
DB *dbp;
|
||||
__bam_iitem(dbc, hp, indxp, key, data, op, flags)
|
||||
DBC *dbc;
|
||||
PAGE **hp;
|
||||
db_indx_t *indxp;
|
||||
DBT *key, *data;
|
||||
@ -434,6 +85,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
{
|
||||
BTREE *t;
|
||||
BKEYDATA *bk;
|
||||
DB *dbp;
|
||||
DBT tdbt;
|
||||
PAGE *h;
|
||||
db_indx_t indx, nbytes;
|
||||
@ -442,6 +94,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
|
||||
COMPQUIET(bk, NULL);
|
||||
|
||||
dbp = dbc->dbp;
|
||||
t = dbp->internal;
|
||||
h = *hp;
|
||||
indx = *indxp;
|
||||
@ -473,21 +126,21 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
default:
|
||||
return (__db_pgfmt(dbp, h->pgno));
|
||||
}
|
||||
if ((ret = __db_ditem(dbp, *hp, *indxp, nbytes)) != 0)
|
||||
if ((ret = __db_ditem(dbc, *hp, *indxp, nbytes)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Put the new/replacement item onto the page. */
|
||||
if ((ret = __db_dput(dbp, data, hp, indxp, __bam_new)) != 0)
|
||||
if ((ret = __db_dput(dbc, data, hp, indxp, __bam_new)) != 0)
|
||||
return (ret);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Handle fixed-length records: build the real record. */
|
||||
if (F_ISSET(dbp, DB_RE_FIXEDLEN) && data->size != t->bt_recno->re_len) {
|
||||
if (F_ISSET(dbp, DB_RE_FIXEDLEN) && data->size != t->recno->re_len) {
|
||||
tdbt = *data;
|
||||
if ((ret = __bam_fixed(t, &tdbt)) != 0)
|
||||
if ((ret = __bam_fixed(dbc, &tdbt)) != 0)
|
||||
return (ret);
|
||||
data = &tdbt;
|
||||
}
|
||||
@ -554,7 +207,8 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
/* Handle partial puts: build the real record. */
|
||||
if (F_ISSET(data, DB_DBT_PARTIAL)) {
|
||||
tdbt = *data;
|
||||
if ((ret = __bam_partial(dbp, &tdbt, h, indx, data_size)) != 0)
|
||||
if ((ret = __bam_partial(dbc,
|
||||
&tdbt, h, indx, data_size, flags)) != 0)
|
||||
return (ret);
|
||||
data = &tdbt;
|
||||
}
|
||||
@ -583,10 +237,10 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
|
||||
/* Add the key. */
|
||||
if (bigkey) {
|
||||
if ((ret = __bam_ovput(dbp, h, indx, key)) != 0)
|
||||
if ((ret = __bam_ovput(dbc, h, indx, key)) != 0)
|
||||
return (ret);
|
||||
} else
|
||||
if ((ret = __db_pitem(dbp, h, indx,
|
||||
if ((ret = __db_pitem(dbc, h, indx,
|
||||
BKEYDATA_SIZE(key->size), NULL, key)) != 0)
|
||||
return (ret);
|
||||
++indx;
|
||||
@ -598,7 +252,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
* Adjust the cursor and copy in the key for
|
||||
* the duplicate.
|
||||
*/
|
||||
if ((ret = __bam_adjindx(dbp,
|
||||
if ((ret = __bam_adjindx(dbc,
|
||||
h, indx + P_INDX, indx, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
@ -620,7 +274,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
* the duplicate.
|
||||
*/
|
||||
if ((ret =
|
||||
__bam_adjindx(dbp, h, indx, indx, 1)) != 0)
|
||||
__bam_adjindx(dbc, h, indx, indx, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
++indx;
|
||||
@ -639,7 +293,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
* delete and then re-add the item.
|
||||
*/
|
||||
if (bigdata || B_TYPE(bk->type) != B_KEYDATA) {
|
||||
if ((ret = __bam_ditem(dbp, h, indx)) != 0)
|
||||
if ((ret = __bam_ditem(dbc, h, indx)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
}
|
||||
@ -654,7 +308,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
|
||||
/* Add the data. */
|
||||
if (bigdata) {
|
||||
if ((ret = __bam_ovput(dbp, h, indx, data)) != 0)
|
||||
if ((ret = __bam_ovput(dbc, h, indx, data)) != 0)
|
||||
return (ret);
|
||||
} else {
|
||||
BKEYDATA __bk;
|
||||
@ -665,12 +319,12 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
__bk.len = data->size;
|
||||
__hdr.data = &__bk;
|
||||
__hdr.size = SSZA(BKEYDATA, data);
|
||||
ret = __db_pitem(dbp, h, indx,
|
||||
ret = __db_pitem(dbc, h, indx,
|
||||
BKEYDATA_SIZE(data->size), &__hdr, data);
|
||||
} else if (replace)
|
||||
ret = __bam_ritem(dbp, h, indx, data);
|
||||
ret = __bam_ritem(dbc, h, indx, data);
|
||||
else
|
||||
ret = __db_pitem(dbp, h, indx,
|
||||
ret = __db_pitem(dbc, h, indx,
|
||||
BKEYDATA_SIZE(data->size), NULL, data);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
@ -686,7 +340,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
*/
|
||||
if (dupadjust && P_FREESPACE(h) <= dbp->pgsize / 2) {
|
||||
--indx;
|
||||
if ((ret = __bam_ndup(dbp, h, indx)) != 0)
|
||||
if ((ret = __bam_ndup(dbc, h, indx)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -700,14 +354,12 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
|
||||
done: if (LF_ISSET(BI_DOINCR) ||
|
||||
(op != DB_CURRENT &&
|
||||
(F_ISSET(dbp, DB_BT_RECNUM) || dbp->type == DB_RECNO)))
|
||||
if ((ret = __bam_adjust(dbp, t, 1)) != 0)
|
||||
if ((ret = __bam_adjust(dbc, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* If we've modified a recno file, set the flag */
|
||||
if (t->bt_recno != NULL)
|
||||
F_SET(t->bt_recno, RECNO_MODIFIED);
|
||||
|
||||
++t->lstat.bt_added;
|
||||
if (t->recno != NULL)
|
||||
F_SET(t->recno, RECNO_MODIFIED);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -770,7 +422,7 @@ __bam_partsize(data, h, indx)
|
||||
memset(&__hdr, 0, sizeof(__hdr)); \
|
||||
__hdr.data = &bo; \
|
||||
__hdr.size = BOVERFLOW_SIZE; \
|
||||
if ((ret = __db_pitem(dbp, \
|
||||
if ((ret = __db_pitem(dbc, \
|
||||
h, indx, BOVERFLOW_SIZE, &__hdr, NULL)) != 0) \
|
||||
return (ret); \
|
||||
} while (0)
|
||||
@ -780,8 +432,8 @@ __bam_partsize(data, h, indx)
|
||||
* Build an overflow item and put it on the page.
|
||||
*/
|
||||
static int
|
||||
__bam_ovput(dbp, h, indx, item)
|
||||
DB *dbp;
|
||||
__bam_ovput(dbc, h, indx, item)
|
||||
DBC *dbc;
|
||||
PAGE *h;
|
||||
u_int32_t indx;
|
||||
DBT *item;
|
||||
@ -789,10 +441,12 @@ __bam_ovput(dbp, h, indx, item)
|
||||
BOVERFLOW bo;
|
||||
int ret;
|
||||
|
||||
UMRW(bo.unused1);
|
||||
B_TSET(bo.type, B_OVERFLOW, 0);
|
||||
bo.tlen = item->size;
|
||||
if ((ret = __db_poff(dbp, item, &bo.pgno, __bam_new)) != 0)
|
||||
UMRW(bo.unused2);
|
||||
if ((ret = __db_poff(dbc, item, &bo.pgno, __bam_new)) != 0)
|
||||
return (ret);
|
||||
bo.tlen = item->size;
|
||||
|
||||
OVPUT(h, indx, bo);
|
||||
|
||||
@ -803,22 +457,25 @@ __bam_ovput(dbp, h, indx, item)
|
||||
* __bam_ritem --
|
||||
* Replace an item on a page.
|
||||
*
|
||||
* PUBLIC: int __bam_ritem __P((DB *, PAGE *, u_int32_t, DBT *));
|
||||
* PUBLIC: int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *));
|
||||
*/
|
||||
int
|
||||
__bam_ritem(dbp, h, indx, data)
|
||||
DB *dbp;
|
||||
__bam_ritem(dbc, h, indx, data)
|
||||
DBC *dbc;
|
||||
PAGE *h;
|
||||
u_int32_t indx;
|
||||
DBT *data;
|
||||
{
|
||||
BKEYDATA *bk;
|
||||
DB *dbp;
|
||||
DBT orig, repl;
|
||||
db_indx_t cnt, lo, ln, min, off, prefix, suffix;
|
||||
int32_t nbytes;
|
||||
int ret;
|
||||
u_int8_t *p, *t;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/*
|
||||
* Replace a single item onto a page. The logic figuring out where
|
||||
* to insert and whether it fits is handled in the caller. All we do
|
||||
@ -827,7 +484,7 @@ __bam_ritem(dbp, h, indx, data)
|
||||
bk = GET_BKEYDATA(h, indx);
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
/*
|
||||
* We might as well check to see if the two data items share
|
||||
* a common prefix and suffix -- it can save us a lot of log
|
||||
@ -851,7 +508,7 @@ __bam_ritem(dbp, h, indx, data)
|
||||
orig.size = bk->len - (prefix + suffix);
|
||||
repl.data = (u_int8_t *)data->data + prefix;
|
||||
repl.size = data->size - (prefix + suffix);
|
||||
if ((ret = __bam_repl_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if ((ret = __bam_repl_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&LSN(h), 0, dbp->log_fileid, PGNO(h), &LSN(h),
|
||||
(u_int32_t)indx, (u_int32_t)B_DISSET(bk->type),
|
||||
&orig, &repl, (u_int32_t)prefix, (u_int32_t)suffix)) != 0)
|
||||
@ -907,18 +564,21 @@ __bam_ritem(dbp, h, indx, data)
|
||||
* If it should, create it.
|
||||
*/
|
||||
static int
|
||||
__bam_ndup(dbp, h, indx)
|
||||
DB *dbp;
|
||||
__bam_ndup(dbc, h, indx)
|
||||
DBC *dbc;
|
||||
PAGE *h;
|
||||
u_int32_t indx;
|
||||
{
|
||||
BKEYDATA *bk;
|
||||
BOVERFLOW bo;
|
||||
DB *dbp;
|
||||
DBT hdr;
|
||||
PAGE *cp;
|
||||
db_indx_t cnt, cpindx, first, sz;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
while (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX])
|
||||
indx -= P_INDX;
|
||||
for (cnt = 0, sz = 0, first = indx;; ++cnt, indx += P_INDX) {
|
||||
@ -941,7 +601,7 @@ __bam_ndup(dbp, h, indx)
|
||||
return (0);
|
||||
|
||||
/* Get a new page. */
|
||||
if ((ret = __bam_new(dbp, P_DUPLICATE, &cp)) != 0)
|
||||
if ((ret = __bam_new(dbc, P_DUPLICATE, &cp)) != 0)
|
||||
return (ret);
|
||||
|
||||
/*
|
||||
@ -957,7 +617,7 @@ __bam_ndup(dbp, h, indx)
|
||||
hdr.size = B_TYPE(bk->type) == B_KEYDATA ?
|
||||
BKEYDATA_SIZE(bk->len) : BOVERFLOW_SIZE;
|
||||
if ((ret =
|
||||
__db_pitem(dbp, cp, cpindx, hdr.size, &hdr, NULL)) != 0)
|
||||
__db_pitem(dbc, cp, cpindx, hdr.size, &hdr, NULL)) != 0)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
@ -970,18 +630,20 @@ __bam_ndup(dbp, h, indx)
|
||||
PGNO(h), first, indx - O_INDX, PGNO(cp), cpindx);
|
||||
|
||||
/* Delete the data item. */
|
||||
if ((ret = __db_ditem(dbp, h, indx, hdr.size)) != 0)
|
||||
if ((ret = __db_ditem(dbc, h, indx, hdr.size)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Delete all but the first reference to the key. */
|
||||
if (--cnt == 0)
|
||||
break;
|
||||
if ((ret = __bam_adjindx(dbp, h, indx, first, 0)) != 0)
|
||||
if ((ret = __bam_adjindx(dbc, h, indx, first, 0)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Put in a new data item that points to the duplicates page. */
|
||||
UMRW(bo.unused1);
|
||||
B_TSET(bo.type, B_DUPLICATE, 0);
|
||||
UMRW(bo.unused2);
|
||||
bo.pgno = cp->pgno;
|
||||
bo.tlen = 0;
|
||||
|
||||
@ -989,7 +651,7 @@ __bam_ndup(dbp, h, indx)
|
||||
|
||||
return (memp_fput(dbp->mpf, cp, DB_MPOOL_DIRTY));
|
||||
|
||||
err: (void)__bam_free(dbp, cp);
|
||||
err: (void)__bam_free(dbc, cp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -998,13 +660,16 @@ err: (void)__bam_free(dbp, cp);
|
||||
* Build the real record for a fixed length put.
|
||||
*/
|
||||
static int
|
||||
__bam_fixed(t, dbt)
|
||||
BTREE *t;
|
||||
__bam_fixed(dbc, dbt)
|
||||
DBC *dbc;
|
||||
DBT *dbt;
|
||||
{
|
||||
DB *dbp;
|
||||
RECNO *rp;
|
||||
int ret;
|
||||
|
||||
rp = t->bt_recno;
|
||||
dbp = dbc->dbp;
|
||||
rp = ((BTREE *)dbp->internal)->recno;
|
||||
|
||||
/*
|
||||
* If database contains fixed-length records, and the record is long,
|
||||
@ -1018,29 +683,27 @@ __bam_fixed(t, dbt)
|
||||
* short. Pad it out. We use the record data return memory, it's
|
||||
* only a short-term use.
|
||||
*/
|
||||
if (t->bt_rdata.ulen < rp->re_len) {
|
||||
t->bt_rdata.data = t->bt_rdata.data == NULL ?
|
||||
(void *)__db_malloc(rp->re_len) :
|
||||
(void *)__db_realloc(t->bt_rdata.data, rp->re_len);
|
||||
if (t->bt_rdata.data == NULL) {
|
||||
t->bt_rdata.ulen = 0;
|
||||
return (ENOMEM);
|
||||
if (dbc->rdata.ulen < rp->re_len) {
|
||||
if ((ret = __os_realloc(&dbc->rdata.data, rp->re_len)) != 0) {
|
||||
dbc->rdata.ulen = 0;
|
||||
dbc->rdata.data = NULL;
|
||||
return (ret);
|
||||
}
|
||||
t->bt_rdata.ulen = rp->re_len;
|
||||
dbc->rdata.ulen = rp->re_len;
|
||||
}
|
||||
memcpy(t->bt_rdata.data, dbt->data, dbt->size);
|
||||
memset((u_int8_t *)t->bt_rdata.data + dbt->size,
|
||||
memcpy(dbc->rdata.data, dbt->data, dbt->size);
|
||||
memset((u_int8_t *)dbc->rdata.data + dbt->size,
|
||||
rp->re_pad, rp->re_len - dbt->size);
|
||||
|
||||
/*
|
||||
* Clean up our flags and other information just in case, and
|
||||
* change the caller's DBT to reference our created record.
|
||||
*/
|
||||
t->bt_rdata.size = rp->re_len;
|
||||
t->bt_rdata.dlen = 0;
|
||||
t->bt_rdata.doff = 0;
|
||||
t->bt_rdata.flags = 0;
|
||||
*dbt = t->bt_rdata;
|
||||
dbc->rdata.size = rp->re_len;
|
||||
dbc->rdata.dlen = 0;
|
||||
dbc->rdata.doff = 0;
|
||||
dbc->rdata.flags = 0;
|
||||
*dbt = dbc->rdata;
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -1050,15 +713,15 @@ __bam_fixed(t, dbt)
|
||||
* Build the real record for a partial put.
|
||||
*/
|
||||
static int
|
||||
__bam_partial(dbp, dbt, h, indx, nbytes)
|
||||
DB *dbp;
|
||||
__bam_partial(dbc, dbt, h, indx, nbytes, flags)
|
||||
DBC *dbc;
|
||||
DBT *dbt;
|
||||
PAGE *h;
|
||||
u_int32_t indx, nbytes;
|
||||
u_int32_t indx, nbytes, flags;
|
||||
{
|
||||
BTREE *t;
|
||||
BKEYDATA *bk, tbk;
|
||||
BOVERFLOW *bo;
|
||||
DB *dbp;
|
||||
DBT copy;
|
||||
u_int32_t len, tlen;
|
||||
u_int8_t *p;
|
||||
@ -1066,18 +729,34 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
|
||||
|
||||
COMPQUIET(bo, NULL);
|
||||
|
||||
t = dbp->internal;
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/* We use the record data return memory, it's only a short-term use. */
|
||||
if (t->bt_rdata.ulen < nbytes) {
|
||||
t->bt_rdata.data = t->bt_rdata.data == NULL ?
|
||||
(void *)__db_malloc(nbytes) :
|
||||
(void *)__db_realloc(t->bt_rdata.data, nbytes);
|
||||
if (t->bt_rdata.data == NULL) {
|
||||
t->bt_rdata.ulen = 0;
|
||||
return (ENOMEM);
|
||||
if (dbc->rdata.ulen < nbytes) {
|
||||
if ((ret = __os_realloc(&dbc->rdata.data, nbytes)) != 0) {
|
||||
dbc->rdata.ulen = 0;
|
||||
dbc->rdata.data = NULL;
|
||||
return (ret);
|
||||
}
|
||||
t->bt_rdata.ulen = nbytes;
|
||||
dbc->rdata.ulen = nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use nul bytes for any part of the record that isn't specified;
|
||||
* get it over with.
|
||||
*/
|
||||
memset(dbc->rdata.data, 0, nbytes);
|
||||
|
||||
/*
|
||||
* In the next clauses, we need to do three things: a) set p to point
|
||||
* to the place at which to copy the user's data, b) set tlen to the
|
||||
* total length of the record, not including the bytes contributed by
|
||||
* the user, and c) copy any valid data from an existing record.
|
||||
*/
|
||||
if (LF_ISSET(BI_NEWKEY)) {
|
||||
tlen = dbt->doff;
|
||||
p = (u_int8_t *)dbc->rdata.data + dbt->doff;
|
||||
goto ucopy;
|
||||
}
|
||||
|
||||
/* Find the current record. */
|
||||
@ -1089,13 +768,6 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
|
||||
B_TSET(bk->type, B_KEYDATA, 0);
|
||||
bk->len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use nul bytes for any part of the record that isn't specified,
|
||||
* get it over with.
|
||||
*/
|
||||
memset(t->bt_rdata.data, 0, nbytes);
|
||||
|
||||
if (B_TYPE(bk->type) == B_OVERFLOW) {
|
||||
/*
|
||||
* In the case of an overflow record, we shift things around
|
||||
@ -1103,12 +775,12 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
|
||||
*/
|
||||
memset(©, 0, sizeof(copy));
|
||||
if ((ret = __db_goff(dbp, ©, bo->tlen,
|
||||
bo->pgno, &t->bt_rdata.data, &t->bt_rdata.ulen)) != 0)
|
||||
bo->pgno, &dbc->rdata.data, &dbc->rdata.ulen)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Skip any leading data from the original record. */
|
||||
tlen = dbt->doff;
|
||||
p = (u_int8_t *)t->bt_rdata.data + dbt->doff;
|
||||
p = (u_int8_t *)dbc->rdata.data + dbt->doff;
|
||||
|
||||
/*
|
||||
* Copy in any trailing data from the original record.
|
||||
@ -1127,20 +799,12 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
|
||||
memmove(p + dbt->size, p + dbt->dlen, len);
|
||||
tlen += len;
|
||||
}
|
||||
|
||||
/* Copy in the application provided data. */
|
||||
memcpy(p, dbt->data, dbt->size);
|
||||
tlen += dbt->size;
|
||||
} else {
|
||||
/* Copy in any leading data from the original record. */
|
||||
memcpy(t->bt_rdata.data,
|
||||
memcpy(dbc->rdata.data,
|
||||
bk->data, dbt->doff > bk->len ? bk->len : dbt->doff);
|
||||
tlen = dbt->doff;
|
||||
p = (u_int8_t *)t->bt_rdata.data + dbt->doff;
|
||||
|
||||
/* Copy in the application provided data. */
|
||||
memcpy(p, dbt->data, dbt->size);
|
||||
tlen += dbt->size;
|
||||
p = (u_int8_t *)dbc->rdata.data + dbt->doff;
|
||||
|
||||
/* Copy in any trailing data from the original record. */
|
||||
len = dbt->doff + dbt->dlen;
|
||||
@ -1150,11 +814,18 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
|
||||
}
|
||||
}
|
||||
|
||||
ucopy: /*
|
||||
* Copy in the application provided data -- p and tlen must have been
|
||||
* initialized above.
|
||||
*/
|
||||
memcpy(p, dbt->data, dbt->size);
|
||||
tlen += dbt->size;
|
||||
|
||||
/* Set the DBT to reference our new record. */
|
||||
t->bt_rdata.size = tlen;
|
||||
t->bt_rdata.dlen = 0;
|
||||
t->bt_rdata.doff = 0;
|
||||
t->bt_rdata.flags = 0;
|
||||
*dbt = t->bt_rdata;
|
||||
dbc->rdata.size = tlen;
|
||||
dbc->rdata.dlen = 0;
|
||||
dbc->rdata.doff = 0;
|
||||
dbc->rdata.flags = 0;
|
||||
*dbt = dbc->rdata;
|
||||
return (0);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_rec.c 10.21 (Sleepycat) 4/28/98";
|
||||
static const char sccsid[] = "@(#)bt_rec.c 10.28 (Sleepycat) 9/27/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -45,7 +45,8 @@ __bam_pg_alloc_recover(logp, dbtp, lsnp, redo, info)
|
||||
BTMETA *meta;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
db_pgno_t pgno;
|
||||
int cmp_n, cmp_p, modified, ret;
|
||||
|
||||
@ -101,7 +102,6 @@ __bam_pg_alloc_recover(logp, dbtp, lsnp, redo, info)
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
(void)memp_fput(mpf, meta, 0);
|
||||
goto out;
|
||||
}
|
||||
@ -121,12 +121,10 @@ __bam_pg_alloc_recover(logp, dbtp, lsnp, redo, info)
|
||||
meta->free = argp->pgno;
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: REC_CLOSE;
|
||||
@ -149,7 +147,8 @@ __bam_pg_free_recover(logp, dbtp, lsnp, redo, info)
|
||||
{
|
||||
__bam_pg_free_args *argp;
|
||||
BTMETA *meta;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
db_pgno_t pgno;
|
||||
@ -192,10 +191,8 @@ __bam_pg_free_recover(logp, dbtp, lsnp, redo, info)
|
||||
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix up the metadata page. If we're redoing or undoing the operation
|
||||
@ -224,10 +221,8 @@ __bam_pg_free_recover(logp, dbtp, lsnp, redo, info)
|
||||
meta->lsn = argp->meta_lsn;
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
@ -251,7 +246,8 @@ __bam_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__bam_split_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
|
||||
db_pgno_t pgno;
|
||||
@ -310,12 +306,9 @@ __bam_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
goto done;
|
||||
|
||||
/* Allocate and initialize new left/right child pages. */
|
||||
if ((_lp = (PAGE *)__db_malloc(file_dbp->pgsize)) == NULL ||
|
||||
(_rp = (PAGE *)__db_malloc(file_dbp->pgsize)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
__db_err(file_dbp->dbenv, "%s", strerror(ret));
|
||||
if ((ret = __os_malloc(file_dbp->pgsize, NULL, &_lp)) != 0 ||
|
||||
(ret = __os_malloc(file_dbp->pgsize, NULL, &_rp)) != 0)
|
||||
goto out;
|
||||
}
|
||||
if (rootsplit) {
|
||||
P_INIT(_lp, file_dbp->pgsize, argp->left,
|
||||
PGNO_INVALID,
|
||||
@ -352,7 +345,7 @@ __bam_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
memcpy(lp, _lp, file_dbp->pgsize);
|
||||
lp->lsn = *lsnp;
|
||||
if ((ret = memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
|
||||
goto fatal;
|
||||
goto out;
|
||||
lp = NULL;
|
||||
}
|
||||
|
||||
@ -367,7 +360,7 @@ __bam_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
memcpy(rp, _rp, file_dbp->pgsize);
|
||||
rp->lsn = *lsnp;
|
||||
if ((ret = memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
|
||||
goto fatal;
|
||||
goto out;
|
||||
rp = NULL;
|
||||
}
|
||||
|
||||
@ -392,7 +385,7 @@ __bam_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
__bam_total(_lp) + __bam_total(_rp) : 0);
|
||||
pp->lsn = *lsnp;
|
||||
if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
|
||||
goto fatal;
|
||||
goto out;
|
||||
pp = NULL;
|
||||
}
|
||||
|
||||
@ -412,9 +405,9 @@ __bam_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
if (log_compare(&LSN(np), &argp->nlsn) == 0) {
|
||||
PREV_PGNO(np) = argp->right;
|
||||
np->lsn = *lsnp;
|
||||
if ((ret = memp_fput(mpf,
|
||||
np, DB_MPOOL_DIRTY)) != 0)
|
||||
goto fatal;
|
||||
if ((ret =
|
||||
memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0)
|
||||
goto out;
|
||||
np = NULL;
|
||||
}
|
||||
}
|
||||
@ -433,7 +426,7 @@ __bam_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
if (log_compare(lsnp, &LSN(pp)) == 0) {
|
||||
memcpy(pp, argp->pg.data, argp->pg.size);
|
||||
if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
|
||||
goto fatal;
|
||||
goto out;
|
||||
pp = NULL;
|
||||
}
|
||||
|
||||
@ -451,7 +444,7 @@ lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
|
||||
lp->lsn = argp->llsn;
|
||||
if ((ret =
|
||||
memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
|
||||
goto fatal;
|
||||
goto out;
|
||||
lp = NULL;
|
||||
}
|
||||
if (rp != NULL &&
|
||||
@ -459,7 +452,7 @@ lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
|
||||
rp->lsn = argp->rlsn;
|
||||
if ((ret =
|
||||
memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
|
||||
goto fatal;
|
||||
goto out;
|
||||
rp = NULL;
|
||||
}
|
||||
}
|
||||
@ -481,7 +474,7 @@ lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
|
||||
PREV_PGNO(np) = argp->left;
|
||||
np->lsn = argp->nlsn;
|
||||
if (memp_fput(mpf, np, DB_MPOOL_DIRTY))
|
||||
goto fatal;
|
||||
goto out;
|
||||
np = NULL;
|
||||
}
|
||||
}
|
||||
@ -490,9 +483,6 @@ lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
if (0) {
|
||||
fatal: (void)__db_panic(file_dbp);
|
||||
}
|
||||
out: /* Free any pages that weren't dirtied. */
|
||||
if (pp != NULL && (t_ret = memp_fput(mpf, pp, 0)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
@ -505,9 +495,9 @@ out: /* Free any pages that weren't dirtied. */
|
||||
|
||||
/* Free any allocated space. */
|
||||
if (_lp != NULL)
|
||||
__db_free(_lp);
|
||||
__os_free(_lp, file_dbp->pgsize);
|
||||
if (_rp != NULL)
|
||||
__db_free(_rp);
|
||||
__os_free(_rp, file_dbp->pgsize);
|
||||
|
||||
REC_CLOSE;
|
||||
}
|
||||
@ -528,7 +518,8 @@ __bam_rsplit_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__bam_rsplit_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
db_pgno_t pgno;
|
||||
@ -558,16 +549,14 @@ __bam_rsplit_recover(logp, dbtp, lsnp, redo, info)
|
||||
P_INIT(pagep, file_dbp->pgsize, PGNO_ROOT,
|
||||
argp->nrec, PGNO_INVALID, pagep->level + 1,
|
||||
file_dbp->type == DB_BTREE ? P_IBTREE : P_IRECNO);
|
||||
if ((ret = __db_pitem(file_dbp, pagep, 0,
|
||||
if ((ret = __db_pitem(dbc, pagep, 0,
|
||||
argp->rootent.size, &argp->rootent, NULL)) != 0)
|
||||
goto out;
|
||||
pagep->lsn = argp->rootlsn;
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix the page copied over the root page. It's possible that the
|
||||
@ -592,10 +581,8 @@ __bam_rsplit_recover(logp, dbtp, lsnp, redo, info)
|
||||
memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
@ -619,7 +606,8 @@ __bam_adj_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__bam_adj_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
int cmp_n, cmp_p, modified, ret;
|
||||
@ -640,7 +628,7 @@ __bam_adj_recover(logp, dbtp, lsnp, redo, info)
|
||||
cmp_p = log_compare(&LSN(pagep), &argp->lsn);
|
||||
if (cmp_p == 0 && redo) {
|
||||
/* Need to redo update described. */
|
||||
if ((ret = __bam_adjindx(file_dbp,
|
||||
if ((ret = __bam_adjindx(dbc,
|
||||
pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0)
|
||||
goto err;
|
||||
|
||||
@ -648,7 +636,7 @@ __bam_adj_recover(logp, dbtp, lsnp, redo, info)
|
||||
modified = 1;
|
||||
} else if (cmp_n == 0 && !redo) {
|
||||
/* Need to undo update described. */
|
||||
if ((ret = __bam_adjindx(file_dbp,
|
||||
if ((ret = __bam_adjindx(dbc,
|
||||
pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0)
|
||||
goto err;
|
||||
|
||||
@ -684,7 +672,8 @@ __bam_cadjust_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__bam_cadjust_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
int cmp_n, cmp_p, modified, ret;
|
||||
@ -760,7 +749,8 @@ __bam_cdel_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__bam_cdel_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
int cmp_n, cmp_p, modified, ret;
|
||||
@ -781,13 +771,19 @@ __bam_cdel_recover(logp, dbtp, lsnp, redo, info)
|
||||
cmp_p = log_compare(&LSN(pagep), &argp->lsn);
|
||||
if (cmp_p == 0 && redo) {
|
||||
/* Need to redo update described. */
|
||||
B_DSET(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type);
|
||||
if (pagep->type == P_DUPLICATE)
|
||||
B_DSET(GET_BKEYDATA(pagep, argp->indx)->type);
|
||||
else
|
||||
B_DSET(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type);
|
||||
|
||||
LSN(pagep) = *lsnp;
|
||||
modified = 1;
|
||||
} else if (cmp_n == 0 && !redo) {
|
||||
/* Need to undo update described. */
|
||||
B_DCLR(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type);
|
||||
if (pagep->type == P_DUPLICATE)
|
||||
B_DCLR(GET_BKEYDATA(pagep, argp->indx)->type);
|
||||
else
|
||||
B_DCLR(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type);
|
||||
|
||||
LSN(pagep) = argp->lsn;
|
||||
modified = 1;
|
||||
@ -818,7 +814,8 @@ __bam_repl_recover(logp, dbtp, lsnp, redo, info)
|
||||
{
|
||||
__bam_repl_args *argp;
|
||||
BKEYDATA *bk;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DBT dbt;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
@ -848,10 +845,8 @@ __bam_repl_recover(logp, dbtp, lsnp, redo, info)
|
||||
*/
|
||||
memset(&dbt, 0, sizeof(dbt));
|
||||
dbt.size = argp->prefix + argp->suffix + argp->repl.size;
|
||||
if ((dbt.data = __db_malloc(dbt.size)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_malloc(dbt.size, NULL, &dbt.data)) != 0)
|
||||
goto err;
|
||||
}
|
||||
p = dbt.data;
|
||||
memcpy(p, bk->data, argp->prefix);
|
||||
p += argp->prefix;
|
||||
@ -859,8 +854,8 @@ __bam_repl_recover(logp, dbtp, lsnp, redo, info)
|
||||
p += argp->repl.size;
|
||||
memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
|
||||
|
||||
ret = __bam_ritem(file_dbp, pagep, argp->indx, &dbt);
|
||||
__db_free(dbt.data);
|
||||
ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
|
||||
__os_free(dbt.data, dbt.size);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
@ -874,10 +869,8 @@ __bam_repl_recover(logp, dbtp, lsnp, redo, info)
|
||||
*/
|
||||
memset(&dbt, 0, sizeof(dbt));
|
||||
dbt.size = argp->prefix + argp->suffix + argp->orig.size;
|
||||
if ((dbt.data = __db_malloc(dbt.size)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_malloc(dbt.size, NULL, &dbt.data)) != 0)
|
||||
goto err;
|
||||
}
|
||||
p = dbt.data;
|
||||
memcpy(p, bk->data, argp->prefix);
|
||||
p += argp->prefix;
|
||||
@ -885,8 +878,8 @@ __bam_repl_recover(logp, dbtp, lsnp, redo, info)
|
||||
p += argp->orig.size;
|
||||
memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
|
||||
|
||||
ret = __bam_ritem(file_dbp, pagep, argp->indx, &dbt);
|
||||
__db_free(dbt.data);
|
||||
ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
|
||||
__os_free(dbt.data, dbt.size);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_rsearch.c 10.15 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)bt_rsearch.c 10.21 (Sleepycat) 12/2/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -59,39 +59,37 @@ static const char sccsid[] = "@(#)bt_rsearch.c 10.15 (Sleepycat) 5/6/98";
|
||||
* __bam_rsearch --
|
||||
* Search a btree for a record number.
|
||||
*
|
||||
* PUBLIC: int __bam_rsearch __P((DB *, db_recno_t *, u_int32_t, int, int *));
|
||||
* PUBLIC: int __bam_rsearch __P((DBC *, db_recno_t *, u_int32_t, int, int *));
|
||||
*/
|
||||
int
|
||||
__bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
DB *dbp;
|
||||
__bam_rsearch(dbc, recnop, flags, stop, exactp)
|
||||
DBC *dbc;
|
||||
db_recno_t *recnop;
|
||||
u_int32_t flags;
|
||||
int stop, *exactp;
|
||||
{
|
||||
BINTERNAL *bi;
|
||||
BTREE *t;
|
||||
CURSOR *cp;
|
||||
DB *dbp;
|
||||
DB_LOCK lock;
|
||||
PAGE *h;
|
||||
RINTERNAL *ri;
|
||||
db_indx_t indx, top;
|
||||
db_pgno_t pg;
|
||||
db_recno_t i, recno, total;
|
||||
int isappend, ret, stack;
|
||||
int ret, stack;
|
||||
|
||||
t = dbp->internal;
|
||||
dbp = dbc->dbp;
|
||||
cp = dbc->internal;
|
||||
|
||||
/*
|
||||
* We test for groups of flags, S_APPEND is the only one that can be
|
||||
* OR'd into the set. Clear it now so that the tests for equality
|
||||
* will work.
|
||||
*/
|
||||
if ((isappend = LF_ISSET(S_APPEND)) != 0)
|
||||
LF_CLR(S_APPEND);
|
||||
BT_STK_CLR(cp);
|
||||
|
||||
/*
|
||||
* There are several ways we search a btree tree. The flags argument
|
||||
* specifies if we're acquiring read or write locks and if we are
|
||||
* locking pairs of pages. See btree.h for more details.
|
||||
* locking pairs of pages. In addition, if we're adding or deleting
|
||||
* an item, we have to lock the entire tree, regardless. See btree.h
|
||||
* for more details.
|
||||
*
|
||||
* If write-locking pages, we need to know whether or not to acquire a
|
||||
* write lock on a page before getting it. This depends on how deep it
|
||||
@ -102,15 +100,36 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
* Retrieve the root page.
|
||||
*/
|
||||
pg = PGNO_ROOT;
|
||||
if ((ret = __bam_lget(dbp, 0, PGNO_ROOT,
|
||||
flags == S_INSERT || flags == S_DELETE ?
|
||||
DB_LOCK_WRITE : DB_LOCK_READ, &lock)) != 0)
|
||||
stack = LF_ISSET(S_STACK);
|
||||
if ((ret = __bam_lget(dbc,
|
||||
0, pg, stack ? DB_LOCK_WRITE : DB_LOCK_READ, &lock)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0) {
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) {
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
return (ret);
|
||||
}
|
||||
total = RE_NREC(h);
|
||||
|
||||
/*
|
||||
* Decide if we need to save this page; if we do, write lock it.
|
||||
* We deliberately don't lock-couple on this call. If the tree
|
||||
* is tiny, i.e., one page, and two threads are busily updating
|
||||
* the root page, we're almost guaranteed deadlocks galore, as
|
||||
* each one gets a read lock and then blocks the other's attempt
|
||||
* for a write lock.
|
||||
*/
|
||||
if (!stack &&
|
||||
((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) ||
|
||||
(LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
if ((ret = __bam_lget(dbc, 0, pg, DB_LOCK_WRITE, &lock)) != 0)
|
||||
return (ret);
|
||||
if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) {
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
return (ret);
|
||||
}
|
||||
stack = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If appending to the tree, set the record number now -- we have the
|
||||
@ -124,7 +143,8 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
* for the record immediately after the last record in the tree, so do
|
||||
* a fast check now.
|
||||
*/
|
||||
if (isappend) {
|
||||
total = RE_NREC(h);
|
||||
if (LF_ISSET(S_APPEND)) {
|
||||
*exactp = 0;
|
||||
*recnop = recno = total + 1;
|
||||
} else {
|
||||
@ -133,33 +153,14 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
*exactp = 1;
|
||||
else {
|
||||
*exactp = 0;
|
||||
if (!PAST_END_OK(flags) || recno > total + 1) {
|
||||
if (!LF_ISSET(S_PAST_EOF) || recno > total + 1) {
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
return (DB_NOTFOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Decide if we're building a stack based on the operation. */
|
||||
BT_STK_CLR(t);
|
||||
stack = flags == S_DELETE || flags == S_INSERT;
|
||||
|
||||
/*
|
||||
* Decide if we need to save this page; if we do, write lock it, and
|
||||
* start to build a stack.
|
||||
*/
|
||||
if (LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) {
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
if ((ret = __bam_lget(dbp, 1, pg, DB_LOCK_WRITE, &lock)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0) {
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
return (ret);
|
||||
}
|
||||
stack = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Record numbers in the tree are 0-based, but the recno is
|
||||
@ -177,7 +178,7 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
* not exist if there are enough deleted records in the
|
||||
* page.
|
||||
*/
|
||||
if (recno <= NUM_ENT(h))
|
||||
if (recno <= (db_recno_t)NUM_ENT(h) / P_INDX)
|
||||
for (i = recno - 1;; --i) {
|
||||
if (B_DISSET(GET_BKEYDATA(h,
|
||||
i * P_INDX + O_INDX)->type))
|
||||
@ -185,10 +186,10 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
if (recno > NUM_ENT(h)) {
|
||||
if (recno > (db_recno_t)NUM_ENT(h) / P_INDX) {
|
||||
*exactp = 0;
|
||||
if (!PAST_END_OK(flags) ||
|
||||
recno > (db_recno_t)(NUM_ENT(h) + 1)) {
|
||||
if (!LF_ISSET(S_PAST_EOF) || recno >
|
||||
(db_recno_t)(NUM_ENT(h) / P_INDX + 1)) {
|
||||
ret = DB_NOTFOUND;
|
||||
goto err;
|
||||
}
|
||||
@ -197,7 +198,7 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
|
||||
/* Correct from 1-based to 0-based for a page offset. */
|
||||
--recno;
|
||||
BT_STK_ENTER(t, h, recno * P_INDX, lock, ret);
|
||||
BT_STK_ENTER(cp, h, recno * P_INDX, lock, ret);
|
||||
return (ret);
|
||||
case P_IBTREE:
|
||||
for (indx = 0, top = NUM_ENT(h);;) {
|
||||
@ -213,7 +214,7 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
|
||||
/* Correct from 1-based to 0-based for a page offset. */
|
||||
--recno;
|
||||
BT_STK_ENTER(t, h, recno, lock, ret);
|
||||
BT_STK_ENTER(cp, h, recno, lock, ret);
|
||||
return (ret);
|
||||
case P_IRECNO:
|
||||
for (indx = 0, top = NUM_ENT(h);;) {
|
||||
@ -232,42 +233,42 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
|
||||
if (stack) {
|
||||
/* Return if this is the lowest page wanted. */
|
||||
if (LF_ISSET(S_PARENT) && stop == h->level) {
|
||||
BT_STK_ENTER(t, h, indx, lock, ret);
|
||||
BT_STK_ENTER(cp, h, indx, lock, ret);
|
||||
return (ret);
|
||||
}
|
||||
BT_STK_PUSH(t, h, indx, lock, ret);
|
||||
if (ret)
|
||||
BT_STK_PUSH(cp, h, indx, lock, ret);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
if ((ret = __bam_lget(dbp, 0, pg,
|
||||
LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ,
|
||||
&lock)) != 0)
|
||||
if ((ret =
|
||||
__bam_lget(dbc, 0, pg, DB_LOCK_WRITE, &lock)) != 0)
|
||||
goto err;
|
||||
} else {
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
|
||||
/*
|
||||
* Decide if we want to return a pointer to the next
|
||||
* page in the stack. If we do, write lock it and
|
||||
* never unlock it.
|
||||
*/
|
||||
if (LF_ISSET(S_PARENT) &&
|
||||
(u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1))
|
||||
if ((LF_ISSET(S_PARENT) &&
|
||||
(u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1)) ||
|
||||
(h->level - 1) == LEAFLEVEL)
|
||||
stack = 1;
|
||||
|
||||
if ((ret = __bam_lget(dbp, 1, pg,
|
||||
LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ,
|
||||
&lock)) != 0)
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
|
||||
if ((ret =
|
||||
__bam_lget(dbc, 1, pg, stack && LF_ISSET(S_WRITE) ?
|
||||
DB_LOCK_WRITE : DB_LOCK_READ, &lock)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0)
|
||||
goto err;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
||||
err: BT_STK_POP(t);
|
||||
__bam_stkrel(dbp);
|
||||
err: BT_STK_POP(cp);
|
||||
__bam_stkrel(dbc, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -275,25 +276,29 @@ err: BT_STK_POP(t);
|
||||
* __bam_adjust --
|
||||
* Adjust the tree after adding or deleting a record.
|
||||
*
|
||||
* PUBLIC: int __bam_adjust __P((DB *, BTREE *, int32_t));
|
||||
* PUBLIC: int __bam_adjust __P((DBC *, int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_adjust(dbp, t, adjust)
|
||||
DB *dbp;
|
||||
BTREE *t;
|
||||
__bam_adjust(dbc, adjust)
|
||||
DBC *dbc;
|
||||
int32_t adjust;
|
||||
{
|
||||
CURSOR *cp;
|
||||
DB *dbp;
|
||||
EPG *epg;
|
||||
PAGE *h;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
cp = dbc->internal;
|
||||
|
||||
/* Update the record counts for the tree. */
|
||||
for (epg = t->bt_sp; epg <= t->bt_csp; ++epg) {
|
||||
for (epg = cp->sp; epg <= cp->csp; ++epg) {
|
||||
h = epg->page;
|
||||
if (TYPE(h) == P_IBTREE || TYPE(h) == P_IRECNO) {
|
||||
if (DB_LOGGING(dbp) &&
|
||||
if (DB_LOGGING(dbc) &&
|
||||
(ret = __bam_cadjust_log(dbp->dbenv->lg_info,
|
||||
dbp->txn, &LSN(h), 0, dbp->log_fileid,
|
||||
dbc->txn, &LSN(h), 0, dbp->log_fileid,
|
||||
PGNO(h), &LSN(h), (u_int32_t)epg->indx,
|
||||
adjust, 1)) != 0)
|
||||
return (ret);
|
||||
@ -317,28 +322,31 @@ __bam_adjust(dbp, t, adjust)
|
||||
* __bam_nrecs --
|
||||
* Return the number of records in the tree.
|
||||
*
|
||||
* PUBLIC: int __bam_nrecs __P((DB *, db_recno_t *));
|
||||
* PUBLIC: int __bam_nrecs __P((DBC *, db_recno_t *));
|
||||
*/
|
||||
int
|
||||
__bam_nrecs(dbp, rep)
|
||||
DB *dbp;
|
||||
__bam_nrecs(dbc, rep)
|
||||
DBC *dbc;
|
||||
db_recno_t *rep;
|
||||
{
|
||||
DB *dbp;
|
||||
DB_LOCK lock;
|
||||
PAGE *h;
|
||||
db_pgno_t pgno;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
pgno = PGNO_ROOT;
|
||||
if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &lock)) != 0)
|
||||
if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_READ, &lock)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
|
||||
return (ret);
|
||||
|
||||
*rep = RE_NREC(h);
|
||||
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_TLPUT(dbp, lock);
|
||||
(void)__BT_TLPUT(dbc, lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_search.c 10.15 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)bt_search.c 10.25 (Sleepycat) 12/16/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -65,38 +65,41 @@ static const char sccsid[] = "@(#)bt_search.c 10.15 (Sleepycat) 5/6/98";
|
||||
* __bam_search --
|
||||
* Search a btree for a key.
|
||||
*
|
||||
* PUBLIC: int __bam_search __P((DB *,
|
||||
* PUBLIC: int __bam_search __P((DBC *,
|
||||
* PUBLIC: const DBT *, u_int32_t, int, db_recno_t *, int *));
|
||||
*/
|
||||
int
|
||||
__bam_search(dbp, key, flags, stop, recnop, exactp)
|
||||
DB *dbp;
|
||||
__bam_search(dbc, key, flags, stop, recnop, exactp)
|
||||
DBC *dbc;
|
||||
const DBT *key;
|
||||
u_int32_t flags;
|
||||
int stop, *exactp;
|
||||
db_recno_t *recnop;
|
||||
{
|
||||
BTREE *t;
|
||||
CURSOR *cp;
|
||||
DB *dbp;
|
||||
DB_LOCK lock;
|
||||
EPG cur;
|
||||
PAGE *h;
|
||||
db_indx_t base, i, indx, lim;
|
||||
db_pgno_t pg;
|
||||
db_recno_t recno;
|
||||
int cmp, jump, ret, stack;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
cp = dbc->internal;
|
||||
t = dbp->internal;
|
||||
recno = 0;
|
||||
|
||||
BT_STK_CLR(t);
|
||||
BT_STK_CLR(cp);
|
||||
|
||||
/*
|
||||
* There are several ways we search a btree tree. The flags argument
|
||||
* specifies if we're acquiring read or write locks, if we position
|
||||
* to the first or last item in a set of duplicates, if we return
|
||||
* deleted items, and if we are locking pairs of pages. See btree.h
|
||||
* for more details. In addition, if we're doing record numbers, we
|
||||
* have to lock the entire tree regardless.
|
||||
* deleted items, and if we are locking pairs of pages. In addition,
|
||||
* if we're modifying record numbers, we have to lock the entire tree
|
||||
* regardless. See btree.h for more details.
|
||||
*
|
||||
* If write-locking pages, we need to know whether or not to acquire a
|
||||
* write lock on a page before getting it. This depends on how deep it
|
||||
@ -108,11 +111,11 @@ __bam_search(dbp, key, flags, stop, recnop, exactp)
|
||||
*/
|
||||
pg = PGNO_ROOT;
|
||||
stack = F_ISSET(dbp, DB_BT_RECNUM) && LF_ISSET(S_STACK);
|
||||
if ((ret = __bam_lget(dbp,
|
||||
if ((ret = __bam_lget(dbc,
|
||||
0, pg, stack ? DB_LOCK_WRITE : DB_LOCK_READ, &lock)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0) {
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) {
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -128,14 +131,13 @@ __bam_search(dbp, key, flags, stop, recnop, exactp)
|
||||
((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) ||
|
||||
(LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) {
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
if ((ret = __bam_lget(dbp, 0, pg, DB_LOCK_WRITE, &lock)) != 0)
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
if ((ret = __bam_lget(dbc, 0, pg, DB_LOCK_WRITE, &lock)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0) {
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) {
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
stack = 1;
|
||||
}
|
||||
|
||||
@ -147,12 +149,12 @@ __bam_search(dbp, key, flags, stop, recnop, exactp)
|
||||
* per page item. If we find an exact match on a leaf page,
|
||||
* we're done.
|
||||
*/
|
||||
cur.page = h;
|
||||
jump = TYPE(h) == P_LBTREE ? P_INDX : O_INDX;
|
||||
for (base = 0,
|
||||
lim = NUM_ENT(h) / (db_indx_t)jump; lim != 0; lim >>= 1) {
|
||||
cur.indx = indx = base + ((lim >> 1) * jump);
|
||||
if ((cmp = __bam_cmp(dbp, key, &cur)) == 0) {
|
||||
indx = base + ((lim >> 1) * jump);
|
||||
if ((cmp =
|
||||
__bam_cmp(dbp, key, h, indx, t->bt_compare)) == 0) {
|
||||
if (TYPE(h) == P_LBTREE)
|
||||
goto match;
|
||||
goto next;
|
||||
@ -184,7 +186,7 @@ __bam_search(dbp, key, flags, stop, recnop, exactp)
|
||||
* to find an undeleted record. This is handled in the
|
||||
* __bam_c_search() routine.
|
||||
*/
|
||||
BT_STK_ENTER(t, h, base, lock, ret);
|
||||
BT_STK_ENTER(cp, h, base, lock, ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -208,39 +210,39 @@ next: pg = GET_BINTERNAL(h, indx)->pgno;
|
||||
if (stack) {
|
||||
/* Return if this is the lowest page wanted. */
|
||||
if (LF_ISSET(S_PARENT) && stop == h->level) {
|
||||
BT_STK_ENTER(t, h, indx, lock, ret);
|
||||
BT_STK_ENTER(cp, h, indx, lock, ret);
|
||||
return (ret);
|
||||
}
|
||||
BT_STK_PUSH(t, h, indx, lock, ret);
|
||||
BT_STK_PUSH(cp, h, indx, lock, ret);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
if ((ret =
|
||||
__bam_lget(dbp, 0, pg, DB_LOCK_WRITE, &lock)) != 0)
|
||||
__bam_lget(dbc, 0, pg, DB_LOCK_WRITE, &lock)) != 0)
|
||||
goto err;
|
||||
} else {
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
|
||||
/*
|
||||
* Decide if we want to return a pointer to the next
|
||||
* page in the stack. If we do, write lock it and
|
||||
* never unlock it.
|
||||
* Decide if we want to return a reference to the next
|
||||
* page in the return stack. If so, lock it and never
|
||||
* unlock it.
|
||||
*/
|
||||
if ((LF_ISSET(S_PARENT) &&
|
||||
(u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1)) ||
|
||||
(h->level - 1) == LEAFLEVEL)
|
||||
stack = 1;
|
||||
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
|
||||
if ((ret =
|
||||
__bam_lget(dbp, 1, pg, stack && LF_ISSET(S_WRITE) ?
|
||||
__bam_lget(dbc, 1, pg, stack && LF_ISSET(S_WRITE) ?
|
||||
DB_LOCK_WRITE : DB_LOCK_READ, &lock)) != 0)
|
||||
goto err;
|
||||
}
|
||||
if ((ret = __bam_pget(dbp, &h, &pg, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
|
||||
match: *exactp = 1;
|
||||
|
||||
/*
|
||||
@ -288,17 +290,17 @@ match: *exactp = 1;
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
BT_STK_ENTER(t, h, indx, lock, ret);
|
||||
BT_STK_ENTER(cp, h, indx, lock, ret);
|
||||
return (ret);
|
||||
|
||||
notfound:
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
ret = DB_NOTFOUND;
|
||||
|
||||
err: if (t->bt_csp > t->bt_sp) {
|
||||
BT_STK_POP(t);
|
||||
__bam_stkrel(dbp);
|
||||
err: if (cp->csp > cp->sp) {
|
||||
BT_STK_POP(cp);
|
||||
__bam_stkrel(dbc, 0);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
@ -307,20 +309,35 @@ err: if (t->bt_csp > t->bt_sp) {
|
||||
* __bam_stkrel --
|
||||
* Release all pages currently held in the stack.
|
||||
*
|
||||
* PUBLIC: int __bam_stkrel __P((DB *));
|
||||
* PUBLIC: int __bam_stkrel __P((DBC *, int));
|
||||
*/
|
||||
int
|
||||
__bam_stkrel(dbp)
|
||||
DB *dbp;
|
||||
__bam_stkrel(dbc, nolocks)
|
||||
DBC *dbc;
|
||||
int nolocks;
|
||||
{
|
||||
BTREE *t;
|
||||
CURSOR *cp;
|
||||
DB *dbp;
|
||||
EPG *epg;
|
||||
|
||||
t = dbp->internal;
|
||||
for (epg = t->bt_sp; epg <= t->bt_csp; ++epg) {
|
||||
(void)memp_fput(dbp->mpf, epg->page, 0);
|
||||
(void)__BT_TLPUT(dbp, epg->lock);
|
||||
dbp = dbc->dbp;
|
||||
cp = dbc->internal;
|
||||
|
||||
/* Release inner pages first. */
|
||||
for (epg = cp->sp; epg <= cp->csp; ++epg) {
|
||||
if (epg->page != NULL)
|
||||
(void)memp_fput(dbp->mpf, epg->page, 0);
|
||||
if (epg->lock != LOCK_INVALID) {
|
||||
if (nolocks)
|
||||
(void)__BT_LPUT(dbc, epg->lock);
|
||||
else
|
||||
(void)__BT_TLPUT(dbc, epg->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the stack, all pages have been released. */
|
||||
BT_STK_CLR(cp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -328,24 +345,25 @@ __bam_stkrel(dbp)
|
||||
* __bam_stkgrow --
|
||||
* Grow the stack.
|
||||
*
|
||||
* PUBLIC: int __bam_stkgrow __P((BTREE *));
|
||||
* PUBLIC: int __bam_stkgrow __P((CURSOR *));
|
||||
*/
|
||||
int
|
||||
__bam_stkgrow(t)
|
||||
BTREE *t;
|
||||
__bam_stkgrow(cp)
|
||||
CURSOR *cp;
|
||||
{
|
||||
EPG *p;
|
||||
size_t entries;
|
||||
int ret;
|
||||
|
||||
entries = t->bt_esp - t->bt_sp;
|
||||
entries = cp->esp - cp->sp;
|
||||
|
||||
if ((p = (EPG *)__db_calloc(entries * 2, sizeof(EPG))) == NULL)
|
||||
return (ENOMEM);
|
||||
memcpy(p, t->bt_sp, entries * sizeof(EPG));
|
||||
if (t->bt_sp != t->bt_stack)
|
||||
FREE(t->bt_sp, entries * sizeof(EPG));
|
||||
t->bt_sp = p;
|
||||
t->bt_csp = p + entries;
|
||||
t->bt_esp = p + entries * 2;
|
||||
if ((ret = __os_calloc(entries * 2, sizeof(EPG), &p)) != 0)
|
||||
return (ret);
|
||||
memcpy(p, cp->sp, entries * sizeof(EPG));
|
||||
if (cp->sp != cp->stack)
|
||||
__os_free(cp->sp, entries * sizeof(EPG));
|
||||
cp->sp = p;
|
||||
cp->csp = p + entries;
|
||||
cp->esp = p + entries * 2;
|
||||
return (0);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_split.c 10.23 (Sleepycat) 5/23/98";
|
||||
static const char sccsid[] = "@(#)bt_split.c 10.33 (Sleepycat) 10/13/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -59,27 +59,31 @@ static const char sccsid[] = "@(#)bt_split.c 10.23 (Sleepycat) 5/23/98";
|
||||
#include "db_page.h"
|
||||
#include "btree.h"
|
||||
|
||||
static int __bam_page __P((DB *, EPG *, EPG *));
|
||||
static int __bam_pinsert __P((DB *, EPG *, PAGE *, PAGE *));
|
||||
static int __bam_psplit __P((DB *, EPG *, PAGE *, PAGE *, int));
|
||||
static int __bam_root __P((DB *, EPG *));
|
||||
static int __bam_broot __P((DBC *, PAGE *, PAGE *, PAGE *));
|
||||
static int __bam_page __P((DBC *, EPG *, EPG *));
|
||||
static int __bam_pinsert __P((DBC *, EPG *, PAGE *, PAGE *));
|
||||
static int __bam_psplit __P((DBC *, EPG *, PAGE *, PAGE *, db_indx_t *));
|
||||
static int __bam_root __P((DBC *, EPG *));
|
||||
static int __ram_root __P((DBC *, PAGE *, PAGE *, PAGE *));
|
||||
|
||||
/*
|
||||
* __bam_split --
|
||||
* Split a page.
|
||||
*
|
||||
* PUBLIC: int __bam_split __P((DB *, void *));
|
||||
* PUBLIC: int __bam_split __P((DBC *, void *));
|
||||
*/
|
||||
int
|
||||
__bam_split(dbp, arg)
|
||||
DB *dbp;
|
||||
__bam_split(dbc, arg)
|
||||
DBC *dbc;
|
||||
void *arg;
|
||||
{
|
||||
BTREE *t;
|
||||
CURSOR *cp;
|
||||
DB *dbp;
|
||||
enum { UP, DOWN } dir;
|
||||
int exact, level, ret;
|
||||
|
||||
t = dbp->internal;
|
||||
dbp = dbc->dbp;
|
||||
cp = dbc->internal;
|
||||
|
||||
/*
|
||||
* The locking protocol we use to avoid deadlock to acquire locks by
|
||||
@ -113,15 +117,16 @@ __bam_split(dbp, arg)
|
||||
* Acquire a page and its parent, locked.
|
||||
*/
|
||||
if ((ret = (dbp->type == DB_BTREE ?
|
||||
__bam_search(dbp, arg, S_WRPAIR, level, NULL, &exact) :
|
||||
__bam_rsearch(dbp,
|
||||
__bam_search(dbc, arg, S_WRPAIR, level, NULL, &exact) :
|
||||
__bam_rsearch(dbc,
|
||||
(db_recno_t *)arg, S_WRPAIR, level, &exact))) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Split the page. */
|
||||
ret = t->bt_csp[0].page->pgno == PGNO_ROOT ?
|
||||
__bam_root(dbp, &t->bt_csp[0]) :
|
||||
__bam_page(dbp, &t->bt_csp[-1], &t->bt_csp[0]);
|
||||
ret = cp->csp[0].page->pgno == PGNO_ROOT ?
|
||||
__bam_root(dbc, &cp->csp[0]) :
|
||||
__bam_page(dbc, &cp->csp[-1], &cp->csp[0]);
|
||||
BT_STK_CLR(cp);
|
||||
|
||||
switch (ret) {
|
||||
case 0:
|
||||
@ -155,15 +160,16 @@ __bam_split(dbp, arg)
|
||||
* Split the root page of a btree.
|
||||
*/
|
||||
static int
|
||||
__bam_root(dbp, cp)
|
||||
DB *dbp;
|
||||
__bam_root(dbc, cp)
|
||||
DBC *dbc;
|
||||
EPG *cp;
|
||||
{
|
||||
BTREE *t;
|
||||
DB *dbp;
|
||||
PAGE *lp, *rp;
|
||||
db_indx_t split;
|
||||
int ret;
|
||||
|
||||
t = dbp->internal;
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/* Yeah, right. */
|
||||
if (cp->page->level >= MAXBTREELEVEL) {
|
||||
@ -173,8 +179,8 @@ __bam_root(dbp, cp)
|
||||
|
||||
/* Create new left and right pages for the split. */
|
||||
lp = rp = NULL;
|
||||
if ((ret = __bam_new(dbp, TYPE(cp->page), &lp)) != 0 ||
|
||||
(ret = __bam_new(dbp, TYPE(cp->page), &rp)) != 0)
|
||||
if ((ret = __bam_new(dbc, TYPE(cp->page), &lp)) != 0 ||
|
||||
(ret = __bam_new(dbc, TYPE(cp->page), &rp)) != 0)
|
||||
goto err;
|
||||
P_INIT(lp, dbp->pgsize, lp->pgno,
|
||||
PGNO_INVALID, ISINTERNAL(cp->page) ? PGNO_INVALID : rp->pgno,
|
||||
@ -184,18 +190,18 @@ __bam_root(dbp, cp)
|
||||
cp->page->level, TYPE(cp->page));
|
||||
|
||||
/* Split the page. */
|
||||
if ((ret = __bam_psplit(dbp, cp, lp, rp, 1)) != 0)
|
||||
if ((ret = __bam_psplit(dbc, cp, lp, rp, &split)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
DBT __a;
|
||||
DB_LSN __lsn;
|
||||
memset(&__a, 0, sizeof(__a));
|
||||
__a.data = cp->page;
|
||||
__a.size = dbp->pgsize;
|
||||
ZERO_LSN(__lsn);
|
||||
if ((ret = __bam_split_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if ((ret = __bam_split_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&LSN(cp->page), 0, dbp->log_fileid, PGNO(lp), &LSN(lp),
|
||||
PGNO(rp), &LSN(rp), (u_int32_t)NUM_ENT(lp), 0, &__lsn,
|
||||
&__a)) != 0)
|
||||
@ -205,26 +211,27 @@ __bam_root(dbp, cp)
|
||||
|
||||
/* Clean up the new root page. */
|
||||
if ((ret = (dbp->type == DB_RECNO ?
|
||||
__ram_root(dbp, cp->page, lp, rp) :
|
||||
__bam_broot(dbp, cp->page, lp, rp))) != 0)
|
||||
__ram_root(dbc, cp->page, lp, rp) :
|
||||
__bam_broot(dbc, cp->page, lp, rp))) != 0)
|
||||
goto err;
|
||||
|
||||
/* Adjust any cursors. Do it last so we don't have to undo it. */
|
||||
__bam_ca_split(dbp, cp->page->pgno, lp->pgno, rp->pgno, split, 1);
|
||||
|
||||
/* Success -- write the real pages back to the store. */
|
||||
(void)memp_fput(dbp->mpf, cp->page, DB_MPOOL_DIRTY);
|
||||
(void)__BT_TLPUT(dbp, cp->lock);
|
||||
(void)__BT_TLPUT(dbc, cp->lock);
|
||||
(void)memp_fput(dbp->mpf, lp, DB_MPOOL_DIRTY);
|
||||
(void)memp_fput(dbp->mpf, rp, DB_MPOOL_DIRTY);
|
||||
|
||||
++t->lstat.bt_split;
|
||||
++t->lstat.bt_rootsplit;
|
||||
return (0);
|
||||
|
||||
err: if (lp != NULL)
|
||||
(void)__bam_free(dbp, lp);
|
||||
(void)__bam_free(dbc, lp);
|
||||
if (rp != NULL)
|
||||
(void)__bam_free(dbp, rp);
|
||||
(void)__bam_free(dbc, rp);
|
||||
(void)memp_fput(dbp->mpf, cp->page, 0);
|
||||
(void)__BT_TLPUT(dbp, cp->lock);
|
||||
(void)__BT_TLPUT(dbc, cp->lock);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -233,19 +240,22 @@ err: if (lp != NULL)
|
||||
* Split the non-root page of a btree.
|
||||
*/
|
||||
static int
|
||||
__bam_page(dbp, pp, cp)
|
||||
DB *dbp;
|
||||
__bam_page(dbc, pp, cp)
|
||||
DBC *dbc;
|
||||
EPG *pp, *cp;
|
||||
{
|
||||
DB *dbp;
|
||||
DB_LOCK tplock;
|
||||
PAGE *lp, *rp, *tp;
|
||||
db_indx_t split;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
lp = rp = tp = NULL;
|
||||
ret = -1;
|
||||
|
||||
/* Create new right page for the split. */
|
||||
if ((ret = __bam_new(dbp, TYPE(cp->page), &rp)) != 0)
|
||||
if ((ret = __bam_new(dbc, TYPE(cp->page), &rp)) != 0)
|
||||
goto err;
|
||||
P_INIT(rp, dbp->pgsize, rp->pgno,
|
||||
ISINTERNAL(cp->page) ? PGNO_INVALID : cp->page->pgno,
|
||||
@ -253,13 +263,8 @@ __bam_page(dbp, pp, cp)
|
||||
cp->page->level, TYPE(cp->page));
|
||||
|
||||
/* Create new left page for the split. */
|
||||
if ((lp = (PAGE *)__db_malloc(dbp->pgsize)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_malloc(dbp->pgsize, NULL, &lp)) != 0)
|
||||
goto err;
|
||||
}
|
||||
#ifdef DIAGNOSTIC
|
||||
memset(lp, 0xff, dbp->pgsize);
|
||||
#endif
|
||||
P_INIT(lp, dbp->pgsize, cp->page->pgno,
|
||||
ISINTERNAL(cp->page) ? PGNO_INVALID : cp->page->prev_pgno,
|
||||
ISINTERNAL(cp->page) ? PGNO_INVALID : rp->pgno,
|
||||
@ -276,7 +281,7 @@ __bam_page(dbp, pp, cp)
|
||||
* change, we swap the original and the allocated left page after the
|
||||
* split.
|
||||
*/
|
||||
if ((ret = __bam_psplit(dbp, cp, lp, rp, 0)) != 0)
|
||||
if ((ret = __bam_psplit(dbc, cp, lp, rp, &split)) != 0)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
@ -293,19 +298,19 @@ __bam_page(dbp, pp, cp)
|
||||
* the page we're splitting.
|
||||
*/
|
||||
if (TYPE(cp->page) == P_LBTREE && rp->next_pgno != PGNO_INVALID) {
|
||||
if ((ret = __bam_lget(dbp,
|
||||
if ((ret = __bam_lget(dbc,
|
||||
0, rp->next_pgno, DB_LOCK_WRITE, &tplock)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_pget(dbp, &tp, &rp->next_pgno, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &rp->next_pgno, 0, &tp)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Insert the new pages into the parent page. */
|
||||
if ((ret = __bam_pinsert(dbp, pp, lp, rp)) != 0)
|
||||
if ((ret = __bam_pinsert(dbc, pp, lp, rp)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
DBT __a;
|
||||
DB_LSN __lsn;
|
||||
memset(&__a, 0, sizeof(__a));
|
||||
@ -313,7 +318,7 @@ __bam_page(dbp, pp, cp)
|
||||
__a.size = dbp->pgsize;
|
||||
if (tp == NULL)
|
||||
ZERO_LSN(__lsn);
|
||||
if ((ret = __bam_split_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if ((ret = __bam_split_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&cp->page->lsn, 0, dbp->log_fileid, PGNO(cp->page),
|
||||
&LSN(cp->page), PGNO(rp), &LSN(rp), (u_int32_t)NUM_ENT(lp),
|
||||
tp == NULL ? 0 : PGNO(tp),
|
||||
@ -329,56 +334,69 @@ __bam_page(dbp, pp, cp)
|
||||
memcpy(cp->page, lp, LOFFSET(lp));
|
||||
memcpy((u_int8_t *)cp->page + HOFFSET(lp),
|
||||
(u_int8_t *)lp + HOFFSET(lp), dbp->pgsize - HOFFSET(lp));
|
||||
FREE(lp, dbp->pgsize);
|
||||
__os_free(lp, dbp->pgsize);
|
||||
lp = NULL;
|
||||
|
||||
/* Finish the next-page link. */
|
||||
if (tp != NULL)
|
||||
tp->prev_pgno = rp->pgno;
|
||||
|
||||
/* Adjust any cursors. Do so last so we don't have to undo it. */
|
||||
__bam_ca_split(dbp, cp->page->pgno, cp->page->pgno, rp->pgno, split, 0);
|
||||
|
||||
/* Success -- write the real pages back to the store. */
|
||||
(void)memp_fput(dbp->mpf, pp->page, DB_MPOOL_DIRTY);
|
||||
(void)__BT_TLPUT(dbp, pp->lock);
|
||||
(void)__BT_TLPUT(dbc, pp->lock);
|
||||
(void)memp_fput(dbp->mpf, cp->page, DB_MPOOL_DIRTY);
|
||||
(void)__BT_TLPUT(dbp, cp->lock);
|
||||
(void)__BT_TLPUT(dbc, cp->lock);
|
||||
(void)memp_fput(dbp->mpf, rp, DB_MPOOL_DIRTY);
|
||||
if (tp != NULL) {
|
||||
(void)memp_fput(dbp->mpf, tp, DB_MPOOL_DIRTY);
|
||||
(void)__BT_TLPUT(dbp, tplock);
|
||||
(void)__BT_TLPUT(dbc, tplock);
|
||||
}
|
||||
return (0);
|
||||
|
||||
err: if (lp != NULL)
|
||||
FREE(lp, dbp->pgsize);
|
||||
__os_free(lp, dbp->pgsize);
|
||||
if (rp != NULL)
|
||||
(void)__bam_free(dbp, rp);
|
||||
(void)__bam_free(dbc, rp);
|
||||
if (tp != NULL) {
|
||||
(void)memp_fput(dbp->mpf, tp, 0);
|
||||
(void)__BT_TLPUT(dbp, tplock);
|
||||
if (ret == DB_NEEDSPLIT)
|
||||
(void)__BT_LPUT(dbc, tplock);
|
||||
else
|
||||
(void)__BT_TLPUT(dbc, tplock);
|
||||
}
|
||||
(void)memp_fput(dbp->mpf, pp->page, 0);
|
||||
(void)__BT_TLPUT(dbp, pp->lock);
|
||||
if (ret == DB_NEEDSPLIT)
|
||||
(void)__BT_LPUT(dbc, pp->lock);
|
||||
else
|
||||
(void)__BT_TLPUT(dbc, pp->lock);
|
||||
(void)memp_fput(dbp->mpf, cp->page, 0);
|
||||
(void)__BT_TLPUT(dbp, cp->lock);
|
||||
if (ret == DB_NEEDSPLIT)
|
||||
(void)__BT_LPUT(dbc, cp->lock);
|
||||
else
|
||||
(void)__BT_TLPUT(dbc, cp->lock);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_broot --
|
||||
* Fix up the btree root page after it has been split.
|
||||
*
|
||||
* PUBLIC: int __bam_broot __P((DB *, PAGE *, PAGE *, PAGE *));
|
||||
*/
|
||||
int
|
||||
__bam_broot(dbp, rootp, lp, rp)
|
||||
DB *dbp;
|
||||
static int
|
||||
__bam_broot(dbc, rootp, lp, rp)
|
||||
DBC *dbc;
|
||||
PAGE *rootp, *lp, *rp;
|
||||
{
|
||||
BINTERNAL bi, *child_bi;
|
||||
BKEYDATA *child_bk;
|
||||
DB *dbp;
|
||||
DBT hdr, data;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/*
|
||||
* If the root page was a leaf page, change it into an internal page.
|
||||
* We copy the key we split on (but not the key's data, in the case of
|
||||
@ -405,7 +423,7 @@ __bam_broot(dbp, rootp, lp, rp)
|
||||
hdr.data = &bi;
|
||||
hdr.size = SSZA(BINTERNAL, data);
|
||||
if ((ret =
|
||||
__db_pitem(dbp, rootp, 0, BINTERNAL_SIZE(0), &hdr, NULL)) != 0)
|
||||
__db_pitem(dbc, rootp, 0, BINTERNAL_SIZE(0), &hdr, NULL)) != 0)
|
||||
return (ret);
|
||||
|
||||
switch (TYPE(rp)) {
|
||||
@ -424,13 +442,13 @@ __bam_broot(dbp, rootp, lp, rp)
|
||||
hdr.size = SSZA(BINTERNAL, data);
|
||||
data.data = child_bi->data;
|
||||
data.size = child_bi->len;
|
||||
if ((ret = __db_pitem(dbp, rootp, 1,
|
||||
if ((ret = __db_pitem(dbc, rootp, 1,
|
||||
BINTERNAL_SIZE(child_bi->len), &hdr, &data)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Increment the overflow ref count. */
|
||||
if (B_TYPE(child_bi->type) == B_OVERFLOW)
|
||||
if ((ret = __db_ovref(dbp,
|
||||
if ((ret = __db_ovref(dbc,
|
||||
((BOVERFLOW *)(child_bi->data))->pgno, 1)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
@ -450,7 +468,7 @@ __bam_broot(dbp, rootp, lp, rp)
|
||||
hdr.size = SSZA(BINTERNAL, data);
|
||||
data.data = child_bk->data;
|
||||
data.size = child_bk->len;
|
||||
if ((ret = __db_pitem(dbp, rootp, 1,
|
||||
if ((ret = __db_pitem(dbc, rootp, 1,
|
||||
BINTERNAL_SIZE(child_bk->len), &hdr, &data)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
@ -467,13 +485,13 @@ __bam_broot(dbp, rootp, lp, rp)
|
||||
hdr.size = SSZA(BINTERNAL, data);
|
||||
data.data = child_bk;
|
||||
data.size = BOVERFLOW_SIZE;
|
||||
if ((ret = __db_pitem(dbp, rootp, 1,
|
||||
if ((ret = __db_pitem(dbc, rootp, 1,
|
||||
BINTERNAL_SIZE(BOVERFLOW_SIZE), &hdr, &data)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Increment the overflow ref count. */
|
||||
if (B_TYPE(child_bk->type) == B_OVERFLOW)
|
||||
if ((ret = __db_ovref(dbp,
|
||||
if ((ret = __db_ovref(dbc,
|
||||
((BOVERFLOW *)child_bk)->pgno, 1)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
@ -490,18 +508,19 @@ __bam_broot(dbp, rootp, lp, rp)
|
||||
/*
|
||||
* __ram_root --
|
||||
* Fix up the recno root page after it has been split.
|
||||
*
|
||||
* PUBLIC: int __ram_root __P((DB *, PAGE *, PAGE *, PAGE *));
|
||||
*/
|
||||
int
|
||||
__ram_root(dbp, rootp, lp, rp)
|
||||
DB *dbp;
|
||||
static int
|
||||
__ram_root(dbc, rootp, lp, rp)
|
||||
DBC *dbc;
|
||||
PAGE *rootp, *lp, *rp;
|
||||
{
|
||||
DB *dbp;
|
||||
DBT hdr;
|
||||
RINTERNAL ri;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/* Initialize the page. */
|
||||
P_INIT(rootp, dbp->pgsize,
|
||||
PGNO_ROOT, PGNO_INVALID, PGNO_INVALID, lp->level + 1, P_IRECNO);
|
||||
@ -514,12 +533,12 @@ __ram_root(dbp, rootp, lp, rp)
|
||||
/* Insert the left and right keys, set the header information. */
|
||||
ri.pgno = lp->pgno;
|
||||
ri.nrecs = __bam_total(lp);
|
||||
if ((ret = __db_pitem(dbp, rootp, 0, RINTERNAL_SIZE, &hdr, NULL)) != 0)
|
||||
if ((ret = __db_pitem(dbc, rootp, 0, RINTERNAL_SIZE, &hdr, NULL)) != 0)
|
||||
return (ret);
|
||||
RE_NREC_SET(rootp, ri.nrecs);
|
||||
ri.pgno = rp->pgno;
|
||||
ri.nrecs = __bam_total(rp);
|
||||
if ((ret = __db_pitem(dbp, rootp, 1, RINTERNAL_SIZE, &hdr, NULL)) != 0)
|
||||
if ((ret = __db_pitem(dbc, rootp, 1, RINTERNAL_SIZE, &hdr, NULL)) != 0)
|
||||
return (ret);
|
||||
RE_NREC_ADJ(rootp, ri.nrecs);
|
||||
return (0);
|
||||
@ -530,14 +549,15 @@ __ram_root(dbp, rootp, lp, rp)
|
||||
* Insert a new key into a parent page, completing the split.
|
||||
*/
|
||||
static int
|
||||
__bam_pinsert(dbp, parent, lchild, rchild)
|
||||
DB *dbp;
|
||||
__bam_pinsert(dbc, parent, lchild, rchild)
|
||||
DBC *dbc;
|
||||
EPG *parent;
|
||||
PAGE *lchild, *rchild;
|
||||
{
|
||||
BINTERNAL bi, *child_bi;
|
||||
BKEYDATA *child_bk, *tmp_bk;
|
||||
BTREE *t;
|
||||
DB *dbp;
|
||||
DBT a, b, hdr, data;
|
||||
PAGE *ppage;
|
||||
RINTERNAL ri;
|
||||
@ -546,6 +566,7 @@ __bam_pinsert(dbp, parent, lchild, rchild)
|
||||
u_int32_t n, nbytes, nksize;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
t = dbp->internal;
|
||||
ppage = parent->page;
|
||||
|
||||
@ -600,13 +621,13 @@ __bam_pinsert(dbp, parent, lchild, rchild)
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = child_bi->data;
|
||||
data.size = child_bi->len;
|
||||
if ((ret = __db_pitem(dbp, ppage, off,
|
||||
if ((ret = __db_pitem(dbc, ppage, off,
|
||||
BINTERNAL_SIZE(child_bi->len), &hdr, &data)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Increment the overflow ref count. */
|
||||
if (B_TYPE(child_bi->type) == B_OVERFLOW)
|
||||
if ((ret = __db_ovref(dbp,
|
||||
if ((ret = __db_ovref(dbc,
|
||||
((BOVERFLOW *)(child_bi->data))->pgno, 1)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
@ -630,10 +651,9 @@ __bam_pinsert(dbp, parent, lchild, rchild)
|
||||
b.size = child_bk->len;
|
||||
b.data = child_bk->data;
|
||||
nksize = t->bt_prefix(&a, &b);
|
||||
if ((n = BINTERNAL_PSIZE(nksize)) < nbytes) {
|
||||
t->lstat.bt_pfxsaved += nbytes - n;
|
||||
if ((n = BINTERNAL_PSIZE(nksize)) < nbytes)
|
||||
nbytes = n;
|
||||
} else
|
||||
else
|
||||
noprefix: nksize = child_bk->len;
|
||||
|
||||
if (P_FREESPACE(ppage) < nbytes)
|
||||
@ -650,7 +670,7 @@ noprefix: nksize = child_bk->len;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = child_bk->data;
|
||||
data.size = nksize;
|
||||
if ((ret = __db_pitem(dbp, ppage, off,
|
||||
if ((ret = __db_pitem(dbc, ppage, off,
|
||||
BINTERNAL_SIZE(nksize), &hdr, &data)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
@ -672,13 +692,13 @@ noprefix: nksize = child_bk->len;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = child_bk;
|
||||
data.size = BOVERFLOW_SIZE;
|
||||
if ((ret = __db_pitem(dbp, ppage, off,
|
||||
if ((ret = __db_pitem(dbc, ppage, off,
|
||||
BINTERNAL_SIZE(BOVERFLOW_SIZE), &hdr, &data)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Increment the overflow ref count. */
|
||||
if (B_TYPE(child_bk->type) == B_OVERFLOW)
|
||||
if ((ret = __db_ovref(dbp,
|
||||
if ((ret = __db_ovref(dbc,
|
||||
((BOVERFLOW *)child_bk)->pgno, 1)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
@ -699,7 +719,7 @@ noprefix: nksize = child_bk->len;
|
||||
hdr.size = RINTERNAL_SIZE;
|
||||
ri.pgno = rchild->pgno;
|
||||
ri.nrecs = nrecs;
|
||||
if ((ret = __db_pitem(dbp,
|
||||
if ((ret = __db_pitem(dbc,
|
||||
ppage, off, RINTERNAL_SIZE, &hdr, NULL)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
@ -710,9 +730,9 @@ noprefix: nksize = child_bk->len;
|
||||
/* Adjust the parent page's left page record count. */
|
||||
if (dbp->type == DB_RECNO || F_ISSET(dbp, DB_BT_RECNUM)) {
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp) &&
|
||||
if (DB_LOGGING(dbc) &&
|
||||
(ret = __bam_cadjust_log(dbp->dbenv->lg_info,
|
||||
dbp->txn, &LSN(ppage), 0, dbp->log_fileid,
|
||||
dbc->txn, &LSN(ppage), 0, dbp->log_fileid,
|
||||
PGNO(ppage), &LSN(ppage), (u_int32_t)parent->indx,
|
||||
-(int32_t)nrecs, (int32_t)0)) != 0)
|
||||
return (ret);
|
||||
@ -732,18 +752,18 @@ noprefix: nksize = child_bk->len;
|
||||
* Do the real work of splitting the page.
|
||||
*/
|
||||
static int
|
||||
__bam_psplit(dbp, cp, lp, rp, cleft)
|
||||
DB *dbp;
|
||||
__bam_psplit(dbc, cp, lp, rp, splitret)
|
||||
DBC *dbc;
|
||||
EPG *cp;
|
||||
PAGE *lp, *rp;
|
||||
int cleft;
|
||||
db_indx_t *splitret;
|
||||
{
|
||||
BTREE *t;
|
||||
DB *dbp;
|
||||
PAGE *pp;
|
||||
db_indx_t half, nbytes, off, splitp, top;
|
||||
int adjust, cnt, isbigkey, ret;
|
||||
|
||||
t = dbp->internal;
|
||||
dbp = dbc->dbp;
|
||||
pp = cp->page;
|
||||
adjust = TYPE(pp) == P_LBTREE ? P_INDX : O_INDX;
|
||||
|
||||
@ -762,11 +782,8 @@ __bam_psplit(dbp, cp, lp, rp, cleft)
|
||||
else if (PREV_PGNO(pp) == PGNO_INVALID && cp->indx == 0)
|
||||
off = adjust;
|
||||
|
||||
++t->lstat.bt_split;
|
||||
if (off != 0) {
|
||||
++t->lstat.bt_fastsplit;
|
||||
if (off != 0)
|
||||
goto sort;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split the data to the left and right pages. Try not to split on
|
||||
@ -887,8 +904,7 @@ sort: splitp = off;
|
||||
if ((ret = __bam_copy(dbp, pp, rp, splitp, NUM_ENT(pp))) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Adjust the cursors. */
|
||||
__bam_ca_split(dbp, pp->pgno, lp->pgno, rp->pgno, splitp, cleft);
|
||||
*splitret = splitp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)bt_stat.c 10.17 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)bt_stat.c 10.27 (Sleepycat) 11/25/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -22,8 +22,6 @@ static const char sccsid[] = "@(#)bt_stat.c 10.17 (Sleepycat) 4/26/98";
|
||||
#include "db_page.h"
|
||||
#include "btree.h"
|
||||
|
||||
static void __bam_add_rstat __P((DB_BTREE_LSTAT *, DB_BTREE_STAT *));
|
||||
|
||||
/*
|
||||
* __bam_stat --
|
||||
* Gather/print the btree statistics
|
||||
@ -31,62 +29,62 @@ static void __bam_add_rstat __P((DB_BTREE_LSTAT *, DB_BTREE_STAT *));
|
||||
* PUBLIC: int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
|
||||
*/
|
||||
int
|
||||
__bam_stat(argdbp, spp, db_malloc, flags)
|
||||
DB *argdbp;
|
||||
__bam_stat(dbp, spp, db_malloc, flags)
|
||||
DB *dbp;
|
||||
void *spp;
|
||||
void *(*db_malloc) __P((size_t));
|
||||
u_int32_t flags;
|
||||
{
|
||||
BTMETA *meta;
|
||||
BTREE *t;
|
||||
DB *dbp;
|
||||
DBC *dbc;
|
||||
DB_BTREE_STAT *sp;
|
||||
DB_LOCK lock;
|
||||
PAGE *h;
|
||||
db_pgno_t lastpgno, pgno;
|
||||
int ret;
|
||||
int ret, t_ret;
|
||||
|
||||
DEBUG_LWRITE(argdbp, NULL, "bam_stat", NULL, NULL, flags);
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
/* Check for invalid flags. */
|
||||
if ((ret = __db_statchk(argdbp, flags)) != 0)
|
||||
if ((ret = __db_statchk(dbp, flags)) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
DEBUG_LWRITE(dbc, NULL, "bam_stat", NULL, NULL, flags);
|
||||
|
||||
t = dbp->internal;
|
||||
|
||||
if (spp == NULL)
|
||||
return (0);
|
||||
|
||||
GETHANDLE(argdbp, NULL, &dbp, ret);
|
||||
t = dbp->internal;
|
||||
|
||||
/* Allocate and clear the structure. */
|
||||
if ((sp = db_malloc == NULL ?
|
||||
(DB_BTREE_STAT *)__db_malloc(sizeof(*sp)) :
|
||||
(DB_BTREE_STAT *)db_malloc(sizeof(*sp))) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_malloc(sizeof(*sp), db_malloc, &sp)) != 0)
|
||||
goto err;
|
||||
}
|
||||
memset(sp, 0, sizeof(*sp));
|
||||
|
||||
/* If the app just wants the record count, make it fast. */
|
||||
if (LF_ISSET(DB_RECORDCOUNT)) {
|
||||
if (flags == DB_RECORDCOUNT) {
|
||||
pgno = PGNO_ROOT;
|
||||
if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &lock)) != 0)
|
||||
if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_READ, &lock)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_pget(dbp, (PAGE **)&h, &pgno, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&h)) != 0)
|
||||
goto err;
|
||||
|
||||
sp->bt_nrecs = RE_NREC(h);
|
||||
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get the meta-data page. */
|
||||
pgno = PGNO_METADATA;
|
||||
if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_READ, &lock)) != 0)
|
||||
if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_READ, &lock)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_pget(dbp, (PAGE **)&meta, &pgno, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Translate the metadata flags. */
|
||||
@ -110,24 +108,13 @@ __bam_stat(argdbp, spp, db_malloc, flags)
|
||||
/* Get the page size from the DB. */
|
||||
sp->bt_pagesize = dbp->pgsize;
|
||||
|
||||
/* Initialize counters with the meta-data page information. */
|
||||
__bam_add_rstat(&meta->stat, sp);
|
||||
|
||||
/*
|
||||
* Add in the local information from this handle.
|
||||
*
|
||||
* !!!
|
||||
* This is a bit odd, but it gets us closer to the truth.
|
||||
*/
|
||||
__bam_add_rstat(&t->lstat, sp);
|
||||
|
||||
/* Walk the free list, counting pages. */
|
||||
for (sp->bt_free = 0, pgno = meta->free; pgno != PGNO_INVALID;) {
|
||||
++sp->bt_free;
|
||||
|
||||
if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0) {
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
|
||||
(void)memp_fput(dbp->mpf, meta, 0);
|
||||
(void)__BT_TLPUT(dbp, lock);
|
||||
(void)__BT_TLPUT(dbc, lock);
|
||||
goto err;
|
||||
}
|
||||
pgno = h->next_pgno;
|
||||
@ -136,7 +123,7 @@ __bam_stat(argdbp, spp, db_malloc, flags)
|
||||
|
||||
/* Discard the meta-data page. */
|
||||
(void)memp_fput(dbp->mpf, meta, 0);
|
||||
(void)__BT_TLPUT(dbp, lock);
|
||||
(void)__BT_TLPUT(dbc, lock);
|
||||
|
||||
/* Determine the last page of the database. */
|
||||
if ((ret = memp_fget(dbp->mpf, &lastpgno, DB_MPOOL_LAST, &h)) != 0)
|
||||
@ -145,10 +132,10 @@ __bam_stat(argdbp, spp, db_malloc, flags)
|
||||
|
||||
/* Get the root page. */
|
||||
pgno = PGNO_ROOT;
|
||||
if ((ret = __bam_lget(dbp, 0, PGNO_ROOT, DB_LOCK_READ, &lock)) != 0)
|
||||
if ((ret = __bam_lget(dbc, 0, PGNO_ROOT, DB_LOCK_READ, &lock)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0) {
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -185,19 +172,19 @@ __bam_stat(argdbp, spp, db_malloc, flags)
|
||||
break;
|
||||
default:
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
return (__db_pgfmt(dbp, pgno));
|
||||
}
|
||||
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
|
||||
if (++pgno > lastpgno)
|
||||
break;
|
||||
if (__bam_lget(dbp, 0, pgno, DB_LOCK_READ, &lock))
|
||||
if (__bam_lget(dbc, 0, pgno, DB_LOCK_READ, &lock))
|
||||
break;
|
||||
if (memp_fget(dbp->mpf, &pgno, 0, &h) != 0) {
|
||||
(void)__BT_LPUT(dbp, lock);
|
||||
(void)__BT_LPUT(dbc, lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -205,50 +192,7 @@ __bam_stat(argdbp, spp, db_malloc, flags)
|
||||
done: *(DB_BTREE_STAT **)spp = sp;
|
||||
ret = 0;
|
||||
|
||||
err: PUTHANDLE(dbp);
|
||||
err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_add_mstat --
|
||||
* Add the local statistics to the meta-data page statistics.
|
||||
*
|
||||
* PUBLIC: void __bam_add_mstat __P((DB_BTREE_LSTAT *, DB_BTREE_LSTAT *));
|
||||
*/
|
||||
void
|
||||
__bam_add_mstat(from, to)
|
||||
DB_BTREE_LSTAT *from;
|
||||
DB_BTREE_LSTAT *to;
|
||||
{
|
||||
to->bt_freed += from->bt_freed;
|
||||
to->bt_pfxsaved += from->bt_pfxsaved;
|
||||
to->bt_split += from->bt_split;
|
||||
to->bt_rootsplit += from->bt_rootsplit;
|
||||
to->bt_fastsplit += from->bt_fastsplit;
|
||||
to->bt_added += from->bt_added;
|
||||
to->bt_deleted += from->bt_deleted;
|
||||
to->bt_get += from->bt_get;
|
||||
to->bt_cache_hit += from->bt_cache_hit;
|
||||
to->bt_cache_miss += from->bt_cache_miss;
|
||||
}
|
||||
|
||||
/*
|
||||
* __bam_add_rstat --
|
||||
* Add the local statistics to the returned statistics.
|
||||
*/
|
||||
static void
|
||||
__bam_add_rstat(from, to)
|
||||
DB_BTREE_LSTAT *from;
|
||||
DB_BTREE_STAT *to;
|
||||
{
|
||||
to->bt_freed += from->bt_freed;
|
||||
to->bt_pfxsaved += from->bt_pfxsaved;
|
||||
to->bt_split += from->bt_split;
|
||||
to->bt_rootsplit += from->bt_rootsplit;
|
||||
to->bt_fastsplit += from->bt_fastsplit;
|
||||
to->bt_added += from->bt_added;
|
||||
to->bt_deleted += from->bt_deleted;
|
||||
to->bt_get += from->bt_get;
|
||||
to->bt_cache_hit += from->bt_cache_hit;
|
||||
to->bt_cache_miss += from->bt_cache_miss;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "shqueue.h"
|
||||
#include "db_page.h"
|
||||
#include "db_dispatch.h"
|
||||
#include "btree.h"
|
||||
@ -43,8 +42,7 @@ int __bam_pg_alloc_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_pg_alloc;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -55,8 +53,8 @@ int __bam_pg_alloc_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(pgno)
|
||||
+ sizeof(ptype)
|
||||
+ sizeof(next);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -90,7 +88,7 @@ int __bam_pg_alloc_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -135,7 +133,7 @@ __bam_pg_alloc_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tptype: %lu\n", (u_long)argp->ptype);
|
||||
printf("\tnext: %lu\n", (u_long)argp->next);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -149,11 +147,12 @@ __bam_pg_alloc_read(recbuf, argpp)
|
||||
{
|
||||
__bam_pg_alloc_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_pg_alloc_args *)__db_malloc(sizeof(__bam_pg_alloc_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_pg_alloc_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));
|
||||
@ -206,8 +205,7 @@ int __bam_pg_free_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_pg_free;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -217,8 +215,8 @@ int __bam_pg_free_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(*meta_lsn)
|
||||
+ sizeof(u_int32_t) + (header == NULL ? 0 : header->size)
|
||||
+ sizeof(next);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -255,7 +253,7 @@ int __bam_pg_free_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -306,7 +304,7 @@ __bam_pg_free_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\n");
|
||||
printf("\tnext: %lu\n", (u_long)argp->next);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -320,11 +318,12 @@ __bam_pg_free_read(recbuf, argpp)
|
||||
{
|
||||
__bam_pg_free_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_pg_free_args *)__db_malloc(sizeof(__bam_pg_free_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_pg_free_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));
|
||||
@ -383,8 +382,7 @@ int __bam_split_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_split;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -398,8 +396,8 @@ int __bam_split_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(npgno)
|
||||
+ sizeof(*nlsn)
|
||||
+ sizeof(u_int32_t) + (pg == NULL ? 0 : pg->size);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -450,7 +448,7 @@ int __bam_split_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -507,7 +505,7 @@ __bam_split_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
}
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -521,11 +519,12 @@ __bam_split_read(recbuf, argpp)
|
||||
{
|
||||
__bam_split_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_split_args *)__db_malloc(sizeof(__bam_split_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_split_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));
|
||||
@ -587,8 +586,7 @@ int __bam_rsplit_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_rsplit;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -599,8 +597,8 @@ int __bam_rsplit_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(nrec)
|
||||
+ sizeof(u_int32_t) + (rootent == NULL ? 0 : rootent->size)
|
||||
+ sizeof(*rootlsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -647,7 +645,7 @@ int __bam_rsplit_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -707,7 +705,7 @@ __bam_rsplit_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\trootlsn: [%lu][%lu]\n",
|
||||
(u_long)argp->rootlsn.file, (u_long)argp->rootlsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -721,11 +719,12 @@ __bam_rsplit_read(recbuf, argpp)
|
||||
{
|
||||
__bam_rsplit_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_rsplit_args *)__db_malloc(sizeof(__bam_rsplit_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_rsplit_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));
|
||||
@ -782,8 +781,7 @@ int __bam_adj_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_adj;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -794,8 +792,8 @@ int __bam_adj_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(indx)
|
||||
+ sizeof(indx_copy)
|
||||
+ sizeof(is_insert);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -826,7 +824,7 @@ int __bam_adj_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -870,7 +868,7 @@ __bam_adj_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tindx_copy: %lu\n", (u_long)argp->indx_copy);
|
||||
printf("\tis_insert: %lu\n", (u_long)argp->is_insert);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -884,11 +882,12 @@ __bam_adj_read(recbuf, argpp)
|
||||
{
|
||||
__bam_adj_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_adj_args *)__db_malloc(sizeof(__bam_adj_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_adj_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));
|
||||
@ -941,8 +940,7 @@ int __bam_cadjust_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_cadjust;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -953,8 +951,8 @@ int __bam_cadjust_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(indx)
|
||||
+ sizeof(adjust)
|
||||
+ sizeof(total);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -985,7 +983,7 @@ int __bam_cadjust_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1029,7 +1027,7 @@ __bam_cadjust_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tadjust: %ld\n", (long)argp->adjust);
|
||||
printf("\ttotal: %ld\n", (long)argp->total);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1043,11 +1041,12 @@ __bam_cadjust_read(recbuf, argpp)
|
||||
{
|
||||
__bam_cadjust_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_cadjust_args *)__db_malloc(sizeof(__bam_cadjust_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_cadjust_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));
|
||||
@ -1097,8 +1096,7 @@ int __bam_cdel_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_cdel;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -1107,8 +1105,8 @@ int __bam_cdel_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(pgno)
|
||||
+ sizeof(*lsn)
|
||||
+ sizeof(indx);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -1135,7 +1133,7 @@ int __bam_cdel_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1177,7 +1175,7 @@ __bam_cdel_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
(u_long)argp->lsn.file, (u_long)argp->lsn.offset);
|
||||
printf("\tindx: %lu\n", (u_long)argp->indx);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1191,11 +1189,12 @@ __bam_cdel_read(recbuf, argpp)
|
||||
{
|
||||
__bam_cdel_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_cdel_args *)__db_malloc(sizeof(__bam_cdel_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_cdel_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));
|
||||
@ -1250,8 +1249,7 @@ int __bam_repl_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_bam_repl;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -1265,8 +1263,8 @@ int __bam_repl_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(u_int32_t) + (repl == NULL ? 0 : repl->size)
|
||||
+ sizeof(prefix)
|
||||
+ sizeof(suffix);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -1319,7 +1317,7 @@ int __bam_repl_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1382,7 +1380,7 @@ __bam_repl_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tprefix: %lu\n", (u_long)argp->prefix);
|
||||
printf("\tsuffix: %lu\n", (u_long)argp->suffix);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1396,11 +1394,12 @@ __bam_repl_read(recbuf, argpp)
|
||||
{
|
||||
__bam_repl_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__bam_repl_args *)__db_malloc(sizeof(__bam_repl_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__bam_repl_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));
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_appinit.c 10.52 (Sleepycat) 6/2/98";
|
||||
static const char sccsid[] = "@(#)db_appinit.c 10.66 (Sleepycat) 12/7/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -16,7 +16,6 @@ static const char sccsid[] = "@(#)db_appinit.c 10.52 (Sleepycat) 6/2/98";
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -34,9 +33,21 @@ static const char sccsid[] = "@(#)db_appinit.c 10.52 (Sleepycat) 6/2/98";
|
||||
|
||||
static int __db_home __P((DB_ENV *, const char *, u_int32_t));
|
||||
static int __db_parse __P((DB_ENV *, char *));
|
||||
static int __db_tmp_dir __P((DB_ENV *, u_int32_t));
|
||||
static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, int *));
|
||||
|
||||
/*
|
||||
* This conflict array is used for concurrent db access (cdb). It
|
||||
* uses the same locks as the db_rw_conflict array, but adds an IW
|
||||
* mode to be used for write cursors.
|
||||
*/
|
||||
static u_int8_t const db_cdb_conflicts[] = {
|
||||
/* N R W IW */
|
||||
/* N */ 0, 0, 0, 0,
|
||||
/* R */ 0, 0, 1, 0,
|
||||
/* W */ 0, 1, 1, 1,
|
||||
/* IW */ 0, 0, 1, 1
|
||||
};
|
||||
|
||||
/*
|
||||
* db_version --
|
||||
* Return version information.
|
||||
@ -70,21 +81,24 @@ db_appinit(db_home, db_config, dbenv, flags)
|
||||
char * const *p;
|
||||
char *lp, buf[MAXPATHLEN * 2];
|
||||
|
||||
fp = NULL;
|
||||
|
||||
/* Validate arguments. */
|
||||
if (dbenv == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
|
||||
#ifdef HAVE_SPINLOCKS
|
||||
#define OKFLAGS \
|
||||
(DB_CREATE | DB_NOMMAP | DB_THREAD | DB_INIT_LOCK | DB_INIT_LOG | \
|
||||
DB_INIT_MPOOL | DB_INIT_TXN | DB_MPOOL_PRIVATE | DB_RECOVER | \
|
||||
DB_RECOVER_FATAL | DB_TXN_NOSYNC | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT)
|
||||
(DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG | \
|
||||
DB_INIT_MPOOL | DB_INIT_TXN | DB_MPOOL_PRIVATE | DB_NOMMAP | \
|
||||
DB_RECOVER | DB_RECOVER_FATAL | DB_THREAD | DB_TXN_NOSYNC | \
|
||||
DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT)
|
||||
#else
|
||||
#define OKFLAGS \
|
||||
(DB_CREATE | DB_NOMMAP | DB_INIT_LOCK | DB_INIT_LOG | \
|
||||
DB_INIT_MPOOL | DB_INIT_TXN | DB_MPOOL_PRIVATE | DB_RECOVER | \
|
||||
DB_RECOVER_FATAL | DB_TXN_NOSYNC | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT)
|
||||
(DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG | \
|
||||
DB_INIT_MPOOL | DB_INIT_TXN | DB_MPOOL_PRIVATE | DB_NOMMAP | \
|
||||
DB_RECOVER | DB_RECOVER_FATAL | DB_TXN_NOSYNC | \
|
||||
DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT)
|
||||
#endif
|
||||
if ((ret = __db_fchk(dbenv, "db_appinit", flags, OKFLAGS)) != 0)
|
||||
return (ret);
|
||||
@ -97,8 +111,6 @@ db_appinit(db_home, db_config, dbenv, flags)
|
||||
if (LF_ISSET(DB_THREAD))
|
||||
F_SET(dbenv, DB_ENV_THREAD);
|
||||
|
||||
fp = NULL;
|
||||
|
||||
/* Set the database home. */
|
||||
if ((ret = __db_home(dbenv, db_home, flags)) != 0)
|
||||
goto err;
|
||||
@ -127,8 +139,17 @@ db_appinit(db_home, db_config, dbenv, flags)
|
||||
(void)strcat(buf, CONFIG_NAME);
|
||||
if ((fp = fopen(buf, "r")) != NULL) {
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
if ((lp = strchr(buf, '\n')) != NULL)
|
||||
*lp = '\0';
|
||||
if ((lp = strchr(buf, '\n')) == NULL) {
|
||||
__db_err(dbenv,
|
||||
"%s: line too long", CONFIG_NAME);
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
*lp = '\0';
|
||||
if (buf[0] == '\0' ||
|
||||
buf[0] == '#' || isspace(buf[0]))
|
||||
continue;
|
||||
|
||||
if ((ret = __db_parse(dbenv, buf)) != 0)
|
||||
goto err;
|
||||
}
|
||||
@ -138,11 +159,14 @@ db_appinit(db_home, db_config, dbenv, flags)
|
||||
}
|
||||
|
||||
/* Set up the tmp directory path. */
|
||||
if (dbenv->db_tmp_dir == NULL &&
|
||||
(ret = __db_tmp_dir(dbenv, flags)) != 0)
|
||||
if (dbenv->db_tmp_dir == NULL && (ret = __os_tmpdir(dbenv, flags)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Indicate that the path names have been set. */
|
||||
/*
|
||||
* Flag that the structure has been initialized by the application.
|
||||
* Note, this must be set before calling into the subsystems as it
|
||||
* is used when we're doing file naming.
|
||||
*/
|
||||
F_SET(dbenv, DB_ENV_APPINIT);
|
||||
|
||||
/*
|
||||
@ -166,6 +190,18 @@ db_appinit(db_home, db_config, dbenv, flags)
|
||||
* Default permissions are read-write for both owner and group.
|
||||
*/
|
||||
mode = __db_omode("rwrw--");
|
||||
if (LF_ISSET(DB_INIT_CDB)) {
|
||||
if (LF_ISSET(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN)) {
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
F_SET(dbenv, DB_ENV_CDB);
|
||||
dbenv->lk_conflicts = db_cdb_conflicts;
|
||||
dbenv->lk_modes = DB_LOCK_RW_N + 1;
|
||||
if ((ret = lock_open(NULL, LF_ISSET(DB_CREATE | DB_THREAD),
|
||||
mode, dbenv, &dbenv->lk_info)) != 0)
|
||||
goto err;
|
||||
}
|
||||
if (LF_ISSET(DB_INIT_LOCK) && (ret = lock_open(NULL,
|
||||
LF_ISSET(DB_CREATE | DB_THREAD),
|
||||
mode, dbenv, &dbenv->lk_info)) != 0)
|
||||
@ -232,28 +268,32 @@ db_appexit(dbenv)
|
||||
if (dbenv->tx_info && (t_ret = txn_close(dbenv->tx_info)) != 0)
|
||||
if (ret == 0)
|
||||
ret = t_ret;
|
||||
if (dbenv->mp_info && (t_ret = memp_close(dbenv->mp_info)) != 0)
|
||||
if (dbenv->lg_info && (t_ret = log_close(dbenv->lg_info)) != 0)
|
||||
if (ret == 0)
|
||||
ret = t_ret;
|
||||
if (dbenv->lg_info && (t_ret = log_close(dbenv->lg_info)) != 0)
|
||||
if (dbenv->mp_info && (t_ret = memp_close(dbenv->mp_info)) != 0)
|
||||
if (ret == 0)
|
||||
ret = t_ret;
|
||||
if (dbenv->lk_info && (t_ret = lock_close(dbenv->lk_info)) != 0)
|
||||
if (ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
/* Clear initialized flag (after subsystems, it affects naming). */
|
||||
F_CLR(dbenv, DB_ENV_APPINIT);
|
||||
|
||||
/* Free allocated memory. */
|
||||
if (dbenv->db_home != NULL)
|
||||
FREES(dbenv->db_home);
|
||||
__os_freestr(dbenv->db_home);
|
||||
if ((p = dbenv->db_data_dir) != NULL) {
|
||||
for (; *p != NULL; ++p)
|
||||
FREES(*p);
|
||||
FREE(dbenv->db_data_dir, dbenv->data_cnt * sizeof(char **));
|
||||
__os_freestr(*p);
|
||||
__os_free(dbenv->db_data_dir,
|
||||
dbenv->data_cnt * sizeof(char **));
|
||||
}
|
||||
if (dbenv->db_log_dir != NULL)
|
||||
FREES(dbenv->db_log_dir);
|
||||
__os_freestr(dbenv->db_log_dir);
|
||||
if (dbenv->db_tmp_dir != NULL)
|
||||
FREES(dbenv->db_tmp_dir);
|
||||
__os_freestr(dbenv->db_tmp_dir);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -261,7 +301,7 @@ db_appexit(dbenv)
|
||||
#define DB_ADDSTR(str) { \
|
||||
if ((str) != NULL) { \
|
||||
/* If leading slash, start over. */ \
|
||||
if (__db_abspath(str)) { \
|
||||
if (__os_abspath(str)) { \
|
||||
p = start; \
|
||||
slash = 0; \
|
||||
} \
|
||||
@ -317,10 +357,9 @@ __db_appname(dbenv, appname, dir, file, tmp_oflags, fdp, namep)
|
||||
* path, we're done. If the directory is, simply append the file and
|
||||
* return.
|
||||
*/
|
||||
if (file != NULL && __db_abspath(file))
|
||||
return ((*namep =
|
||||
(char *)__db_strdup(file)) == NULL ? ENOMEM : 0);
|
||||
if (dir != NULL && __db_abspath(dir)) {
|
||||
if (file != NULL && __os_abspath(file))
|
||||
return (__os_strdup(file, namep));
|
||||
if (dir != NULL && __os_abspath(dir)) {
|
||||
a = dir;
|
||||
goto done;
|
||||
}
|
||||
@ -417,7 +456,7 @@ retry: switch (appname) {
|
||||
if (0) {
|
||||
tmp: if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_APPINIT)) {
|
||||
memset(&etmp, 0, sizeof(etmp));
|
||||
if ((ret = __db_tmp_dir(&etmp, DB_USE_ENVIRON)) != 0)
|
||||
if ((ret = __os_tmpdir(&etmp, DB_USE_ENVIRON)) != 0)
|
||||
return (ret);
|
||||
tmp_free = 1;
|
||||
a = etmp.db_tmp_dir;
|
||||
@ -437,12 +476,11 @@ done: len =
|
||||
* name.
|
||||
*/
|
||||
#define DB_TRAIL "XXXXXX"
|
||||
if ((start =
|
||||
(char *)__db_malloc(len + sizeof(DB_TRAIL) + 10)) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
if ((ret =
|
||||
__os_malloc(len + sizeof(DB_TRAIL) + 10, NULL, &start)) != 0) {
|
||||
if (tmp_free)
|
||||
FREES(etmp.db_tmp_dir);
|
||||
return (ENOMEM);
|
||||
__os_freestr(etmp.db_tmp_dir);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
slash = 0;
|
||||
@ -452,28 +490,32 @@ done: len =
|
||||
DB_ADDSTR(file);
|
||||
*p = '\0';
|
||||
|
||||
/* Discard any space allocated to find the temp directory. */
|
||||
if (tmp_free) {
|
||||
__os_freestr(etmp.db_tmp_dir);
|
||||
tmp_free = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're opening a data file, see if it exists. If it does,
|
||||
* return it, otherwise, try and find another one to open.
|
||||
*/
|
||||
if (data_entry != -1 && __db_exists(start, NULL) != 0) {
|
||||
FREES(start);
|
||||
if (data_entry != -1 && __os_exists(start, NULL) != 0) {
|
||||
__os_freestr(start);
|
||||
a = b = c = NULL;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Discard any space allocated to find the temp directory. */
|
||||
if (tmp_free)
|
||||
FREES(etmp.db_tmp_dir);
|
||||
|
||||
/* Create the file if so requested. */
|
||||
if (tmp_create &&
|
||||
(ret = __db_tmp_open(dbenv, tmp_oflags, start, fdp)) != 0) {
|
||||
FREES(start);
|
||||
__os_freestr(start);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (namep != NULL)
|
||||
if (namep == NULL)
|
||||
__os_freestr(start);
|
||||
else
|
||||
*namep = start;
|
||||
return (0);
|
||||
}
|
||||
@ -511,11 +553,7 @@ __db_home(dbenv, db_home, flags)
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
|
||||
if ((dbenv->db_home = (char *)__db_strdup(p)) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
return (ENOMEM);
|
||||
}
|
||||
return (0);
|
||||
return (__os_strdup(p, &dbenv->db_home));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -530,152 +568,73 @@ __db_parse(dbenv, s)
|
||||
int ret;
|
||||
char *local_s, *name, *value, **p, *tp;
|
||||
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* We need to strdup the argument in case the caller passed us
|
||||
* static data.
|
||||
*/
|
||||
if ((local_s = (char *)__db_strdup(s)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_strdup(s, &local_s)) != 0)
|
||||
return (ret);
|
||||
|
||||
tp = local_s;
|
||||
while ((name = strsep(&tp, " \t")) != NULL && *name == '\0')
|
||||
/*
|
||||
* Name/value pairs are parsed as two white-space separated strings.
|
||||
* Leading and trailing white-space is trimmed from the value, but
|
||||
* it may contain embedded white-space. Note: we use the isspace(3)
|
||||
* macro because it's more portable, but that means that you can use
|
||||
* characters like form-feed to separate the strings.
|
||||
*/
|
||||
name = local_s;
|
||||
for (tp = name; *tp != '\0' && !isspace(*tp); ++tp)
|
||||
;
|
||||
if (name == NULL)
|
||||
if (*tp == '\0' || tp == name)
|
||||
goto illegal;
|
||||
while ((value = strsep(&tp, " \t")) != NULL && *value == '\0')
|
||||
*tp = '\0';
|
||||
for (++tp; isspace(*tp); ++tp)
|
||||
;
|
||||
if (value == NULL) {
|
||||
if (*tp == '\0')
|
||||
goto illegal;
|
||||
value = tp;
|
||||
for (++tp; *tp != '\0'; ++tp)
|
||||
;
|
||||
for (--tp; isspace(*tp); --tp)
|
||||
;
|
||||
if (tp == value) {
|
||||
illegal: ret = EINVAL;
|
||||
__db_err(dbenv, "illegal name-value pair: %s", s);
|
||||
goto err;
|
||||
}
|
||||
*++tp = '\0';
|
||||
|
||||
#define DATA_INIT_CNT 20 /* Start with 20 data slots. */
|
||||
if (!strcmp(name, "DB_DATA_DIR")) {
|
||||
if (dbenv->db_data_dir == NULL) {
|
||||
if ((dbenv->db_data_dir =
|
||||
(char **)__db_calloc(DATA_INIT_CNT,
|
||||
sizeof(char **))) == NULL)
|
||||
goto nomem;
|
||||
if ((ret = __os_calloc(DATA_INIT_CNT,
|
||||
sizeof(char **), &dbenv->db_data_dir)) != 0)
|
||||
goto err;
|
||||
dbenv->data_cnt = DATA_INIT_CNT;
|
||||
} else if (dbenv->data_next == dbenv->data_cnt - 1) {
|
||||
dbenv->data_cnt *= 2;
|
||||
if ((dbenv->db_data_dir =
|
||||
(char **)__db_realloc(dbenv->db_data_dir,
|
||||
dbenv->data_cnt * sizeof(char **))) == NULL)
|
||||
goto nomem;
|
||||
if ((ret = __os_realloc(&dbenv->db_data_dir,
|
||||
dbenv->data_cnt * sizeof(char **))) != 0)
|
||||
goto err;
|
||||
}
|
||||
p = &dbenv->db_data_dir[dbenv->data_next++];
|
||||
} else if (!strcmp(name, "DB_LOG_DIR")) {
|
||||
if (dbenv->db_log_dir != NULL)
|
||||
FREES(dbenv->db_log_dir);
|
||||
__os_freestr(dbenv->db_log_dir);
|
||||
p = &dbenv->db_log_dir;
|
||||
} else if (!strcmp(name, "DB_TMP_DIR")) {
|
||||
if (dbenv->db_tmp_dir != NULL)
|
||||
FREES(dbenv->db_tmp_dir);
|
||||
__os_freestr(dbenv->db_tmp_dir);
|
||||
p = &dbenv->db_tmp_dir;
|
||||
} else
|
||||
goto err;
|
||||
|
||||
if ((*p = (char *)__db_strdup(value)) == NULL) {
|
||||
nomem: ret = ENOMEM;
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
}
|
||||
ret = __os_strdup(value, p);
|
||||
|
||||
err: FREES(local_s);
|
||||
err: __os_freestr(local_s);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef macintosh
|
||||
#include <TFileSpec.h>
|
||||
|
||||
static char *sTempFolder;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* tmp --
|
||||
* Set the temporary directory path.
|
||||
*/
|
||||
static int
|
||||
__db_tmp_dir(dbenv, flags)
|
||||
DB_ENV *dbenv;
|
||||
u_int32_t flags;
|
||||
{
|
||||
static const char * list[] = { /* Ordered: see db_appinit(3). */
|
||||
"/var/tmp",
|
||||
"/usr/tmp",
|
||||
"/temp", /* WIN32. */
|
||||
"/tmp",
|
||||
"C:/temp", /* WIN32. */
|
||||
"C:/tmp", /* WIN32. */
|
||||
NULL
|
||||
};
|
||||
const char **lp, *p;
|
||||
|
||||
/* Use the environment if it's permitted and initialized. */
|
||||
p = NULL;
|
||||
#ifdef HAVE_GETEUID
|
||||
if (LF_ISSET(DB_USE_ENVIRON) ||
|
||||
(LF_ISSET(DB_USE_ENVIRON_ROOT) && getuid() == 0)) {
|
||||
#else
|
||||
if (LF_ISSET(DB_USE_ENVIRON)) {
|
||||
#endif
|
||||
if ((p = getenv("TMPDIR")) != NULL && p[0] == '\0') {
|
||||
__db_err(dbenv, "illegal TMPDIR environment variable");
|
||||
return (EINVAL);
|
||||
}
|
||||
/* WIN32 */
|
||||
if (p == NULL && (p = getenv("TEMP")) != NULL && p[0] == '\0') {
|
||||
__db_err(dbenv, "illegal TEMP environment variable");
|
||||
return (EINVAL);
|
||||
}
|
||||
/* WIN32 */
|
||||
if (p == NULL && (p = getenv("TMP")) != NULL && p[0] == '\0') {
|
||||
__db_err(dbenv, "illegal TMP environment variable");
|
||||
return (EINVAL);
|
||||
}
|
||||
/* Macintosh */
|
||||
if (p == NULL &&
|
||||
(p = getenv("TempFolder")) != NULL && p[0] == '\0') {
|
||||
__db_err(dbenv,
|
||||
"illegal TempFolder environment variable");
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef macintosh
|
||||
/* Get the path to the temporary folder. */
|
||||
if (p == NULL) {
|
||||
FSSpec spec;
|
||||
|
||||
if (!Special2FSSpec(kTemporaryFolderType,
|
||||
kOnSystemDisk, 0, &spec)) {
|
||||
p = FSp2FullPath(&spec);
|
||||
sTempFolder = __db_malloc(strlen(p) + 1);
|
||||
strcpy(sTempFolder, p);
|
||||
p = sTempFolder;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Step through the list looking for a possibility. */
|
||||
if (p == NULL)
|
||||
for (lp = list; *lp != NULL; ++lp)
|
||||
if (__db_exists(p = *lp, NULL) == 0)
|
||||
break;
|
||||
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
|
||||
if ((dbenv->db_tmp_dir = (char *)__db_strdup(p)) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
return (ENOMEM);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_tmp_open --
|
||||
* Create a temporary file.
|
||||
@ -687,9 +646,6 @@ __db_tmp_open(dbenv, flags, path, fdp)
|
||||
char *path;
|
||||
int *fdp;
|
||||
{
|
||||
#ifdef HAVE_SIGFILLSET
|
||||
sigset_t set, oset;
|
||||
#endif
|
||||
u_long pid;
|
||||
int mode, isdir, ret;
|
||||
const char *p;
|
||||
@ -699,7 +655,7 @@ __db_tmp_open(dbenv, flags, path, fdp)
|
||||
* Check the target directory; if you have six X's and it doesn't
|
||||
* exist, this runs for a *very* long time.
|
||||
*/
|
||||
if ((ret = __db_exists(path, &isdir)) != 0) {
|
||||
if ((ret = __os_exists(path, &isdir)) != 0) {
|
||||
__db_err(dbenv, "%s: %s", path, strerror(ret));
|
||||
return (ret);
|
||||
}
|
||||
@ -738,27 +694,9 @@ __db_tmp_open(dbenv, flags, path, fdp)
|
||||
LF_SET(DB_CREATE | DB_EXCL);
|
||||
mode = __db_omode("rw----");
|
||||
|
||||
/*
|
||||
* Try to open a file. We block every signal we can get our hands
|
||||
* on so that, if we're interrupted at the wrong time, the temporary
|
||||
* file isn't left around -- of course, if we drop core in-between
|
||||
* the calls we'll hang forever, but that's probably okay. ;-}
|
||||
*/
|
||||
#ifdef HAVE_SIGFILLSET
|
||||
if (LF_ISSET(DB_TEMPORARY))
|
||||
(void)sigfillset(&set);
|
||||
#endif
|
||||
/* Loop, trying to open a file. */
|
||||
for (;;) {
|
||||
#ifdef HAVE_SIGFILLSET
|
||||
if (LF_ISSET(DB_TEMPORARY))
|
||||
(void)sigprocmask(SIG_BLOCK, &set, &oset);
|
||||
#endif
|
||||
ret = __db_open(path, flags, flags, mode, fdp);
|
||||
#ifdef HAVE_SIGFILLSET
|
||||
if (LF_ISSET(DB_TEMPORARY))
|
||||
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
#endif
|
||||
if (ret == 0)
|
||||
if ((ret = __db_open(path, flags, flags, mode, fdp)) == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
|
@ -11,7 +11,7 @@
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1996, 1997, 1998\n\
|
||||
Sleepycat Software Inc. All rights reserved.\n";
|
||||
static const char sccsid[] = "@(#)db_apprec.c 10.30 (Sleepycat) 5/3/98";
|
||||
static const char sccsid[] = "@(#)db_apprec.c 10.33 (Sleepycat) 10/5/98";
|
||||
#endif
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -44,7 +44,8 @@ __db_apprec(dbenv, flags)
|
||||
{
|
||||
DBT data;
|
||||
DB_LOG *lp;
|
||||
DB_LSN ckp_lsn, first_lsn, lsn;
|
||||
DB_LSN ckp_lsn, first_lsn, lsn, open_lsn;
|
||||
__txn_ckp_args *ckp_args;
|
||||
time_t now;
|
||||
u_int32_t is_thread;
|
||||
int ret;
|
||||
@ -65,10 +66,16 @@ __db_apprec(dbenv, flags)
|
||||
|
||||
/*
|
||||
* Recovery is done in three passes:
|
||||
* Pass #0:
|
||||
* We need to find the position from which we will open files
|
||||
* We need to open files beginning with the last to next
|
||||
* checkpoint because we might have crashed after writing the
|
||||
* last checkpoint record, but before having written out all
|
||||
* the open file information.
|
||||
* Pass #1:
|
||||
* Read forward through the log from the last checkpoint to the
|
||||
* end of the log, opening and closing files so that at the end
|
||||
* of the log we have the "current" set of files open.
|
||||
* Read forward through the log from the second to last checkpoint
|
||||
* opening and closing files so that at the end of the log we have
|
||||
* the "current" set of files open.
|
||||
* Pass #2:
|
||||
* Read backward through the log undoing any uncompleted TXNs.
|
||||
* If doing catastrophic recovery, we read to the beginning of
|
||||
@ -84,33 +91,50 @@ __db_apprec(dbenv, flags)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Find the last checkpoint in the log. This is the point from which
|
||||
* we want to begin pass #1 (the TXN_OPENFILES pass).
|
||||
* Find the second to last checkpoint in the log. This is the point
|
||||
* from which we want to begin pass #1 (the TXN_OPENFILES pass).
|
||||
*/
|
||||
memset(&data, 0, sizeof(data));
|
||||
ckp_args = NULL;
|
||||
|
||||
if ((ret = log_get(lp, &ckp_lsn, &data, DB_CHECKPOINT)) != 0) {
|
||||
/*
|
||||
* If we don't find a checkpoint, start from the beginning.
|
||||
* If that fails, we're done. Note, we do not require that
|
||||
* there be log records if we're performing recovery.
|
||||
*/
|
||||
if ((ret = log_get(lp, &ckp_lsn, &data, DB_FIRST)) != 0) {
|
||||
first: if ((ret = log_get(lp, &ckp_lsn, &data, DB_FIRST)) != 0) {
|
||||
if (ret == DB_NOTFOUND)
|
||||
ret = 0;
|
||||
else
|
||||
__db_err(dbenv, "First log record not found");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
open_lsn = ckp_lsn;
|
||||
} else if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
|
||||
__db_err(dbenv, "Invalid checkpoint record at [%ld][%ld]\n",
|
||||
(u_long)ckp_lsn.file, (u_long)ckp_lsn.offset);
|
||||
goto out;
|
||||
} else if (IS_ZERO_LSN(ckp_args->last_ckp) ||
|
||||
(ret = log_get(lp, &ckp_args->last_ckp, &data, DB_SET)) != 0)
|
||||
goto first;
|
||||
else
|
||||
open_lsn = ckp_args->last_ckp;
|
||||
|
||||
/*
|
||||
* Now, ckp_lsn is either the lsn of the last checkpoint or the lsn
|
||||
* of the first record in the log. Begin the TXN_OPENFILES pass from
|
||||
* that lsn, and proceed to the end of the log.
|
||||
* of the first record in the log. Open_lsn is the second to last
|
||||
* checkpoint or the beinning of the log; begin the TXN_OPENFILES
|
||||
* pass from that lsn, and proceed to the end of the log.
|
||||
*/
|
||||
lsn = ckp_lsn;
|
||||
lsn = open_lsn;
|
||||
for (;;) {
|
||||
ret = __db_dispatch(lp, &data, &lsn, TXN_OPENFILES, txninfo);
|
||||
if (dbenv->tx_recover != NULL)
|
||||
ret = dbenv->tx_recover(lp,
|
||||
&data, &lsn, TXN_OPENFILES, txninfo);
|
||||
else
|
||||
ret = __db_dispatch(lp,
|
||||
&data, &lsn, TXN_OPENFILES, txninfo);
|
||||
if (ret != 0 && ret != DB_TXN_CKP)
|
||||
goto msgerr;
|
||||
if ((ret = log_get(lp, &lsn, &data, DB_NEXT)) != 0) {
|
||||
@ -148,8 +172,12 @@ __db_apprec(dbenv, flags)
|
||||
for (ret = log_get(lp, &lsn, &data, DB_LAST);
|
||||
ret == 0 && log_compare(&lsn, &first_lsn) > 0;
|
||||
ret = log_get(lp, &lsn, &data, DB_PREV)) {
|
||||
ret = __db_dispatch(lp,
|
||||
&data, &lsn, TXN_BACKWARD_ROLL, txninfo);
|
||||
if (dbenv->tx_recover != NULL)
|
||||
ret = dbenv->tx_recover(lp,
|
||||
&data, &lsn, TXN_BACKWARD_ROLL, txninfo);
|
||||
else
|
||||
ret = __db_dispatch(lp,
|
||||
&data, &lsn, TXN_BACKWARD_ROLL, txninfo);
|
||||
if (ret != 0) {
|
||||
if (ret != DB_TXN_CKP)
|
||||
goto msgerr;
|
||||
@ -165,7 +193,12 @@ __db_apprec(dbenv, flags)
|
||||
*/
|
||||
for (ret = log_get(lp, &lsn, &data, DB_NEXT);
|
||||
ret == 0; ret = log_get(lp, &lsn, &data, DB_NEXT)) {
|
||||
ret = __db_dispatch(lp, &data, &lsn, TXN_FORWARD_ROLL, txninfo);
|
||||
if (dbenv->tx_recover != NULL)
|
||||
ret = dbenv->tx_recover(lp,
|
||||
&data, &lsn, TXN_FORWARD_ROLL, txninfo);
|
||||
else
|
||||
ret = __db_dispatch(lp,
|
||||
&data, &lsn, TXN_FORWARD_ROLL, txninfo);
|
||||
if (ret != 0) {
|
||||
if (ret != DB_TXN_CKP)
|
||||
goto msgerr;
|
||||
@ -207,6 +240,8 @@ msgerr: __db_err(dbenv, "Recovery function for LSN %lu %lu failed",
|
||||
|
||||
out: F_SET(lp, is_thread);
|
||||
__db_txnlist_end(txninfo);
|
||||
if (ckp_args != NULL)
|
||||
__os_free(ckp_args, sizeof(*ckp_args));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
@ -8,13 +8,15 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_err.c 10.25 (Sleepycat) 5/2/98";
|
||||
static const char sccsid[] = "@(#)db_err.c 10.42 (Sleepycat) 11/24/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
#include <stdarg.h>
|
||||
@ -24,10 +26,67 @@ static const char sccsid[] = "@(#)db_err.c 10.25 (Sleepycat) 5/2/98";
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "shqueue.h"
|
||||
#include "db_shash.h"
|
||||
#include "lock.h"
|
||||
#include "lock_ext.h"
|
||||
#include "log.h"
|
||||
#include "log_ext.h"
|
||||
#include "mp.h"
|
||||
#include "mp_ext.h"
|
||||
#include "txn.h"
|
||||
#include "txn_ext.h"
|
||||
#include "common_ext.h"
|
||||
#include "clib_ext.h"
|
||||
|
||||
static int __db_keyempty __P((const DB_ENV *));
|
||||
static int __db_rdonly __P((const DB_ENV *, const char *));
|
||||
/*
|
||||
* __db_fchk --
|
||||
* General flags checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_fchk(dbenv, name, flags, ok_flags)
|
||||
DB_ENV *dbenv;
|
||||
const char *name;
|
||||
u_int32_t flags, ok_flags;
|
||||
{
|
||||
return (flags & ~ok_flags ? __db_ferr(dbenv, name, 0) : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_fcchk --
|
||||
* General combination flags checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_fcchk
|
||||
* PUBLIC: __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_fcchk(dbenv, name, flags, flag1, flag2)
|
||||
DB_ENV *dbenv;
|
||||
const char *name;
|
||||
u_int32_t flags, flag1, flag2;
|
||||
{
|
||||
return ((flags & flag1) &&
|
||||
(flags & flag2) ? __db_ferr(dbenv, name, 1) : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_ferr --
|
||||
* Common flag errors.
|
||||
*
|
||||
* PUBLIC: int __db_ferr __P((const DB_ENV *, const char *, int));
|
||||
*/
|
||||
int
|
||||
__db_ferr(dbenv, name, iscombo)
|
||||
const DB_ENV *dbenv;
|
||||
const char *name;
|
||||
int iscombo;
|
||||
{
|
||||
__db_err(dbenv, "illegal flag %sspecified to %s",
|
||||
iscombo ? "combination " : "", name);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_err --
|
||||
@ -55,561 +114,98 @@ __db_err(dbenv, fmt, va_alist)
|
||||
if (dbenv == NULL)
|
||||
return;
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
if (dbenv->db_errcall != NULL) {
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void)vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
|
||||
dbenv->db_errcall(dbenv->db_errpfx, errbuf);
|
||||
va_end(ap);
|
||||
}
|
||||
if (dbenv->db_errfile != NULL) {
|
||||
if (dbenv->db_errpfx != NULL)
|
||||
(void)fprintf(dbenv->db_errfile, "%s: ",
|
||||
dbenv->db_errpfx);
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void)vfprintf(dbenv->db_errfile, fmt, ap);
|
||||
(void)fprintf(dbenv->db_errfile, "\n");
|
||||
(void)fflush(dbenv->db_errfile);
|
||||
va_end(ap);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Provide ANSI C prototypes for the panic functions. Some compilers, (e.g.,
|
||||
* MS VC 4.2) get upset if they aren't here, even though the K&R declaration
|
||||
* appears before the assignment in the __db__panic() call.
|
||||
* __db_pgerr --
|
||||
* Error when unable to retrieve a specified page.
|
||||
*
|
||||
* PUBLIC: int __db_pgerr __P((DB *, db_pgno_t));
|
||||
*/
|
||||
static int __db_ecursor __P((DB *, DB_TXN *, DBC **));
|
||||
static int __db_edel __P((DB *, DB_TXN *, DBT *, u_int32_t));
|
||||
static int __db_efd __P((DB *, int *));
|
||||
static int __db_egp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
static int __db_estat __P((DB *, void *, void *(*)(size_t), u_int32_t));
|
||||
static int __db_esync __P((DB *, u_int32_t));
|
||||
|
||||
/*
|
||||
* __db_ecursor --
|
||||
* After-panic cursor routine.
|
||||
*/
|
||||
static int
|
||||
__db_ecursor(a, b, c)
|
||||
DB *a;
|
||||
DB_TXN *b;
|
||||
DBC **c;
|
||||
int
|
||||
__db_pgerr(dbp, pgno)
|
||||
DB *dbp;
|
||||
db_pgno_t pgno;
|
||||
{
|
||||
COMPQUIET(a, NULL);
|
||||
COMPQUIET(b, NULL);
|
||||
COMPQUIET(c, NULL);
|
||||
|
||||
return (EPERM);
|
||||
/*
|
||||
* Three things are certain:
|
||||
* Death, taxes, and lost data.
|
||||
* Guess which has occurred.
|
||||
*/
|
||||
__db_err(dbp->dbenv,
|
||||
"unable to create/retrieve page %lu", (u_long)pgno);
|
||||
return (__db_panic(dbp->dbenv, EIO));
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_edel --
|
||||
* After-panic delete routine.
|
||||
* __db_pgfmt --
|
||||
* Error when a page has the wrong format.
|
||||
*
|
||||
* PUBLIC: int __db_pgfmt __P((DB *, db_pgno_t));
|
||||
*/
|
||||
static int
|
||||
__db_edel(a, b, c, d)
|
||||
DB *a;
|
||||
DB_TXN *b;
|
||||
DBT *c;
|
||||
u_int32_t d;
|
||||
int
|
||||
__db_pgfmt(dbp, pgno)
|
||||
DB *dbp;
|
||||
db_pgno_t pgno;
|
||||
{
|
||||
COMPQUIET(a, NULL);
|
||||
COMPQUIET(b, NULL);
|
||||
COMPQUIET(c, NULL);
|
||||
COMPQUIET(d, 0);
|
||||
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_efd --
|
||||
* After-panic fd routine.
|
||||
*/
|
||||
static int
|
||||
__db_efd(a, b)
|
||||
DB *a;
|
||||
int *b;
|
||||
{
|
||||
COMPQUIET(a, NULL);
|
||||
COMPQUIET(b, NULL);
|
||||
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_egp --
|
||||
* After-panic get/put routine.
|
||||
*/
|
||||
static int
|
||||
__db_egp(a, b, c, d, e)
|
||||
DB *a;
|
||||
DB_TXN *b;
|
||||
DBT *c, *d;
|
||||
u_int32_t e;
|
||||
{
|
||||
COMPQUIET(a, NULL);
|
||||
COMPQUIET(b, NULL);
|
||||
COMPQUIET(c, NULL);
|
||||
COMPQUIET(d, NULL);
|
||||
COMPQUIET(e, 0);
|
||||
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_estat --
|
||||
* After-panic stat routine.
|
||||
*/
|
||||
static int
|
||||
__db_estat(a, b, c, d)
|
||||
DB *a;
|
||||
void *b;
|
||||
void *(*c) __P((size_t));
|
||||
u_int32_t d;
|
||||
{
|
||||
COMPQUIET(a, NULL);
|
||||
COMPQUIET(b, NULL);
|
||||
COMPQUIET(c, NULL);
|
||||
COMPQUIET(d, 0);
|
||||
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_esync --
|
||||
* After-panic sync routine.
|
||||
*/
|
||||
static int
|
||||
__db_esync(a, b)
|
||||
DB *a;
|
||||
u_int32_t b;
|
||||
{
|
||||
COMPQUIET(a, NULL);
|
||||
COMPQUIET(b, 0);
|
||||
|
||||
return (EPERM);
|
||||
__db_err(dbp->dbenv,
|
||||
"page %lu: illegal page type or format", (u_long)pgno);
|
||||
return (__db_panic(dbp->dbenv, EINVAL));
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_panic --
|
||||
* Lock out the tree due to unrecoverable error.
|
||||
*
|
||||
* PUBLIC: int __db_panic __P((DB *));
|
||||
* PUBLIC: int __db_panic __P((DB_ENV *, int));
|
||||
*/
|
||||
int
|
||||
__db_panic(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
/*
|
||||
* XXX
|
||||
* We should shut down all of the process's cursors, too.
|
||||
*
|
||||
* We should call mpool and have it shut down the file, so we get
|
||||
* other processes sharing this file as well.
|
||||
*
|
||||
* Chaos reigns within.
|
||||
* Reflect, repent, and reboot.
|
||||
* Order shall return.
|
||||
*/
|
||||
dbp->cursor = __db_ecursor;
|
||||
dbp->del = __db_edel;
|
||||
dbp->fd = __db_efd;
|
||||
dbp->get = __db_egp;
|
||||
dbp->put = __db_egp;
|
||||
dbp->stat = __db_estat;
|
||||
dbp->sync = __db_esync;
|
||||
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
/* Check for invalid flags. */
|
||||
#undef DB_CHECK_FLAGS
|
||||
#define DB_CHECK_FLAGS(dbenv, name, flags, ok_flags) \
|
||||
if ((flags) & ~(ok_flags)) \
|
||||
return (__db_ferr(dbenv, name, 0));
|
||||
/* Check for invalid flag combinations. */
|
||||
#undef DB_CHECK_FCOMBO
|
||||
#define DB_CHECK_FCOMBO(dbenv, name, flags, flag1, flag2) \
|
||||
if ((flags) & (flag1) && (flags) & (flag2)) \
|
||||
return (__db_ferr(dbenv, name, 1));
|
||||
|
||||
/*
|
||||
* __db_fchk --
|
||||
* General flags checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_fchk(dbenv, name, flags, ok_flags)
|
||||
__db_panic(dbenv, errval)
|
||||
DB_ENV *dbenv;
|
||||
const char *name;
|
||||
u_int32_t flags, ok_flags;
|
||||
int errval;
|
||||
{
|
||||
DB_CHECK_FLAGS(dbenv, name, flags, ok_flags);
|
||||
return (0);
|
||||
}
|
||||
if (dbenv != NULL) {
|
||||
dbenv->db_panic = errval;
|
||||
|
||||
/*
|
||||
* __db_fcchk --
|
||||
* General combination flags checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_fcchk
|
||||
* PUBLIC: __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_fcchk(dbenv, name, flags, flag1, flag2)
|
||||
DB_ENV *dbenv;
|
||||
const char *name;
|
||||
u_int32_t flags, flag1, flag2;
|
||||
{
|
||||
DB_CHECK_FCOMBO(dbenv, name, flags, flag1, flag2);
|
||||
return (0);
|
||||
}
|
||||
(void)__log_panic(dbenv);
|
||||
(void)__memp_panic(dbenv);
|
||||
(void)__lock_panic(dbenv);
|
||||
(void)__txn_panic(dbenv);
|
||||
|
||||
/*
|
||||
* __db_cdelchk --
|
||||
* Common cursor delete argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int, int));
|
||||
*/
|
||||
int
|
||||
__db_cdelchk(dbp, flags, isrdonly, isvalid)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
int isrdonly, isvalid;
|
||||
{
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "c_del"));
|
||||
__db_err(dbenv, "PANIC: %s", strerror(errval));
|
||||
|
||||
/* Check for invalid dbc->c_del() function flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "c_del", flags, 0);
|
||||
if (dbenv->db_paniccall != NULL)
|
||||
dbenv->db_paniccall(dbenv, errval);
|
||||
}
|
||||
|
||||
/*
|
||||
* The cursor must be initialized, return -1 for an invalid cursor,
|
||||
* otherwise 0.
|
||||
* Chaos reigns within.
|
||||
* Reflect, repent, and reboot.
|
||||
* Order shall return.
|
||||
*/
|
||||
return (isvalid ? 0 : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_cgetchk --
|
||||
* Common cursor get argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
|
||||
*/
|
||||
int
|
||||
__db_cgetchk(dbp, key, data, flags, isvalid)
|
||||
const DB *dbp;
|
||||
DBT *key, *data;
|
||||
u_int32_t flags;
|
||||
int isvalid;
|
||||
{
|
||||
int key_einval, key_flags;
|
||||
|
||||
key_flags = key_einval = 0;
|
||||
|
||||
/* Check for invalid dbc->c_get() function flags. */
|
||||
switch (flags) {
|
||||
case DB_CURRENT:
|
||||
case DB_FIRST:
|
||||
case DB_LAST:
|
||||
case DB_NEXT:
|
||||
case DB_PREV:
|
||||
key_flags = 1;
|
||||
break;
|
||||
case DB_SET_RANGE:
|
||||
key_einval = key_flags = 1;
|
||||
break;
|
||||
case DB_SET:
|
||||
key_einval = 1;
|
||||
break;
|
||||
case DB_GET_RECNO:
|
||||
if (!F_ISSET(dbp, DB_BT_RECNUM))
|
||||
goto err;
|
||||
break;
|
||||
case DB_SET_RECNO:
|
||||
if (!F_ISSET(dbp, DB_BT_RECNUM))
|
||||
goto err;
|
||||
key_einval = key_flags = 1;
|
||||
break;
|
||||
default:
|
||||
err: return (__db_ferr(dbp->dbenv, "c_get", 0));
|
||||
}
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
if (key_flags)
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "key", key->flags,
|
||||
DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "data", data->flags,
|
||||
DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
|
||||
/* Check dbt's for valid flags when multi-threaded. */
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) {
|
||||
if (!F_ISSET(data, DB_DBT_USERMEM | DB_DBT_MALLOC))
|
||||
return (__db_ferr(dbp->dbenv, "threaded data", 1));
|
||||
if (key_flags &&
|
||||
!F_ISSET(key, DB_DBT_USERMEM | DB_DBT_MALLOC))
|
||||
return (__db_ferr(dbp->dbenv, "threaded key", 1));
|
||||
}
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key_einval && (key->data == NULL || key->size == 0))
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
/*
|
||||
* The cursor must be initialized for DB_CURRENT, return -1 for an
|
||||
* invalid cursor, otherwise 0.
|
||||
*/
|
||||
return (isvalid || flags != DB_CURRENT ? 0 : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_cputchk --
|
||||
* Common cursor put argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_cputchk __P((const DB *,
|
||||
* PUBLIC: const DBT *, DBT *, u_int32_t, int, int));
|
||||
*/
|
||||
int
|
||||
__db_cputchk(dbp, key, data, flags, isrdonly, isvalid)
|
||||
const DB *dbp;
|
||||
const DBT *key;
|
||||
DBT *data;
|
||||
u_int32_t flags;
|
||||
int isrdonly, isvalid;
|
||||
{
|
||||
int key_einval, key_flags;
|
||||
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "c_put"));
|
||||
|
||||
/* Check for invalid dbc->c_put() function flags. */
|
||||
key_einval = key_flags = 0;
|
||||
switch (flags) {
|
||||
case DB_AFTER:
|
||||
case DB_BEFORE:
|
||||
if (dbp->type == DB_RECNO && !F_ISSET(dbp, DB_RE_RENUMBER))
|
||||
goto err;
|
||||
if (dbp->type != DB_RECNO && !F_ISSET(dbp, DB_AM_DUP))
|
||||
goto err;
|
||||
break;
|
||||
case DB_CURRENT:
|
||||
break;
|
||||
case DB_KEYFIRST:
|
||||
case DB_KEYLAST:
|
||||
if (dbp->type == DB_RECNO)
|
||||
goto err;
|
||||
key_einval = key_flags = 1;
|
||||
break;
|
||||
default:
|
||||
err: return (__db_ferr(dbp->dbenv, "c_put", 0));
|
||||
}
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
if (key_flags)
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "key", key->flags,
|
||||
DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "data", data->flags,
|
||||
DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key_einval && (key->data == NULL || key->size == 0))
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
/*
|
||||
* The cursor must be initialized for anything other than DB_KEYFIRST
|
||||
* and DB_KEYLAST, return -1 for an invalid cursor, otherwise 0.
|
||||
*/
|
||||
return (isvalid ||
|
||||
(flags != DB_KEYFIRST && flags != DB_KEYLAST) ? 0 : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_delchk --
|
||||
* Common delete argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t, int));
|
||||
*/
|
||||
int
|
||||
__db_delchk(dbp, key, flags, isrdonly)
|
||||
const DB *dbp;
|
||||
DBT *key;
|
||||
u_int32_t flags;
|
||||
int isrdonly;
|
||||
{
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "delete"));
|
||||
|
||||
/* Check for invalid db->del() function flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "delete", flags, 0);
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key->data == NULL || key->size == 0)
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_getchk --
|
||||
* Common get argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_getchk(dbp, key, data, flags)
|
||||
const DB *dbp;
|
||||
const DBT *key;
|
||||
DBT *data;
|
||||
u_int32_t flags;
|
||||
{
|
||||
/* Check for invalid db->get() function flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv,
|
||||
"get", flags, F_ISSET(dbp, DB_BT_RECNUM) ? DB_SET_RECNO : 0);
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "key", key->flags, 0);
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "data", data->flags,
|
||||
DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
DB_CHECK_FCOMBO(dbp->dbenv,
|
||||
"data", data->flags, DB_DBT_MALLOC, DB_DBT_USERMEM);
|
||||
if (F_ISSET(dbp, DB_AM_THREAD) &&
|
||||
!F_ISSET(data, DB_DBT_MALLOC | DB_DBT_USERMEM))
|
||||
return (__db_ferr(dbp->dbenv, "threaded data", 1));
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key->data == NULL || key->size == 0)
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_putchk --
|
||||
* Common put argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_putchk
|
||||
* PUBLIC: __P((const DB *, DBT *, const DBT *, u_int32_t, int, int));
|
||||
*/
|
||||
int
|
||||
__db_putchk(dbp, key, data, flags, isrdonly, isdup)
|
||||
const DB *dbp;
|
||||
DBT *key;
|
||||
const DBT *data;
|
||||
u_int32_t flags;
|
||||
int isrdonly, isdup;
|
||||
{
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "put"));
|
||||
|
||||
/* Check for invalid db->put() function flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "put", flags,
|
||||
DB_NOOVERWRITE | (dbp->type == DB_RECNO ? DB_APPEND : 0));
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "key", key->flags, 0);
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "data", data->flags,
|
||||
DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
DB_CHECK_FCOMBO(dbp->dbenv,
|
||||
"data", data->flags, DB_DBT_MALLOC, DB_DBT_USERMEM);
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key->data == NULL || key->size == 0)
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
/* Check for partial puts in the presence of duplicates. */
|
||||
if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) {
|
||||
__db_err(dbp->dbenv,
|
||||
"a partial put in the presence of duplicates requires a cursor operation");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_statchk --
|
||||
* Common stat argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_statchk __P((const DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_statchk(dbp, flags)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
/* Check for invalid db->stat() function flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "stat", flags, DB_RECORDCOUNT);
|
||||
|
||||
if (LF_ISSET(DB_RECORDCOUNT) &&
|
||||
dbp->type == DB_BTREE && !F_ISSET(dbp, DB_BT_RECNUM))
|
||||
return (__db_ferr(dbp->dbenv, "stat", 0));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_syncchk --
|
||||
* Common sync argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_syncchk __P((const DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_syncchk(dbp, flags)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
/* Check for invalid db->sync() function flags. */
|
||||
DB_CHECK_FLAGS(dbp->dbenv, "sync", flags, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_ferr --
|
||||
* Common flag errors.
|
||||
*
|
||||
* PUBLIC: int __db_ferr __P((const DB_ENV *, const char *, int));
|
||||
*/
|
||||
int
|
||||
__db_ferr(dbenv, name, iscombo)
|
||||
const DB_ENV *dbenv;
|
||||
const char *name;
|
||||
int iscombo;
|
||||
{
|
||||
__db_err(dbenv, "illegal flag %sspecified to %s",
|
||||
iscombo ? "combination " : "", name);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_rdonly --
|
||||
* Common readonly message.
|
||||
*/
|
||||
static int
|
||||
__db_rdonly(dbenv, name)
|
||||
const DB_ENV *dbenv;
|
||||
const char *name;
|
||||
{
|
||||
__db_err(dbenv, "%s: attempt to modify a read-only tree", name);
|
||||
return (EACCES);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_keyempty --
|
||||
* Common missing or empty key value message.
|
||||
*/
|
||||
static int
|
||||
__db_keyempty(dbenv)
|
||||
const DB_ENV *dbenv;
|
||||
{
|
||||
__db_err(dbenv, "missing or empty key value specified");
|
||||
return (EINVAL);
|
||||
return (DB_RUNRECOVERY);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_region.c 10.46 (Sleepycat) 5/26/98";
|
||||
static const char sccsid[] = "@(#)db_region.c 10.53 (Sleepycat) 11/10/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -46,7 +46,7 @@ __db_rattach(infop)
|
||||
ret = retry_cnt = 0;
|
||||
|
||||
/* Round off the requested size to the next page boundary. */
|
||||
DB_ROUNDOFF(infop->size);
|
||||
DB_ROUNDOFF(infop->size, DB_VMPAGESIZE);
|
||||
|
||||
/* Some architectures have hard limits on the maximum region size. */
|
||||
#ifdef DB_REGIONSIZE_MAX
|
||||
@ -61,7 +61,7 @@ loop: infop->addr = NULL;
|
||||
infop->fd = -1;
|
||||
infop->segid = INVALID_SEGID;
|
||||
if (infop->name != NULL) {
|
||||
FREES(infop->name);
|
||||
__os_freestr(infop->name);
|
||||
infop->name = NULL;
|
||||
}
|
||||
F_CLR(infop, REGION_CANGROW | REGION_CREATED);
|
||||
@ -74,6 +74,11 @@ loop: infop->addr = NULL;
|
||||
* (Theoretically, we could probably get a file descriptor to lock
|
||||
* other types of shared regions, but I don't see any reason to
|
||||
* bother.)
|
||||
*
|
||||
* Since we may be using shared memory regions, e.g., shmget(2),
|
||||
* and not mmap of regular files, the backing file may be only a
|
||||
* few tens of bytes in length. So, this depends on the ability
|
||||
* to fcntl lock file offsets much larger than the physical file.
|
||||
*/
|
||||
malloc_possible = 0;
|
||||
#endif
|
||||
@ -91,15 +96,16 @@ loop: infop->addr = NULL;
|
||||
* than either anonymous memory or a shared file.
|
||||
*/
|
||||
if (malloc_possible && F_ISSET(infop, REGION_PRIVATE)) {
|
||||
if ((infop->addr = __db_malloc(infop->size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(infop->size, NULL, &infop->addr)) != 0)
|
||||
return (ret);
|
||||
|
||||
/*
|
||||
* It's sometimes significantly faster to page-fault in all
|
||||
* of the region's pages before we run the application, as
|
||||
* we can see fairly nasty side-effects when we page-fault
|
||||
* while holding various locks, i.e., the lock takes a long
|
||||
* time, and other threads convoy behind the lock holder.
|
||||
* It's sometimes significantly faster to page-fault in all of
|
||||
* the region's pages before we run the application, as we see
|
||||
* nasty side-effects when we page-fault while holding various
|
||||
* locks, i.e., the lock takes a long time to acquire because
|
||||
* of the underlying page fault, and the other threads convoy
|
||||
* behind the lock holder.
|
||||
*/
|
||||
if (DB_GLOBAL(db_region_init))
|
||||
for (p = infop->addr;
|
||||
@ -159,7 +165,7 @@ loop: infop->addr = NULL;
|
||||
* 3. Memory backed by a regular file (mmap(2)).
|
||||
*
|
||||
* We instantiate a backing file in all cases, which contains at least
|
||||
* the RLAYOUT structure, and in case #4, contains the actual region.
|
||||
* the RLAYOUT structure, and in case #3, contains the actual region.
|
||||
* This is necessary for a couple of reasons:
|
||||
*
|
||||
* First, the mpool region uses temporary files to name regions, and
|
||||
@ -218,7 +224,7 @@ loop: infop->addr = NULL;
|
||||
* And yes, this makes me want to take somebody and kill them,
|
||||
* but I can't think of any other solution.
|
||||
*/
|
||||
if ((ret = __db_ioinfo(infop->name,
|
||||
if ((ret = __os_ioinfo(infop->name,
|
||||
infop->fd, &mbytes, &bytes, NULL)) != 0)
|
||||
goto errmsg;
|
||||
size = mbytes * MEGABYTE + bytes;
|
||||
@ -233,7 +239,7 @@ loop: infop->addr = NULL;
|
||||
if (size < sizeof(RLAYOUT))
|
||||
goto retry;
|
||||
if ((ret =
|
||||
__db_read(infop->fd, &rl, sizeof(rl), &nr)) != 0)
|
||||
__os_read(infop->fd, &rl, sizeof(rl), &nr)) != 0)
|
||||
goto retry;
|
||||
if (rl.valid != DB_REGIONMAGIC)
|
||||
goto retry;
|
||||
@ -284,6 +290,7 @@ loop: infop->addr = NULL;
|
||||
} else
|
||||
goto err;
|
||||
}
|
||||
|
||||
region_init:
|
||||
/*
|
||||
* Initialize the common region information.
|
||||
@ -321,6 +328,7 @@ region_init:
|
||||
rlp->refcnt = 1;
|
||||
rlp->size = infop->size;
|
||||
db_version(&rlp->majver, &rlp->minver, &rlp->patch);
|
||||
rlp->panic = 0;
|
||||
rlp->segid = infop->segid;
|
||||
rlp->flags = 0;
|
||||
if (F_ISSET(infop, REGION_ANONYMOUS))
|
||||
@ -347,13 +355,19 @@ region_init:
|
||||
* the file.
|
||||
*/
|
||||
if (F_ISSET(infop, REGION_ANONYMOUS)) {
|
||||
if ((ret = __db_seek(infop->fd, 0, 0, 0, 0, 0)) != 0)
|
||||
if ((ret = __os_seek(infop->fd, 0, 0, 0, 0, 0)) != 0)
|
||||
goto err;
|
||||
if ((ret =
|
||||
__db_write(infop->fd, rlp, sizeof(*rlp), &nw)) != 0)
|
||||
__os_write(infop->fd, rlp, sizeof(*rlp), &nw)) != 0)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
/* Check to see if the region has had catastrophic failure. */
|
||||
if (rlp->panic) {
|
||||
ret = DB_RUNRECOVERY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the valid flag to ensure the region is initialized.
|
||||
* If the valid flag has not been set, the mutex may not have
|
||||
@ -379,18 +393,6 @@ region_init:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Problem #2: We want a bigger region than has previously been
|
||||
* created. Detected by checking if the region is smaller than
|
||||
* our caller requested. If it is, we grow the region, (which
|
||||
* does the detach and re-attach for us).
|
||||
*/
|
||||
if (grow_region != 0 &&
|
||||
(ret = __db_rgrow(infop, grow_region)) != 0) {
|
||||
(void)__db_mutex_unlock(&rlp->lock, infop->fd);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Problem #3: when we checked the size of the file, it was
|
||||
* still growing as part of creation. Detected by the fact
|
||||
@ -419,16 +421,16 @@ retry: /* Discard the region. */
|
||||
|
||||
/* Discard the backing file. */
|
||||
if (infop->fd != -1) {
|
||||
(void)__db_close(infop->fd);
|
||||
(void)__os_close(infop->fd);
|
||||
infop->fd = -1;
|
||||
|
||||
if (F_ISSET(infop, REGION_CREATED))
|
||||
(void)__db_unlink(infop->name);
|
||||
(void)__os_unlink(infop->name);
|
||||
}
|
||||
|
||||
/* Discard the name. */
|
||||
if (infop->name != NULL) {
|
||||
FREES(infop->name);
|
||||
__os_freestr(infop->name);
|
||||
infop->name = NULL;
|
||||
}
|
||||
|
||||
@ -438,7 +440,7 @@ retry: /* Discard the region. */
|
||||
*/
|
||||
if (ret == 0) {
|
||||
if (++retry_cnt <= 3) {
|
||||
__db_sleep(retry_cnt * 2, 0);
|
||||
__os_sleep(retry_cnt * 2, 0);
|
||||
goto loop;
|
||||
}
|
||||
ret = EAGAIN;
|
||||
@ -481,10 +483,11 @@ retry: /* Discard the region. */
|
||||
F_SET(infop, REGION_REMOVED);
|
||||
F_CLR(infop, REGION_CANGROW);
|
||||
|
||||
(void)__db_close(infop->fd);
|
||||
(void)__db_unlink(infop->name);
|
||||
(void)__os_close(infop->fd);
|
||||
(void)__os_unlink(infop->name);
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -514,7 +517,7 @@ __db_rdetach(infop)
|
||||
* action required is freeing the memory.
|
||||
*/
|
||||
if (F_ISSET(infop, REGION_MALLOC)) {
|
||||
__db_free(infop->addr);
|
||||
__os_free(infop->addr, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -549,7 +552,7 @@ __db_rdetach(infop)
|
||||
(void)__db_mutex_unlock(&rlp->lock, infop->fd);
|
||||
|
||||
/* Close the backing file descriptor. */
|
||||
(void)__db_close(infop->fd);
|
||||
(void)__os_close(infop->fd);
|
||||
infop->fd = -1;
|
||||
|
||||
/* Discard our mapping of the region. */
|
||||
@ -561,13 +564,13 @@ __db_rdetach(infop)
|
||||
if ((t_ret =
|
||||
__db_unlinkregion(infop->name, infop) != 0) && ret == 0)
|
||||
ret = t_ret;
|
||||
if ((t_ret = __db_unlink(infop->name) != 0) && ret == 0)
|
||||
if ((t_ret = __os_unlink(infop->name) != 0) && ret == 0)
|
||||
ret = t_ret;
|
||||
}
|
||||
|
||||
done: /* Discard the name. */
|
||||
if (infop->name != NULL) {
|
||||
FREES(infop->name);
|
||||
__os_freestr(infop->name);
|
||||
infop->name = NULL;
|
||||
}
|
||||
|
||||
@ -629,8 +632,8 @@ __db_runlink(infop, force)
|
||||
* (REGION_PRIVATE) ones, regardless of whether or not it's used to
|
||||
* back the region. If that file doesn't exist, we're done.
|
||||
*/
|
||||
if (__db_exists(name, NULL) != 0) {
|
||||
FREES(name);
|
||||
if (__os_exists(name, NULL) != 0) {
|
||||
__os_freestr(name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -641,12 +644,12 @@ __db_runlink(infop, force)
|
||||
*/
|
||||
if ((ret = __db_open(name, DB_RDONLY, DB_RDONLY, 0, &fd)) != 0)
|
||||
goto errmsg;
|
||||
if ((ret = __db_ioinfo(name, fd, &mbytes, &bytes, NULL)) != 0)
|
||||
if ((ret = __os_ioinfo(name, fd, &mbytes, &bytes, NULL)) != 0)
|
||||
goto errmsg;
|
||||
size = mbytes * MEGABYTE + bytes;
|
||||
|
||||
if (size <= sizeof(RLAYOUT)) {
|
||||
if ((ret = __db_read(fd, &rl, sizeof(rl), &nr)) != 0)
|
||||
if ((ret = __os_read(fd, &rl, sizeof(rl), &nr)) != 0)
|
||||
goto errmsg;
|
||||
if (rl.valid != DB_REGIONMAGIC) {
|
||||
__db_err(infop->dbenv,
|
||||
@ -673,16 +676,16 @@ __db_runlink(infop, force)
|
||||
* because some architectures (e.g., Win32) won't unlink a file if
|
||||
* open file descriptors remain.
|
||||
*/
|
||||
(void)__db_close(fd);
|
||||
if ((t_ret = __db_unlink(name)) != 0 && ret == 0)
|
||||
(void)__os_close(fd);
|
||||
if ((t_ret = __os_unlink(name)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
if (0) {
|
||||
errmsg: __db_err(infop->dbenv, "%s: %s", name, strerror(ret));
|
||||
err: (void)__db_close(fd);
|
||||
err: (void)__os_close(fd);
|
||||
}
|
||||
|
||||
FREES(name);
|
||||
__os_freestr(name);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -715,7 +718,7 @@ __db_rgrow(infop, new_size)
|
||||
* determine the additional space required.
|
||||
*/
|
||||
rlp = (RLAYOUT *)infop->addr;
|
||||
DB_ROUNDOFF(new_size);
|
||||
DB_ROUNDOFF(new_size, DB_VMPAGESIZE);
|
||||
increment = new_size - rlp->size;
|
||||
|
||||
if ((ret = __db_growregion(infop, increment)) != 0)
|
||||
@ -745,7 +748,7 @@ __db_growregion(infop, increment)
|
||||
char buf[DB_VMPAGESIZE];
|
||||
|
||||
/* Seek to the end of the region. */
|
||||
if ((ret = __db_seek(infop->fd, 0, 0, 0, 0, SEEK_END)) != 0)
|
||||
if ((ret = __os_seek(infop->fd, 0, 0, 0, 0, SEEK_END)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Write nuls to the new bytes. */
|
||||
@ -760,7 +763,7 @@ __db_growregion(infop, increment)
|
||||
/* Extend the region by writing each new page. */
|
||||
for (i = 0; i < increment; i += DB_VMPAGESIZE) {
|
||||
if ((ret =
|
||||
__db_write(infop->fd, buf, sizeof(buf), &nw)) != 0)
|
||||
__os_write(infop->fd, buf, sizeof(buf), &nw)) != 0)
|
||||
goto err;
|
||||
if (nw != sizeof(buf))
|
||||
goto eio;
|
||||
@ -776,36 +779,44 @@ __db_growregion(infop, increment)
|
||||
*/
|
||||
pages = (increment - DB_VMPAGESIZE) / MEGABYTE;
|
||||
relative = (increment - DB_VMPAGESIZE) % MEGABYTE;
|
||||
if ((ret = __db_seek(infop->fd,
|
||||
if ((ret = __os_seek(infop->fd,
|
||||
MEGABYTE, pages, relative, 0, SEEK_CUR)) != 0)
|
||||
goto err;
|
||||
if ((ret = __db_write(infop->fd, buf, sizeof(buf), &nw)) != 0)
|
||||
if ((ret = __os_write(infop->fd, buf, sizeof(buf), &nw)) != 0)
|
||||
goto err;
|
||||
if (nw != sizeof(buf))
|
||||
goto eio;
|
||||
|
||||
/*
|
||||
* It's sometimes significantly faster to page-fault in all
|
||||
* of the region's pages before we run the application, as
|
||||
* we can see fairly nasty side-effects when we page-fault
|
||||
* while holding various locks, i.e., the lock takes a long
|
||||
* time, and other threads convoy behind the lock holder.
|
||||
* It's sometimes significantly faster to page-fault in all of
|
||||
* the region's pages before we run the application, as we see
|
||||
* nasty side-effects when we page-fault while holding various
|
||||
* locks, i.e., the lock takes a long time to acquire because
|
||||
* of the underlying page fault, and the other threads convoy
|
||||
* behind the lock holder.
|
||||
*
|
||||
* We also use REGION_INIT to guarantee that there is enough
|
||||
* disk space for the region, so we also write a byte to each
|
||||
* page. Reading the byte is insufficient as some systems
|
||||
* (e.g., Solaris) do not instantiate disk pages to satisfy
|
||||
* a read, and so we don't know if there is enough disk space
|
||||
* or not.
|
||||
*/
|
||||
if (DB_GLOBAL(db_region_init)) {
|
||||
pages = increment / MEGABYTE;
|
||||
relative = increment % MEGABYTE;
|
||||
if ((ret = __db_seek(infop->fd,
|
||||
if ((ret = __os_seek(infop->fd,
|
||||
MEGABYTE, pages, relative, 1, SEEK_END)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Read a byte from each page. */
|
||||
/* Write a byte to each page. */
|
||||
for (i = 0; i < increment; i += DB_VMPAGESIZE) {
|
||||
if ((ret =
|
||||
__db_read(infop->fd, buf, 1, &nr)) != 0)
|
||||
__os_write(infop->fd, buf, 1, &nr)) != 0)
|
||||
goto err;
|
||||
if (nr != 1)
|
||||
goto eio;
|
||||
if ((ret = __db_seek(infop->fd,
|
||||
if ((ret = __os_seek(infop->fd,
|
||||
0, 0, DB_VMPAGESIZE - 1, 0, SEEK_CUR)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_salloc.c 10.13 (Sleepycat) 5/10/98";
|
||||
static const char sccsid[] = "@(#)db_salloc.c 10.14 (Sleepycat) 11/16/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -170,7 +170,7 @@ __db_shalloc_free(regionp, ptr)
|
||||
|
||||
/* Trash the returned memory. */
|
||||
#ifdef DIAGNOSTIC
|
||||
memset(ptr, 0xff, free_size);
|
||||
memset(ptr, 0xdb, free_size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
389
db2/db.h
389
db2/db.h
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db.h.src 10.131 (Sleepycat) 6/2/98
|
||||
* @(#)db.h 10.174 (Sleepycat) 1/3/99
|
||||
*/
|
||||
|
||||
#ifndef _DB_H_
|
||||
@ -56,34 +56,20 @@
|
||||
* We also provide the standard u_int, u_long etc., if they're not provided
|
||||
* by the system.
|
||||
*/
|
||||
#ifndef __BIT_TYPES_DEFINED__
|
||||
#define __BIT_TYPES_DEFINED__
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define DB_VERSION_MAJOR 2
|
||||
#define DB_VERSION_MINOR 4
|
||||
#define DB_VERSION_PATCH 14
|
||||
#define DB_VERSION_STRING "Sleepycat Software: DB 2.4.14: (6/2/98)"
|
||||
#define DB_VERSION_MINOR 7
|
||||
#define DB_VERSION_PATCH 5
|
||||
#define DB_VERSION_STRING "Sleepycat Software: Berkeley DB 2.7.5: (04/18/99)"
|
||||
|
||||
typedef u_int32_t db_pgno_t; /* Page number type. */
|
||||
typedef u_int16_t db_indx_t; /* Page offset type. */
|
||||
#define DB_MAX_PAGES 0xffffffff /* >= # of pages in a file */
|
||||
|
||||
typedef u_int32_t db_recno_t; /* Record number type. */
|
||||
typedef size_t DB_LOCK; /* Object returned by lock manager. */
|
||||
#define DB_MAX_RECORDS 0xffffffff /* >= # of records in a tree */
|
||||
|
||||
#define DB_FILE_ID_LEN 20 /* DB file ID length. */
|
||||
typedef size_t DB_LOCK; /* Object returned by lock manager. */
|
||||
|
||||
/* Forward structure declarations, so applications get type checking. */
|
||||
struct __db; typedef struct __db DB;
|
||||
@ -93,6 +79,7 @@ struct __db; typedef struct __db DB;
|
||||
struct __db_bt_stat; typedef struct __db_bt_stat DB_BTREE_STAT;
|
||||
struct __db_dbt; typedef struct __db_dbt DBT;
|
||||
struct __db_env; typedef struct __db_env DB_ENV;
|
||||
struct __db_ilock; typedef struct __db_ilock DB_LOCK_ILOCK;
|
||||
struct __db_info; typedef struct __db_info DB_INFO;
|
||||
struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT;
|
||||
struct __db_lockregion; typedef struct __db_lockregion DB_LOCKREGION;
|
||||
@ -121,8 +108,7 @@ struct __db_dbt {
|
||||
u_int32_t dlen; /* RO: get/put record length. */
|
||||
u_int32_t doff; /* RO: get/put record offset. */
|
||||
|
||||
#define DB_DBT_INTERNAL 0x01 /* Perform any mallocs using regular
|
||||
malloc, not the user's malloc. */
|
||||
#define DB_DBT_INTERNAL 0x01 /* Ignore user's malloc (internal). */
|
||||
#define DB_DBT_MALLOC 0x02 /* Return in allocated memory. */
|
||||
#define DB_DBT_PARTIAL 0x04 /* Partial put/get. */
|
||||
#define DB_DBT_USERMEM 0x08 /* Return in user's memory. */
|
||||
@ -130,38 +116,36 @@ struct __db_dbt {
|
||||
};
|
||||
|
||||
/*
|
||||
* DB internal configuration.
|
||||
* DB run-time interface configuration.
|
||||
*
|
||||
* There are a set of functions that the application can replace with its
|
||||
* own versions, and some other knobs which can be turned at run-time.
|
||||
*/
|
||||
#define DB_FUNC_CALLOC 1 /* DELETED: ANSI C calloc. */
|
||||
#define DB_FUNC_CLOSE 2 /* POSIX 1003.1 close. */
|
||||
#define DB_FUNC_DIRFREE 3 /* DB: free directory list. */
|
||||
#define DB_FUNC_DIRLIST 4 /* DB: create directory list. */
|
||||
#define DB_FUNC_EXISTS 5 /* DB: return if file exists. */
|
||||
#define DB_FUNC_FREE 6 /* ANSI C free. */
|
||||
#define DB_FUNC_FSYNC 7 /* POSIX 1003.1 fsync. */
|
||||
#define DB_FUNC_IOINFO 8 /* DB: return file I/O information. */
|
||||
#define DB_FUNC_MALLOC 9 /* ANSI C malloc. */
|
||||
#define DB_FUNC_MAP 10 /* DB: map file into shared memory. */
|
||||
#define DB_FUNC_OPEN 11 /* POSIX 1003.1 open. */
|
||||
#define DB_FUNC_READ 12 /* POSIX 1003.1 read. */
|
||||
#define DB_FUNC_REALLOC 13 /* ANSI C realloc. */
|
||||
#define DB_FUNC_CLOSE 1 /* POSIX 1003.1 close. */
|
||||
#define DB_FUNC_DIRFREE 2 /* DB: free directory list. */
|
||||
#define DB_FUNC_DIRLIST 3 /* DB: create directory list. */
|
||||
#define DB_FUNC_EXISTS 4 /* DB: return if file exists. */
|
||||
#define DB_FUNC_FREE 5 /* ANSI C free. */
|
||||
#define DB_FUNC_FSYNC 6 /* POSIX 1003.1 fsync. */
|
||||
#define DB_FUNC_IOINFO 7 /* DB: return file I/O information. */
|
||||
#define DB_FUNC_MALLOC 8 /* ANSI C malloc. */
|
||||
#define DB_FUNC_MAP 9 /* DB: map file into shared memory. */
|
||||
#define DB_FUNC_OPEN 10 /* POSIX 1003.1 open. */
|
||||
#define DB_FUNC_READ 11 /* POSIX 1003.1 read. */
|
||||
#define DB_FUNC_REALLOC 12 /* ANSI C realloc. */
|
||||
#define DB_FUNC_RUNLINK 13 /* DB: remove a shared region. */
|
||||
#define DB_FUNC_SEEK 14 /* POSIX 1003.1 lseek. */
|
||||
#define DB_FUNC_SLEEP 15 /* DB: sleep secs/usecs. */
|
||||
#define DB_FUNC_STRDUP 16 /* DELETED: DB: strdup(3). */
|
||||
#define DB_FUNC_UNLINK 17 /* POSIX 1003.1 unlink. */
|
||||
#define DB_FUNC_UNMAP 18 /* DB: unmap shared memory file. */
|
||||
#define DB_FUNC_WRITE 19 /* POSIX 1003.1 write. */
|
||||
#define DB_FUNC_YIELD 20 /* DB: yield thread to scheduler. */
|
||||
#define DB_TSL_SPINS 21 /* DB: initialize spin count. */
|
||||
#define DB_FUNC_RUNLINK 22 /* DB: remove a shared region. */
|
||||
#define DB_REGION_ANON 23 /* DB: anonymous, unnamed regions. */
|
||||
#define DB_REGION_INIT 24 /* DB: page-fault regions in create. */
|
||||
#define DB_REGION_NAME 25 /* DB: anonymous, named regions. */
|
||||
#define DB_MUTEXLOCKS 26 /* DB: turn off all mutex locks. */
|
||||
#define DB_PAGEYIELD 27 /* DB: yield the CPU on pool get. */
|
||||
#define DB_FUNC_UNLINK 16 /* POSIX 1003.1 unlink. */
|
||||
#define DB_FUNC_UNMAP 17 /* DB: unmap shared memory file. */
|
||||
#define DB_FUNC_WRITE 18 /* POSIX 1003.1 write. */
|
||||
#define DB_FUNC_YIELD 19 /* DB: yield thread to scheduler. */
|
||||
#define DB_MUTEXLOCKS 20 /* DB: turn off all mutex locks. */
|
||||
#define DB_PAGEYIELD 21 /* DB: yield the CPU on pool get. */
|
||||
#define DB_REGION_ANON 22 /* DB: anonymous, unnamed regions. */
|
||||
#define DB_REGION_INIT 23 /* DB: page-fault regions in create. */
|
||||
#define DB_REGION_NAME 24 /* DB: anonymous, named regions. */
|
||||
#define DB_TSL_SPINS 25 /* DB: initialize spin count. */
|
||||
|
||||
/*
|
||||
* Database configuration and initialization.
|
||||
@ -177,29 +161,18 @@ struct __db_dbt {
|
||||
* Flags understood by db_appinit(3).
|
||||
*/
|
||||
/* 0x000007 COMMON MASK. */
|
||||
#define DB_INIT_LOCK 0x000008 /* Initialize locking. */
|
||||
#define DB_INIT_LOG 0x000010 /* Initialize logging. */
|
||||
#define DB_INIT_MPOOL 0x000020 /* Initialize mpool. */
|
||||
#define DB_INIT_TXN 0x000040 /* Initialize transactions. */
|
||||
#define DB_MPOOL_PRIVATE 0x000080 /* Mpool: private memory pool. */
|
||||
#define __UNUSED_100 0x000100
|
||||
#define DB_INIT_CDB 0x000008 /* Concurrent Access Methods. */
|
||||
#define DB_INIT_LOCK 0x000010 /* Initialize locking. */
|
||||
#define DB_INIT_LOG 0x000020 /* Initialize logging. */
|
||||
#define DB_INIT_MPOOL 0x000040 /* Initialize mpool. */
|
||||
#define DB_INIT_TXN 0x000080 /* Initialize transactions. */
|
||||
#define DB_MPOOL_PRIVATE 0x000100 /* Mpool: private memory pool. */
|
||||
#define DB_RECOVER 0x000200 /* Run normal recovery. */
|
||||
#define DB_RECOVER_FATAL 0x000400 /* Run catastrophic recovery. */
|
||||
#define DB_TXN_NOSYNC 0x000800 /* Do not sync log on commit. */
|
||||
#define DB_USE_ENVIRON 0x001000 /* Use the environment. */
|
||||
#define DB_USE_ENVIRON_ROOT 0x002000 /* Use the environment if root. */
|
||||
|
||||
/* CURRENTLY UNUSED LOCK FLAGS. */
|
||||
#define DB_TXN_LOCK_2PL 0x000000 /* Two-phase locking. */
|
||||
#define DB_TXN_LOCK_OPTIMIST 0x000000 /* Optimistic locking. */
|
||||
#define DB_TXN_LOCK_MASK 0x000000 /* Lock flags mask. */
|
||||
|
||||
/* CURRENTLY UNUSED LOG FLAGS. */
|
||||
#define DB_TXN_LOG_REDO 0x000000 /* Redo-only logging. */
|
||||
#define DB_TXN_LOG_UNDO 0x000000 /* Undo-only logging. */
|
||||
#define DB_TXN_LOG_UNDOREDO 0x000000 /* Undo/redo write-ahead logging. */
|
||||
#define DB_TXN_LOG_MASK 0x000000 /* Log flags mask. */
|
||||
|
||||
/*
|
||||
* Flags understood by db_open(3).
|
||||
*
|
||||
@ -207,23 +180,22 @@ struct __db_dbt {
|
||||
* DB_SEQUENTIAL is currently internal, but may be exported some day.
|
||||
*/
|
||||
/* 0x000007 COMMON MASK. */
|
||||
/* 0x003fff ALREADY USED. */
|
||||
#define __UNUSED_4000 0x004000
|
||||
#define DB_EXCL 0x008000 /* O_EXCL: exclusive open. */
|
||||
#define DB_RDONLY 0x010000 /* O_RDONLY: read-only. */
|
||||
#define DB_SEQUENTIAL 0x020000 /* Indicate sequential access. */
|
||||
#define DB_TEMPORARY 0x040000 /* Remove on last close. */
|
||||
#define DB_TRUNCATE 0x080000 /* O_TRUNCATE: replace existing DB. */
|
||||
/* 0x001fff ALREADY USED. */
|
||||
#define DB_EXCL 0x002000 /* O_EXCL: exclusive open (internal). */
|
||||
#define DB_RDONLY 0x004000 /* O_RDONLY: read-only. */
|
||||
#define DB_SEQUENTIAL 0x008000 /* Sequential access (internal). */
|
||||
#define DB_TEMPORARY 0x010000 /* Remove on last close (internal). */
|
||||
#define DB_TRUNCATE 0x020000 /* O_TRUNCATE: replace existing DB. */
|
||||
|
||||
/*
|
||||
* Deadlock detector modes; used in the DBENV structure to configure the
|
||||
* locking subsystem.
|
||||
*/
|
||||
#define DB_LOCK_NORUN 0x0
|
||||
#define DB_LOCK_DEFAULT 0x1 /* Default policy. */
|
||||
#define DB_LOCK_OLDEST 0x2 /* Abort oldest transaction. */
|
||||
#define DB_LOCK_RANDOM 0x3 /* Abort random transaction. */
|
||||
#define DB_LOCK_YOUNGEST 0x4 /* Abort youngest transaction. */
|
||||
#define DB_LOCK_NORUN 0
|
||||
#define DB_LOCK_DEFAULT 1 /* Default policy. */
|
||||
#define DB_LOCK_OLDEST 2 /* Abort oldest transaction. */
|
||||
#define DB_LOCK_RANDOM 3 /* Abort random transaction. */
|
||||
#define DB_LOCK_YOUNGEST 4 /* Abort youngest transaction. */
|
||||
|
||||
struct __db_env {
|
||||
int db_lorder; /* Byte order. */
|
||||
@ -233,6 +205,8 @@ struct __db_env {
|
||||
FILE *db_errfile; /* Error message file stream. */
|
||||
const char *db_errpfx; /* Error message prefix. */
|
||||
int db_verbose; /* Generate debugging messages. */
|
||||
int db_panic; /* Panic flag, callback function. */
|
||||
void (*db_paniccall) __P((DB_ENV *, int));
|
||||
|
||||
/* User paths. */
|
||||
char *db_home; /* Database home. */
|
||||
@ -245,7 +219,7 @@ struct __db_env {
|
||||
|
||||
/* Locking. */
|
||||
DB_LOCKTAB *lk_info; /* Return from lock_open(). */
|
||||
u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */
|
||||
const u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */
|
||||
u_int32_t lk_modes; /* Number of lock modes in table. */
|
||||
u_int32_t lk_max; /* Maximum number of locks. */
|
||||
u_int32_t lk_detect; /* Deadlock detect on all conflicts. */
|
||||
@ -265,9 +239,25 @@ struct __db_env {
|
||||
int (*tx_recover) /* Dispatch function for recovery. */
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
|
||||
/*
|
||||
* XA support.
|
||||
*
|
||||
* !!!
|
||||
* Explicit representations of structures in queue.h.
|
||||
*
|
||||
* TAILQ_ENTRY(__db_env);
|
||||
*/
|
||||
struct {
|
||||
struct __db_env *tqe_next;
|
||||
struct __db_env **tqe_prev;
|
||||
} links;
|
||||
int xa_rmid; /* XA Resource Manager ID. */
|
||||
DB_TXN *xa_txn; /* XA Current transaction. */
|
||||
|
||||
#define DB_ENV_APPINIT 0x01 /* Paths initialized by db_appinit(). */
|
||||
#define DB_ENV_STANDALONE 0x02 /* Test: freestanding environment. */
|
||||
#define DB_ENV_THREAD 0x04 /* DB_ENV is multi-threaded. */
|
||||
#define DB_ENV_CDB 0x02 /* Concurrent DB product. */
|
||||
#define DB_ENV_STANDALONE 0x04 /* Test: freestanding environment. */
|
||||
#define DB_ENV_THREAD 0x08 /* DB_ENV is multi-threaded. */
|
||||
u_int32_t flags; /* Flags. */
|
||||
};
|
||||
|
||||
@ -275,7 +265,7 @@ struct __db_env {
|
||||
* Access methods.
|
||||
*******************************************************/
|
||||
/*
|
||||
* XXX
|
||||
* !!!
|
||||
* Changes here must be reflected in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
typedef enum {
|
||||
@ -304,6 +294,8 @@ struct __db_info {
|
||||
|
||||
/* Local heap allocation. */
|
||||
void *(*db_malloc) __P((size_t));
|
||||
int (*dup_compare) /* Duplicate compare function. */
|
||||
__P((const DBT *, const DBT *));
|
||||
|
||||
/* Btree access method. */
|
||||
u_int32_t bt_maxkey; /* Maximum keys per page. */
|
||||
@ -327,44 +319,51 @@ struct __db_info {
|
||||
|
||||
#define DB_DELIMITER 0x0001 /* Recno: re_delim set. */
|
||||
#define DB_DUP 0x0002 /* Btree, Hash: duplicate keys. */
|
||||
#define DB_FIXEDLEN 0x0004 /* Recno: fixed-length records. */
|
||||
#define DB_PAD 0x0008 /* Recno: re_pad set. */
|
||||
#define DB_RECNUM 0x0010 /* Btree: record numbers. */
|
||||
#define DB_RENUMBER 0x0020 /* Recno: renumber on insert/delete. */
|
||||
#define DB_SNAPSHOT 0x0040 /* Recno: snapshot the input. */
|
||||
#define DB_DUPSORT 0x0004 /* Btree, Hash: duplicate keys. */
|
||||
#define DB_FIXEDLEN 0x0008 /* Recno: fixed-length records. */
|
||||
#define DB_PAD 0x0010 /* Recno: re_pad set. */
|
||||
#define DB_RECNUM 0x0020 /* Btree: record numbers. */
|
||||
#define DB_RENUMBER 0x0040 /* Recno: renumber on insert/delete. */
|
||||
#define DB_SNAPSHOT 0x0080 /* Recno: snapshot the input. */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* DB access method and cursor operation codes. These are implemented as
|
||||
* bit fields for future flexibility, but currently only a single one may
|
||||
* be specified to any function.
|
||||
* DB access method and cursor operation values. Each value is an operation
|
||||
* code to which additional bit flags are added.
|
||||
*/
|
||||
#define DB_AFTER 0x000001 /* c_put() */
|
||||
#define DB_APPEND 0x000002 /* put() */
|
||||
#define DB_BEFORE 0x000004 /* c_put() */
|
||||
#define DB_CHECKPOINT 0x000008 /* log_put(), log_get() */
|
||||
#define DB_CURRENT 0x000010 /* c_get(), c_put(), log_get() */
|
||||
#define DB_FIRST 0x000020 /* c_get(), log_get() */
|
||||
#define DB_FLUSH 0x000040 /* log_put() */
|
||||
#define DB_GET_RECNO 0x000080 /* get(), c_get() */
|
||||
#define DB_KEYFIRST 0x000100 /* c_put() */
|
||||
#define DB_KEYLAST 0x000200 /* c_put() */
|
||||
#define DB_LAST 0x000400 /* c_get(), log_get() */
|
||||
#define DB_NEXT 0x000800 /* c_get(), log_get() */
|
||||
#define DB_NOOVERWRITE 0x001000 /* put() */
|
||||
#define DB_NOSYNC 0x002000 /* close() */
|
||||
#define DB_PREV 0x004000 /* c_get(), log_get() */
|
||||
#define DB_RECORDCOUNT 0x008000 /* stat() */
|
||||
#define DB_SET 0x010000 /* c_get(), log_get() */
|
||||
#define DB_SET_RANGE 0x020000 /* c_get() */
|
||||
#define DB_SET_RECNO 0x040000 /* c_get() */
|
||||
#define DB_CURLSN 0x080000 /* log_put() */
|
||||
#define DB_AFTER 1 /* c_put() */
|
||||
#define DB_APPEND 2 /* put() */
|
||||
#define DB_BEFORE 3 /* c_put() */
|
||||
#define DB_CHECKPOINT 4 /* log_put(), log_get() */
|
||||
#define DB_CURLSN 5 /* log_put() */
|
||||
#define DB_CURRENT 6 /* c_get(), c_put(), log_get() */
|
||||
#define DB_FIRST 7 /* c_get(), log_get() */
|
||||
#define DB_FLUSH 8 /* log_put() */
|
||||
#define DB_GET_BOTH 9 /* get(), c_get() */
|
||||
#define DB_GET_RECNO 10 /* c_get() */
|
||||
#define DB_JOIN_ITEM 11 /* c_get(); do not do primary lookup */
|
||||
#define DB_KEYFIRST 12 /* c_put() */
|
||||
#define DB_KEYLAST 13 /* c_put() */
|
||||
#define DB_LAST 14 /* c_get(), log_get() */
|
||||
#define DB_NEXT 15 /* c_get(), log_get() */
|
||||
#define DB_NEXT_DUP 16 /* c_get() */
|
||||
#define DB_NOOVERWRITE 17 /* put() */
|
||||
#define DB_NOSYNC 18 /* close() */
|
||||
#define DB_PREV 19 /* c_get(), log_get() */
|
||||
#define DB_RECORDCOUNT 20 /* stat() */
|
||||
#define DB_SET 21 /* c_get(), log_get() */
|
||||
#define DB_SET_RANGE 22 /* c_get() */
|
||||
#define DB_SET_RECNO 23 /* get(), c_get() */
|
||||
#define DB_WRITELOCK 24 /* cursor() (internal) */
|
||||
|
||||
#define DB_OPFLAGS_MASK 0x1f /* Mask for operations flags. */
|
||||
#define DB_RMW 0x80000000 /* Acquire write flag immediately. */
|
||||
|
||||
/*
|
||||
* DB (user visible) error return codes.
|
||||
*
|
||||
* XXX
|
||||
* !!!
|
||||
* Changes to any of the user visible error return codes must be reflected
|
||||
* in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
@ -376,93 +375,84 @@ struct __db_info {
|
||||
#define DB_LOCK_NOTGRANTED ( -5) /* Lock unavailable, no-wait set. */
|
||||
#define DB_LOCK_NOTHELD ( -6) /* Lock not held by locker. */
|
||||
#define DB_NOTFOUND ( -7) /* Key/data pair not found (EOF). */
|
||||
#define DB_RUNRECOVERY ( -8) /* Panic return. */
|
||||
|
||||
/* DB (private) error return codes. */
|
||||
#define DB_DELETED ( -8) /* Recovery file marked deleted. */
|
||||
#define DB_NEEDSPLIT ( -9) /* Page needs to be split. */
|
||||
#define DB_REGISTERED (-10) /* Entry was previously registered. */
|
||||
#define DB_DELETED ( -9) /* Recovery file marked deleted. */
|
||||
#define DB_NEEDSPLIT (-10) /* Page needs to be split. */
|
||||
#define DB_SWAPBYTES (-11) /* Database needs byte swapping. */
|
||||
#define DB_TXN_CKP (-12) /* Encountered ckp record in log. */
|
||||
#define DB_TXN_CKP (-12) /* Encountered ckp record in log. */
|
||||
|
||||
struct __db_ilock { /* Internal DB access method lock. */
|
||||
db_pgno_t pgno; /* Page being locked. */
|
||||
/* File id. */
|
||||
u_int8_t fileid[DB_FILE_ID_LEN];
|
||||
};
|
||||
#define DB_FILE_ID_LEN 20 /* DB file ID length. */
|
||||
|
||||
/* DB access method description structure. */
|
||||
struct __db {
|
||||
void *mutexp; /* Synchronization for free threading */
|
||||
|
||||
/* Documented, returned information. */
|
||||
DBTYPE type; /* DB access method. */
|
||||
int byteswapped; /* Database byte order is swapped. */
|
||||
|
||||
DB_ENV *dbenv; /* DB_ENV structure. */
|
||||
DB_ENV *mp_dbenv; /* DB_ENV for local mpool creation. */
|
||||
|
||||
DB *master; /* Original DB created by db_open. */
|
||||
void *internal; /* Access method private. */
|
||||
|
||||
DB_MPOOL *mp; /* The access method's mpool. */
|
||||
DB_MPOOLFILE *mpf; /* The access method's mpool file. */
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* !!!
|
||||
* Explicit representations of structures in queue.h.
|
||||
*
|
||||
* TAILQ_HEAD(curs_queue, __dbc);
|
||||
* TAILQ_HEAD(free_queue, __dbc);
|
||||
* TAILQ_HEAD(active_queue, __dbc);
|
||||
*/
|
||||
struct {
|
||||
struct __dbc *tqh_first;
|
||||
struct __dbc **tqh_last;
|
||||
} curs_queue;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Explicit representations of structures in queue.h.
|
||||
*
|
||||
* LIST_HEAD(handleq, __db);
|
||||
* LIST_ENTRY(__db);
|
||||
*/
|
||||
} free_queue;
|
||||
struct {
|
||||
struct __db *lh_first;
|
||||
} handleq; /* List of handles for this DB. */
|
||||
struct {
|
||||
struct __db *le_next;
|
||||
struct __db **le_prev;
|
||||
} links; /* Links for the handle list. */
|
||||
struct __dbc *tqh_first;
|
||||
struct __dbc **tqh_last;
|
||||
} active_queue;
|
||||
|
||||
u_int8_t fileid[DB_FILE_ID_LEN]; /* Uniquely identify this file for
|
||||
locking. */
|
||||
u_int32_t log_fileid; /* Logging file id. */
|
||||
|
||||
DB_TXN *txn; /* Current transaction. */
|
||||
u_int32_t locker; /* Default process' locker id. */
|
||||
DBT lock_dbt; /* DBT referencing lock. */
|
||||
struct __db_ilock lock; /* Lock. */
|
||||
|
||||
size_t pgsize; /* Logical page size of file. */
|
||||
|
||||
/* Local heap allocation. */
|
||||
void *(*db_malloc) __P((size_t));
|
||||
int (*dup_compare) /* Duplicate compare function. */
|
||||
__P((const DBT *, const DBT *));
|
||||
u_int32_t (*h_hash) /* Hash function. */
|
||||
__P((const void *, u_int32_t));
|
||||
|
||||
/* Functions. */
|
||||
int (*am_close) __P((DB *));
|
||||
int (*close) __P((DB *, u_int32_t));
|
||||
int (*cursor) __P((DB *, DB_TXN *, DBC **));
|
||||
int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t));
|
||||
int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t));
|
||||
int (*fd) __P((DB *, int *));
|
||||
int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
int (*join) __P((DB *, DBC **, u_int32_t, DBC **));
|
||||
int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
int (*stat) __P((DB *, void *, void *(*)(size_t), u_int32_t));
|
||||
int (*sync) __P((DB *, u_int32_t));
|
||||
|
||||
#define DB_AM_DUP 0x000001 /* DB_DUP (internal). */
|
||||
#define DB_AM_INMEM 0x000002 /* In-memory; no sync on close. */
|
||||
#define DB_AM_LOCKING 0x000004 /* Perform locking. */
|
||||
#define DB_AM_LOGGING 0x000008 /* Perform logging. */
|
||||
#define DB_AM_MLOCAL 0x000010 /* Database memory pool is local. */
|
||||
#define DB_AM_PGDEF 0x000020 /* Page size was defaulted. */
|
||||
#define DB_AM_RDONLY 0x000040 /* Database is readonly. */
|
||||
#define DB_AM_RECOVER 0x000080 /* In recovery (do not log or lock). */
|
||||
#define DB_AM_CDB 0x000001 /* Concurrent Access Methods. */
|
||||
#define DB_AM_DUP 0x000002 /* DB_DUP (internal). */
|
||||
#define DB_AM_INMEM 0x000004 /* In-memory; no sync on close. */
|
||||
#define DB_AM_LOCKING 0x000008 /* Perform locking. */
|
||||
#define DB_AM_LOGGING 0x000010 /* Perform logging. */
|
||||
#define DB_AM_MLOCAL 0x000020 /* Database memory pool is local. */
|
||||
#define DB_AM_PGDEF 0x000040 /* Page size was defaulted. */
|
||||
#define DB_AM_RDONLY 0x000080 /* Database is readonly. */
|
||||
#define DB_AM_SWAP 0x000100 /* Pages need to be byte-swapped. */
|
||||
#define DB_AM_THREAD 0x000200 /* DB is multi-threaded. */
|
||||
#define DB_BT_RECNUM 0x000400 /* DB_RECNUM (internal) */
|
||||
#define DB_HS_DIRTYMETA 0x000800 /* Hash: Metadata page modified. */
|
||||
#define DB_BT_RECNUM 0x000400 /* DB_RECNUM (internal). */
|
||||
#define DB_DBM_ERROR 0x000800 /* Error in DBM/NDBM database. */
|
||||
#define DB_RE_DELIMITER 0x001000 /* DB_DELIMITER (internal). */
|
||||
#define DB_RE_FIXEDLEN 0x002000 /* DB_FIXEDLEN (internal). */
|
||||
#define DB_RE_PAD 0x004000 /* DB_PAD (internal). */
|
||||
@ -471,13 +461,18 @@ struct __db {
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
struct __db_ilock { /* Internal DB access method lock. */
|
||||
db_pgno_t pgno; /* Page being locked. */
|
||||
u_int8_t fileid[DB_FILE_ID_LEN];/* File id. */
|
||||
};
|
||||
|
||||
/* Cursor description structure. */
|
||||
struct __dbc {
|
||||
DB *dbp; /* Related DB access method. */
|
||||
DB_TXN *txn; /* Associated transaction. */
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* !!!
|
||||
* Explicit representations of structures in queue.h.
|
||||
*
|
||||
* TAILQ_ENTRY(__dbc);
|
||||
@ -487,12 +482,30 @@ struct __dbc {
|
||||
struct __dbc **tqe_prev;
|
||||
} links;
|
||||
|
||||
u_int32_t lid; /* Default process' locker id. */
|
||||
u_int32_t locker; /* Locker for this operation. */
|
||||
DBT lock_dbt; /* DBT referencing lock. */
|
||||
DB_LOCK_ILOCK lock; /* Object to be locked. */
|
||||
DB_LOCK mylock; /* Lock held on this cursor. */
|
||||
|
||||
DBT rkey; /* Returned key. */
|
||||
DBT rdata; /* Returned data. */
|
||||
|
||||
int (*c_am_close) __P((DBC *));
|
||||
int (*c_am_destroy) __P((DBC *));
|
||||
int (*c_close) __P((DBC *));
|
||||
int (*c_del) __P((DBC *, u_int32_t));
|
||||
int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
|
||||
void *internal; /* Access method private. */
|
||||
|
||||
int (*c_close) __P((DBC *));
|
||||
int (*c_del) __P((DBC *, u_int32_t));
|
||||
int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
#define DBC_CONTINUE 0x001 /* Continue dup search: next item. */
|
||||
#define DBC_KEYSET 0x002 /* Continue dup search: current item. */
|
||||
#define DBC_RECOVER 0x004 /* In recovery (do not log or lock). */
|
||||
#define DBC_RMW 0x008 /* Acquire write flag in read op. */
|
||||
#define DBC_WRITER 0x010 /* Cursor immediately writing (CDB). */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/* Btree/recno statistics structure. */
|
||||
@ -510,24 +523,36 @@ struct __db_bt_stat {
|
||||
u_int32_t bt_dup_pg; /* Duplicate pages. */
|
||||
u_int32_t bt_over_pg; /* Overflow pages. */
|
||||
u_int32_t bt_free; /* Pages on the free list. */
|
||||
u_int32_t bt_freed; /* Pages freed for reuse. */
|
||||
u_int32_t bt_int_pgfree; /* Bytes free in internal pages. */
|
||||
u_int32_t bt_leaf_pgfree; /* Bytes free in leaf pages. */
|
||||
u_int32_t bt_dup_pgfree; /* Bytes free in duplicate pages. */
|
||||
u_int32_t bt_over_pgfree; /* Bytes free in overflow pages. */
|
||||
u_int32_t bt_pfxsaved; /* Bytes saved by prefix compression. */
|
||||
u_int32_t bt_split; /* Total number of splits. */
|
||||
u_int32_t bt_rootsplit; /* Root page splits. */
|
||||
u_int32_t bt_fastsplit; /* Fast splits. */
|
||||
u_int32_t bt_added; /* Items added. */
|
||||
u_int32_t bt_deleted; /* Items deleted. */
|
||||
u_int32_t bt_get; /* Items retrieved. */
|
||||
u_int32_t bt_cache_hit; /* Hits in fast-insert code. */
|
||||
u_int32_t bt_cache_miss; /* Misses in fast-insert code. */
|
||||
u_int32_t bt_magic; /* Magic number. */
|
||||
u_int32_t bt_version; /* Version number. */
|
||||
};
|
||||
|
||||
/* Hash statistics structure. */
|
||||
struct __db_h_stat {
|
||||
u_int32_t hash_accesses; /* Number of accesses to this table. */
|
||||
u_int32_t hash_collisions; /* Number of collisions on search. */
|
||||
u_int32_t hash_expansions; /* Number of times we added a bucket. */
|
||||
u_int32_t hash_overflows; /* Number of overflow pages. */
|
||||
u_int32_t hash_bigpages; /* Number of big key/data pages. */
|
||||
u_int32_t hash_dup; /* Number of dup pages. */
|
||||
u_int32_t hash_free; /* Pages on the free list. */
|
||||
u_int32_t hash_bfree; /* Bytes free on bucket pages. */
|
||||
u_int32_t hash_dup_free; /* Bytes free on duplicate pages. */
|
||||
u_int32_t hash_big_bfree; /* Bytes free on big item pages. */
|
||||
u_int32_t hash_buckets; /* Number of hash buckets. */
|
||||
u_int32_t hash_put; /* Number of puts. */
|
||||
u_int32_t hash_deleted; /* Number of deletes. */
|
||||
u_int32_t hash_get; /* Number of gets. */
|
||||
u_int32_t hash_magic; /* Magic number. */
|
||||
u_int32_t hash_version; /* Version number. */
|
||||
u_int32_t hash_pagesize; /* Page size. */
|
||||
u_int32_t hash_nrecs; /* Number of records. */
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -538,6 +563,8 @@ int db_open __P((const char *,
|
||||
DBTYPE, u_int32_t, int, DB_ENV *, DB_INFO *, DB **));
|
||||
int db_value_set __P((int, int));
|
||||
char *db_version __P((int *, int *, int *));
|
||||
int db_xa_open __P((const char *,
|
||||
DBTYPE, u_int32_t, int, DB_INFO *, DB **));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@ -548,8 +575,10 @@ char *db_version __P((int *, int *, int *));
|
||||
#define DB_LOCKVERSION 1
|
||||
#define DB_LOCKMAGIC 0x090193
|
||||
|
||||
/* Flag values for lock_vec(). */
|
||||
/* Flag values for lock_vec(), lock_get(). */
|
||||
#define DB_LOCK_NOWAIT 0x01 /* Don't wait on unavailable lock. */
|
||||
#define DB_LOCK_UPGRADE 0x02 /* Upgrade an existing lock instead
|
||||
of granting a new one (internal). */
|
||||
|
||||
/* Flag values for lock_detect(). */
|
||||
#define DB_LOCK_CONFLICT 0x01 /* Run on any conflict. */
|
||||
@ -557,12 +586,13 @@ char *db_version __P((int *, int *, int *));
|
||||
/*
|
||||
* Request types.
|
||||
*
|
||||
* XXX
|
||||
* !!!
|
||||
* Changes here must be reflected in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
typedef enum {
|
||||
DB_LOCK_DUMP=0, /* Display held locks. */
|
||||
DB_LOCK_GET, /* Get the lock. */
|
||||
DB_LOCK_INHERIT, /* Pass locks to parent. */
|
||||
DB_LOCK_PUT, /* Release the lock. */
|
||||
DB_LOCK_PUT_ALL, /* Release locker's locks. */
|
||||
DB_LOCK_PUT_OBJ /* Release locker's locks on obj. */
|
||||
@ -571,15 +601,20 @@ typedef enum {
|
||||
/*
|
||||
* Simple R/W lock modes and for multi-granularity intention locking.
|
||||
*
|
||||
* XXX
|
||||
* !!!
|
||||
* These values are NOT random, as they are used as an index into the lock
|
||||
* conflicts arrays, i.e., DB_LOCK_IWRITE must be == 3, and DB_LOCK_IREAD
|
||||
* must be == 4.
|
||||
*
|
||||
* !!!
|
||||
* Changes here must be reflected in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
typedef enum {
|
||||
DB_LOCK_NG=0, /* Not granted. */
|
||||
DB_LOCK_READ, /* Shared/read. */
|
||||
DB_LOCK_WRITE, /* Exclusive/write. */
|
||||
DB_LOCK_IREAD, /* Intent to share/read. */
|
||||
DB_LOCK_IWRITE, /* Intent exclusive/write. */
|
||||
DB_LOCK_IREAD, /* Intent to share/read. */
|
||||
DB_LOCK_IWR /* Intent to read and write. */
|
||||
} db_lockmode_t;
|
||||
|
||||
@ -647,10 +682,14 @@ int lock_id __P((DB_LOCKTAB *, u_int32_t *));
|
||||
int lock_open __P((const char *,
|
||||
u_int32_t, int, DB_ENV *, DB_LOCKTAB **));
|
||||
int lock_put __P((DB_LOCKTAB *, DB_LOCK));
|
||||
int lock_tget __P((DB_LOCKTAB *,
|
||||
DB_TXN *, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *));
|
||||
int lock_stat __P((DB_LOCKTAB *, DB_LOCK_STAT **, void *(*)(size_t)));
|
||||
int lock_unlink __P((const char *, int, DB_ENV *));
|
||||
int lock_vec __P((DB_LOCKTAB *,
|
||||
u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
|
||||
int lock_tvec __P((DB_LOCKTAB *,
|
||||
DB_TXN *, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@ -890,6 +929,7 @@ typedef struct {
|
||||
* 4BSD replaced the dbm interface with ndbm, and are not support here.
|
||||
*/
|
||||
#define dbminit(a) __db_dbm_init(a)
|
||||
#define dbmclose __db_dbm_close
|
||||
#if !defined(__cplusplus)
|
||||
#define delete(a) __db_dbm_delete(a)
|
||||
#endif
|
||||
@ -902,12 +942,13 @@ typedef struct {
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int __db_dbm_init __P((char *));
|
||||
int __db_dbm_delete __P((datum));
|
||||
int __db_dbm_close __P((void));
|
||||
int __db_dbm_dbrdonly __P((void));
|
||||
int __db_dbm_delete __P((datum));
|
||||
int __db_dbm_dirf __P((void));
|
||||
datum __db_dbm_fetch __P((datum));
|
||||
datum __db_dbm_firstkey __P((void));
|
||||
int __db_dbm_init __P((char *));
|
||||
datum __db_dbm_nextkey __P((datum));
|
||||
int __db_dbm_pagf __P((void));
|
||||
int __db_dbm_store __P((datum, datum));
|
||||
|
311
db2/db/db.c
311
db2/db/db.c
@ -44,7 +44,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db.c 10.57 (Sleepycat) 5/7/98";
|
||||
static const char sccsid[] = "@(#)db.c 10.75 (Sleepycat) 12/3/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -67,9 +67,6 @@ static const char sccsid[] = "@(#)db.c 10.57 (Sleepycat) 5/7/98";
|
||||
#include "db_am.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
static int db_close __P((DB *, u_int32_t));
|
||||
static int db_fd __P((DB *, int *));
|
||||
|
||||
/*
|
||||
* If the metadata page has the flag set, set the local flag. If the page
|
||||
* does NOT have the flag set, return EINVAL if the user's dbinfo argument
|
||||
@ -87,11 +84,6 @@ static int db_fd __P((DB *, int *));
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
#define db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp) \
|
||||
__nss_db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* db_open --
|
||||
* Main library interface to the DB access methods.
|
||||
@ -141,9 +133,10 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
|
||||
|
||||
/*
|
||||
* Specifying a cachesize to db_open(3), after creating an
|
||||
* environment, is a common mistake.
|
||||
* environment with DB_INIT_MPOOL, is a common mistake.
|
||||
*/
|
||||
if (dbinfo != NULL && dbinfo->db_cachesize != 0) {
|
||||
if (dbenv->mp_info != NULL &&
|
||||
dbinfo != NULL && dbinfo->db_cachesize != 0) {
|
||||
__db_err(dbenv,
|
||||
"cachesize will be ignored if environment exists");
|
||||
return (EINVAL);
|
||||
@ -156,12 +149,16 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
|
||||
real_name = NULL;
|
||||
|
||||
/* Allocate the DB structure, reference the DB_ENV structure. */
|
||||
if ((dbp = (DB *)__db_calloc(1, sizeof(DB))) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
return (ENOMEM);
|
||||
}
|
||||
if ((ret = __os_calloc(1, sizeof(DB), &dbp)) != 0)
|
||||
return (ret);
|
||||
dbp->dbenv = dbenv;
|
||||
|
||||
/* Random initialization. */
|
||||
TAILQ_INIT(&dbp->free_queue);
|
||||
TAILQ_INIT(&dbp->active_queue);
|
||||
if ((ret = __db_init_wrapper(dbp)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Convert the db_open(3) flags. */
|
||||
if (LF_ISSET(DB_RDONLY))
|
||||
F_SET(dbp, DB_AM_RDONLY);
|
||||
@ -191,22 +188,17 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
|
||||
F_SET(dbp, DB_RE_SNAPSHOT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Always set the master and initialize the queues, so we can
|
||||
* use these fields without checking the thread bit.
|
||||
*/
|
||||
dbp->master = dbp;
|
||||
LIST_INIT(&dbp->handleq);
|
||||
LIST_INSERT_HEAD(&dbp->handleq, dbp, links);
|
||||
TAILQ_INIT(&dbp->curs_queue);
|
||||
|
||||
/*
|
||||
* Set based on the dbenv fields, although no logging or transactions
|
||||
* are possible for temporary files.
|
||||
*/
|
||||
if (dbenv != NULL) {
|
||||
if (dbenv->lk_info != NULL)
|
||||
F_SET(dbp, DB_AM_LOCKING);
|
||||
if (dbenv->lk_info != NULL) {
|
||||
if (F_ISSET(dbenv, DB_ENV_CDB))
|
||||
F_SET(dbp, DB_AM_CDB);
|
||||
else
|
||||
F_SET(dbp, DB_AM_LOCKING);
|
||||
}
|
||||
if (fname != NULL && dbenv->lg_info != NULL)
|
||||
F_SET(dbp, DB_AM_LOGGING);
|
||||
}
|
||||
@ -215,9 +207,29 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
|
||||
if (dbinfo == NULL) {
|
||||
dbp->pgsize = 0;
|
||||
dbp->db_malloc = NULL;
|
||||
dbp->dup_compare = NULL;
|
||||
} else {
|
||||
/*
|
||||
* We don't want anything that's not a power-of-2, as we rely
|
||||
* on that for alignment of various types on the pages.
|
||||
*/
|
||||
if ((dbp->pgsize = dbinfo->db_pagesize) != 0 &&
|
||||
(u_int32_t)1 << __db_log2(dbp->pgsize) != dbp->pgsize) {
|
||||
__db_err(dbenv, "page sizes must be a power-of-2");
|
||||
goto einval;
|
||||
}
|
||||
dbp->pgsize = dbinfo->db_pagesize;
|
||||
dbp->db_malloc = dbinfo->db_malloc;
|
||||
if (F_ISSET(dbinfo, DB_DUPSORT)) {
|
||||
if (F_ISSET(dbinfo, DB_DUP))
|
||||
dbp->dup_compare = dbinfo->dup_compare == NULL ?
|
||||
__bam_defcmp : dbinfo->dup_compare;
|
||||
else {
|
||||
__db_err(dbenv, "DB_DUPSORT requires DB_DUP");
|
||||
goto einval;
|
||||
}
|
||||
F_CLR(dbinfo, DB_DUPSORT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in the default file mode. */
|
||||
@ -235,6 +247,7 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
dbp->byteswapped = F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* If we have a file name, try and read the first page, figure out
|
||||
@ -289,7 +302,7 @@ open_retry: if (LF_ISSET(DB_CREATE)) {
|
||||
* sizes, we limit the default pagesize to 16K.
|
||||
*/
|
||||
if (dbp->pgsize == 0) {
|
||||
if ((ret = __db_ioinfo(real_name,
|
||||
if ((ret = __os_ioinfo(real_name,
|
||||
fd, NULL, NULL, &iopsize)) != 0) {
|
||||
__db_err(dbenv,
|
||||
"%s: %s", real_name, strerror(ret));
|
||||
@ -299,6 +312,14 @@ open_retry: if (LF_ISSET(DB_CREATE)) {
|
||||
iopsize = 512;
|
||||
if (iopsize > 16 * 1024)
|
||||
iopsize = 16 * 1024;
|
||||
|
||||
/*
|
||||
* Sheer paranoia, but we don't want anything that's
|
||||
* not a power-of-2, as we rely on that for alignment
|
||||
* of various types on the pages.
|
||||
*/
|
||||
DB_ROUNDOFF(iopsize, 512);
|
||||
|
||||
dbp->pgsize = iopsize;
|
||||
F_SET(dbp, DB_AM_PGDEF);
|
||||
}
|
||||
@ -308,11 +329,11 @@ open_retry: if (LF_ISSET(DB_CREATE)) {
|
||||
* that the meta-data for all access methods fits in 512
|
||||
* bytes, and that no database will be smaller than that.
|
||||
*/
|
||||
if ((ret = __db_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)
|
||||
if ((ret = __os_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)
|
||||
goto err;
|
||||
|
||||
/* The fd is no longer needed. */
|
||||
(void)__db_close(fd);
|
||||
(void)__os_close(fd);
|
||||
fd = -1;
|
||||
|
||||
if (nr != sizeof(mbuf)) {
|
||||
@ -337,7 +358,7 @@ open_retry: if (LF_ISSET(DB_CREATE)) {
|
||||
*/
|
||||
if (retry_cnt++ < 3 &&
|
||||
!LF_ISSET(DB_CREATE | DB_TRUNCATE)) {
|
||||
__db_sleep(1, 0);
|
||||
__os_sleep(1, 0);
|
||||
goto open_retry;
|
||||
}
|
||||
if (type == DB_UNKNOWN) {
|
||||
@ -396,7 +417,7 @@ retry: switch (((BTMETA *)mbuf)->magic) {
|
||||
|
||||
/* Copy the file's unique id. */
|
||||
need_fileid = 0;
|
||||
memcpy(dbp->lock.fileid, btm->uid, DB_FILE_ID_LEN);
|
||||
memcpy(dbp->fileid, btm->uid, DB_FILE_ID_LEN);
|
||||
break;
|
||||
case DB_HASHMAGIC:
|
||||
if (type != DB_HASH && type != DB_UNKNOWN)
|
||||
@ -425,7 +446,7 @@ retry: switch (((BTMETA *)mbuf)->magic) {
|
||||
|
||||
/* Copy the file's unique id. */
|
||||
need_fileid = 0;
|
||||
memcpy(dbp->lock.fileid, hashm->uid, DB_FILE_ID_LEN);
|
||||
memcpy(dbp->fileid, hashm->uid, DB_FILE_ID_LEN);
|
||||
break;
|
||||
default:
|
||||
if (swapped) {
|
||||
@ -489,11 +510,9 @@ empty: /*
|
||||
F_SET(dbp, DB_AM_MLOCAL);
|
||||
|
||||
if (dbenv == NULL) {
|
||||
if ((dbp->mp_dbenv =
|
||||
(DB_ENV *)__db_calloc(sizeof(DB_ENV), 1)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_calloc(1,
|
||||
sizeof(DB_ENV), &dbp->mp_dbenv)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
envp = dbp->mp_dbenv;
|
||||
restore = 0;
|
||||
@ -554,20 +573,20 @@ empty: /*
|
||||
*/
|
||||
if (need_fileid) {
|
||||
if (fname == NULL) {
|
||||
memset(dbp->lock.fileid, 0, DB_FILE_ID_LEN);
|
||||
memset(dbp->fileid, 0, DB_FILE_ID_LEN);
|
||||
if (F_ISSET(dbp, DB_AM_LOCKING) &&
|
||||
(ret = lock_id(dbenv->lk_info,
|
||||
(u_int32_t *)dbp->lock.fileid)) != 0)
|
||||
(u_int32_t *)dbp->fileid)) != 0)
|
||||
goto err;
|
||||
} else
|
||||
if ((ret = __db_fileid(dbenv,
|
||||
real_name, 1, dbp->lock.fileid)) != 0)
|
||||
if ((ret = __os_fileid(dbenv,
|
||||
real_name, 1, dbp->fileid)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* No further use for the real name. */
|
||||
if (real_name != NULL)
|
||||
FREES(real_name);
|
||||
__os_freestr(real_name);
|
||||
real_name = NULL;
|
||||
|
||||
/*
|
||||
@ -595,7 +614,7 @@ empty: /*
|
||||
memset(&finfo, 0, sizeof(finfo));
|
||||
finfo.ftype = ftype;
|
||||
finfo.pgcookie = &pgcookie;
|
||||
finfo.fileid = dbp->lock.fileid;
|
||||
finfo.fileid = dbp->fileid;
|
||||
finfo.lsn_offset = 0;
|
||||
finfo.clear_len = DB_PAGE_CLEAR_LEN;
|
||||
if ((ret = memp_fopen(dbp->mp, fname,
|
||||
@ -605,12 +624,21 @@ empty: /*
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Truly spectacular layering violation. We need a per-thread mutex
|
||||
* that lives in shared memory (thanks, HP-UX!) and so we acquire a
|
||||
* pointer to the mpool one.
|
||||
* We need a per-thread mutex that lives in shared memory -- HP-UX
|
||||
* can't allocate mutexes in malloc'd memory. Allocate it from the
|
||||
* shared memory region, since it's the only one that is guaranteed
|
||||
* to exist.
|
||||
*/
|
||||
if (F_ISSET(dbp, DB_AM_THREAD))
|
||||
dbp->mutexp = dbp->mpf->mutexp;
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) {
|
||||
if ((ret = __memp_reg_alloc(dbp->mp,
|
||||
sizeof(db_mutex_t), NULL, &dbp->mutexp)) != 0)
|
||||
goto err;
|
||||
/*
|
||||
* Since we only get here if DB_THREAD was specified, we know
|
||||
* we have spinlocks and no file offset argument is needed.
|
||||
*/
|
||||
(void)__db_mutex_init(dbp->mutexp, 0);
|
||||
}
|
||||
|
||||
/* Get a log file id. */
|
||||
if (F_ISSET(dbp, DB_AM_LOGGING) &&
|
||||
@ -618,18 +646,6 @@ empty: /*
|
||||
dbp, fname, type, &dbp->log_fileid)) != 0)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Get a locker id for this DB, and build the lock cookie: the first
|
||||
* db_pgno_t bytes are the page number, the next N bytes are the file
|
||||
* id.
|
||||
*/
|
||||
if (F_ISSET(dbp, DB_AM_LOCKING)) {
|
||||
if ((ret = lock_id(dbenv->lk_info, &dbp->locker)) != 0)
|
||||
goto err;
|
||||
dbp->lock_dbt.size = sizeof(dbp->lock);
|
||||
dbp->lock_dbt.data = &dbp->lock;
|
||||
}
|
||||
|
||||
/* Call the real open function. */
|
||||
switch (type) {
|
||||
case DB_BTREE:
|
||||
@ -639,7 +655,7 @@ empty: /*
|
||||
if (dbinfo != NULL && (ret = __db_fcchk(dbenv,
|
||||
"db_open", dbinfo->flags, DB_DUP, DB_RECNUM)) != 0)
|
||||
goto err;
|
||||
if ((ret = __bam_open(dbp, type, dbinfo)) != 0)
|
||||
if ((ret = __bam_open(dbp, dbinfo)) != 0)
|
||||
goto err;
|
||||
break;
|
||||
case DB_HASH:
|
||||
@ -655,24 +671,20 @@ empty: /*
|
||||
if (dbinfo != NULL && (ret = __db_fchk(dbenv,
|
||||
"db_open", dbinfo->flags, DB_INFO_FLAGS)) != 0)
|
||||
goto err;
|
||||
if ((ret = __ram_open(dbp, type, dbinfo)) != 0)
|
||||
if ((ret = __ram_open(dbp, dbinfo)) != 0)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Call a local close routine. */
|
||||
dbp->close = db_close;
|
||||
dbp->fd = db_fd;
|
||||
|
||||
*dbpp = dbp;
|
||||
return (0);
|
||||
|
||||
einval: ret = EINVAL;
|
||||
err: /* Close the file descriptor. */
|
||||
if (fd != -1)
|
||||
(void)__db_close(fd);
|
||||
(void)__os_close(fd);
|
||||
|
||||
/* Discard the log file id. */
|
||||
if (dbp->log_fileid != 0)
|
||||
@ -688,90 +700,60 @@ err: /* Close the file descriptor. */
|
||||
|
||||
/* If we allocated a DB_ENV, discard it. */
|
||||
if (dbp->mp_dbenv != NULL)
|
||||
FREE(dbp->mp_dbenv, sizeof(DB_ENV));
|
||||
__os_free(dbp->mp_dbenv, sizeof(DB_ENV));
|
||||
|
||||
if (real_name != NULL)
|
||||
FREES(real_name);
|
||||
__os_freestr(real_name);
|
||||
if (dbp != NULL)
|
||||
FREE(dbp, sizeof(DB));
|
||||
__os_free(dbp, sizeof(DB));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
# undef db_open
|
||||
weak_alias (__nss_db_open, db_open)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* db_close --
|
||||
* __db_close --
|
||||
* Close a DB tree.
|
||||
*
|
||||
* PUBLIC: int __db_close __P((DB *, u_int32_t));
|
||||
*/
|
||||
static int
|
||||
db_close(dbp, flags)
|
||||
int
|
||||
__db_close(dbp, flags)
|
||||
DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DBC *dbc;
|
||||
DB *tdbp;
|
||||
int ret, t_ret;
|
||||
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((ret = __db_fchk(dbp->dbenv, "db_close", flags, DB_NOSYNC)) != 0)
|
||||
if ((ret = __db_closechk(dbp, flags)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Sync the underlying file. */
|
||||
if (!LF_ISSET(DB_NOSYNC) &&
|
||||
if (flags != DB_NOSYNC &&
|
||||
(t_ret = dbp->sync(dbp, 0)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
/*
|
||||
* Call the underlying access method close routine for all the
|
||||
* cursors and handles.
|
||||
* Go through the active cursors and call the cursor recycle routine,
|
||||
* which resolves pending operations and moves the cursors onto the
|
||||
* free list. Then, walk the free list and call the cursor destroy
|
||||
* routine.
|
||||
*/
|
||||
for (tdbp = LIST_FIRST(&dbp->handleq);
|
||||
tdbp != NULL; tdbp = LIST_NEXT(tdbp, links)) {
|
||||
while ((dbc = TAILQ_FIRST(&tdbp->curs_queue)) != NULL)
|
||||
switch (tdbp->type) {
|
||||
case DB_BTREE:
|
||||
if ((t_ret =
|
||||
__bam_c_iclose(tdbp, dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
break;
|
||||
case DB_HASH:
|
||||
if ((t_ret =
|
||||
__ham_c_iclose(tdbp, dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
break;
|
||||
case DB_RECNO:
|
||||
if ((t_ret =
|
||||
__ram_c_iclose(tdbp, dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
|
||||
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
|
||||
if ((t_ret = __db_c_destroy(dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
switch (tdbp->type) {
|
||||
case DB_BTREE:
|
||||
if ((t_ret = __bam_close(tdbp)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
break;
|
||||
case DB_HASH:
|
||||
if ((t_ret = __ham_close(tdbp)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
break;
|
||||
case DB_RECNO:
|
||||
if ((t_ret = __ram_close(tdbp)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
/* Call the access specific close function. */
|
||||
if ((t_ret = dbp->am_close(dbp)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
/* Sync the memory pool. */
|
||||
if (!LF_ISSET(DB_NOSYNC) && (t_ret = memp_fsync(dbp->mpf)) != 0 &&
|
||||
if (flags != DB_NOSYNC && (t_ret = memp_fsync(dbp->mpf)) != 0 &&
|
||||
t_ret != DB_INCOMPLETE && ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
@ -788,91 +770,12 @@ db_close(dbp, flags)
|
||||
if (F_ISSET(dbp, DB_AM_LOGGING))
|
||||
(void)log_unregister(dbp->dbenv->lg_info, dbp->log_fileid);
|
||||
|
||||
/* Discard the lock cookie for all handles. */
|
||||
for (tdbp = LIST_FIRST(&dbp->handleq);
|
||||
tdbp != NULL; tdbp = LIST_NEXT(tdbp, links))
|
||||
if (F_ISSET(tdbp, DB_AM_LOCKING)) {
|
||||
#ifdef DEBUG
|
||||
DB_LOCKREQ request;
|
||||
|
||||
/*
|
||||
* If we're running tests, display any locks currently
|
||||
* held. It's possible that some applications may hold
|
||||
* locks for long periods, e.g., conference room locks,
|
||||
* but the DB tests should never close holding locks.
|
||||
*/
|
||||
request.op = DB_LOCK_DUMP;
|
||||
if ((t_ret = lock_vec(tdbp->dbenv->lk_info,
|
||||
tdbp->locker, 0, &request, 1, NULL)) != 0 &&
|
||||
ret == 0)
|
||||
ret = EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If we allocated a DB_ENV, discard it. */
|
||||
if (dbp->mp_dbenv != NULL)
|
||||
FREE(dbp->mp_dbenv, sizeof(DB_ENV));
|
||||
__os_free(dbp->mp_dbenv, sizeof(DB_ENV));
|
||||
|
||||
/* Free all of the DB's. */
|
||||
LIST_REMOVE(dbp, links);
|
||||
while ((tdbp = LIST_FIRST(&dbp->handleq)) != NULL) {
|
||||
LIST_REMOVE(tdbp, links);
|
||||
FREE(tdbp, sizeof(*tdbp));
|
||||
}
|
||||
FREE(dbp, sizeof(*dbp));
|
||||
/* Free the DB. */
|
||||
__os_free(dbp, sizeof(*dbp));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_fd --
|
||||
* Return a file descriptor for flock'ing.
|
||||
*/
|
||||
static int
|
||||
db_fd(dbp, fdp)
|
||||
DB *dbp;
|
||||
int *fdp;
|
||||
{
|
||||
/*
|
||||
* XXX
|
||||
* Truly spectacular layering violation.
|
||||
*/
|
||||
return (__mp_xxx_fd(dbp->mpf, fdp));
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_pgerr --
|
||||
* Error when unable to retrieve a specified page.
|
||||
*
|
||||
* PUBLIC: int __db_pgerr __P((DB *, db_pgno_t));
|
||||
*/
|
||||
int
|
||||
__db_pgerr(dbp, pgno)
|
||||
DB *dbp;
|
||||
db_pgno_t pgno;
|
||||
{
|
||||
/*
|
||||
* Three things are certain:
|
||||
* Death, taxes, and lost data.
|
||||
* Guess which has occurred.
|
||||
*/
|
||||
__db_err(dbp->dbenv,
|
||||
"unable to create/retrieve page %lu", (u_long)pgno);
|
||||
return (__db_panic(dbp));
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_pgfmt --
|
||||
* Error when a page has the wrong format.
|
||||
*
|
||||
* PUBLIC: int __db_pgfmt __P((DB *, db_pgno_t));
|
||||
*/
|
||||
int
|
||||
__db_pgfmt(dbp, pgno)
|
||||
DB *dbp;
|
||||
db_pgno_t pgno;
|
||||
{
|
||||
__db_err(dbp->dbenv,
|
||||
"page %lu: illegal page type or format", (u_long)pgno);
|
||||
return (__db_panic(dbp));
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db.src 10.6 (Sleepycat) 4/28/98
|
||||
* @(#)db.src 10.8 (Sleepycat) 9/20/98
|
||||
*/
|
||||
|
||||
PREFIX db
|
||||
@ -98,6 +98,7 @@ END
|
||||
/*
|
||||
* relink -- Handles relinking around a page.
|
||||
*
|
||||
* opcode: indicates if this is an addpage or delete page
|
||||
* pgno: the page being changed.
|
||||
* lsn the page's original lsn.
|
||||
* prev: the previous page.
|
||||
@ -106,6 +107,7 @@ END
|
||||
* lsn_next: the previous page's original lsn.
|
||||
*/
|
||||
BEGIN relink
|
||||
ARG opcode u_int32_t lu
|
||||
ARG fileid u_int32_t lu
|
||||
ARG pgno db_pgno_t lu
|
||||
POINTER lsn DB_LSN * lu
|
||||
@ -148,12 +150,3 @@ DBT key DBT s
|
||||
DBT data DBT s
|
||||
ARG arg_flags u_int32_t lu
|
||||
END
|
||||
|
||||
/*
|
||||
* noop -- do nothing, but get an LSN.
|
||||
*/
|
||||
BEGIN noop
|
||||
ARG fileid u_int32_t lu
|
||||
ARG pgno db_pgno_t lu
|
||||
POINTER prevlsn DB_LSN * lu
|
||||
END
|
||||
|
430
db2/db/db_am.c
Normal file
430
db2/db/db_am.c
Normal file
@ -0,0 +1,430 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_am.c 10.15 (Sleepycat) 12/30/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "shqueue.h"
|
||||
#include "db_page.h"
|
||||
#include "db_shash.h"
|
||||
#include "mp.h"
|
||||
#include "btree.h"
|
||||
#include "hash.h"
|
||||
#include "db_am.h"
|
||||
#include "db_ext.h"
|
||||
|
||||
static int __db_c_close __P((DBC *));
|
||||
static int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t));
|
||||
static int __db_fd __P((DB *, int *));
|
||||
static int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
static int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
|
||||
/*
|
||||
* __db_init_wrapper --
|
||||
* Wrapper layer to implement generic DB functions.
|
||||
*
|
||||
* PUBLIC: int __db_init_wrapper __P((DB *));
|
||||
*/
|
||||
int
|
||||
__db_init_wrapper(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
dbp->close = __db_close;
|
||||
dbp->cursor = __db_cursor;
|
||||
dbp->del = NULL; /* !!! Must be set by access method. */
|
||||
dbp->fd = __db_fd;
|
||||
dbp->get = __db_get;
|
||||
dbp->join = __db_join;
|
||||
dbp->put = __db_put;
|
||||
dbp->stat = NULL; /* !!! Must be set by access method. */
|
||||
dbp->sync = __db_sync;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_cursor --
|
||||
* Allocate and return a cursor.
|
||||
*/
|
||||
static int
|
||||
__db_cursor(dbp, txn, dbcp, flags)
|
||||
DB *dbp;
|
||||
DB_TXN *txn;
|
||||
DBC **dbcp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DBC *dbc, *adbc;
|
||||
int ret;
|
||||
db_lockmode_t mode;
|
||||
u_int32_t op;
|
||||
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
/* Take one from the free list if it's available. */
|
||||
DB_THREAD_LOCK(dbp);
|
||||
if ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
|
||||
TAILQ_REMOVE(&dbp->free_queue, dbc, links);
|
||||
else {
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
if ((ret = __os_calloc(1, sizeof(DBC), &dbc)) != 0)
|
||||
return (ret);
|
||||
|
||||
dbc->dbp = dbp;
|
||||
dbc->c_close = __db_c_close;
|
||||
|
||||
/* Set up locking information. */
|
||||
if (F_ISSET(dbp, DB_AM_LOCKING | DB_AM_CDB)) {
|
||||
/*
|
||||
* If we are not threaded, then there is no need to
|
||||
* create new locker ids. We know that no one else
|
||||
* is running concurrently using this DB, so we can
|
||||
* take a peek at any cursors on the active queue.
|
||||
*/
|
||||
if (!F_ISSET(dbp, DB_AM_THREAD) &&
|
||||
(adbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
|
||||
dbc->lid = adbc->lid;
|
||||
else
|
||||
if ((ret = lock_id(dbp->dbenv->lk_info,
|
||||
&dbc->lid)) != 0)
|
||||
goto err;
|
||||
|
||||
memcpy(dbc->lock.fileid, dbp->fileid, DB_FILE_ID_LEN);
|
||||
if (F_ISSET(dbp, DB_AM_CDB)) {
|
||||
dbc->lock_dbt.size = DB_FILE_ID_LEN;
|
||||
dbc->lock_dbt.data = dbc->lock.fileid;
|
||||
} else {
|
||||
dbc->lock_dbt.size = sizeof(dbc->lock);
|
||||
dbc->lock_dbt.data = &dbc->lock;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dbp->type) {
|
||||
case DB_BTREE:
|
||||
case DB_RECNO:
|
||||
if ((ret = __bam_c_init(dbc)) != 0)
|
||||
goto err;
|
||||
break;
|
||||
case DB_HASH:
|
||||
if ((ret = __ham_c_init(dbc)) != 0)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
DB_THREAD_LOCK(dbp);
|
||||
}
|
||||
|
||||
if ((dbc->txn = txn) == NULL)
|
||||
dbc->locker = dbc->lid;
|
||||
else
|
||||
dbc->locker = txn->txnid;
|
||||
|
||||
TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links);
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
/*
|
||||
* If this is the concurrent DB product, then we do all locking
|
||||
* in the interface, which is right here.
|
||||
*/
|
||||
if (F_ISSET(dbp, DB_AM_CDB)) {
|
||||
op = LF_ISSET(DB_OPFLAGS_MASK);
|
||||
mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE :
|
||||
(LF_ISSET(DB_RMW) ? DB_LOCK_IWRITE : DB_LOCK_READ);
|
||||
if ((ret = lock_get(dbp->dbenv->lk_info, dbc->locker, 0,
|
||||
&dbc->lock_dbt, mode, &dbc->mylock)) != 0) {
|
||||
(void)__db_c_close(dbc);
|
||||
return (EAGAIN);
|
||||
}
|
||||
if (LF_ISSET(DB_RMW))
|
||||
F_SET(dbc, DBC_RMW);
|
||||
if (op == DB_WRITELOCK)
|
||||
F_SET(dbc, DBC_WRITER);
|
||||
}
|
||||
|
||||
*dbcp = dbc;
|
||||
return (0);
|
||||
|
||||
err: __os_free(dbc, sizeof(*dbc));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_c_close --
|
||||
* Close the cursor (recycle for later use).
|
||||
*/
|
||||
static int
|
||||
__db_c_close(dbc)
|
||||
DBC *dbc;
|
||||
{
|
||||
DB *dbp;
|
||||
int ret, t_ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* We cannot release the lock until after we've called the
|
||||
* access method specific routine, since btrees may have pending
|
||||
* deletes.
|
||||
*/
|
||||
|
||||
/* Remove the cursor from the active queue. */
|
||||
DB_THREAD_LOCK(dbp);
|
||||
TAILQ_REMOVE(&dbp->active_queue, dbc, links);
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
/* Call the access specific cursor close routine. */
|
||||
if ((t_ret = dbc->c_am_close(dbc)) != 0 && ret == 0)
|
||||
t_ret = ret;
|
||||
|
||||
/* Release the lock. */
|
||||
if (F_ISSET(dbc->dbp, DB_AM_CDB) && dbc->mylock != LOCK_INVALID) {
|
||||
ret = lock_put(dbc->dbp->dbenv->lk_info, dbc->mylock);
|
||||
dbc->mylock = LOCK_INVALID;
|
||||
}
|
||||
|
||||
/* Clean up the cursor. */
|
||||
dbc->flags = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Check for leftover locks, unless we're running with transactions.
|
||||
*
|
||||
* If we're running tests, display any locks currently held. It's
|
||||
* possible that some applications may hold locks for long periods,
|
||||
* e.g., conference room locks, but the DB tests should never close
|
||||
* holding locks.
|
||||
*/
|
||||
if (F_ISSET(dbp, DB_AM_LOCKING) && dbc->lid == dbc->locker) {
|
||||
DB_LOCKREQ request;
|
||||
|
||||
request.op = DB_LOCK_DUMP;
|
||||
if ((t_ret = lock_vec(dbp->dbenv->lk_info,
|
||||
dbc->locker, 0, &request, 1, NULL)) != 0 && ret == 0)
|
||||
ret = EAGAIN;
|
||||
}
|
||||
#endif
|
||||
/* Move the cursor to the free queue. */
|
||||
DB_THREAD_LOCK(dbp);
|
||||
TAILQ_INSERT_TAIL(&dbp->free_queue, dbc, links);
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* __db_cprint --
|
||||
* Display the current cursor list.
|
||||
*
|
||||
* PUBLIC: int __db_cprint __P((DB *));
|
||||
*/
|
||||
int
|
||||
__db_cprint(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
static const FN fn[] = {
|
||||
{ DBC_RECOVER, "recover" },
|
||||
{ DBC_RMW, "read-modify-write" },
|
||||
{ 0 },
|
||||
};
|
||||
DBC *dbc;
|
||||
|
||||
DB_THREAD_LOCK(dbp);
|
||||
for (dbc = TAILQ_FIRST(&dbp->active_queue);
|
||||
dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
|
||||
fprintf(stderr,
|
||||
"%#0x: dbp: %#0x txn: %#0x lid: %lu locker: %lu",
|
||||
(u_int)dbc, (u_int)dbc->dbp, (u_int)dbc->txn,
|
||||
(u_long)dbc->lid, (u_long)dbc->locker);
|
||||
__db_prflags(dbc->flags, fn, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* __db_c_destroy --
|
||||
* Destroy the cursor.
|
||||
*
|
||||
* PUBLIC: int __db_c_destroy __P((DBC *));
|
||||
*/
|
||||
int
|
||||
__db_c_destroy(dbc)
|
||||
DBC *dbc;
|
||||
{
|
||||
DB *dbp;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/* Remove the cursor from the free queue. */
|
||||
DB_THREAD_LOCK(dbp);
|
||||
TAILQ_REMOVE(&dbp->free_queue, dbc, links);
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
|
||||
/* Call the access specific cursor destroy routine. */
|
||||
ret = dbc->c_am_destroy == NULL ? 0 : dbc->c_am_destroy(dbc);
|
||||
|
||||
/* Free up allocated memory. */
|
||||
if (dbc->rkey.data != NULL)
|
||||
__os_free(dbc->rkey.data, dbc->rkey.ulen);
|
||||
if (dbc->rdata.data != NULL)
|
||||
__os_free(dbc->rdata.data, dbc->rdata.ulen);
|
||||
__os_free(dbc, sizeof(*dbc));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* db_fd --
|
||||
* Return a file descriptor for flock'ing.
|
||||
*/
|
||||
static int
|
||||
__db_fd(dbp, fdp)
|
||||
DB *dbp;
|
||||
int *fdp;
|
||||
{
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Truly spectacular layering violation.
|
||||
*/
|
||||
return (__mp_xxx_fd(dbp->mpf, fdp));
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_get --
|
||||
* Return a key/data pair.
|
||||
*/
|
||||
static int
|
||||
__db_get(dbp, txn, key, data, flags)
|
||||
DB *dbp;
|
||||
DB_TXN *txn;
|
||||
DBT *key, *data;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DBC *dbc;
|
||||
int ret, t_ret;
|
||||
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
if ((ret = __db_getchk(dbp, key, data, flags)) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
DEBUG_LREAD(dbc, txn, "__db_get", key, NULL, flags);
|
||||
|
||||
ret = dbc->c_get(dbc, key, data,
|
||||
flags == 0 || flags == DB_RMW ? flags | DB_SET : flags);
|
||||
|
||||
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_put --
|
||||
* Store a key/data pair.
|
||||
*/
|
||||
static int
|
||||
__db_put(dbp, txn, key, data, flags)
|
||||
DB *dbp;
|
||||
DB_TXN *txn;
|
||||
DBT *key, *data;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DBC *dbc;
|
||||
DBT tdata;
|
||||
int ret, t_ret;
|
||||
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
if ((ret = __db_putchk(dbp, key, data,
|
||||
flags, F_ISSET(dbp, DB_AM_RDONLY), F_ISSET(dbp, DB_AM_DUP))) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
|
||||
return (ret);
|
||||
|
||||
DEBUG_LWRITE(dbc, txn, "__db_put", key, data, flags);
|
||||
|
||||
if (flags == DB_NOOVERWRITE) {
|
||||
/*
|
||||
* Set DB_DBT_USERMEM, this might be a threaded application and
|
||||
* the flags checking will catch us. We don't want the actual
|
||||
* data, so request a partial of length 0.
|
||||
*/
|
||||
memset(&tdata, 0, sizeof(tdata));
|
||||
F_SET(&tdata, DB_DBT_USERMEM | DB_DBT_PARTIAL);
|
||||
if ((ret = dbc->c_get(dbc, key, &tdata, DB_SET | DB_RMW)) == 0)
|
||||
ret = DB_KEYEXIST;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = dbc->c_put(dbc, key, data, DB_KEYLAST);
|
||||
|
||||
if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_sync --
|
||||
* Flush the database cache.
|
||||
*
|
||||
* PUBLIC: int __db_sync __P((DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_sync(dbp, flags)
|
||||
DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
int ret;
|
||||
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
if ((ret = __db_syncchk(dbp, flags)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* If it wasn't possible to modify the file, we're done. */
|
||||
if (F_ISSET(dbp, DB_AM_INMEM | DB_AM_RDONLY))
|
||||
return (0);
|
||||
|
||||
/* Flush any dirty pages from the cache to the backing file. */
|
||||
if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE)
|
||||
ret = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
299
db2/db/db_auto.c
299
db2/db/db_auto.c
@ -10,7 +10,6 @@
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "shqueue.h"
|
||||
#include "db_page.h"
|
||||
#include "db_dispatch.h"
|
||||
#include "db_am.h"
|
||||
@ -46,8 +45,7 @@ int __db_addrem_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_db_addrem;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -60,8 +58,8 @@ int __db_addrem_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(u_int32_t) + (hdr == NULL ? 0 : hdr->size)
|
||||
+ sizeof(u_int32_t) + (dbt == NULL ? 0 : dbt->size)
|
||||
+ sizeof(*pagelsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -112,7 +110,7 @@ int __db_addrem_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -174,7 +172,7 @@ __db_addrem_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tpagelsn: [%lu][%lu]\n",
|
||||
(u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -188,11 +186,12 @@ __db_addrem_read(recbuf, argpp)
|
||||
{
|
||||
__db_addrem_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__db_addrem_args *)__db_malloc(sizeof(__db_addrem_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__db_addrem_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));
|
||||
@ -253,8 +252,7 @@ int __db_split_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_db_split;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -264,8 +262,8 @@ int __db_split_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(pgno)
|
||||
+ sizeof(u_int32_t) + (pageimage == NULL ? 0 : pageimage->size)
|
||||
+ sizeof(*pagelsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -302,7 +300,7 @@ int __db_split_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -353,7 +351,7 @@ __db_split_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tpagelsn: [%lu][%lu]\n",
|
||||
(u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -367,11 +365,12 @@ __db_split_read(recbuf, argpp)
|
||||
{
|
||||
__db_split_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__db_split_args *)__db_malloc(sizeof(__db_split_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__db_split_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));
|
||||
@ -430,8 +429,7 @@ int __db_big_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_db_big;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -445,8 +443,8 @@ int __db_big_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(*pagelsn)
|
||||
+ sizeof(*prevlsn)
|
||||
+ sizeof(*nextlsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -497,7 +495,7 @@ int __db_big_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -554,7 +552,7 @@ __db_big_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tnextlsn: [%lu][%lu]\n",
|
||||
(u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -568,11 +566,12 @@ __db_big_read(recbuf, argpp)
|
||||
{
|
||||
__db_big_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__db_big_args *)__db_malloc(sizeof(__db_big_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__db_big_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));
|
||||
@ -630,8 +629,7 @@ int __db_ovref_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_db_ovref;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -640,8 +638,8 @@ int __db_ovref_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(pgno)
|
||||
+ sizeof(adjust)
|
||||
+ sizeof(*lsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -668,7 +666,7 @@ int __db_ovref_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -710,7 +708,7 @@ __db_ovref_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tlsn: [%lu][%lu]\n",
|
||||
(u_long)argp->lsn.file, (u_long)argp->lsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -724,11 +722,12 @@ __db_ovref_read(recbuf, argpp)
|
||||
{
|
||||
__db_ovref_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__db_ovref_args *)__db_malloc(sizeof(__db_ovref_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__db_ovref_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));
|
||||
@ -752,16 +751,17 @@ __db_ovref_read(recbuf, argpp)
|
||||
/*
|
||||
* PUBLIC: int __db_relink_log
|
||||
* PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
* PUBLIC: u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t,
|
||||
* PUBLIC: DB_LSN *, db_pgno_t, DB_LSN *));
|
||||
* PUBLIC: u_int32_t, u_int32_t, db_pgno_t, DB_LSN *,
|
||||
* PUBLIC: db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *));
|
||||
*/
|
||||
int __db_relink_log(logp, txnid, ret_lsnp, flags,
|
||||
fileid, pgno, lsn, prev, lsn_prev, next,
|
||||
lsn_next)
|
||||
opcode, fileid, pgno, lsn, prev, lsn_prev,
|
||||
next, lsn_next)
|
||||
DB_LOG *logp;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN *ret_lsnp;
|
||||
u_int32_t flags;
|
||||
u_int32_t opcode;
|
||||
u_int32_t fileid;
|
||||
db_pgno_t pgno;
|
||||
DB_LSN * lsn;
|
||||
@ -779,12 +779,12 @@ int __db_relink_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_db_relink;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
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(pgno)
|
||||
+ sizeof(*lsn)
|
||||
@ -792,8 +792,8 @@ int __db_relink_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(*lsn_prev)
|
||||
+ sizeof(next)
|
||||
+ sizeof(*lsn_next);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -802,6 +802,8 @@ int __db_relink_log(logp, txnid, ret_lsnp, flags,
|
||||
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, &pgno, sizeof(pgno));
|
||||
@ -832,7 +834,7 @@ int __db_relink_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -868,6 +870,7 @@ __db_relink_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
(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: %lu\n", (u_long)argp->fileid);
|
||||
printf("\tpgno: %lu\n", (u_long)argp->pgno);
|
||||
printf("\tlsn: [%lu][%lu]\n",
|
||||
@ -879,7 +882,7 @@ __db_relink_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tlsn_next: [%lu][%lu]\n",
|
||||
(u_long)argp->lsn_next.file, (u_long)argp->lsn_next.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -893,11 +896,12 @@ __db_relink_read(recbuf, argpp)
|
||||
{
|
||||
__db_relink_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__db_relink_args *)__db_malloc(sizeof(__db_relink_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__db_relink_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));
|
||||
@ -906,6 +910,8 @@ __db_relink_read(recbuf, argpp)
|
||||
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->pgno, bp, sizeof(argp->pgno));
|
||||
@ -951,8 +957,7 @@ int __db_addpage_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_db_addpage;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -962,8 +967,8 @@ int __db_addpage_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(*lsn)
|
||||
+ sizeof(nextpgno)
|
||||
+ sizeof(*nextlsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -995,7 +1000,7 @@ int __db_addpage_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1039,7 +1044,7 @@ __db_addpage_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tnextlsn: [%lu][%lu]\n",
|
||||
(u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1053,11 +1058,12 @@ __db_addpage_read(recbuf, argpp)
|
||||
{
|
||||
__db_addpage_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__db_addpage_args *)__db_malloc(sizeof(__db_addpage_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__db_addpage_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));
|
||||
@ -1108,8 +1114,7 @@ int __db_debug_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_db_debug;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -1119,8 +1124,8 @@ int __db_debug_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(u_int32_t) + (key == NULL ? 0 : key->size)
|
||||
+ sizeof(u_int32_t) + (data == NULL ? 0 : data->size)
|
||||
+ sizeof(arg_flags);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -1170,7 +1175,7 @@ int __db_debug_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1236,7 +1241,7 @@ __db_debug_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\n");
|
||||
printf("\targ_flags: %lu\n", (u_long)argp->arg_flags);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1250,11 +1255,12 @@ __db_debug_read(recbuf, argpp)
|
||||
{
|
||||
__db_debug_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__db_debug_args *)__db_malloc(sizeof(__db_debug_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__db_debug_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));
|
||||
@ -1283,143 +1289,6 @@ __db_debug_read(recbuf, argpp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __db_noop_log
|
||||
* PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
* PUBLIC: u_int32_t, db_pgno_t, DB_LSN *));
|
||||
*/
|
||||
int __db_noop_log(logp, txnid, ret_lsnp, flags,
|
||||
fileid, pgno, prevlsn)
|
||||
DB_LOG *logp;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN *ret_lsnp;
|
||||
u_int32_t flags;
|
||||
u_int32_t fileid;
|
||||
db_pgno_t pgno;
|
||||
DB_LSN * prevlsn;
|
||||
{
|
||||
DBT logrec;
|
||||
DB_LSN *lsnp, null_lsn;
|
||||
u_int32_t rectype, txn_num;
|
||||
int ret;
|
||||
u_int8_t *bp;
|
||||
|
||||
rectype = DB_db_noop;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
|
||||
+ sizeof(fileid)
|
||||
+ sizeof(pgno)
|
||||
+ sizeof(*prevlsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
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, &pgno, sizeof(pgno));
|
||||
bp += sizeof(pgno);
|
||||
if (prevlsn != NULL)
|
||||
memcpy(bp, prevlsn, sizeof(*prevlsn));
|
||||
else
|
||||
memset(bp, 0, sizeof(*prevlsn));
|
||||
bp += sizeof(*prevlsn);
|
||||
#ifdef DIAGNOSTIC
|
||||
if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
|
||||
fprintf(stderr, "Error in log record length");
|
||||
#endif
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __db_noop_print
|
||||
* PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
*/
|
||||
int
|
||||
__db_noop_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
DB_LOG *notused1;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
int notused2;
|
||||
void *notused3;
|
||||
{
|
||||
__db_noop_args *argp;
|
||||
u_int32_t i;
|
||||
u_int ch;
|
||||
int ret;
|
||||
|
||||
i = 0;
|
||||
ch = 0;
|
||||
notused1 = NULL;
|
||||
notused2 = 0;
|
||||
notused3 = NULL;
|
||||
|
||||
if ((ret = __db_noop_read(dbtp->data, &argp)) != 0)
|
||||
return (ret);
|
||||
printf("[%lu][%lu]db_noop: 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: %lu\n", (u_long)argp->fileid);
|
||||
printf("\tpgno: %lu\n", (u_long)argp->pgno);
|
||||
printf("\tprevlsn: [%lu][%lu]\n",
|
||||
(u_long)argp->prevlsn.file, (u_long)argp->prevlsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __db_noop_read __P((void *, __db_noop_args **));
|
||||
*/
|
||||
int
|
||||
__db_noop_read(recbuf, argpp)
|
||||
void *recbuf;
|
||||
__db_noop_args **argpp;
|
||||
{
|
||||
__db_noop_args *argp;
|
||||
u_int8_t *bp;
|
||||
|
||||
argp = (__db_noop_args *)__db_malloc(sizeof(__db_noop_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
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->pgno, bp, sizeof(argp->pgno));
|
||||
bp += sizeof(argp->pgno);
|
||||
memcpy(&argp->prevlsn, bp, sizeof(argp->prevlsn));
|
||||
bp += sizeof(argp->prevlsn);
|
||||
*argpp = argp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC: int __db_init_print __P((DB_ENV *));
|
||||
*/
|
||||
@ -1450,9 +1319,6 @@ __db_init_print(dbenv)
|
||||
if ((ret = __db_add_recovery(dbenv,
|
||||
__db_debug_print, DB_db_debug)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv,
|
||||
__db_noop_print, DB_db_noop)) != 0)
|
||||
return (ret);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1486,9 +1352,6 @@ __db_init_recover(dbenv)
|
||||
if ((ret = __db_add_recovery(dbenv,
|
||||
__db_debug_recover, DB_db_debug)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_add_recovery(dbenv,
|
||||
__db_noop_recover, DB_db_noop)) != 0)
|
||||
return (ret);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -43,13 +43,14 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_dispatch.c 10.14 (Sleepycat) 5/3/98";
|
||||
static const char sccsid[] = "@(#)db_dispatch.c 10.20 (Sleepycat) 10/10/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <shqueue.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -61,6 +62,7 @@ static const char sccsid[] = "@(#)db_dispatch.c 10.14 (Sleepycat) 5/3/98";
|
||||
#include "db_am.h"
|
||||
#include "common_ext.h"
|
||||
#include "log_auto.h"
|
||||
#include "txn.h"
|
||||
#include "txn_auto.h"
|
||||
|
||||
/*
|
||||
@ -148,27 +150,16 @@ __db_add_recovery(dbenv, func, ndx)
|
||||
u_int32_t ndx;
|
||||
{
|
||||
u_int32_t i;
|
||||
int ret;
|
||||
|
||||
/* Check if function is already registered. */
|
||||
if (dispatch_table && ndx < dispatch_size &&
|
||||
dispatch_table[ndx] != 0 && dispatch_table[ndx] != func)
|
||||
return (DB_REGISTERED);
|
||||
COMPQUIET(dbenv, NULL); /* !!!: not currently used. */
|
||||
|
||||
/* Check if we have to grow the table. */
|
||||
if (ndx >= dispatch_size) {
|
||||
if (dispatch_table == NULL)
|
||||
dispatch_table = (int (**)
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *)))
|
||||
__db_malloc(DB_user_BEGIN * sizeof(dispatch_table[0]));
|
||||
else
|
||||
dispatch_table = (int (**)
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *)))
|
||||
__db_realloc(dispatch_table, (DB_user_BEGIN +
|
||||
dispatch_size) * sizeof(dispatch_table[0]));
|
||||
if (dispatch_table == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
return (ENOMEM);
|
||||
}
|
||||
if ((ret = __os_realloc(&dispatch_table,
|
||||
(DB_user_BEGIN + dispatch_size) *
|
||||
sizeof(dispatch_table[0]))) != 0)
|
||||
return (ret);
|
||||
for (i = dispatch_size,
|
||||
dispatch_size += DB_user_BEGIN; i < dispatch_size; ++i)
|
||||
dispatch_table[i] = NULL;
|
||||
@ -189,9 +180,10 @@ __db_txnlist_init(retp)
|
||||
void *retp;
|
||||
{
|
||||
DB_TXNHEAD *headp;
|
||||
int ret;
|
||||
|
||||
if ((headp = (DB_TXNHEAD *)__db_malloc(sizeof(DB_TXNHEAD))) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(sizeof(DB_TXNHEAD), NULL, &headp)) != 0)
|
||||
return (ret);
|
||||
|
||||
LIST_INIT(&headp->head);
|
||||
headp->maxid = 0;
|
||||
@ -214,9 +206,10 @@ __db_txnlist_add(listp, txnid)
|
||||
{
|
||||
DB_TXNHEAD *hp;
|
||||
DB_TXNLIST *elp;
|
||||
int ret;
|
||||
|
||||
if ((elp = (DB_TXNLIST *)__db_malloc(sizeof(DB_TXNLIST))) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(sizeof(DB_TXNLIST), NULL, &elp)) != 0)
|
||||
return (ret);
|
||||
|
||||
elp->txnid = txnid;
|
||||
hp = (DB_TXNHEAD *)listp;
|
||||
@ -269,9 +262,9 @@ __db_txnlist_end(listp)
|
||||
hp = (DB_TXNHEAD *)listp;
|
||||
while ((p = LIST_FIRST(&hp->head)) != LIST_END(&hp->head)) {
|
||||
LIST_REMOVE(p, links);
|
||||
__db_free(p);
|
||||
__os_free(p, 0);
|
||||
}
|
||||
__db_free(listp);
|
||||
__os_free(listp, sizeof(DB_TXNHEAD));
|
||||
}
|
||||
|
||||
/*
|
||||
|
511
db2/db/db_dup.c
511
db2/db/db_dup.c
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_dup.c 10.18 (Sleepycat) 5/31/98";
|
||||
static const char sccsid[] = "@(#)db_dup.c 10.35 (Sleepycat) 12/2/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -23,25 +23,25 @@ static const char sccsid[] = "@(#)db_dup.c 10.18 (Sleepycat) 5/31/98";
|
||||
#include "btree.h"
|
||||
#include "db_am.h"
|
||||
|
||||
static int __db_addpage __P((DB *,
|
||||
PAGE **, db_indx_t *, int (*)(DB *, u_int32_t, PAGE **)));
|
||||
static int __db_dsplit __P((DB *,
|
||||
PAGE **, db_indx_t *, u_int32_t, int (*)(DB *, u_int32_t, PAGE **)));
|
||||
static int __db_addpage __P((DBC *,
|
||||
PAGE **, db_indx_t *, int (*)(DBC *, u_int32_t, PAGE **)));
|
||||
static int __db_dsplit __P((DBC *,
|
||||
PAGE **, db_indx_t *, u_int32_t, int (*)(DBC *, u_int32_t, PAGE **)));
|
||||
|
||||
/*
|
||||
* __db_dput --
|
||||
* Put a duplicate item onto a duplicate page at the given index.
|
||||
*
|
||||
* PUBLIC: int __db_dput __P((DB *,
|
||||
* PUBLIC: DBT *, PAGE **, db_indx_t *, int (*)(DB *, u_int32_t, PAGE **)));
|
||||
* PUBLIC: int __db_dput __P((DBC *, DBT *,
|
||||
* PUBLIC: PAGE **, db_indx_t *, int (*)(DBC *, u_int32_t, PAGE **)));
|
||||
*/
|
||||
int
|
||||
__db_dput(dbp, dbt, pp, indxp, newfunc)
|
||||
DB *dbp;
|
||||
__db_dput(dbc, dbt, pp, indxp, newfunc)
|
||||
DBC *dbc;
|
||||
DBT *dbt;
|
||||
PAGE **pp;
|
||||
db_indx_t *indxp;
|
||||
int (*newfunc) __P((DB *, u_int32_t, PAGE **));
|
||||
int (*newfunc) __P((DBC *, u_int32_t, PAGE **));
|
||||
{
|
||||
BOVERFLOW bo;
|
||||
DBT *data_dbtp, hdr_dbt, *hdr_dbtp;
|
||||
@ -54,10 +54,12 @@ __db_dput(dbp, dbt, pp, indxp, newfunc)
|
||||
* We need some access method independent threshold for when we put
|
||||
* a duplicate item onto an overflow page.
|
||||
*/
|
||||
if (dbt->size > 0.25 * dbp->pgsize) {
|
||||
if ((ret = __db_poff(dbp, dbt, &pgno, newfunc)) != 0)
|
||||
if (dbt->size > 0.25 * dbc->dbp->pgsize) {
|
||||
if ((ret = __db_poff(dbc, dbt, &pgno, newfunc)) != 0)
|
||||
return (ret);
|
||||
UMRW(bo.unused1);
|
||||
B_TSET(bo.type, B_OVERFLOW, 0);
|
||||
UMRW(bo.unused2);
|
||||
bo.tlen = dbt->size;
|
||||
bo.pgno = pgno;
|
||||
hdr_dbt.data = &bo;
|
||||
@ -75,11 +77,14 @@ __db_dput(dbp, dbt, pp, indxp, newfunc)
|
||||
pagep = *pp;
|
||||
if (size > P_FREESPACE(pagep)) {
|
||||
if (*indxp == NUM_ENT(*pp) && NEXT_PGNO(*pp) == PGNO_INVALID)
|
||||
ret = __db_addpage(dbp, pp, indxp, newfunc);
|
||||
ret = __db_addpage(dbc, pp, indxp, newfunc);
|
||||
else
|
||||
ret = __db_dsplit(dbp, pp, indxp, isize, newfunc);
|
||||
ret = __db_dsplit(dbc, pp, indxp, isize, newfunc);
|
||||
if (ret != 0)
|
||||
/* XXX: Pages not returned to free list. */
|
||||
/*
|
||||
* XXX
|
||||
* Pages not returned to free list.
|
||||
*/
|
||||
return (ret);
|
||||
pagep = *pp;
|
||||
}
|
||||
@ -88,11 +93,11 @@ __db_dput(dbp, dbt, pp, indxp, newfunc)
|
||||
* Now, pagep references the page on which to insert and indx is the
|
||||
* the location to insert.
|
||||
*/
|
||||
if ((ret = __db_pitem(dbp,
|
||||
if ((ret = __db_pitem(dbc,
|
||||
pagep, (u_int32_t)*indxp, isize, hdr_dbtp, data_dbtp)) != 0)
|
||||
return (ret);
|
||||
|
||||
(void)memp_fset(dbp->mpf, pagep, DB_MPOOL_DIRTY);
|
||||
(void)memp_fset(dbc->dbp->mpf, pagep, DB_MPOOL_DIRTY);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -100,15 +105,15 @@ __db_dput(dbp, dbt, pp, indxp, newfunc)
|
||||
* __db_drem --
|
||||
* Remove a duplicate at the given index on the given page.
|
||||
*
|
||||
* PUBLIC: int __db_drem __P((DB *,
|
||||
* PUBLIC: PAGE **, u_int32_t, int (*)(DB *, PAGE *)));
|
||||
* PUBLIC: int __db_drem __P((DBC *,
|
||||
* PUBLIC: PAGE **, u_int32_t, int (*)(DBC *, PAGE *)));
|
||||
*/
|
||||
int
|
||||
__db_drem(dbp, pp, indx, freefunc)
|
||||
DB *dbp;
|
||||
__db_drem(dbc, pp, indx, freefunc)
|
||||
DBC *dbc;
|
||||
PAGE **pp;
|
||||
u_int32_t indx;
|
||||
int (*freefunc) __P((DB *, PAGE *));
|
||||
int (*freefunc) __P((DBC *, PAGE *));
|
||||
{
|
||||
PAGE *pagep;
|
||||
int ret;
|
||||
@ -117,12 +122,12 @@ __db_drem(dbp, pp, indx, freefunc)
|
||||
|
||||
/* Check if we are freeing a big item. */
|
||||
if (B_TYPE(GET_BKEYDATA(pagep, indx)->type) == B_OVERFLOW) {
|
||||
if ((ret = __db_doff(dbp,
|
||||
if ((ret = __db_doff(dbc,
|
||||
GET_BOVERFLOW(pagep, indx)->pgno, freefunc)) != 0)
|
||||
return (ret);
|
||||
ret = __db_ditem(dbp, pagep, indx, BOVERFLOW_SIZE);
|
||||
ret = __db_ditem(dbc, pagep, indx, BOVERFLOW_SIZE);
|
||||
} else
|
||||
ret = __db_ditem(dbp, pagep, indx,
|
||||
ret = __db_ditem(dbc, pagep, indx,
|
||||
BKEYDATA_SIZE(GET_BKEYDATA(pagep, indx)->len));
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
@ -137,12 +142,12 @@ __db_drem(dbp, pp, indx, freefunc)
|
||||
* !!!
|
||||
* __db_relink will set the dirty bit for us.
|
||||
*/
|
||||
if ((ret = __db_relink(dbp, pagep, pp, 0)) != 0)
|
||||
if ((ret = __db_relink(dbc, DB_REM_PAGE, pagep, pp, 0)) != 0)
|
||||
return (ret);
|
||||
if ((ret = freefunc(dbp, pagep)) != 0)
|
||||
if ((ret = freefunc(dbc, pagep)) != 0)
|
||||
return (ret);
|
||||
} else
|
||||
(void)memp_fset(dbp->mpf, pagep, DB_MPOOL_DIRTY);
|
||||
(void)memp_fset(dbc->dbp->mpf, pagep, DB_MPOOL_DIRTY);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -151,32 +156,41 @@ __db_drem(dbp, pp, indx, freefunc)
|
||||
* __db_dend --
|
||||
* Find the last page in a set of offpage duplicates.
|
||||
*
|
||||
* PUBLIC: int __db_dend __P((DB *, db_pgno_t, PAGE **));
|
||||
* PUBLIC: int __db_dend __P((DBC *, db_pgno_t, PAGE **));
|
||||
*/
|
||||
int
|
||||
__db_dend(dbp, pgno, pagep)
|
||||
DB *dbp;
|
||||
__db_dend(dbc, pgno, pp)
|
||||
DBC *dbc;
|
||||
db_pgno_t pgno;
|
||||
PAGE **pagep;
|
||||
PAGE **pp;
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *h;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/*
|
||||
* This implements DB_KEYLAST. The last page is returned in pp; pgno
|
||||
* should be the page number of the first page of the duplicate chain.
|
||||
*
|
||||
* *pp may be non-NULL -- if given a valid page use it.
|
||||
*/
|
||||
if (*pp != NULL)
|
||||
goto started;
|
||||
for (;;) {
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, pp)) != 0) {
|
||||
(void)__db_pgerr(dbp, pgno);
|
||||
return (ret);
|
||||
}
|
||||
started: h = *pp;
|
||||
|
||||
if ((pgno = NEXT_PGNO(h)) == PGNO_INVALID)
|
||||
break;
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
}
|
||||
|
||||
*pagep = h;
|
||||
if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -191,41 +205,44 @@ __db_dend(dbp, pgno, pagep)
|
||||
* the page on which the insert should happen, not yet put.
|
||||
*/
|
||||
static int
|
||||
__db_dsplit(dbp, hp, indxp, size, newfunc)
|
||||
DB *dbp;
|
||||
__db_dsplit(dbc, hp, indxp, size, newfunc)
|
||||
DBC *dbc;
|
||||
PAGE **hp;
|
||||
db_indx_t *indxp;
|
||||
u_int32_t size;
|
||||
int (*newfunc) __P((DB *, u_int32_t, PAGE **));
|
||||
int (*newfunc) __P((DBC *, u_int32_t, PAGE **));
|
||||
{
|
||||
PAGE *h, *np, *tp;
|
||||
BKEYDATA *bk;
|
||||
DBT page_dbt;
|
||||
DB *dbp;
|
||||
size_t pgsize;
|
||||
db_indx_t halfbytes, i, indx, lastsum, nindex, oindex, s, sum;
|
||||
int did_indx, ret;
|
||||
int did_indx, ret, t_ret;
|
||||
|
||||
h = *hp;
|
||||
indx = *indxp;
|
||||
ret = 0;
|
||||
dbp = dbc->dbp;
|
||||
pgsize = dbp->pgsize;
|
||||
|
||||
/* Create a temporary page to do compaction onto. */
|
||||
if ((tp = (PAGE *)__db_malloc(dbp->pgsize)) == NULL)
|
||||
return (ENOMEM);
|
||||
#ifdef DIAGNOSTIC
|
||||
memset(tp, 0xff, dbp->pgsize);
|
||||
#endif
|
||||
if ((ret = __os_malloc(pgsize, NULL, &tp)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Create new page for the split. */
|
||||
if ((ret = newfunc(dbp, P_DUPLICATE, &np)) != 0) {
|
||||
FREE(tp, dbp->pgsize);
|
||||
if ((ret = newfunc(dbc, P_DUPLICATE, &np)) != 0) {
|
||||
__os_free(tp, pgsize);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
P_INIT(np, dbp->pgsize, PGNO(np), PGNO(h), NEXT_PGNO(h), 0,
|
||||
P_INIT(np, pgsize, PGNO(np), PGNO(h), NEXT_PGNO(h), 0,
|
||||
P_DUPLICATE);
|
||||
P_INIT(tp, dbp->pgsize, PGNO(h), PREV_PGNO(h), PGNO(np), 0,
|
||||
P_INIT(tp, pgsize, PGNO(h), PREV_PGNO(h), PGNO(np), 0,
|
||||
P_DUPLICATE);
|
||||
|
||||
/* Figure out the split point */
|
||||
halfbytes = (dbp->pgsize - HOFFSET(h)) / 2;
|
||||
halfbytes = (pgsize - HOFFSET(h)) / 2;
|
||||
did_indx = 0;
|
||||
for (sum = 0, lastsum = 0, i = 0; i < NUM_ENT(h); i++) {
|
||||
if (i == indx) {
|
||||
@ -237,7 +254,6 @@ __db_dsplit(dbp, hp, indxp, size, newfunc)
|
||||
(db_indx_t)(sum - halfbytes)) {
|
||||
*hp = np;
|
||||
*indxp = 0;
|
||||
i--;
|
||||
} else
|
||||
*indxp = i;
|
||||
break;
|
||||
@ -252,29 +268,28 @@ __db_dsplit(dbp, hp, indxp, size, newfunc)
|
||||
|
||||
if (lastsum < halfbytes && sum >= halfbytes) {
|
||||
/* We've crossed the halfway point. */
|
||||
if ((db_indx_t)(halfbytes - lastsum) <
|
||||
(db_indx_t)(sum - halfbytes))
|
||||
i--;
|
||||
if ((db_indx_t)(sum - halfbytes) <
|
||||
(db_indx_t)(halfbytes - lastsum))
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we have set the return values of the index pointer and
|
||||
* page pointer.
|
||||
*/
|
||||
if (!did_indx) {
|
||||
*hp = np;
|
||||
*indxp = indx - i - 1;
|
||||
*indxp = indx - i;
|
||||
}
|
||||
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
page_dbt.size = dbp->pgsize;
|
||||
page_dbt.data = h;
|
||||
if ((ret = __db_split_log(dbp->dbenv->lg_info,
|
||||
dbp->txn, &LSN(h), 0, DB_SPLITOLD, dbp->log_fileid,
|
||||
dbc->txn, &LSN(h), 0, DB_SPLITOLD, dbp->log_fileid,
|
||||
PGNO(h), &page_dbt, &LSN(h))) != 0) {
|
||||
FREE(tp, dbp->pgsize);
|
||||
__os_free(tp, pgsize);
|
||||
return (ret);
|
||||
}
|
||||
LSN(tp) = LSN(h);
|
||||
@ -283,12 +298,12 @@ __db_dsplit(dbp, hp, indxp, size, newfunc)
|
||||
/*
|
||||
* If it's a btree, adjust the cursors.
|
||||
*
|
||||
* i is the index of the last element to stay on the page.
|
||||
* i is the index of the first element to move onto the new page.
|
||||
*/
|
||||
if (dbp->type == DB_BTREE || dbp->type == DB_RECNO)
|
||||
__bam_ca_split(dbp, PGNO(h), PGNO(h), PGNO(np), i + 1, 0);
|
||||
if (dbp->type == DB_BTREE)
|
||||
__bam_ca_split(dbp, PGNO(h), PGNO(h), PGNO(np), i, 0);
|
||||
|
||||
for (nindex = 0, oindex = i + 1; oindex < NUM_ENT(h); oindex++) {
|
||||
for (nindex = 0, oindex = i; oindex < NUM_ENT(h); oindex++) {
|
||||
bk = GET_BKEYDATA(h, oindex);
|
||||
if (B_TYPE(bk->type) == B_KEYDATA)
|
||||
s = BKEYDATA_SIZE(bk->len);
|
||||
@ -304,7 +319,7 @@ __db_dsplit(dbp, hp, indxp, size, newfunc)
|
||||
* Now do data compaction by copying the remaining stuff onto the
|
||||
* temporary page and then copying it back to the real page.
|
||||
*/
|
||||
for (nindex = 0, oindex = 0; oindex <= i; oindex++) {
|
||||
for (nindex = 0, oindex = 0; oindex < i; oindex++) {
|
||||
bk = GET_BKEYDATA(h, oindex);
|
||||
if (B_TYPE(bk->type) == B_KEYDATA)
|
||||
s = BKEYDATA_SIZE(bk->len);
|
||||
@ -324,59 +339,73 @@ __db_dsplit(dbp, hp, indxp, size, newfunc)
|
||||
*/
|
||||
memcpy(h, tp, LOFFSET(tp));
|
||||
memcpy((u_int8_t *)h + HOFFSET(tp),
|
||||
(u_int8_t *)tp + HOFFSET(tp), dbp->pgsize - HOFFSET(tp));
|
||||
FREE(tp, dbp->pgsize);
|
||||
(u_int8_t *)tp + HOFFSET(tp), pgsize - HOFFSET(tp));
|
||||
__os_free(tp, pgsize);
|
||||
|
||||
if (DB_LOGGING(dbp)) {
|
||||
page_dbt.size = dbp->pgsize;
|
||||
if (DB_LOGGING(dbc)) {
|
||||
/*
|
||||
* XXX
|
||||
* If either of these fails, are we leaving pages pinned?
|
||||
* Yes, but it seems like this happens in error case.
|
||||
*/
|
||||
page_dbt.size = pgsize;
|
||||
page_dbt.data = h;
|
||||
if ((ret = __db_split_log(dbp->dbenv->lg_info,
|
||||
dbp->txn, &LSN(h), 0, DB_SPLITNEW, dbp->log_fileid,
|
||||
dbc->txn, &LSN(h), 0, DB_SPLITNEW, dbp->log_fileid,
|
||||
PGNO(h), &page_dbt, &LSN(h))) != 0)
|
||||
return (ret);
|
||||
|
||||
page_dbt.size = dbp->pgsize;
|
||||
page_dbt.size = pgsize;
|
||||
page_dbt.data = np;
|
||||
if ((ret = __db_split_log(dbp->dbenv->lg_info,
|
||||
dbp->txn, &LSN(np), 0, DB_SPLITNEW, dbp->log_fileid,
|
||||
dbc->txn, &LSN(np), 0, DB_SPLITNEW, dbp->log_fileid,
|
||||
PGNO(np), &page_dbt, &LSN(np))) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, if there was a next page after the page being
|
||||
* split, fix its prev pointer.
|
||||
*/
|
||||
if (np->next_pgno != PGNO_INVALID)
|
||||
ret = __db_relink(dbc, DB_ADD_PAGE, np, NULL, 1);
|
||||
|
||||
/*
|
||||
* Figure out if the location we're interested in is on the new
|
||||
* page, and if so, reset the callers' pointer. Push the other
|
||||
* page back to the store.
|
||||
*/
|
||||
if (*hp == h)
|
||||
ret = memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY);
|
||||
t_ret = memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY);
|
||||
else
|
||||
ret = memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY);
|
||||
t_ret = memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY);
|
||||
|
||||
return (ret);
|
||||
return (ret != 0 ? ret : t_ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_ditem --
|
||||
* Remove an item from a page.
|
||||
*
|
||||
* PUBLIC: int __db_ditem __P((DB *, PAGE *, u_int32_t, u_int32_t));
|
||||
* PUBLIC: int __db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_ditem(dbp, pagep, indx, nbytes)
|
||||
DB *dbp;
|
||||
__db_ditem(dbc, pagep, indx, nbytes)
|
||||
DBC *dbc;
|
||||
PAGE *pagep;
|
||||
u_int32_t indx, nbytes;
|
||||
{
|
||||
DB *dbp;
|
||||
DBT ldbt;
|
||||
db_indx_t cnt, offset;
|
||||
int ret;
|
||||
u_int8_t *from;
|
||||
|
||||
if (DB_LOGGING(dbp)) {
|
||||
dbp = dbc->dbp;
|
||||
if (DB_LOGGING(dbc)) {
|
||||
ldbt.data = P_ENTRY(pagep, indx);
|
||||
ldbt.size = nbytes;
|
||||
if ((ret = __db_addrem_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if ((ret = __db_addrem_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&LSN(pagep), 0, DB_REM_DUP, dbp->log_fileid, PGNO(pagep),
|
||||
(u_int32_t)indx, nbytes, &ldbt, NULL, &LSN(pagep))) != 0)
|
||||
return (ret);
|
||||
@ -413,7 +442,7 @@ __db_ditem(dbp, pagep, indx, nbytes)
|
||||
sizeof(db_indx_t) * (NUM_ENT(pagep) - indx));
|
||||
|
||||
/* If it's a btree, adjust the cursors. */
|
||||
if (dbp->type == DB_BTREE || dbp->type == DB_RECNO)
|
||||
if (dbp->type == DB_BTREE)
|
||||
__bam_ca_di(dbp, PGNO(pagep), indx, -1);
|
||||
|
||||
return (0);
|
||||
@ -424,16 +453,17 @@ __db_ditem(dbp, pagep, indx, nbytes)
|
||||
* Put an item on a page.
|
||||
*
|
||||
* PUBLIC: int __db_pitem
|
||||
* PUBLIC: __P((DB *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *));
|
||||
* PUBLIC: __P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *));
|
||||
*/
|
||||
int
|
||||
__db_pitem(dbp, pagep, indx, nbytes, hdr, data)
|
||||
DB *dbp;
|
||||
__db_pitem(dbc, pagep, indx, nbytes, hdr, data)
|
||||
DBC *dbc;
|
||||
PAGE *pagep;
|
||||
u_int32_t indx;
|
||||
u_int32_t nbytes;
|
||||
DBT *hdr, *data;
|
||||
{
|
||||
DB *dbp;
|
||||
BKEYDATA bk;
|
||||
DBT thdr;
|
||||
int ret;
|
||||
@ -456,8 +486,9 @@ __db_pitem(dbp, pagep, indx, nbytes, hdr, data)
|
||||
* the passed in header sizes must be adjusted for the structure's
|
||||
* placeholder for the trailing variable-length data field.
|
||||
*/
|
||||
if (DB_LOGGING(dbp))
|
||||
if ((ret = __db_addrem_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
dbp = dbc->dbp;
|
||||
if (DB_LOGGING(dbc))
|
||||
if ((ret = __db_addrem_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&LSN(pagep), 0, DB_ADD_DUP, dbp->log_fileid, PGNO(pagep),
|
||||
(u_int32_t)indx, nbytes, hdr, data, &LSN(pagep))) != 0)
|
||||
return (ret);
|
||||
@ -485,7 +516,7 @@ __db_pitem(dbp, pagep, indx, nbytes, hdr, data)
|
||||
memcpy(p + hdr->size, data->data, data->size);
|
||||
|
||||
/* If it's a btree, adjust the cursors. */
|
||||
if (dbp->type == DB_BTREE || dbp->type == DB_RECNO)
|
||||
if (dbp->type == DB_BTREE)
|
||||
__bam_ca_di(dbp, PGNO(pagep), indx, 1);
|
||||
|
||||
return (0);
|
||||
@ -495,14 +526,16 @@ __db_pitem(dbp, pagep, indx, nbytes, hdr, data)
|
||||
* __db_relink --
|
||||
* Relink around a deleted page.
|
||||
*
|
||||
* PUBLIC: int __db_relink __P((DB *, PAGE *, PAGE **, int));
|
||||
* PUBLIC: int __db_relink __P((DBC *, u_int32_t, PAGE *, PAGE **, int));
|
||||
*/
|
||||
int
|
||||
__db_relink(dbp, pagep, new_next, needlock)
|
||||
DB *dbp;
|
||||
__db_relink(dbc, add_rem, pagep, new_next, needlock)
|
||||
DBC *dbc;
|
||||
u_int32_t add_rem;
|
||||
PAGE *pagep, **new_next;
|
||||
int needlock;
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *np, *pp;
|
||||
DB_LOCK npl, ppl;
|
||||
DB_LSN *nlsnp, *plsnp;
|
||||
@ -512,10 +545,15 @@ __db_relink(dbp, pagep, new_next, needlock)
|
||||
np = pp = NULL;
|
||||
npl = ppl = LOCK_INVALID;
|
||||
nlsnp = plsnp = NULL;
|
||||
dbp = dbc->dbp;
|
||||
|
||||
/* Retrieve and lock the two pages. */
|
||||
/*
|
||||
* Retrieve and lock the one/two pages. For a remove, we may need
|
||||
* two pages (the before and after). For an add, we only need one
|
||||
* because, the split took care of the prev.
|
||||
*/
|
||||
if (pagep->next_pgno != PGNO_INVALID) {
|
||||
if (needlock && (ret = __bam_lget(dbp,
|
||||
if (needlock && (ret = __bam_lget(dbc,
|
||||
0, pagep->next_pgno, DB_LOCK_WRITE, &npl)) != 0)
|
||||
goto err;
|
||||
if ((ret = memp_fget(dbp->mpf,
|
||||
@ -525,8 +563,8 @@ __db_relink(dbp, pagep, new_next, needlock)
|
||||
}
|
||||
nlsnp = &np->lsn;
|
||||
}
|
||||
if (pagep->prev_pgno != PGNO_INVALID) {
|
||||
if (needlock && (ret = __bam_lget(dbp,
|
||||
if (add_rem == DB_REM_PAGE && pagep->prev_pgno != PGNO_INVALID) {
|
||||
if (needlock && (ret = __bam_lget(dbc,
|
||||
0, pagep->prev_pgno, DB_LOCK_WRITE, &ppl)) != 0)
|
||||
goto err;
|
||||
if ((ret = memp_fget(dbp->mpf,
|
||||
@ -538,9 +576,10 @@ __db_relink(dbp, pagep, new_next, needlock)
|
||||
}
|
||||
|
||||
/* Log the change. */
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if ((ret = __db_relink_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
&pagep->lsn, 0, dbp->log_fileid, pagep->pgno, &pagep->lsn,
|
||||
if (DB_LOGGING(dbc)) {
|
||||
if ((ret = __db_relink_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&pagep->lsn, 0, add_rem, dbp->log_fileid,
|
||||
pagep->pgno, &pagep->lsn,
|
||||
pagep->prev_pgno, plsnp, pagep->next_pgno, nlsnp)) != 0)
|
||||
goto err;
|
||||
if (np != NULL)
|
||||
@ -558,7 +597,10 @@ __db_relink(dbp, pagep, new_next, needlock)
|
||||
* set to NULL.
|
||||
*/
|
||||
if (np != NULL) {
|
||||
np->prev_pgno = pagep->prev_pgno;
|
||||
if (add_rem == DB_ADD_PAGE)
|
||||
np->prev_pgno = pagep->pgno;
|
||||
else
|
||||
np->prev_pgno = pagep->prev_pgno;
|
||||
if (new_next == NULL)
|
||||
ret = memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY);
|
||||
else {
|
||||
@ -568,7 +610,7 @@ __db_relink(dbp, pagep, new_next, needlock)
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
if (needlock)
|
||||
(void)__bam_lput(dbp, npl);
|
||||
(void)__bam_lput(dbc, npl);
|
||||
} else if (new_next != NULL)
|
||||
*new_next = NULL;
|
||||
|
||||
@ -577,18 +619,18 @@ __db_relink(dbp, pagep, new_next, needlock)
|
||||
if ((ret = memp_fput(dbp->mpf, pp, DB_MPOOL_DIRTY)) != 0)
|
||||
goto err;
|
||||
if (needlock)
|
||||
(void)__bam_lput(dbp, ppl);
|
||||
(void)__bam_lput(dbc, ppl);
|
||||
}
|
||||
return (0);
|
||||
|
||||
err: if (np != NULL)
|
||||
(void)memp_fput(dbp->mpf, np, 0);
|
||||
if (needlock && npl != LOCK_INVALID)
|
||||
(void)__bam_lput(dbp, npl);
|
||||
(void)__bam_lput(dbc, npl);
|
||||
if (pp != NULL)
|
||||
(void)memp_fput(dbp->mpf, pp, 0);
|
||||
if (needlock && ppl != LOCK_INVALID)
|
||||
(void)__bam_lput(dbp, ppl);
|
||||
(void)__bam_lput(dbc, ppl);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -596,34 +638,37 @@ err: if (np != NULL)
|
||||
* __db_ddup --
|
||||
* Delete an offpage chain of duplicates.
|
||||
*
|
||||
* PUBLIC: int __db_ddup __P((DB *, db_pgno_t, int (*)(DB *, PAGE *)));
|
||||
* PUBLIC: int __db_ddup __P((DBC *, db_pgno_t, int (*)(DBC *, PAGE *)));
|
||||
*/
|
||||
int
|
||||
__db_ddup(dbp, pgno, freefunc)
|
||||
DB *dbp;
|
||||
__db_ddup(dbc, pgno, freefunc)
|
||||
DBC *dbc;
|
||||
db_pgno_t pgno;
|
||||
int (*freefunc) __P((DB *, PAGE *));
|
||||
int (*freefunc) __P((DBC *, PAGE *));
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *pagep;
|
||||
DBT tmp_dbt;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
do {
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) {
|
||||
(void)__db_pgerr(dbp, pgno);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
tmp_dbt.data = pagep;
|
||||
tmp_dbt.size = dbp->pgsize;
|
||||
if ((ret = __db_split_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
&LSN(pagep), 0, DB_SPLITOLD, dbp->log_fileid,
|
||||
PGNO(pagep), &tmp_dbt, &LSN(pagep))) != 0)
|
||||
if ((ret = __db_split_log(dbp->dbenv->lg_info,
|
||||
dbc->txn, &LSN(pagep), 0, DB_SPLITOLD,
|
||||
dbp->log_fileid, PGNO(pagep), &tmp_dbt,
|
||||
&LSN(pagep))) != 0)
|
||||
return (ret);
|
||||
}
|
||||
pgno = pagep->next_pgno;
|
||||
if ((ret = freefunc(dbp, pagep)) != 0)
|
||||
if ((ret = freefunc(dbc, pagep)) != 0)
|
||||
return (ret);
|
||||
} while (pgno != PGNO_INVALID);
|
||||
|
||||
@ -636,21 +681,23 @@ __db_ddup(dbp, pgno, freefunc)
|
||||
* current page.
|
||||
*/
|
||||
static int
|
||||
__db_addpage(dbp, hp, indxp, newfunc)
|
||||
DB *dbp;
|
||||
__db_addpage(dbc, hp, indxp, newfunc)
|
||||
DBC *dbc;
|
||||
PAGE **hp;
|
||||
db_indx_t *indxp;
|
||||
int (*newfunc) __P((DB *, u_int32_t, PAGE **));
|
||||
int (*newfunc) __P((DBC *, u_int32_t, PAGE **));
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *newpage;
|
||||
int ret;
|
||||
|
||||
if ((ret = newfunc(dbp, P_DUPLICATE, &newpage)) != 0)
|
||||
dbp = dbc->dbp;
|
||||
if ((ret = newfunc(dbc, P_DUPLICATE, &newpage)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
if ((ret = __db_addpage_log(dbp->dbenv->lg_info,
|
||||
dbp->txn, &LSN(*hp), 0, dbp->log_fileid,
|
||||
dbc->txn, &LSN(*hp), 0, dbp->log_fileid,
|
||||
PGNO(*hp), &LSN(*hp), PGNO(newpage), &LSN(newpage))) != 0) {
|
||||
return (ret);
|
||||
}
|
||||
@ -666,3 +713,235 @@ __db_addpage(dbp, hp, indxp, newfunc)
|
||||
*indxp = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_dsearch --
|
||||
* Search a set of duplicates for the proper position for a new duplicate.
|
||||
*
|
||||
* + pgno is the page number of the page on which to begin searching.
|
||||
* Since we can continue duplicate searches, it might not be the first
|
||||
* page.
|
||||
*
|
||||
* + If we are continuing a search, then *pp may be non-NULL in which
|
||||
* case we do not have to retrieve the page.
|
||||
*
|
||||
* + If we are continuing a search, then *indxp contains the first
|
||||
* on pgno of where we should begin the search.
|
||||
*
|
||||
* NOTE: if there is no comparison function, then continuing is
|
||||
* meaningless, and *pp should always be NULL and *indxp will be
|
||||
* ignored.
|
||||
*
|
||||
* 3 return values::
|
||||
*
|
||||
* + pp is the returned page pointer of where this element should go.
|
||||
* + indxp is the returned index on that page
|
||||
* + cmpp is the returned final comparison result.
|
||||
*
|
||||
* PUBLIC: int __db_dsearch __P((DBC *,
|
||||
* PUBLIC: int, DBT *, db_pgno_t, db_indx_t *, PAGE **, int *));
|
||||
*/
|
||||
int
|
||||
__db_dsearch(dbc, is_insert, dbt, pgno, indxp, pp, cmpp)
|
||||
DBC *dbc;
|
||||
int is_insert, *cmpp;
|
||||
DBT *dbt;
|
||||
db_pgno_t pgno;
|
||||
db_indx_t *indxp;
|
||||
PAGE **pp;
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *h;
|
||||
db_indx_t base, indx, lim, save_indx;
|
||||
db_pgno_t save_pgno;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
if (dbp->dup_compare == NULL) {
|
||||
/*
|
||||
* We may have been given a valid page, but we may not be
|
||||
* able to use it. The problem is that the application is
|
||||
* doing a join and we're trying to continue the search,
|
||||
* but since the items aren't sorted, we can't. Discard
|
||||
* the page if it's not the one we're going to start with
|
||||
* anyway.
|
||||
*/
|
||||
if (*pp != NULL && (*pp)->pgno != pgno) {
|
||||
if ((ret = memp_fput(dbp->mpf, *pp, 0)) != 0)
|
||||
return (ret);
|
||||
*pp = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no duplicate function is specified, just go to the end
|
||||
* of the duplicate set.
|
||||
*/
|
||||
if (is_insert) {
|
||||
if ((ret = __db_dend(dbc, pgno, pp)) != 0)
|
||||
return (ret);
|
||||
*indxp = NUM_ENT(*pp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are looking for a specific duplicate, so do a linear
|
||||
* search.
|
||||
*/
|
||||
if (*pp != NULL)
|
||||
goto nocmp_started;
|
||||
for (;;) {
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, pp)) != 0)
|
||||
goto pg_err;
|
||||
nocmp_started: h = *pp;
|
||||
|
||||
for (*indxp = 0; *indxp < NUM_ENT(h); ++*indxp) {
|
||||
if ((*cmpp = __bam_cmp(dbp,
|
||||
dbt, h, *indxp, __bam_defcmp)) != 0)
|
||||
continue;
|
||||
/*
|
||||
* The duplicate may have already been deleted,
|
||||
* if it's a btree page, in which case we skip
|
||||
* it.
|
||||
*/
|
||||
if (dbp->type == DB_BTREE &&
|
||||
B_DISSET(GET_BKEYDATA(h, *indxp)->type))
|
||||
continue;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((pgno = h->next_pgno) == PGNO_INVALID)
|
||||
break;
|
||||
|
||||
if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
*cmpp = 1; /* We didn't succeed... */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a comparison routine, i.e., the duplicates are sorted.
|
||||
* Walk through the chain of duplicates, checking the last entry
|
||||
* on each page to decide if it's the page we want to search.
|
||||
*
|
||||
* *pp may be non-NULL -- if we were given a valid page (e.g., are
|
||||
* in mid-search), then use the provided page.
|
||||
*/
|
||||
if (*pp != NULL)
|
||||
goto cmp_started;
|
||||
for (;;) {
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, pp)) != 0)
|
||||
goto pg_err;
|
||||
cmp_started: h = *pp;
|
||||
|
||||
if ((pgno = h->next_pgno) == PGNO_INVALID || __bam_cmp(dbp,
|
||||
dbt, h, h->entries - 1, dbp->dup_compare) <= 0)
|
||||
break;
|
||||
/*
|
||||
* Even when continuing a search, make sure we don't skip
|
||||
* entries on a new page
|
||||
*/
|
||||
*indxp = 0;
|
||||
|
||||
if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Next, do a binary search on the page. */
|
||||
base = F_ISSET(dbc, DBC_CONTINUE) ? *indxp : 0;
|
||||
for (lim = NUM_ENT(h) - base; lim != 0; lim >>= 1) {
|
||||
indx = base + (lim >> 1);
|
||||
if ((*cmpp = __bam_cmp(dbp,
|
||||
dbt, h, indx, dbp->dup_compare)) == 0) {
|
||||
*indxp = indx;
|
||||
|
||||
if (dbp->type != DB_BTREE ||
|
||||
!B_DISSET(GET_BKEYDATA(h, *indxp)->type))
|
||||
return (0);
|
||||
goto check_delete;
|
||||
}
|
||||
if (*cmpp > 0) {
|
||||
base = indx + 1;
|
||||
lim--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Base references the smallest index larger than the supplied DBT's
|
||||
* data item, potentially both 0 and NUM_ENT.
|
||||
*/
|
||||
*indxp = base;
|
||||
return (0);
|
||||
|
||||
check_delete:
|
||||
/*
|
||||
* The duplicate may have already been deleted, if it's a btree page,
|
||||
* in which case we wander around, hoping to find an entry that hasn't
|
||||
* been deleted. First, wander in a forwardly direction.
|
||||
*/
|
||||
save_pgno = (*pp)->pgno;
|
||||
save_indx = *indxp;
|
||||
for (++*indxp;;) {
|
||||
for (; *indxp < NUM_ENT(h); ++*indxp) {
|
||||
if ((*cmpp = __bam_cmp(dbp,
|
||||
dbt, h, *indxp, dbp->dup_compare)) != 0)
|
||||
goto check_delete_rev;
|
||||
|
||||
if (!B_DISSET(GET_BKEYDATA(h, *indxp)->type))
|
||||
return (0);
|
||||
}
|
||||
if ((pgno = h->next_pgno) == PGNO_INVALID)
|
||||
break;
|
||||
|
||||
if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, pp)) != 0)
|
||||
goto pg_err;
|
||||
h = *pp;
|
||||
|
||||
*indxp = 0;
|
||||
}
|
||||
|
||||
check_delete_rev:
|
||||
/* Go back to where we started, and wander in a backwardly direction. */
|
||||
if (h->pgno != save_pgno) {
|
||||
if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
|
||||
return (ret);
|
||||
if ((ret = memp_fget(dbp->mpf, &save_pgno, 0, pp)) != 0)
|
||||
goto pg_err;
|
||||
h = *pp;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
while (*indxp > 0) {
|
||||
--*indxp;
|
||||
if ((*cmpp = __bam_cmp(dbp,
|
||||
dbt, h, *indxp, dbp->dup_compare)) != 0)
|
||||
goto check_delete_fail;
|
||||
|
||||
if (!B_DISSET(GET_BKEYDATA(h, *indxp)->type))
|
||||
return (0);
|
||||
}
|
||||
if ((pgno = h->prev_pgno) == PGNO_INVALID)
|
||||
break;
|
||||
|
||||
if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, pp)) != 0)
|
||||
goto pg_err;
|
||||
h = *pp;
|
||||
|
||||
*indxp = NUM_ENT(h);
|
||||
}
|
||||
|
||||
check_delete_fail:
|
||||
*cmpp = 1; /* We didn't succeed... */
|
||||
return (0);
|
||||
|
||||
pg_err: __db_pgerr(dbp, pgno);
|
||||
return (ret);
|
||||
}
|
||||
|
488
db2/db/db_iface.c
Normal file
488
db2/db/db_iface.c
Normal file
@ -0,0 +1,488 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_iface.c 10.40 (Sleepycat) 12/19/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "db_auto.h"
|
||||
#include "db_ext.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
static int __db_keyempty __P((const DB_ENV *));
|
||||
static int __db_rdonly __P((const DB_ENV *, const char *));
|
||||
static int __dbt_ferr __P((const DB *, const char *, const DBT *, int));
|
||||
|
||||
/*
|
||||
* __db_cdelchk --
|
||||
* Common cursor delete argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int, int));
|
||||
*/
|
||||
int
|
||||
__db_cdelchk(dbp, flags, isrdonly, isvalid)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
int isrdonly, isvalid;
|
||||
{
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "c_del"));
|
||||
|
||||
/* Check for invalid function flags. */
|
||||
switch (flags) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (__db_ferr(dbp->dbenv, "DBcursor->c_del", 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* The cursor must be initialized, return -1 for an invalid cursor,
|
||||
* otherwise 0.
|
||||
*/
|
||||
return (isvalid ? 0 : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_cgetchk --
|
||||
* Common cursor get argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
|
||||
*/
|
||||
int
|
||||
__db_cgetchk(dbp, key, data, flags, isvalid)
|
||||
const DB *dbp;
|
||||
DBT *key, *data;
|
||||
u_int32_t flags;
|
||||
int isvalid;
|
||||
{
|
||||
int key_einval, key_flags, ret;
|
||||
|
||||
key_einval = key_flags = 0;
|
||||
|
||||
/* Check for invalid function flags. */
|
||||
LF_CLR(DB_RMW);
|
||||
switch (flags) {
|
||||
case DB_NEXT_DUP:
|
||||
if (dbp->type == DB_RECNO)
|
||||
goto err;
|
||||
/* FALLTHROUGH */
|
||||
case DB_CURRENT:
|
||||
case DB_FIRST:
|
||||
case DB_LAST:
|
||||
case DB_NEXT:
|
||||
case DB_PREV:
|
||||
key_flags = 1;
|
||||
break;
|
||||
case DB_GET_BOTH:
|
||||
case DB_SET_RANGE:
|
||||
key_einval = key_flags = 1;
|
||||
break;
|
||||
case DB_SET:
|
||||
key_einval = 1;
|
||||
break;
|
||||
case DB_GET_RECNO:
|
||||
if (!F_ISSET(dbp, DB_BT_RECNUM))
|
||||
goto err;
|
||||
break;
|
||||
case DB_SET_RECNO:
|
||||
if (!F_ISSET(dbp, DB_BT_RECNUM))
|
||||
goto err;
|
||||
key_einval = key_flags = 1;
|
||||
break;
|
||||
default:
|
||||
err: return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0));
|
||||
}
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key_einval && (key->data == NULL || key->size == 0))
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
/*
|
||||
* The cursor must be initialized for DB_CURRENT, return -1 for an
|
||||
* invalid cursor, otherwise 0.
|
||||
*/
|
||||
return (isvalid || flags != DB_CURRENT ? 0 : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_cputchk --
|
||||
* Common cursor put argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_cputchk __P((const DB *,
|
||||
* PUBLIC: const DBT *, DBT *, u_int32_t, int, int));
|
||||
*/
|
||||
int
|
||||
__db_cputchk(dbp, key, data, flags, isrdonly, isvalid)
|
||||
const DB *dbp;
|
||||
const DBT *key;
|
||||
DBT *data;
|
||||
u_int32_t flags;
|
||||
int isrdonly, isvalid;
|
||||
{
|
||||
int key_einval, key_flags, ret;
|
||||
|
||||
key_einval = key_flags = 0;
|
||||
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "c_put"));
|
||||
|
||||
/* Check for invalid function flags. */
|
||||
switch (flags) {
|
||||
case DB_AFTER:
|
||||
case DB_BEFORE:
|
||||
if (dbp->dup_compare != NULL)
|
||||
goto err;
|
||||
if (dbp->type == DB_RECNO && !F_ISSET(dbp, DB_RE_RENUMBER))
|
||||
goto err;
|
||||
if (dbp->type != DB_RECNO && !F_ISSET(dbp, DB_AM_DUP))
|
||||
goto err;
|
||||
break;
|
||||
case DB_CURRENT:
|
||||
/*
|
||||
* If there is a comparison function, doing a DB_CURRENT
|
||||
* must not change the part of the data item that is used
|
||||
* for the comparison.
|
||||
*/
|
||||
break;
|
||||
case DB_KEYFIRST:
|
||||
case DB_KEYLAST:
|
||||
if (dbp->type == DB_RECNO)
|
||||
goto err;
|
||||
key_einval = key_flags = 1;
|
||||
break;
|
||||
default:
|
||||
err: return (__db_ferr(dbp->dbenv, "DBcursor->c_put", 0));
|
||||
}
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key_einval && (key->data == NULL || key->size == 0))
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
/*
|
||||
* The cursor must be initialized for anything other than DB_KEYFIRST
|
||||
* and DB_KEYLAST, return -1 for an invalid cursor, otherwise 0.
|
||||
*/
|
||||
return (isvalid ||
|
||||
flags == DB_KEYFIRST || flags == DB_KEYLAST ? 0 : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_closechk --
|
||||
* DB->close flag check.
|
||||
*
|
||||
* PUBLIC: int __db_closechk __P((const DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_closechk(dbp, flags)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
/* Check for invalid function flags. */
|
||||
if (flags != 0 && flags != DB_NOSYNC)
|
||||
return (__db_ferr(dbp->dbenv, "DB->close", 0));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_delchk --
|
||||
* Common delete argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t, int));
|
||||
*/
|
||||
int
|
||||
__db_delchk(dbp, key, flags, isrdonly)
|
||||
const DB *dbp;
|
||||
DBT *key;
|
||||
u_int32_t flags;
|
||||
int isrdonly;
|
||||
{
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "delete"));
|
||||
|
||||
/* Check for invalid function flags. */
|
||||
switch (flags) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (__db_ferr(dbp->dbenv, "DB->del", 0));
|
||||
}
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key->data == NULL || key->size == 0)
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_getchk --
|
||||
* Common get argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_getchk(dbp, key, data, flags)
|
||||
const DB *dbp;
|
||||
const DBT *key;
|
||||
DBT *data;
|
||||
u_int32_t flags;
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check for invalid function flags. */
|
||||
LF_CLR(DB_RMW);
|
||||
switch (flags) {
|
||||
case 0:
|
||||
case DB_GET_BOTH:
|
||||
break;
|
||||
case DB_SET_RECNO:
|
||||
if (!F_ISSET(dbp, DB_BT_RECNUM))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
err: return (__db_ferr(dbp->dbenv, "DB->get", 0));
|
||||
}
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
if ((ret = __dbt_ferr(dbp, "key", key, flags == DB_SET_RECNO)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key->data == NULL || key->size == 0)
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_joinchk --
|
||||
* Common join argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_joinchk __P((const DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_joinchk(dbp, flags)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
if (flags != 0)
|
||||
return (__db_ferr(dbp->dbenv, "DB->join", 0));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_putchk --
|
||||
* Common put argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_putchk
|
||||
* PUBLIC: __P((const DB *, DBT *, const DBT *, u_int32_t, int, int));
|
||||
*/
|
||||
int
|
||||
__db_putchk(dbp, key, data, flags, isrdonly, isdup)
|
||||
const DB *dbp;
|
||||
DBT *key;
|
||||
const DBT *data;
|
||||
u_int32_t flags;
|
||||
int isrdonly, isdup;
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check for changes to a read-only tree. */
|
||||
if (isrdonly)
|
||||
return (__db_rdonly(dbp->dbenv, "put"));
|
||||
|
||||
/* Check for invalid function flags. */
|
||||
switch (flags) {
|
||||
case 0:
|
||||
case DB_NOOVERWRITE:
|
||||
break;
|
||||
case DB_APPEND:
|
||||
if (dbp->type != DB_RECNO)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
err: return (__db_ferr(dbp->dbenv, "DB->put", 0));
|
||||
}
|
||||
|
||||
/* Check for invalid key/data flags. */
|
||||
if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Check for missing keys. */
|
||||
if (key->data == NULL || key->size == 0)
|
||||
return (__db_keyempty(dbp->dbenv));
|
||||
|
||||
/* Check for partial puts in the presence of duplicates. */
|
||||
if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) {
|
||||
__db_err(dbp->dbenv,
|
||||
"a partial put in the presence of duplicates requires a cursor operation");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_statchk --
|
||||
* Common stat argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_statchk __P((const DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_statchk(dbp, flags)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
/* Check for invalid function flags. */
|
||||
switch (flags) {
|
||||
case 0:
|
||||
break;
|
||||
case DB_RECORDCOUNT:
|
||||
if (dbp->type == DB_RECNO)
|
||||
break;
|
||||
if (dbp->type == DB_BTREE && F_ISSET(dbp, DB_BT_RECNUM))
|
||||
break;
|
||||
goto err;
|
||||
default:
|
||||
err: return (__db_ferr(dbp->dbenv, "DB->stat", 0));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_syncchk --
|
||||
* Common sync argument checking routine.
|
||||
*
|
||||
* PUBLIC: int __db_syncchk __P((const DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_syncchk(dbp, flags)
|
||||
const DB *dbp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
/* Check for invalid function flags. */
|
||||
switch (flags) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (__db_ferr(dbp->dbenv, "DB->sync", 0));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __dbt_ferr --
|
||||
* Check a DBT for flag errors.
|
||||
*/
|
||||
static int
|
||||
__dbt_ferr(dbp, name, dbt, check_thread)
|
||||
const DB *dbp;
|
||||
const char *name;
|
||||
const DBT *dbt;
|
||||
int check_thread;
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Check for invalid DBT flags. We allow any of the flags to be
|
||||
* specified to any DB or DBcursor call so that applications can
|
||||
* set DB_DBT_MALLOC when retrieving a data item from a secondary
|
||||
* database and then specify that same DBT as a key to a primary
|
||||
* database, without having to clear flags.
|
||||
*/
|
||||
if ((ret = __db_fchk(dbp->dbenv, name, dbt->flags,
|
||||
DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_fcchk(dbp->dbenv, name,
|
||||
dbt->flags, DB_DBT_MALLOC, DB_DBT_USERMEM)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (check_thread && F_ISSET(dbp, DB_AM_THREAD) &&
|
||||
!F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_USERMEM)) {
|
||||
__db_err(dbp->dbenv,
|
||||
"missing flag thread flag for %s DBT", name);
|
||||
return (EINVAL);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_eopnotsup --
|
||||
* Common operation not supported message.
|
||||
*
|
||||
* PUBLIC: int __db_eopnotsup __P((const DB_ENV *));
|
||||
*/
|
||||
int
|
||||
__db_eopnotsup(dbenv)
|
||||
const DB_ENV *dbenv;
|
||||
{
|
||||
__db_err(dbenv, "operation not supported");
|
||||
#ifdef EOPNOTSUPP
|
||||
return (EOPNOTSUPP);
|
||||
#else
|
||||
return (EINVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_keyempty --
|
||||
* Common missing or empty key value message.
|
||||
*/
|
||||
static int
|
||||
__db_keyempty(dbenv)
|
||||
const DB_ENV *dbenv;
|
||||
{
|
||||
__db_err(dbenv, "missing or empty key value specified");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_rdonly --
|
||||
* Common readonly message.
|
||||
*/
|
||||
static int
|
||||
__db_rdonly(dbenv, name)
|
||||
const DB_ENV *dbenv;
|
||||
const char *name;
|
||||
{
|
||||
__db_err(dbenv, "%s: attempt to modify a read-only tree", name);
|
||||
return (EACCES);
|
||||
}
|
271
db2/db/db_join.c
Normal file
271
db2/db/db_join.c
Normal file
@ -0,0 +1,271 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_join.c 10.10 (Sleepycat) 10/9/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "db_join.h"
|
||||
#include "db_am.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
static int __db_join_close __P((DBC *));
|
||||
static int __db_join_del __P((DBC *, u_int32_t));
|
||||
static int __db_join_get __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
static int __db_join_put __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
|
||||
/*
|
||||
* This is the duplicate-assisted join functionality. Right now we're
|
||||
* going to write it such that we return one item at a time, although
|
||||
* I think we may need to optimize it to return them all at once.
|
||||
* It should be easier to get it working this way, and I believe that
|
||||
* changing it should be fairly straightforward.
|
||||
*
|
||||
* XXX
|
||||
* Right now we do not maintain the number of duplicates so we do
|
||||
* not optimize the join. If the caller does, then best performance
|
||||
* will be achieved by putting the cursor with the smallest cardinality
|
||||
* first.
|
||||
*
|
||||
* The first cursor moves sequentially through the duplicate set while
|
||||
* the others search explicitly for the duplicate in question.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* __db_join --
|
||||
* This is the interface to the duplicate-assisted join functionality.
|
||||
* In the same way that cursors mark a position in a database, a cursor
|
||||
* can mark a position in a join. While most cursors are created by the
|
||||
* cursor method of a DB, join cursors are created through an explicit
|
||||
* call to DB->join.
|
||||
*
|
||||
* The curslist is an array of existing, intialized cursors and primary
|
||||
* is the DB of the primary file. The data item that joins all the
|
||||
* cursors in the curslist is used as the key into the primary and that
|
||||
* key and data are returned. When no more items are left in the join
|
||||
* set, the c_next operation off the join cursor will return DB_NOTFOUND.
|
||||
*
|
||||
* PUBLIC: int __db_join __P((DB *, DBC **, u_int32_t, DBC **));
|
||||
*/
|
||||
int
|
||||
__db_join(primary, curslist, flags, dbcp)
|
||||
DB *primary;
|
||||
DBC **curslist, **dbcp;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DBC *dbc;
|
||||
JOIN_CURSOR *jc;
|
||||
int i, ret;
|
||||
|
||||
DB_PANIC_CHECK(primary);
|
||||
|
||||
if ((ret = __db_joinchk(primary, flags)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (curslist == NULL || curslist[0] == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
dbc = NULL;
|
||||
jc = NULL;
|
||||
|
||||
if ((ret = __os_calloc(1, sizeof(DBC), &dbc)) != 0)
|
||||
goto err;
|
||||
|
||||
if ((ret = __os_calloc(1, sizeof(JOIN_CURSOR), &jc)) != 0)
|
||||
goto err;
|
||||
|
||||
if ((ret = __os_malloc(256, NULL, &jc->j_key.data)) != 0)
|
||||
goto err;
|
||||
jc->j_key.ulen = 256;
|
||||
F_SET(&jc->j_key, DB_DBT_USERMEM);
|
||||
|
||||
for (jc->j_curslist = curslist;
|
||||
*jc->j_curslist != NULL; jc->j_curslist++)
|
||||
;
|
||||
if ((ret = __os_calloc((jc->j_curslist - curslist + 1),
|
||||
sizeof(DBC *), &jc->j_curslist)) != 0)
|
||||
goto err;
|
||||
for (i = 0; curslist[i] != NULL; i++) {
|
||||
if (i != 0)
|
||||
F_SET(curslist[i], DBC_KEYSET);
|
||||
jc->j_curslist[i] = curslist[i];
|
||||
}
|
||||
|
||||
dbc->c_close = __db_join_close;
|
||||
dbc->c_del = __db_join_del;
|
||||
dbc->c_get = __db_join_get;
|
||||
dbc->c_put = __db_join_put;
|
||||
dbc->internal = jc;
|
||||
dbc->dbp = primary;
|
||||
jc->j_init = 1;
|
||||
jc->j_primary = primary;
|
||||
|
||||
*dbcp = dbc;
|
||||
|
||||
return (0);
|
||||
|
||||
err: if (jc != NULL) {
|
||||
if (jc->j_curslist != NULL)
|
||||
__os_free(jc->j_curslist,
|
||||
(jc->j_curslist - curslist + 1) * sizeof(DBC *));
|
||||
__os_free(jc, sizeof(JOIN_CURSOR));
|
||||
}
|
||||
if (dbc != NULL)
|
||||
__os_free(dbc, sizeof(DBC));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
__db_join_put(dbc, key, data, flags)
|
||||
DBC *dbc;
|
||||
DBT *key;
|
||||
DBT *data;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DB_PANIC_CHECK(dbc->dbp);
|
||||
|
||||
COMPQUIET(key, NULL);
|
||||
COMPQUIET(data, NULL);
|
||||
COMPQUIET(flags, 0);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
__db_join_del(dbc, flags)
|
||||
DBC *dbc;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DB_PANIC_CHECK(dbc->dbp);
|
||||
|
||||
COMPQUIET(flags, 0);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
__db_join_get(dbc, key, data, flags)
|
||||
DBC *dbc;
|
||||
DBT *key, *data;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DB *dbp;
|
||||
DBC **cpp;
|
||||
JOIN_CURSOR *jc;
|
||||
int ret;
|
||||
u_int32_t operation;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
operation = LF_ISSET(DB_OPFLAGS_MASK);
|
||||
if (operation != 0 && operation != DB_JOIN_ITEM)
|
||||
return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0));
|
||||
|
||||
LF_CLR(DB_OPFLAGS_MASK);
|
||||
if ((ret =
|
||||
__db_fchk(dbp->dbenv, "DBcursor->c_get", flags, DB_RMW)) != 0)
|
||||
return (ret);
|
||||
|
||||
jc = (JOIN_CURSOR *)dbc->internal;
|
||||
retry:
|
||||
ret = jc->j_curslist[0]->c_get(jc->j_curslist[0],
|
||||
&jc->j_key, key, jc->j_init ? DB_CURRENT : DB_NEXT_DUP);
|
||||
|
||||
if (ret == ENOMEM) {
|
||||
jc->j_key.ulen <<= 1;
|
||||
if ((ret = __os_realloc(&jc->j_key.data, jc->j_key.ulen)) != 0)
|
||||
return (ret);
|
||||
goto retry;
|
||||
}
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
jc->j_init = 0;
|
||||
do {
|
||||
/*
|
||||
* We have the first element; now look for it in the
|
||||
* other cursors.
|
||||
*/
|
||||
for (cpp = jc->j_curslist + 1; *cpp != NULL; cpp++) {
|
||||
retry2: if ((ret = ((*cpp)->c_get)(*cpp,
|
||||
&jc->j_key, key, DB_GET_BOTH)) == DB_NOTFOUND)
|
||||
break;
|
||||
if (ret == ENOMEM) {
|
||||
jc->j_key.ulen <<= 1;
|
||||
if ((ret = __os_realloc(&jc->j_key.data,
|
||||
jc->j_key.ulen)) != 0)
|
||||
return (ret);
|
||||
goto retry2;
|
||||
}
|
||||
if (F_ISSET(*cpp, DBC_KEYSET)) {
|
||||
F_CLR(*cpp, DBC_KEYSET);
|
||||
F_SET(*cpp, DBC_CONTINUE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we got out of here with ret != 0, then we failed to
|
||||
* find the duplicate in one of the files, so we go on to
|
||||
* the next item in the outermost relation. If ret was
|
||||
* equal to 0, then we've got something to return.
|
||||
*/
|
||||
if (ret == 0)
|
||||
break;
|
||||
} while ((ret = jc->j_curslist[0]->c_get(jc->j_curslist[0],
|
||||
&jc->j_key, key, DB_NEXT_DUP)) == 0);
|
||||
|
||||
/*
|
||||
* If ret != 0 here, we've exhausted the first file. Otherwise,
|
||||
* key and data are set and we need to do the lookup on the
|
||||
* primary.
|
||||
*/
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
if (operation == DB_JOIN_ITEM)
|
||||
return (0);
|
||||
else
|
||||
return ((jc->j_primary->get)(jc->j_primary,
|
||||
jc->j_curslist[0]->txn, key, data, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
__db_join_close(dbc)
|
||||
DBC *dbc;
|
||||
{
|
||||
JOIN_CURSOR *jc;
|
||||
int i;
|
||||
|
||||
DB_PANIC_CHECK(dbc->dbp);
|
||||
|
||||
jc = (JOIN_CURSOR *)dbc->internal;
|
||||
|
||||
/*
|
||||
* Clear the optimization flag in the cursors.
|
||||
*/
|
||||
for (i = 0; jc->j_curslist[i] != NULL; i++)
|
||||
F_CLR(jc->j_curslist[i], DBC_CONTINUE | DBC_KEYSET);
|
||||
|
||||
__os_free(jc->j_curslist, 0);
|
||||
__os_free(jc->j_key.data, jc->j_key.ulen);
|
||||
__os_free(jc, sizeof(JOIN_CURSOR));
|
||||
__os_free(dbc, sizeof(DBC));
|
||||
|
||||
return (0);
|
||||
}
|
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_overflow.c 10.11 (Sleepycat) 5/7/98";
|
||||
static const char sccsid[] = "@(#)db_overflow.c 10.21 (Sleepycat) 9/27/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -60,6 +60,7 @@ static const char sccsid[] = "@(#)db_overflow.c 10.11 (Sleepycat) 5/7/98";
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "db_am.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
/*
|
||||
* Big key/data code.
|
||||
@ -106,29 +107,20 @@ __db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
|
||||
needed = tlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate any necessary memory.
|
||||
*
|
||||
* XXX: Never allocate 0 bytes;
|
||||
*/
|
||||
/* Allocate any necessary memory. */
|
||||
if (F_ISSET(dbt, DB_DBT_USERMEM)) {
|
||||
if (needed > dbt->ulen) {
|
||||
dbt->size = needed;
|
||||
return (ENOMEM);
|
||||
}
|
||||
} else if (F_ISSET(dbt, DB_DBT_MALLOC)) {
|
||||
dbt->data = dbp->db_malloc == NULL ?
|
||||
(void *)__db_malloc(needed + 1) :
|
||||
(void *)dbp->db_malloc(needed + 1);
|
||||
if (dbt->data == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret =
|
||||
__os_malloc(needed, dbp->db_malloc, &dbt->data)) != 0)
|
||||
return (ret);
|
||||
} else if (*bpsz == 0 || *bpsz < needed) {
|
||||
*bpp = (*bpp == NULL ?
|
||||
(void *)__db_malloc(needed + 1) :
|
||||
(void *)__db_realloc(*bpp, needed + 1));
|
||||
if (*bpp == NULL)
|
||||
return (ENOMEM);
|
||||
*bpsz = needed + 1;
|
||||
if ((ret = __os_realloc(bpp, needed)) != 0)
|
||||
return (ret);
|
||||
*bpsz = needed;
|
||||
dbt->data = *bpp;
|
||||
} else
|
||||
dbt->data = *bpp;
|
||||
@ -168,16 +160,17 @@ __db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
|
||||
* __db_poff --
|
||||
* Put an offpage item.
|
||||
*
|
||||
* PUBLIC: int __db_poff __P((DB *, const DBT *, db_pgno_t *,
|
||||
* PUBLIC: int (*)(DB *, u_int32_t, PAGE **)));
|
||||
* PUBLIC: int __db_poff __P((DBC *, const DBT *, db_pgno_t *,
|
||||
* PUBLIC: int (*)(DBC *, u_int32_t, PAGE **)));
|
||||
*/
|
||||
int
|
||||
__db_poff(dbp, dbt, pgnop, newfunc)
|
||||
DB *dbp;
|
||||
__db_poff(dbc, dbt, pgnop, newfunc)
|
||||
DBC *dbc;
|
||||
const DBT *dbt;
|
||||
db_pgno_t *pgnop;
|
||||
int (*newfunc) __P((DB *, u_int32_t, PAGE **));
|
||||
int (*newfunc) __P((DBC *, u_int32_t, PAGE **));
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *pagep, *lastp;
|
||||
DB_LSN new_lsn, null_lsn;
|
||||
DBT tmp_dbt;
|
||||
@ -191,6 +184,7 @@ __db_poff(dbp, dbt, pgnop, newfunc)
|
||||
* number of bytes we get for pages we fill completely with a single
|
||||
* item.
|
||||
*/
|
||||
dbp = dbc->dbp;
|
||||
pagespace = P_MAXSPACE(dbp->pgsize);
|
||||
|
||||
lastp = NULL;
|
||||
@ -208,13 +202,13 @@ __db_poff(dbp, dbt, pgnop, newfunc)
|
||||
* the item onto the page. If sz is less than pagespace, we
|
||||
* have a partial record.
|
||||
*/
|
||||
if ((ret = newfunc(dbp, P_OVERFLOW, &pagep)) != 0)
|
||||
if ((ret = newfunc(dbc, P_OVERFLOW, &pagep)) != 0)
|
||||
return (ret);
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
tmp_dbt.data = p;
|
||||
tmp_dbt.size = pagespace;
|
||||
ZERO_LSN(null_lsn);
|
||||
if ((ret = __db_big_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if ((ret = __db_big_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&new_lsn, 0, DB_ADD_BIG, dbp->log_fileid,
|
||||
PGNO(pagep), lastp ? PGNO(lastp) : PGNO_INVALID,
|
||||
PGNO_INVALID, &tmp_dbt, &LSN(pagep),
|
||||
@ -256,24 +250,26 @@ __db_poff(dbp, dbt, pgnop, newfunc)
|
||||
* __db_ovref --
|
||||
* Increment/decrement the reference count on an overflow page.
|
||||
*
|
||||
* PUBLIC: int __db_ovref __P((DB *, db_pgno_t, int32_t));
|
||||
* PUBLIC: int __db_ovref __P((DBC *, db_pgno_t, int32_t));
|
||||
*/
|
||||
int
|
||||
__db_ovref(dbp, pgno, adjust)
|
||||
DB *dbp;
|
||||
__db_ovref(dbc, pgno, adjust)
|
||||
DBC *dbc;
|
||||
db_pgno_t pgno;
|
||||
int32_t adjust;
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *h;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
|
||||
(void)__db_pgerr(dbp, pgno);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (DB_LOGGING(dbp))
|
||||
if ((ret = __db_ovref_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if (DB_LOGGING(dbc))
|
||||
if ((ret = __db_ovref_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&LSN(h), 0, dbp->log_fileid, h->pgno, adjust,
|
||||
&LSN(h))) != 0)
|
||||
return (ret);
|
||||
@ -287,19 +283,21 @@ __db_ovref(dbp, pgno, adjust)
|
||||
* __db_doff --
|
||||
* Delete an offpage chain of overflow pages.
|
||||
*
|
||||
* PUBLIC: int __db_doff __P((DB *, db_pgno_t, int (*)(DB *, PAGE *)));
|
||||
* PUBLIC: int __db_doff __P((DBC *, db_pgno_t, int (*)(DBC *, PAGE *)));
|
||||
*/
|
||||
int
|
||||
__db_doff(dbp, pgno, freefunc)
|
||||
DB *dbp;
|
||||
__db_doff(dbc, pgno, freefunc)
|
||||
DBC *dbc;
|
||||
db_pgno_t pgno;
|
||||
int (*freefunc) __P((DB *, PAGE *));
|
||||
int (*freefunc) __P((DBC *, PAGE *));
|
||||
{
|
||||
DB *dbp;
|
||||
PAGE *pagep;
|
||||
DB_LSN null_lsn;
|
||||
DBT tmp_dbt;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
do {
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) {
|
||||
(void)__db_pgerr(dbp, pgno);
|
||||
@ -312,21 +310,21 @@ __db_doff(dbp, pgno, freefunc)
|
||||
*/
|
||||
if (TYPE(pagep) == P_OVERFLOW && OV_REF(pagep) > 1) {
|
||||
(void)memp_fput(dbp->mpf, pagep, 0);
|
||||
return (__db_ovref(dbp, pgno, -1));
|
||||
return (__db_ovref(dbc, pgno, -1));
|
||||
}
|
||||
|
||||
if (DB_LOGGING(dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
tmp_dbt.data = (u_int8_t *)pagep + P_OVERHEAD;
|
||||
tmp_dbt.size = OV_LEN(pagep);
|
||||
ZERO_LSN(null_lsn);
|
||||
if ((ret = __db_big_log(dbp->dbenv->lg_info, dbp->txn,
|
||||
if ((ret = __db_big_log(dbp->dbenv->lg_info, dbc->txn,
|
||||
&LSN(pagep), 0, DB_REM_BIG, dbp->log_fileid,
|
||||
PGNO(pagep), PREV_PGNO(pagep), NEXT_PGNO(pagep),
|
||||
&tmp_dbt, &LSN(pagep), &null_lsn, &null_lsn)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
pgno = pagep->next_pgno;
|
||||
if ((ret = freefunc(dbp, pagep)) != 0)
|
||||
if ((ret = freefunc(dbc, pagep)) != 0)
|
||||
return (ret);
|
||||
} while (pgno != PGNO_INVALID);
|
||||
|
||||
@ -339,44 +337,71 @@ __db_doff(dbp, pgno, freefunc)
|
||||
*
|
||||
* Given a starting page number and a key, return <0, 0, >0 to indicate if the
|
||||
* key on the page is less than, equal to or greater than the key specified.
|
||||
* We optimize this by doing chunk at a time comparison unless the user has
|
||||
* specified a comparison function. In this case, we need to materialize
|
||||
* the entire object and call their comparison routine.
|
||||
*
|
||||
* PUBLIC: int __db_moff __P((DB *, const DBT *, db_pgno_t));
|
||||
* PUBLIC: int __db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t,
|
||||
* PUBLIC: int (*)(const DBT *, const DBT *), int *));
|
||||
*/
|
||||
int
|
||||
__db_moff(dbp, dbt, pgno)
|
||||
__db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp)
|
||||
DB *dbp;
|
||||
const DBT *dbt;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t tlen;
|
||||
int (*cmpfunc) __P((const DBT *, const DBT *)), *cmpp;
|
||||
{
|
||||
PAGE *pagep;
|
||||
u_int32_t cmp_bytes, key_left;
|
||||
DBT local_dbt;
|
||||
void *buf;
|
||||
u_int32_t bufsize, cmp_bytes, key_left;
|
||||
u_int8_t *p1, *p2;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If there is a user-specified comparison function, build a
|
||||
* contiguous copy of the key, and call it.
|
||||
*/
|
||||
if (cmpfunc != NULL) {
|
||||
memset(&local_dbt, 0, sizeof(local_dbt));
|
||||
buf = NULL;
|
||||
bufsize = 0;
|
||||
|
||||
if ((ret = __db_goff(dbp,
|
||||
&local_dbt, tlen, pgno, &buf, &bufsize)) != 0)
|
||||
return (ret);
|
||||
*cmpp = cmpfunc(&local_dbt, dbt);
|
||||
__os_free(buf, bufsize);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* While there are both keys to compare. */
|
||||
for (ret = 0, p1 = dbt->data,
|
||||
for (*cmpp = 0, p1 = dbt->data,
|
||||
key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) {
|
||||
if (memp_fget(dbp->mpf, &pgno, 0, &pagep) != 0) {
|
||||
(void)__db_pgerr(dbp, pgno);
|
||||
return (0); /* No system error return. */
|
||||
}
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0)
|
||||
return (ret);
|
||||
|
||||
cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left;
|
||||
key_left -= cmp_bytes;
|
||||
for (p2 =
|
||||
(u_int8_t *)pagep + P_OVERHEAD; cmp_bytes-- > 0; ++p1, ++p2)
|
||||
if (*p1 != *p2) {
|
||||
ret = (long)*p1 - (long)*p2;
|
||||
*cmpp = (long)*p1 - (long)*p2;
|
||||
break;
|
||||
}
|
||||
pgno = NEXT_PGNO(pagep);
|
||||
(void)memp_fput(dbp->mpf, pagep, 0);
|
||||
if (ret != 0)
|
||||
if ((ret = memp_fput(dbp->mpf, pagep, 0)) != 0)
|
||||
return (ret);
|
||||
if (*cmpp != 0)
|
||||
return (0);
|
||||
}
|
||||
if (key_left > 0) /* DBT is longer than page key. */
|
||||
return (-1);
|
||||
if (pgno != PGNO_INVALID) /* DBT is shorter than page key. */
|
||||
return (1);
|
||||
*cmpp = -1;
|
||||
else if (pgno != PGNO_INVALID) /* DBT is shorter than page key. */
|
||||
*cmpp = 1;
|
||||
else
|
||||
*cmpp = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
110
db2/db/db_pr.c
110
db2/db/db_pr.c
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_pr.c 10.29 (Sleepycat) 5/23/98";
|
||||
static const char sccsid[] = "@(#)db_pr.c 10.40 (Sleepycat) 11/22/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -126,11 +126,10 @@ __db_prdb(dbp)
|
||||
{ DB_AM_MLOCAL, "local mpool" },
|
||||
{ DB_AM_PGDEF, "default page size" },
|
||||
{ DB_AM_RDONLY, "read-only" },
|
||||
{ DB_AM_RECOVER, "recover" },
|
||||
{ DB_AM_SWAP, "needswap" },
|
||||
{ DB_AM_THREAD, "thread" },
|
||||
{ DB_BT_RECNUM, "btree:records" },
|
||||
{ DB_HS_DIRTYMETA, "hash:dirty-meta" },
|
||||
{ DB_BT_RECNUM, "btree:recnum" },
|
||||
{ DB_DBM_ERROR, "dbm/ndbm error" },
|
||||
{ DB_RE_DELIMITER, "recno:delimiter" },
|
||||
{ DB_RE_FIXEDLEN, "recno:fixed-length" },
|
||||
{ DB_RE_PAD, "recno:pad" },
|
||||
@ -178,42 +177,55 @@ __db_prbtree(dbp)
|
||||
static const FN mfn[] = {
|
||||
{ BTM_DUP, "duplicates" },
|
||||
{ BTM_RECNO, "recno" },
|
||||
{ BTM_RECNUM, "btree:records" },
|
||||
{ BTM_RECNUM, "btree:recnum" },
|
||||
{ BTM_FIXEDLEN, "recno:fixed-length" },
|
||||
{ BTM_RENUMBER, "recno:renumber" },
|
||||
{ 0 },
|
||||
};
|
||||
DBC *dbc;
|
||||
BTMETA *mp;
|
||||
BTREE *t;
|
||||
EPG *epg;
|
||||
FILE *fp;
|
||||
PAGE *h;
|
||||
RECNO *rp;
|
||||
db_pgno_t i;
|
||||
int ret;
|
||||
int cnt, ret;
|
||||
const char *sep;
|
||||
|
||||
t = dbp->internal;
|
||||
fp = __db_prinit(NULL);
|
||||
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
(void)fprintf(fp, "%s\nOn-page metadata:\n", DB_LINE);
|
||||
|
||||
i = PGNO_METADATA;
|
||||
if ((ret = __bam_pget(dbp, (PAGE **)&mp, &i, 0)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &i, 0, (PAGE **)&mp)) != 0) {
|
||||
(void)dbc->c_close(dbc);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
fprintf(fp, "lsn.file: %lu lsn.offset: %lu\n",
|
||||
(u_long)LSN(mp).file, (u_long)LSN(mp).offset);
|
||||
(void)fprintf(fp, "magic %#lx\n", (u_long)mp->magic);
|
||||
(void)fprintf(fp, "version %#lx\n", (u_long)mp->version);
|
||||
(void)fprintf(fp, "pagesize %lu\n", (u_long)mp->pagesize);
|
||||
(void)fprintf(fp, "maxkey: %lu minkey: %lu\n",
|
||||
(u_long)mp->maxkey, (u_long)mp->minkey);
|
||||
|
||||
(void)fprintf(fp, "free %lu", (u_long)mp->free);
|
||||
for (i = mp->free; i != PGNO_INVALID;) {
|
||||
if ((ret = __bam_pget(dbp, &h, &i, 0)) != 0)
|
||||
(void)fprintf(fp, "free list: %lu", (u_long)mp->free);
|
||||
for (i = mp->free, cnt = 0, sep = ", "; i != PGNO_INVALID;) {
|
||||
if ((ret = memp_fget(dbp->mpf, &i, 0, &h)) != 0)
|
||||
return (ret);
|
||||
i = h->next_pgno;
|
||||
(void)memp_fput(dbp->mpf, h, 0);
|
||||
(void)fprintf(fp, ", %lu", (u_long)i);
|
||||
(void)fprintf(fp, "%s%lu", sep, (u_long)i);
|
||||
if (++cnt % 10 == 0) {
|
||||
(void)fprintf(fp, "\n");
|
||||
cnt = 0;
|
||||
sep = "";
|
||||
} else
|
||||
sep = ", ";
|
||||
}
|
||||
(void)fprintf(fp, "\n");
|
||||
|
||||
@ -227,7 +239,7 @@ __db_prbtree(dbp)
|
||||
(u_long)t->bt_maxkey, (u_long)t->bt_minkey);
|
||||
(void)fprintf(fp, "bt_compare: %#lx bt_prefix: %#lx\n",
|
||||
(u_long)t->bt_compare, (u_long)t->bt_prefix);
|
||||
if ((rp = t->bt_recno) != NULL) {
|
||||
if ((rp = t->recno) != NULL) {
|
||||
(void)fprintf(fp,
|
||||
"re_delim: %#lx re_pad: %#lx re_len: %lu re_source: %s\n",
|
||||
(u_long)rp->re_delim, (u_long)rp->re_pad,
|
||||
@ -238,13 +250,9 @@ __db_prbtree(dbp)
|
||||
(u_long)rp->re_cmap, (u_long)rp->re_smap,
|
||||
(u_long)rp->re_emap, (u_long)rp->re_msize);
|
||||
}
|
||||
(void)fprintf(fp, "stack:");
|
||||
for (epg = t->bt_stack; epg < t->bt_sp; ++epg)
|
||||
(void)fprintf(fp, " %lu", (u_long)epg->page->pgno);
|
||||
(void)fprintf(fp, "\n");
|
||||
(void)fprintf(fp, "ovflsize: %lu\n", (u_long)t->bt_ovflsize);
|
||||
(void)fflush(fp);
|
||||
return (0);
|
||||
return (dbc->c_close(dbc));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -258,51 +266,50 @@ __db_prhash(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
FILE *fp;
|
||||
HTAB *t;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
int i, put_page, ret;
|
||||
db_pgno_t pgno;
|
||||
|
||||
t = dbp->internal;
|
||||
|
||||
fp = __db_prinit(NULL);
|
||||
if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
|
||||
return (ret);
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
|
||||
fprintf(fp, "\thash_accesses %lu\n", (u_long)t->hash_accesses);
|
||||
fprintf(fp, "\thash_collisions %lu\n", (u_long)t->hash_collisions);
|
||||
fprintf(fp, "\thash_expansions %lu\n", (u_long)t->hash_expansions);
|
||||
fprintf(fp, "\thash_overflows %lu\n", (u_long)t->hash_overflows);
|
||||
fprintf(fp, "\thash_bigpages %lu\n", (u_long)t->hash_bigpages);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
if (t->hdr == NULL) {
|
||||
/*
|
||||
* In this case, hcp->hdr will never be null, if we decide
|
||||
* to pass dbc's to this routine instead, then it could be.
|
||||
*/
|
||||
if (hcp->hdr == NULL) {
|
||||
pgno = PGNO_METADATA;
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &t->hdr)) != 0)
|
||||
if ((ret = memp_fget(dbp->mpf, &pgno, 0, &hcp->hdr)) != 0)
|
||||
return (ret);
|
||||
put_page = 1;
|
||||
} else
|
||||
put_page = 0;
|
||||
|
||||
fprintf(fp, "\tmagic %#lx\n", (u_long)t->hdr->magic);
|
||||
fprintf(fp, "\tversion %lu\n", (u_long)t->hdr->version);
|
||||
fprintf(fp, "\tpagesize %lu\n", (u_long)t->hdr->pagesize);
|
||||
fprintf(fp, "\tovfl_point %lu\n", (u_long)t->hdr->ovfl_point);
|
||||
fprintf(fp, "\tlast_freed %lu\n", (u_long)t->hdr->last_freed);
|
||||
fprintf(fp, "\tmax_bucket %lu\n", (u_long)t->hdr->max_bucket);
|
||||
fprintf(fp, "\thigh_mask %#lx\n", (u_long)t->hdr->high_mask);
|
||||
fprintf(fp, "\tlow_mask %#lx\n", (u_long)t->hdr->low_mask);
|
||||
fprintf(fp, "\tffactor %lu\n", (u_long)t->hdr->ffactor);
|
||||
fprintf(fp, "\tnelem %lu\n", (u_long)t->hdr->nelem);
|
||||
fprintf(fp, "\th_charkey %#lx\n", (u_long)t->hdr->h_charkey);
|
||||
fprintf(fp, "\tmagic %#lx\n", (u_long)hcp->hdr->magic);
|
||||
fprintf(fp, "\tversion %lu\n", (u_long)hcp->hdr->version);
|
||||
fprintf(fp, "\tpagesize %lu\n", (u_long)hcp->hdr->pagesize);
|
||||
fprintf(fp, "\tovfl_point %lu\n", (u_long)hcp->hdr->ovfl_point);
|
||||
fprintf(fp, "\tlast_freed %lu\n", (u_long)hcp->hdr->last_freed);
|
||||
fprintf(fp, "\tmax_bucket %lu\n", (u_long)hcp->hdr->max_bucket);
|
||||
fprintf(fp, "\thigh_mask %#lx\n", (u_long)hcp->hdr->high_mask);
|
||||
fprintf(fp, "\tlow_mask %#lx\n", (u_long)hcp->hdr->low_mask);
|
||||
fprintf(fp, "\tffactor %lu\n", (u_long)hcp->hdr->ffactor);
|
||||
fprintf(fp, "\tnelem %lu\n", (u_long)hcp->hdr->nelem);
|
||||
fprintf(fp, "\th_charkey %#lx\n", (u_long)hcp->hdr->h_charkey);
|
||||
|
||||
for (i = 0; i < NCACHED; i++)
|
||||
fprintf(fp, "%lu ", (u_long)t->hdr->spares[i]);
|
||||
fprintf(fp, "%lu ", (u_long)hcp->hdr->spares[i]);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
(void)fflush(fp);
|
||||
if (put_page) {
|
||||
(void)memp_fput(dbp->mpf, (PAGE *)t->hdr, 0);
|
||||
t->hdr = NULL;
|
||||
(void)memp_fput(dbp->mpf, (PAGE *)hcp->hdr, 0);
|
||||
hcp->hdr = NULL;
|
||||
}
|
||||
return (0);
|
||||
return (dbc->c_close(dbc));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -318,22 +325,18 @@ __db_prtree(mpf, all)
|
||||
{
|
||||
PAGE *h;
|
||||
db_pgno_t i;
|
||||
int ret, t_ret;
|
||||
|
||||
if (set_psize == PSIZE_BOUNDARY)
|
||||
__db_psize(mpf);
|
||||
|
||||
ret = 0;
|
||||
for (i = PGNO_ROOT;; ++i) {
|
||||
if ((ret = memp_fget(mpf, &i, 0, &h)) != 0)
|
||||
if (memp_fget(mpf, &i, 0, &h) != 0)
|
||||
break;
|
||||
if (TYPE(h) != P_INVALID)
|
||||
if ((t_ret = __db_prpage(h, all)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
(void)__db_prpage(h, all);
|
||||
(void)memp_fput(mpf, h, 0);
|
||||
}
|
||||
(void)fflush(__db_prinit(NULL));
|
||||
return (ret);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -425,8 +428,7 @@ __db_prpage(h, all)
|
||||
(TYPE(h) == P_LRECNO && h->pgno == PGNO_ROOT))
|
||||
fprintf(fp, " total records: %4lu", (u_long)RE_NREC(h));
|
||||
fprintf(fp, "\n");
|
||||
if (TYPE(h) == P_LBTREE || TYPE(h) == P_LRECNO ||
|
||||
TYPE(h) == P_DUPLICATE || TYPE(h) == P_OVERFLOW)
|
||||
if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO)
|
||||
fprintf(fp, " prev: %4lu next: %4lu",
|
||||
(u_long)PREV_PGNO(h), (u_long)NEXT_PGNO(h));
|
||||
if (TYPE(h) == P_IBTREE || TYPE(h) == P_LBTREE)
|
||||
|
155
db2/db/db_rec.c
155
db2/db/db_rec.c
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_rec.c 10.16 (Sleepycat) 4/28/98";
|
||||
static const char sccsid[] = "@(#)db_rec.c 10.19 (Sleepycat) 9/27/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -40,7 +40,8 @@ __db_addrem_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__db_addrem_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
u_int32_t change;
|
||||
@ -57,9 +58,7 @@ __db_addrem_recover(logp, dbtp, lsnp, redo, info)
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else
|
||||
if ((ret = memp_fget(mpf,
|
||||
&argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
@ -73,7 +72,7 @@ __db_addrem_recover(logp, dbtp, lsnp, redo, info)
|
||||
(cmp_n == 0 && !redo && argp->opcode == DB_REM_DUP)) {
|
||||
|
||||
/* Need to redo an add, or undo a delete. */
|
||||
if ((ret = __db_pitem(file_dbp, pagep, argp->indx, argp->nbytes,
|
||||
if ((ret = __db_pitem(dbc, pagep, argp->indx, argp->nbytes,
|
||||
argp->hdr.size == 0 ? NULL : &argp->hdr,
|
||||
argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
|
||||
goto out;
|
||||
@ -83,7 +82,7 @@ __db_addrem_recover(logp, dbtp, lsnp, redo, info)
|
||||
} else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_DUP) ||
|
||||
(cmp_p == 0 && redo && argp->opcode == DB_REM_DUP)) {
|
||||
/* Need to undo an add, or redo a delete. */
|
||||
if ((ret = __db_ditem(file_dbp,
|
||||
if ((ret = __db_ditem(dbc,
|
||||
pagep, argp->indx, argp->nbytes)) != 0)
|
||||
goto out;
|
||||
change = DB_MPOOL_DIRTY;
|
||||
@ -96,8 +95,11 @@ __db_addrem_recover(logp, dbtp, lsnp, redo, info)
|
||||
LSN(pagep) = argp->pagelsn;
|
||||
}
|
||||
|
||||
if ((ret = memp_fput(mpf, pagep, change)) == 0)
|
||||
*lsnp = argp->prev_lsn;
|
||||
if ((ret = memp_fput(mpf, pagep, change)) != 0)
|
||||
goto out;
|
||||
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: REC_CLOSE;
|
||||
}
|
||||
@ -114,7 +116,8 @@ __db_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__db_split_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
int change, cmp_n, cmp_p, ret;
|
||||
@ -130,9 +133,7 @@ __db_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else
|
||||
if ((ret = memp_fget(mpf,
|
||||
&argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
@ -169,8 +170,11 @@ __db_split_recover(logp, dbtp, lsnp, redo, info)
|
||||
LSN(pagep) = argp->pagelsn;
|
||||
change = DB_MPOOL_DIRTY;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, change)) == 0)
|
||||
*lsnp = argp->prev_lsn;
|
||||
if ((ret = memp_fput(mpf, pagep, change)) != 0)
|
||||
goto out;
|
||||
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: REC_CLOSE;
|
||||
}
|
||||
@ -187,7 +191,8 @@ __db_big_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__db_big_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
u_int32_t change;
|
||||
@ -209,7 +214,7 @@ __db_big_recover(logp, dbtp, lsnp, redo, info)
|
||||
} else
|
||||
if ((ret = memp_fget(mpf,
|
||||
&argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
goto out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -299,9 +304,7 @@ npage: if (argp->next_pgno != PGNO_INVALID) {
|
||||
* so we would not have to undo anything. In
|
||||
* this case, don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else
|
||||
if ((ret = memp_fget(mpf, &argp->next_pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
@ -323,7 +326,8 @@ npage: if (argp->next_pgno != PGNO_INVALID) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: REC_CLOSE;
|
||||
}
|
||||
@ -343,7 +347,8 @@ __db_ovref_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__db_ovref_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
int modified, ret;
|
||||
@ -370,8 +375,11 @@ __db_ovref_recover(logp, dbtp, lsnp, redo, info)
|
||||
pagep->lsn = argp->lsn;
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) == 0)
|
||||
*lsnp = argp->prev_lsn;
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: REC_CLOSE;
|
||||
}
|
||||
@ -392,17 +400,20 @@ __db_relink_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__db_relink_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
int modified, ret;
|
||||
int cmp_n, cmp_p, modified, ret;
|
||||
|
||||
REC_PRINT(__db_relink_print);
|
||||
REC_INTRO(__db_relink_read);
|
||||
|
||||
/*
|
||||
* There are three pages we need to check -- the page, and the
|
||||
* previous and next pages, if they existed.
|
||||
* There are up to three pages we need to check -- the page, and the
|
||||
* previous and next pages, if they existed. For a page add operation,
|
||||
* the current page is the result of a split and is being recovered
|
||||
* elsewhere, so all we need do is recover the next page.
|
||||
*/
|
||||
if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
|
||||
if (redo) {
|
||||
@ -411,6 +422,9 @@ __db_relink_recover(logp, dbtp, lsnp, redo, info)
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
if (argp->opcode == DB_ADD_PAGE)
|
||||
goto next;
|
||||
|
||||
modified = 0;
|
||||
if (log_compare(&LSN(pagep), &argp->lsn) == 0 && redo) {
|
||||
/* Redo the relink. */
|
||||
@ -424,10 +438,8 @@ __db_relink_recover(logp, dbtp, lsnp, redo, info)
|
||||
pagep->lsn = argp->lsn;
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
next: if ((ret = memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
|
||||
if (redo) {
|
||||
@ -437,23 +449,27 @@ next: if ((ret = memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
|
||||
goto prev;
|
||||
}
|
||||
modified = 0;
|
||||
if (log_compare(&LSN(pagep), &argp->lsn_next) == 0 && redo) {
|
||||
/* Redo the relink. */
|
||||
cmp_n = log_compare(lsnp, &LSN(pagep));
|
||||
cmp_p = log_compare(&LSN(pagep), &argp->lsn_next);
|
||||
if ((argp->opcode == DB_REM_PAGE && cmp_p == 0 && redo) ||
|
||||
(argp->opcode == DB_ADD_PAGE && cmp_n == 0 && !redo)) {
|
||||
/* Redo the remove or undo the add. */
|
||||
pagep->prev_pgno = argp->prev;
|
||||
|
||||
pagep->lsn = *lsnp;
|
||||
modified = 1;
|
||||
} else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
|
||||
/* Undo the relink. */
|
||||
} else if ((argp->opcode == DB_REM_PAGE && cmp_n == 0 && !redo) ||
|
||||
(argp->opcode == DB_ADD_PAGE && cmp_p == 0 && redo)) {
|
||||
/* Undo the remove or redo the add. */
|
||||
pagep->prev_pgno = argp->pgno;
|
||||
|
||||
pagep->lsn = argp->lsn_next;
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void)__db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
if (argp->opcode == DB_ADD_PAGE)
|
||||
goto done;
|
||||
|
||||
prev: if ((ret = memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
|
||||
if (redo) {
|
||||
@ -476,10 +492,8 @@ prev: if ((ret = memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
|
||||
pagep->lsn = argp->lsn_prev;
|
||||
modified = 1;
|
||||
}
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
|
||||
(void) __db_panic(file_dbp);
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
@ -500,7 +514,8 @@ __db_addpage_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__db_addpage_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
u_int32_t change;
|
||||
@ -541,8 +556,7 @@ __db_addpage_recover(logp, dbtp, lsnp, redo, info)
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else
|
||||
if ((ret = memp_fget(mpf,
|
||||
&argp->nextpgno, DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
@ -563,11 +577,13 @@ __db_addpage_recover(logp, dbtp, lsnp, redo, info)
|
||||
LSN(pagep) = argp->nextlsn;
|
||||
change = DB_MPOOL_DIRTY;
|
||||
}
|
||||
ret = memp_fput(mpf, pagep, change);
|
||||
if ((ret = memp_fput(mpf, pagep, change)) != 0)
|
||||
goto out;
|
||||
|
||||
out: if (ret == 0)
|
||||
*lsnp = argp->prev_lsn;
|
||||
REC_CLOSE;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: REC_CLOSE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -598,46 +614,3 @@ __db_debug_recover(logp, dbtp, lsnp, redo, info)
|
||||
|
||||
REC_NOOP_CLOSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_noop_recover --
|
||||
* Recovery function for noop.
|
||||
*
|
||||
* PUBLIC: int __db_noop_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
*/
|
||||
int
|
||||
__db_noop_recover(logp, dbtp, lsnp, redo, info)
|
||||
DB_LOG *logp;
|
||||
DBT *dbtp;
|
||||
DB_LSN *lsnp;
|
||||
int redo;
|
||||
void *info;
|
||||
{
|
||||
__db_noop_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
PAGE *pagep;
|
||||
u_int32_t change;
|
||||
int cmp_n, cmp_p, ret;
|
||||
|
||||
REC_PRINT(__db_noop_print);
|
||||
REC_INTRO(__db_noop_read);
|
||||
|
||||
if ((ret = memp_fget(mpf, &argp->pgno, 0, &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) {
|
||||
LSN(pagep) = *lsnp;
|
||||
change = DB_MPOOL_DIRTY;
|
||||
} else if (cmp_n == 0 && !redo) {
|
||||
LSN(pagep) = argp->prevlsn;
|
||||
change = DB_MPOOL_DIRTY;
|
||||
}
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = memp_fput(mpf, pagep, change);
|
||||
|
||||
out: REC_CLOSE;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_ret.c 10.13 (Sleepycat) 5/7/98";
|
||||
static const char sccsid[] = "@(#)db_ret.c 10.16 (Sleepycat) 10/4/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -93,6 +93,8 @@ __db_retcopy(dbt, data, len, memp, memsize, db_malloc)
|
||||
u_int32_t *memsize;
|
||||
void *(*db_malloc) __P((size_t));
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* If returning a partial record, reset the length. */
|
||||
if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
|
||||
data = (u_int8_t *)data + dbt->doff;
|
||||
@ -120,9 +122,6 @@ __db_retcopy(dbt, data, len, memp, memsize, db_malloc)
|
||||
* guarantees consistency, i.e., the application can always free memory
|
||||
* without concern as to how many bytes of the record were requested.
|
||||
*
|
||||
* XXX
|
||||
* Never allocate 0 bytes, it's known to make malloc/realloc unhappy.
|
||||
*
|
||||
* Use the memory specified by the application: DB_DBT_USERMEM.
|
||||
*
|
||||
* !!!
|
||||
@ -130,11 +129,8 @@ __db_retcopy(dbt, data, len, memp, memsize, db_malloc)
|
||||
* memory pointer is allowed to be NULL.
|
||||
*/
|
||||
if (F_ISSET(dbt, DB_DBT_MALLOC)) {
|
||||
dbt->data = db_malloc == NULL ?
|
||||
(void *)__db_malloc(len) :
|
||||
(void *)db_malloc(len + 1);
|
||||
if (dbt->data == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(len, db_malloc, &dbt->data)) != 0)
|
||||
return (ret);
|
||||
} else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
|
||||
if (len != 0 && (dbt->data == NULL || dbt->ulen < len))
|
||||
return (ENOMEM);
|
||||
@ -142,12 +138,9 @@ __db_retcopy(dbt, data, len, memp, memsize, db_malloc)
|
||||
return (EINVAL);
|
||||
} else {
|
||||
if (len != 0 && (*memsize == 0 || *memsize < len)) {
|
||||
*memp = *memp == NULL ?
|
||||
(void *)__db_malloc(len) :
|
||||
(void *)__db_realloc(*memp, len);
|
||||
if (*memp == NULL) {
|
||||
if ((ret = __os_realloc(memp, len)) != 0) {
|
||||
*memsize = 0;
|
||||
return (ENOMEM);
|
||||
return (ret);
|
||||
}
|
||||
*memsize = len;
|
||||
}
|
||||
|
@ -1,121 +0,0 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)db_thread.c 8.15 (Sleepycat) 4/26/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "db_am.h"
|
||||
|
||||
static int __db_getlockid __P((DB *, DB *));
|
||||
|
||||
/*
|
||||
* __db_gethandle --
|
||||
* Called by db access method routines when the DB_THREAD flag is set.
|
||||
* This routine returns a handle, either an existing handle from the
|
||||
* chain of handles, or creating one if necessary.
|
||||
*
|
||||
* PUBLIC: int __db_gethandle __P((DB *, int (*)(DB *, DB *), DB **));
|
||||
*/
|
||||
int
|
||||
__db_gethandle(dbp, am_func, dbpp)
|
||||
DB *dbp, **dbpp;
|
||||
int (*am_func) __P((DB *, DB *));
|
||||
{
|
||||
DB *ret_dbp;
|
||||
int ret, t_ret;
|
||||
|
||||
if ((ret = __db_mutex_lock((db_mutex_t *)dbp->mutexp, -1)) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret_dbp = LIST_FIRST(&dbp->handleq)) != NULL)
|
||||
/* Simply take one off the list. */
|
||||
LIST_REMOVE(ret_dbp, links);
|
||||
else {
|
||||
/* Allocate a new handle. */
|
||||
if ((ret_dbp = (DB *)__db_malloc(sizeof(*dbp))) == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
memcpy(ret_dbp, dbp, sizeof(*dbp));
|
||||
ret_dbp->internal = NULL;
|
||||
TAILQ_INIT(&ret_dbp->curs_queue);
|
||||
|
||||
/* Set the locker, the lock structure and the lock DBT. */
|
||||
if ((ret = __db_getlockid(dbp, ret_dbp)) != 0)
|
||||
goto err;
|
||||
|
||||
/* Finally, call the access method specific dup function. */
|
||||
if ((ret = am_func(dbp, ret_dbp)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
*dbpp = ret_dbp;
|
||||
|
||||
if (0) {
|
||||
err: if (ret_dbp != NULL)
|
||||
FREE(ret_dbp, sizeof(*ret_dbp));
|
||||
}
|
||||
if ((t_ret =
|
||||
__db_mutex_unlock((db_mutex_t *)dbp->mutexp, -1)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_puthandle --
|
||||
* Return a DB handle to the pool for later use.
|
||||
*
|
||||
* PUBLIC: int __db_puthandle __P((DB *));
|
||||
*/
|
||||
int
|
||||
__db_puthandle(dbp)
|
||||
DB *dbp;
|
||||
{
|
||||
DB *master;
|
||||
int ret;
|
||||
|
||||
master = dbp->master;
|
||||
if ((ret = __db_mutex_lock((db_mutex_t *)master->mutexp, -1)) != 0)
|
||||
return (ret);
|
||||
|
||||
LIST_INSERT_HEAD(&master->handleq, dbp, links);
|
||||
|
||||
return (__db_mutex_unlock((db_mutex_t *)master->mutexp, -1));
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_getlockid --
|
||||
* Create a new locker ID and copy the file lock information from
|
||||
* the old DB into the new one.
|
||||
*/
|
||||
static int
|
||||
__db_getlockid(dbp, new_dbp)
|
||||
DB *dbp, *new_dbp;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (F_ISSET(dbp, DB_AM_LOCKING)) {
|
||||
if ((ret = lock_id(dbp->dbenv->lk_info, &new_dbp->locker)) != 0)
|
||||
return (ret);
|
||||
memcpy(new_dbp->lock.fileid, dbp->lock.fileid, DB_FILE_ID_LEN);
|
||||
new_dbp->lock_dbt.size = sizeof(new_dbp->lock);
|
||||
new_dbp->lock_dbt.data = &new_dbp->lock;
|
||||
}
|
||||
return (0);
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1996, 1997, 1998\n\
|
||||
Sleepycat Software Inc. All rights reserved.\n";
|
||||
static const char sccsid[] = "@(#)db185.c 8.17 (Sleepycat) 5/7/98";
|
||||
static const char sccsid[] = "@(#)db185.c 8.21 (Sleepycat) 11/22/98";
|
||||
#endif
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -28,6 +28,10 @@ static const char sccsid[] = "@(#)db185.c 8.17 (Sleepycat) 5/7/98";
|
||||
#include "db185_int.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
static int db185_close __P((DB185 *));
|
||||
static int db185_del __P((const DB185 *, const DBT185 *, u_int));
|
||||
static int db185_fd __P((const DB185 *));
|
||||
@ -37,7 +41,7 @@ static int db185_seq __P((const DB185 *, DBT185 *, DBT185 *, u_int));
|
||||
static int db185_sync __P((const DB185 *, u_int));
|
||||
|
||||
DB185 *
|
||||
__dbopen(file, oflags, mode, type, openinfo)
|
||||
dbopen(file, oflags, mode, type, openinfo)
|
||||
const char *file;
|
||||
int oflags, mode;
|
||||
DBTYPE type;
|
||||
@ -49,9 +53,10 @@ __dbopen(file, oflags, mode, type, openinfo)
|
||||
DB *dbp;
|
||||
DB185 *db185p;
|
||||
DB_INFO dbinfo, *dbinfop;
|
||||
int s_errno;
|
||||
ssize_t nw;
|
||||
int fd, s_errno;
|
||||
|
||||
if ((db185p = (DB185 *)__db_calloc(1, sizeof(DB185))) == NULL)
|
||||
if ((errno = __os_calloc(1, sizeof(DB185), &db185p)) != 0)
|
||||
return (NULL);
|
||||
dbinfop = NULL;
|
||||
memset(&dbinfo, 0, sizeof(dbinfo));
|
||||
@ -93,7 +98,8 @@ __dbopen(file, oflags, mode, type, openinfo)
|
||||
dbinfop->h_ffactor = hi->ffactor;
|
||||
dbinfop->h_nelem = hi->nelem;
|
||||
dbinfop->db_cachesize = hi->cachesize;
|
||||
dbinfop->h_hash = hi->hash;
|
||||
dbinfop->h_hash = (u_int32_t (*)
|
||||
__P((const void *, u_int32_t)))hi->hash;
|
||||
dbinfop->db_lorder = hi->lorder;
|
||||
}
|
||||
|
||||
@ -127,14 +133,15 @@ __dbopen(file, oflags, mode, type, openinfo)
|
||||
* that in DB 2.0, so do that cast.
|
||||
*/
|
||||
if (file != NULL) {
|
||||
if (oflags & O_CREAT && __db_exists(file, NULL) != 0)
|
||||
(void)__os_close(__os_open(file, oflags, mode));
|
||||
if (oflags & O_CREAT && __os_exists(file, NULL) != 0)
|
||||
if (__os_open(file, oflags, mode, &fd) == 0)
|
||||
(void)__os_close(fd);
|
||||
dbinfop->re_source = (char *)file;
|
||||
file = NULL;
|
||||
|
||||
if (O_RDONLY)
|
||||
oflags &= ~O_RDONLY;
|
||||
oflags |= O_RDWR;
|
||||
file = NULL;
|
||||
}
|
||||
|
||||
if ((ri = openinfo) != NULL) {
|
||||
@ -144,7 +151,8 @@ __dbopen(file, oflags, mode, type, openinfo)
|
||||
*/
|
||||
#define BFMSG "DB: DB 1.85's recno bfname field is not supported.\n"
|
||||
if (ri->bfname != NULL) {
|
||||
(void)__os_write(2, BFMSG, sizeof(BFMSG) - 1);
|
||||
(void)__os_write(STDERR_FILENO,
|
||||
BFMSG, sizeof(BFMSG) - 1, &nw);
|
||||
goto einval;
|
||||
}
|
||||
|
||||
@ -196,27 +204,26 @@ __dbopen(file, oflags, mode, type, openinfo)
|
||||
*/
|
||||
if ((errno = db_open(file,
|
||||
type, __db_oflags(oflags), mode, NULL, dbinfop, &dbp)) != 0) {
|
||||
__db_free(db185p);
|
||||
__os_free(db185p, sizeof(DB185));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Create the cursor used for sequential ops. */
|
||||
if ((errno = dbp->cursor(dbp, NULL, &((DB185 *)db185p)->dbc)) != 0) {
|
||||
if ((errno = dbp->cursor(dbp, NULL, &((DB185 *)db185p)->dbc, 0)) != 0) {
|
||||
s_errno = errno;
|
||||
(void)dbp->close(dbp, 0);
|
||||
__db_free(db185p);
|
||||
__set_errno(s_errno);
|
||||
__os_free(db185p, sizeof(DB185));
|
||||
errno = s_errno;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
db185p->internal = dbp;
|
||||
return (db185p);
|
||||
|
||||
einval: __db_free(db185p);
|
||||
__set_errno(EINVAL);
|
||||
einval: __os_free(db185p, sizeof(DB185));
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
weak_alias (__dbopen, dbopen)
|
||||
|
||||
static int
|
||||
db185_close(db185p)
|
||||
@ -226,9 +233,9 @@ db185_close(db185p)
|
||||
|
||||
dbp = (DB *)db185p->internal;
|
||||
|
||||
__set_errno(dbp->close(dbp, 0));
|
||||
errno = dbp->close(dbp, 0);
|
||||
|
||||
__db_free(db185p);
|
||||
__os_free(db185p, sizeof(DB185));
|
||||
|
||||
return (errno == 0 ? 0 : -1);
|
||||
}
|
||||
@ -251,9 +258,9 @@ db185_del(db185p, key185, flags)
|
||||
if (flags & ~R_CURSOR)
|
||||
goto einval;
|
||||
if (flags & R_CURSOR)
|
||||
__set_errno(db185p->dbc->c_del(db185p->dbc, 0));
|
||||
errno = db185p->dbc->c_del(db185p->dbc, 0);
|
||||
else
|
||||
__set_errno(dbp->del(dbp, NULL, &key, 0));
|
||||
errno = dbp->del(dbp, NULL, &key, 0);
|
||||
|
||||
switch (errno) {
|
||||
case 0:
|
||||
@ -263,7 +270,7 @@ db185_del(db185p, key185, flags)
|
||||
}
|
||||
return (-1);
|
||||
|
||||
einval: __set_errno(EINVAL);
|
||||
einval: errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -276,7 +283,7 @@ db185_fd(db185p)
|
||||
|
||||
dbp = (DB *)db185p->internal;
|
||||
|
||||
return ((__set_errno(dbp->fd(dbp, &fd))) == 0 ? fd : -1);
|
||||
return ((errno = dbp->fd(dbp, &fd)) == 0 ? fd : -1);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -301,7 +308,7 @@ db185_get(db185p, key185, data185, flags)
|
||||
if (flags)
|
||||
goto einval;
|
||||
|
||||
switch (__set_errno(dbp->get(dbp, NULL, &key, &data, 0))) {
|
||||
switch (errno = dbp->get(dbp, NULL, &key, &data, 0)) {
|
||||
case 0:
|
||||
data185->data = data.data;
|
||||
data185->size = data.size;
|
||||
@ -311,7 +318,7 @@ db185_get(db185p, key185, data185, flags)
|
||||
}
|
||||
return (-1);
|
||||
|
||||
einval: __set_errno(EINVAL);
|
||||
einval: errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -338,46 +345,46 @@ db185_put(db185p, key185, data185, flags)
|
||||
|
||||
switch (flags) {
|
||||
case 0:
|
||||
__set_errno(dbp->put(dbp, NULL, &key, &data, 0));
|
||||
errno = dbp->put(dbp, NULL, &key, &data, 0);
|
||||
break;
|
||||
case R_CURSOR:
|
||||
__set_errno(
|
||||
db185p->dbc->c_put(db185p->dbc, &key, &data, DB_CURRENT));
|
||||
errno =
|
||||
db185p->dbc->c_put(db185p->dbc, &key, &data, DB_CURRENT);
|
||||
break;
|
||||
case R_IAFTER:
|
||||
case R_IBEFORE:
|
||||
if (dbp->type != DB_RECNO)
|
||||
goto einval;
|
||||
|
||||
if ((__set_errno(dbp->cursor(dbp, NULL, &dbcp_put))) != 0)
|
||||
if ((errno = dbp->cursor(dbp, NULL, &dbcp_put, 0)) != 0)
|
||||
return (-1);
|
||||
if ((__set_errno(
|
||||
dbcp_put->c_get(dbcp_put, &key, &data, DB_SET))) != 0) {
|
||||
if ((errno =
|
||||
dbcp_put->c_get(dbcp_put, &key, &data, DB_SET)) != 0) {
|
||||
s_errno = errno;
|
||||
(void)dbcp_put->c_close(dbcp_put);
|
||||
__set_errno(s_errno);
|
||||
errno = s_errno;
|
||||
return (-1);
|
||||
}
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.data = data185->data;
|
||||
data.size = data185->size;
|
||||
__set_errno(dbcp_put->c_put(dbcp_put,
|
||||
&key, &data, flags == R_IAFTER ? DB_AFTER : DB_BEFORE));
|
||||
errno = dbcp_put->c_put(dbcp_put,
|
||||
&key, &data, flags == R_IAFTER ? DB_AFTER : DB_BEFORE);
|
||||
s_errno = errno;
|
||||
(void)dbcp_put->c_close(dbcp_put);
|
||||
__set_errno(s_errno);
|
||||
errno = s_errno;
|
||||
break;
|
||||
case R_NOOVERWRITE:
|
||||
__set_errno(dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE));
|
||||
errno = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
|
||||
break;
|
||||
case R_SETCURSOR:
|
||||
if (dbp->type != DB_BTREE && dbp->type != DB_RECNO)
|
||||
goto einval;
|
||||
|
||||
if ((__set_errno(dbp->put(dbp, NULL, &key, &data, 0))) != 0)
|
||||
if ((errno = dbp->put(dbp, NULL, &key, &data, 0)) != 0)
|
||||
break;
|
||||
__set_errno(db185p->dbc->c_get(db185p->dbc,
|
||||
&key, &data, DB_SET_RANGE));
|
||||
errno =
|
||||
db185p->dbc->c_get(db185p->dbc, &key, &data, DB_SET_RANGE);
|
||||
break;
|
||||
default:
|
||||
goto einval;
|
||||
@ -393,7 +400,7 @@ db185_put(db185p, key185, data185, flags)
|
||||
}
|
||||
return (-1);
|
||||
|
||||
einval: __set_errno(EINVAL);
|
||||
einval: errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -438,8 +445,7 @@ db185_seq(db185p, key185, data185, flags)
|
||||
default:
|
||||
goto einval;
|
||||
}
|
||||
switch (__set_errno(db185p->dbc->c_get(db185p->dbc,
|
||||
&key, &data, flags))) {
|
||||
switch (errno = db185p->dbc->c_get(db185p->dbc, &key, &data, flags)) {
|
||||
case 0:
|
||||
key185->data = key.data;
|
||||
key185->size = key.size;
|
||||
@ -451,7 +457,7 @@ db185_seq(db185p, key185, data185, flags)
|
||||
}
|
||||
return (-1);
|
||||
|
||||
einval: __set_errno(EINVAL);
|
||||
einval: errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -461,6 +467,7 @@ db185_sync(db185p, flags)
|
||||
u_int flags;
|
||||
{
|
||||
DB *dbp;
|
||||
ssize_t nw;
|
||||
|
||||
dbp = (DB *)db185p->internal;
|
||||
|
||||
@ -473,14 +480,14 @@ db185_sync(db185p, flags)
|
||||
* We can't support the R_RECNOSYNC flag.
|
||||
*/
|
||||
#define RSMSG "DB: DB 1.85's R_RECNOSYNC sync flag is not supported.\n"
|
||||
(void)__os_write(2, RSMSG, sizeof(RSMSG) - 1);
|
||||
(void)__os_write(STDERR_FILENO, RSMSG, sizeof(RSMSG) - 1, &nw);
|
||||
goto einval;
|
||||
default:
|
||||
goto einval;
|
||||
}
|
||||
|
||||
return ((__set_errno(dbp->sync(dbp, 0))) == 0 ? 0 : -1);
|
||||
return ((errno = dbp->sync(dbp, 0)) == 0 ? 0 : -1);
|
||||
|
||||
einval: __set_errno(EINVAL);
|
||||
einval: errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
10
db2/db_185.h
10
db2/db_185.h
@ -65,11 +65,11 @@
|
||||
|
||||
#ifndef __BIT_TYPES_DEFINED__
|
||||
#define __BIT_TYPES_DEFINED__
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@u_int8_decl@
|
||||
@int16_decl@
|
||||
@u_int16_decl@
|
||||
@int32_decl@
|
||||
@u_int32_decl@
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
141
db2/db_int.h
141
db2/db_int.h
@ -4,14 +4,15 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db_int.h.src 10.62 (Sleepycat) 5/23/98
|
||||
* @(#)db_int.h 10.77 (Sleepycat) 1/3/99
|
||||
*/
|
||||
|
||||
#ifndef _DB_INTERNAL_H_
|
||||
#define _DB_INTERNAL_H_
|
||||
|
||||
#include <db.h> /* Standard DB include file. */
|
||||
#include "db.h" /* Standard DB include file. */
|
||||
#include "queue.h"
|
||||
#include "shqueue.h"
|
||||
|
||||
/*******************************************************
|
||||
* General purpose constants and macros.
|
||||
@ -75,27 +76,7 @@
|
||||
#define R_ADDR(base, offset) ((void *)((u_int8_t *)((base)->addr) + offset))
|
||||
#define R_OFFSET(base, p) ((u_int8_t *)(p) - (u_int8_t *)(base)->addr)
|
||||
|
||||
/* Free and free-string macros that overwrite memory. */
|
||||
#ifdef DIAGNOSTIC
|
||||
#undef FREE
|
||||
#define FREE(p, len) { \
|
||||
memset(p, 0xff, len); \
|
||||
__db_free(p); \
|
||||
}
|
||||
#undef FREES
|
||||
#define FREES(p) { \
|
||||
FREE(p, strlen(p)); \
|
||||
}
|
||||
#else
|
||||
#undef FREE
|
||||
#define FREE(p, len) { \
|
||||
__db_free(p); \
|
||||
}
|
||||
#undef FREES
|
||||
#define FREES(p) { \
|
||||
__db_free(p); \
|
||||
}
|
||||
#endif
|
||||
#define DB_DEFAULT 0x000000 /* No flag was specified. */
|
||||
|
||||
/* Structure used to print flag values. */
|
||||
typedef struct __fn {
|
||||
@ -111,24 +92,28 @@ typedef struct __fn {
|
||||
#define LF_CLR(f) (flags &= ~(f))
|
||||
#define LF_ISSET(f) (flags & (f))
|
||||
|
||||
/*
|
||||
* Panic check:
|
||||
* All interfaces check the panic flag, if it's set, the tree is dead.
|
||||
*/
|
||||
#define DB_PANIC_CHECK(dbp) { \
|
||||
if ((dbp)->dbenv != NULL && (dbp)->dbenv->db_panic != 0) \
|
||||
return (DB_RUNRECOVERY); \
|
||||
}
|
||||
|
||||
/* Display separator string. */
|
||||
#undef DB_LINE
|
||||
#define DB_LINE "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
|
||||
|
||||
/* Global variables. */
|
||||
typedef struct __db_globals {
|
||||
int db_mutexlocks; /* DB_MUTEXLOCKS */
|
||||
int db_region_anon; /* DB_REGION_ANON, DB_REGION_NAME */
|
||||
int db_region_init; /* DB_REGION_INIT */
|
||||
int db_tsl_spins; /* DB_TSL_SPINS */
|
||||
int db_pageyield; /* DB_PAGEYIELD */
|
||||
} DB_GLOBALS;
|
||||
extern DB_GLOBALS __db_global_values;
|
||||
#define DB_GLOBAL(v) __db_global_values.v
|
||||
|
||||
/* Unused, or not-used-yet variable. "Shut that bloody compiler up!" */
|
||||
#define COMPQUIET(n, v) (n) = (v)
|
||||
|
||||
/*
|
||||
* Purify and similar run-time tools complain about unitialized reads/writes
|
||||
* for structure fields whose only purpose is padding.
|
||||
*/
|
||||
#define UMRW(v) (v) = 0
|
||||
|
||||
/*
|
||||
* Win16 needs specific syntax on callback functions. Nobody else cares.
|
||||
*/
|
||||
@ -155,8 +140,6 @@ extern DB_GLOBALS __db_global_values;
|
||||
*******************************************************/
|
||||
typedef unsigned char tsl_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Various systems require different alignments for mutexes (the worst we've
|
||||
@ -204,21 +187,6 @@ typedef struct _db_mutex_t {
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) \
|
||||
(void)__db_mutex_unlock((db_mutex_t *)(dbp)->mutexp, -1);
|
||||
|
||||
/* Btree/recno local statistics structure. */
|
||||
struct __db_bt_lstat; typedef struct __db_bt_lstat DB_BTREE_LSTAT;
|
||||
struct __db_bt_lstat {
|
||||
u_int32_t bt_freed; /* Pages freed for reuse. */
|
||||
u_int32_t bt_pfxsaved; /* Bytes saved by prefix compression. */
|
||||
u_int32_t bt_split; /* Total number of splits. */
|
||||
u_int32_t bt_rootsplit; /* Root page splits. */
|
||||
u_int32_t bt_fastsplit; /* Fast splits. */
|
||||
u_int32_t bt_added; /* Items added. */
|
||||
u_int32_t bt_deleted; /* Items deleted. */
|
||||
u_int32_t bt_get; /* Items retrieved. */
|
||||
u_int32_t bt_cache_hit; /* Hits in fast-insert code. */
|
||||
u_int32_t bt_cache_miss; /* Misses in fast-insert code. */
|
||||
};
|
||||
|
||||
/*******************************************************
|
||||
* Environment.
|
||||
*******************************************************/
|
||||
@ -250,6 +218,7 @@ typedef struct _rlayout {
|
||||
int majver; /* Major version number. */
|
||||
int minver; /* Minor version number. */
|
||||
int patch; /* Patch version number. */
|
||||
int panic; /* Region is dead. */
|
||||
#define INVALID_SEGID -1
|
||||
int segid; /* shmget(2) ID, or Win16 segment ID. */
|
||||
|
||||
@ -262,9 +231,9 @@ typedef struct _rlayout {
|
||||
* we don't make the underlying VM unhappy.
|
||||
*/
|
||||
#define DB_VMPAGESIZE (4 * 1024)
|
||||
#define DB_ROUNDOFF(i) { \
|
||||
(i) += DB_VMPAGESIZE - 1; \
|
||||
(i) -= (i) % DB_VMPAGESIZE; \
|
||||
#define DB_ROUNDOFF(n, round) { \
|
||||
(n) += (round) - 1; \
|
||||
(n) -= (n) % (round); \
|
||||
}
|
||||
|
||||
/*
|
||||
@ -292,6 +261,7 @@ struct __db_reginfo {
|
||||
and mmap(2) is being used to map it
|
||||
into our address space. */
|
||||
int segid; /* shmget(2) ID, or Win16 segment ID. */
|
||||
void *wnt_handle; /* Win/NT HANDLE. */
|
||||
|
||||
/* Shared flags. */
|
||||
/* 0x0001 COMMON MASK with RLAYOUT structure. */
|
||||
@ -334,8 +304,8 @@ typedef struct __dbpginfo {
|
||||
#define IS_ZERO_LSN(LSN) ((LSN).file == 0)
|
||||
|
||||
/* Test if we need to log a change. */
|
||||
#define DB_LOGGING(dbp) \
|
||||
(F_ISSET(dbp, DB_AM_LOGGING) && !F_ISSET(dbp, DB_AM_RECOVER))
|
||||
#define DB_LOGGING(dbc) \
|
||||
(F_ISSET((dbc)->dbp, DB_AM_LOGGING) && !F_ISSET(dbc, DBC_RECOVER))
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
@ -350,30 +320,30 @@ typedef struct __dbpginfo {
|
||||
* A data
|
||||
* F flags
|
||||
*/
|
||||
#define LOG_OP(D, T, O, K, A, F) { \
|
||||
#define LOG_OP(C, T, O, K, A, F) { \
|
||||
DB_LSN _lsn; \
|
||||
DBT _op; \
|
||||
if (DB_LOGGING((D))) { \
|
||||
if (DB_LOGGING((C))) { \
|
||||
memset(&_op, 0, sizeof(_op)); \
|
||||
_op.data = O; \
|
||||
_op.size = strlen(O) + 1; \
|
||||
(void)__db_debug_log((D)->dbenv->lg_info, \
|
||||
T, &_lsn, 0, &_op, (D)->log_fileid, K, A, F); \
|
||||
(void)__db_debug_log((C)->dbp->dbenv->lg_info, \
|
||||
T, &_lsn, 0, &_op, (C)->dbp->log_fileid, K, A, F); \
|
||||
} \
|
||||
}
|
||||
#ifdef DEBUG_ROP
|
||||
#define DEBUG_LREAD(D, T, O, K, A, F) LOG_OP(D, T, O, K, A, F)
|
||||
#define DEBUG_LREAD(C, T, O, K, A, F) LOG_OP(C, T, O, K, A, F)
|
||||
#else
|
||||
#define DEBUG_LREAD(D, T, O, K, A, F)
|
||||
#define DEBUG_LREAD(C, T, O, K, A, F)
|
||||
#endif
|
||||
#ifdef DEBUG_WOP
|
||||
#define DEBUG_LWRITE(D, T, O, K, A, F) LOG_OP(D, T, O, K, A, F)
|
||||
#define DEBUG_LWRITE(C, T, O, K, A, F) LOG_OP(C, T, O, K, A, F)
|
||||
#else
|
||||
#define DEBUG_LWRITE(D, T, O, K, A, F)
|
||||
#define DEBUG_LWRITE(C, T, O, K, A, F)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_LREAD(D, T, O, K, A, F)
|
||||
#define DEBUG_LWRITE(D, T, O, K, A, F)
|
||||
#define DEBUG_LREAD(C, T, O, K, A, F)
|
||||
#define DEBUG_LWRITE(C, T, O, K, A, F)
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
/*******************************************************
|
||||
@ -393,10 +363,45 @@ struct __db_txn {
|
||||
DB_LSN last_lsn; /* Lsn of last log write. */
|
||||
u_int32_t txnid; /* Unique transaction id. */
|
||||
size_t off; /* Detail structure within region. */
|
||||
TAILQ_ENTRY(__db_txn) links;
|
||||
TAILQ_ENTRY(__db_txn) links; /* Links transactions off manager. */
|
||||
TAILQ_HEAD(__kids, __db_txn) kids; /* Child transactions. */
|
||||
TAILQ_ENTRY(__db_txn) klinks; /* Links child transactions. */
|
||||
|
||||
#define TXN_MALLOC 0x01 /* Structure allocated by TXN system. */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
#include "os_func.h"
|
||||
/*******************************************************
|
||||
* Global variables.
|
||||
*******************************************************/
|
||||
/*
|
||||
* !!!
|
||||
* Initialized in os/os_config.c, don't change this unless you change it
|
||||
* as well.
|
||||
*/
|
||||
|
||||
struct __rmname {
|
||||
char *dbhome;
|
||||
int rmid;
|
||||
TAILQ_ENTRY(__rmname) links;
|
||||
};
|
||||
|
||||
typedef struct __db_globals {
|
||||
int db_mutexlocks; /* DB_MUTEXLOCKS */
|
||||
int db_pageyield; /* DB_PAGEYIELD */
|
||||
int db_region_anon; /* DB_REGION_ANON, DB_REGION_NAME */
|
||||
int db_region_init; /* DB_REGION_INIT */
|
||||
int db_tsl_spins; /* DB_TSL_SPINS */
|
||||
/* XA: list of opened environments. */
|
||||
TAILQ_HEAD(__db_envq, __db_env) db_envq;
|
||||
/* XA: list of id to dbhome mappings. */
|
||||
TAILQ_HEAD(__db_nameq, __rmname) db_nameq;
|
||||
} DB_GLOBALS;
|
||||
|
||||
extern DB_GLOBALS __db_global_values;
|
||||
#define DB_GLOBAL(v) __db_global_values.v
|
||||
|
||||
#include "os.h"
|
||||
#include "os_ext.h"
|
||||
|
||||
#endif /* !_DB_INTERNAL_H_ */
|
||||
|
199
db2/dbm/dbm.c
199
db2/dbm/dbm.c
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)dbm.c 10.16 (Sleepycat) 5/7/98";
|
||||
static const char sccsid[] = "@(#)dbm.c 10.23 (Sleepycat) 11/22/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -89,6 +89,16 @@ __db_dbm_init(file)
|
||||
}
|
||||
weak_alias (__db_dbm_init, dbminit)
|
||||
|
||||
int
|
||||
__db_dbm_close()
|
||||
{
|
||||
if (__cur_db != NULL) {
|
||||
dbm_close(__cur_db);
|
||||
__cur_db = NULL;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
datum
|
||||
__db_dbm_fetch(key)
|
||||
datum key;
|
||||
@ -140,16 +150,11 @@ int
|
||||
__db_dbm_delete(key)
|
||||
datum key;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (__cur_db == NULL) {
|
||||
__db_no_open();
|
||||
return (-1);
|
||||
}
|
||||
ret = dbm_delete(__cur_db, key);
|
||||
if (ret == 0)
|
||||
ret = (((DB *)__cur_db)->sync)((DB *)__cur_db, 0);
|
||||
return (ret);
|
||||
return (dbm_delete(__cur_db, key));
|
||||
}
|
||||
weak_alias (__db_dbm_delete, delete)
|
||||
|
||||
@ -157,16 +162,11 @@ int
|
||||
__db_dbm_store(key, dat)
|
||||
datum key, dat;
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (__cur_db == NULL) {
|
||||
__db_no_open();
|
||||
return (-1);
|
||||
}
|
||||
ret = dbm_store(__cur_db, key, dat, DBM_REPLACE);
|
||||
if (ret == 0)
|
||||
ret = (((DB *)__cur_db)->sync)((DB *)__cur_db, 0);
|
||||
return (ret);
|
||||
return (dbm_store(__cur_db, key, dat, DBM_REPLACE));
|
||||
}
|
||||
weak_alias (__db_dbm_store, store)
|
||||
|
||||
@ -192,7 +192,9 @@ __db_ndbm_open(file, oflags, mode)
|
||||
int oflags, mode;
|
||||
{
|
||||
DB *dbp;
|
||||
DBC *dbc;
|
||||
DB_INFO dbinfo;
|
||||
int sv_errno;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
memset(&dbinfo, 0, sizeof(dbinfo));
|
||||
@ -215,7 +217,15 @@ __db_ndbm_open(file, oflags, mode)
|
||||
if ((errno = db_open(path,
|
||||
DB_HASH, __db_oflags(oflags), mode, NULL, &dbinfo, &dbp)) != 0)
|
||||
return (NULL);
|
||||
return ((DBM *)dbp);
|
||||
|
||||
if ((errno = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) {
|
||||
sv_errno = errno;
|
||||
(void)dbp->close(dbp, 0);
|
||||
errno = sv_errno;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return ((DBM *)dbc);
|
||||
}
|
||||
weak_alias (__db_ndbm_open, dbm_open)
|
||||
|
||||
@ -224,10 +234,14 @@ weak_alias (__db_ndbm_open, dbm_open)
|
||||
* Nothing.
|
||||
*/
|
||||
void
|
||||
__db_ndbm_close(db)
|
||||
DBM *db;
|
||||
__db_ndbm_close(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
(void)db->close(db, 0);
|
||||
DBC *dbc;
|
||||
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
(void)dbc->dbp->close(dbc->dbp, 0);
|
||||
}
|
||||
weak_alias (__db_ndbm_close, dbm_close)
|
||||
|
||||
@ -237,25 +251,39 @@ weak_alias (__db_ndbm_close, dbm_close)
|
||||
* NULL on failure
|
||||
*/
|
||||
datum
|
||||
__db_ndbm_fetch(db, key)
|
||||
DBM *db;
|
||||
__db_ndbm_fetch(dbm, key)
|
||||
DBM *dbm;
|
||||
datum key;
|
||||
{
|
||||
DBC *dbc;
|
||||
DBT _key, _data;
|
||||
datum data;
|
||||
int ret;
|
||||
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
memset(&_key, 0, sizeof(DBT));
|
||||
memset(&_data, 0, sizeof(DBT));
|
||||
_key.size = key.dsize;
|
||||
_key.data = key.dptr;
|
||||
if ((ret = db->get((DB *)db, NULL, &_key, &_data, 0)) == 0) {
|
||||
|
||||
/*
|
||||
* Note that we can't simply use the dbc we have to do a c_get/SET,
|
||||
* because that cursor is the one used for sequential iteration and
|
||||
* it has to remain stable in the face of intervening gets and puts.
|
||||
*/
|
||||
if ((ret = dbc->dbp->get(dbc->dbp, NULL, &_key, &_data, 0)) == 0) {
|
||||
data.dptr = _data.data;
|
||||
data.dsize = _data.size;
|
||||
} else {
|
||||
data.dptr = NULL;
|
||||
data.dsize = 0;
|
||||
__set_errno (ret == DB_NOTFOUND ? ENOENT : ret);
|
||||
if (ret == DB_NOTFOUND)
|
||||
errno = ENOENT;
|
||||
else {
|
||||
errno = ret;
|
||||
F_SET(dbc->dbp, DB_DBM_ERROR);
|
||||
}
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
@ -267,30 +295,31 @@ weak_alias (__db_ndbm_fetch, dbm_fetch)
|
||||
* NULL on failure
|
||||
*/
|
||||
datum
|
||||
__db_ndbm_firstkey(db)
|
||||
DBM *db;
|
||||
__db_ndbm_firstkey(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
DBC *dbc;
|
||||
DBT _key, _data;
|
||||
datum key;
|
||||
int ret;
|
||||
|
||||
DBC *cp;
|
||||
|
||||
if ((cp = TAILQ_FIRST(&db->curs_queue)) == NULL)
|
||||
if ((errno = db->cursor(db, NULL, &cp)) != 0) {
|
||||
memset(&key, 0, sizeof(key));
|
||||
return (key);
|
||||
}
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
memset(&_key, 0, sizeof(DBT));
|
||||
memset(&_data, 0, sizeof(DBT));
|
||||
if ((ret = (cp->c_get)(cp, &_key, &_data, DB_FIRST)) == 0) {
|
||||
|
||||
if ((ret = dbc->c_get(dbc, &_key, &_data, DB_FIRST)) == 0) {
|
||||
key.dptr = _key.data;
|
||||
key.dsize = _key.size;
|
||||
} else {
|
||||
key.dptr = NULL;
|
||||
key.dsize = 0;
|
||||
__set_errno (ret == DB_NOTFOUND ? ENOENT : ret);
|
||||
if (ret == DB_NOTFOUND)
|
||||
errno = ENOENT;
|
||||
else {
|
||||
errno = ret;
|
||||
F_SET(dbc->dbp, DB_DBM_ERROR);
|
||||
}
|
||||
}
|
||||
return (key);
|
||||
}
|
||||
@ -302,29 +331,31 @@ weak_alias (__db_ndbm_firstkey, dbm_firstkey)
|
||||
* NULL on failure
|
||||
*/
|
||||
datum
|
||||
__db_ndbm_nextkey(db)
|
||||
DBM *db;
|
||||
__db_ndbm_nextkey(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
DBC *cp;
|
||||
DBC *dbc;
|
||||
DBT _key, _data;
|
||||
datum key;
|
||||
int ret;
|
||||
|
||||
if ((cp = TAILQ_FIRST(&db->curs_queue)) == NULL)
|
||||
if ((errno = db->cursor(db, NULL, &cp)) != 0) {
|
||||
memset(&key, 0, sizeof(key));
|
||||
return (key);
|
||||
}
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
memset(&_key, 0, sizeof(DBT));
|
||||
memset(&_data, 0, sizeof(DBT));
|
||||
if ((ret = (cp->c_get)(cp, &_key, &_data, DB_NEXT)) == 0) {
|
||||
|
||||
if ((ret = dbc->c_get(dbc, &_key, &_data, DB_NEXT)) == 0) {
|
||||
key.dptr = _key.data;
|
||||
key.dsize = _key.size;
|
||||
} else {
|
||||
key.dptr = NULL;
|
||||
key.dsize = 0;
|
||||
__set_errno (ret == DB_NOTFOUND ? ENOENT : ret);
|
||||
if (ret == DB_NOTFOUND)
|
||||
errno = ENOENT;
|
||||
else {
|
||||
errno = ret;
|
||||
F_SET(dbc->dbp, DB_DBM_ERROR);
|
||||
}
|
||||
}
|
||||
return (key);
|
||||
}
|
||||
@ -336,19 +367,29 @@ weak_alias (__db_ndbm_nextkey, dbm_nextkey)
|
||||
* <0 failure
|
||||
*/
|
||||
int
|
||||
__db_ndbm_delete(db, key)
|
||||
DBM *db;
|
||||
__db_ndbm_delete(dbm, key)
|
||||
DBM *dbm;
|
||||
datum key;
|
||||
{
|
||||
DBC *dbc;
|
||||
DBT _key;
|
||||
int ret;
|
||||
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
memset(&_key, 0, sizeof(DBT));
|
||||
_key.data = key.dptr;
|
||||
_key.size = key.dsize;
|
||||
if ((ret = (((DB *)db)->del)((DB *)db, NULL, &_key, 0)) == 0)
|
||||
|
||||
if ((ret = dbc->dbp->del(dbc->dbp, NULL, &_key, 0)) == 0)
|
||||
return (0);
|
||||
errno = ret == DB_NOTFOUND ? ENOENT : ret;
|
||||
|
||||
if (ret == DB_NOTFOUND)
|
||||
errno = ENOENT;
|
||||
else {
|
||||
errno = ret;
|
||||
F_SET(dbc->dbp, DB_DBM_ERROR);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
weak_alias (__db_ndbm_delete, dbm_delete)
|
||||
@ -360,49 +401,59 @@ weak_alias (__db_ndbm_delete, dbm_delete)
|
||||
* 1 if DBM_INSERT and entry exists
|
||||
*/
|
||||
int
|
||||
__db_ndbm_store(db, key, data, flags)
|
||||
DBM *db;
|
||||
__db_ndbm_store(dbm, key, data, flags)
|
||||
DBM *dbm;
|
||||
datum key, data;
|
||||
int flags;
|
||||
{
|
||||
DBC *dbc;
|
||||
DBT _key, _data;
|
||||
int ret;
|
||||
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
memset(&_key, 0, sizeof(DBT));
|
||||
memset(&_data, 0, sizeof(DBT));
|
||||
_key.data = key.dptr;
|
||||
_key.size = key.dsize;
|
||||
|
||||
memset(&_data, 0, sizeof(DBT));
|
||||
_data.data = data.dptr;
|
||||
_data.size = data.dsize;
|
||||
if ((ret = db->put((DB *)db, NULL,
|
||||
|
||||
if ((ret = dbc->dbp->put(dbc->dbp, NULL,
|
||||
&_key, &_data, flags == DBM_INSERT ? DB_NOOVERWRITE : 0)) == 0)
|
||||
return (0);
|
||||
|
||||
if (ret == DB_KEYEXIST)
|
||||
return (1);
|
||||
|
||||
errno = ret;
|
||||
F_SET(dbc->dbp, DB_DBM_ERROR);
|
||||
return (-1);
|
||||
}
|
||||
weak_alias (__db_ndbm_store, dbm_store)
|
||||
|
||||
int
|
||||
__db_ndbm_error(db)
|
||||
DBM *db;
|
||||
__db_ndbm_error(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
HTAB *hp;
|
||||
DBC *dbc;
|
||||
|
||||
hp = (HTAB *)db->internal;
|
||||
return (hp->local_errno);
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
return (F_ISSET(dbc->dbp, DB_DBM_ERROR));
|
||||
}
|
||||
weak_alias (__db_ndbm_error, dbm_error)
|
||||
|
||||
int
|
||||
__db_ndbm_clearerr(db)
|
||||
DBM *db;
|
||||
__db_ndbm_clearerr(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
HTAB *hp;
|
||||
DBC *dbc;
|
||||
|
||||
hp = (HTAB *)db->internal;
|
||||
hp->local_errno = 0;
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
F_CLR(dbc->dbp, DB_DBM_ERROR);
|
||||
return (0);
|
||||
}
|
||||
weak_alias (__db_ndbm_clearerr, dbm_clearerr)
|
||||
@ -413,10 +464,14 @@ weak_alias (__db_ndbm_clearerr, dbm_clearerr)
|
||||
* 0 if not read-only
|
||||
*/
|
||||
int
|
||||
__db_ndbm_rdonly(db)
|
||||
DBM *db;
|
||||
__db_ndbm_rdonly(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
return (F_ISSET((DB *)db, DB_AM_RDONLY) ? 1 : 0);
|
||||
DBC *dbc;
|
||||
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
return (F_ISSET(dbc->dbp, DB_AM_RDONLY) ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -426,23 +481,23 @@ __db_ndbm_rdonly(db)
|
||||
* and picked one to use at random.
|
||||
*/
|
||||
int
|
||||
__db_ndbm_dirfno(db)
|
||||
DBM *db;
|
||||
__db_ndbm_dirfno(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
int fd;
|
||||
|
||||
(void)db->fd(db, &fd);
|
||||
return (fd);
|
||||
return (dbm_pagfno(dbm));
|
||||
}
|
||||
weak_alias (__db_ndbm_dirfno, dbm_dirfno)
|
||||
|
||||
int
|
||||
__db_ndbm_pagfno(db)
|
||||
DBM *db;
|
||||
__db_ndbm_pagfno(dbm)
|
||||
DBM *dbm;
|
||||
{
|
||||
DBC *dbc;
|
||||
int fd;
|
||||
|
||||
(void)db->fd(db, &fd);
|
||||
dbc = (DBC *)dbm;
|
||||
|
||||
(void)dbc->dbp->fd(dbc->dbp, &fd);
|
||||
return (fd);
|
||||
}
|
||||
weak_alias (__db_ndbm_pagfno, dbm_pagfno)
|
||||
|
1181
db2/hash/hash.c
1181
db2/hash/hash.c
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,6 @@
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "shqueue.h"
|
||||
#include "db_page.h"
|
||||
#include "db_dispatch.h"
|
||||
#include "hash.h"
|
||||
@ -46,8 +45,7 @@ int __ham_insdel_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_insdel;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -59,8 +57,8 @@ int __ham_insdel_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(*pagelsn)
|
||||
+ sizeof(u_int32_t) + (key == NULL ? 0 : key->size)
|
||||
+ sizeof(u_int32_t) + (data == NULL ? 0 : data->size);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -109,7 +107,7 @@ int __ham_insdel_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -170,7 +168,7 @@ __ham_insdel_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
}
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -184,11 +182,12 @@ __ham_insdel_read(recbuf, argpp)
|
||||
{
|
||||
__ham_insdel_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_insdel_args *)__db_malloc(sizeof(__ham_insdel_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_insdel_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));
|
||||
@ -250,8 +249,7 @@ int __ham_newpage_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_newpage;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -264,8 +262,8 @@ int __ham_newpage_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(*pagelsn)
|
||||
+ sizeof(next_pgno)
|
||||
+ sizeof(*nextlsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -306,7 +304,7 @@ int __ham_newpage_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -354,7 +352,7 @@ __ham_newpage_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tnextlsn: [%lu][%lu]\n",
|
||||
(u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -368,11 +366,12 @@ __ham_newpage_read(recbuf, argpp)
|
||||
{
|
||||
__ham_newpage_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_newpage_args *)__db_malloc(sizeof(__ham_newpage_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_newpage_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));
|
||||
@ -428,8 +427,7 @@ int __ham_splitmeta_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_splitmeta;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -439,8 +437,8 @@ int __ham_splitmeta_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(ovflpoint)
|
||||
+ sizeof(spares)
|
||||
+ sizeof(*metalsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -469,7 +467,7 @@ int __ham_splitmeta_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -512,7 +510,7 @@ __ham_splitmeta_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tmetalsn: [%lu][%lu]\n",
|
||||
(u_long)argp->metalsn.file, (u_long)argp->metalsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -526,11 +524,12 @@ __ham_splitmeta_read(recbuf, argpp)
|
||||
{
|
||||
__ham_splitmeta_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_splitmeta_args *)__db_malloc(sizeof(__ham_splitmeta_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_splitmeta_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));
|
||||
@ -581,8 +580,7 @@ int __ham_splitdata_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_splitdata;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -592,8 +590,8 @@ int __ham_splitdata_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(pgno)
|
||||
+ sizeof(u_int32_t) + (pageimage == NULL ? 0 : pageimage->size)
|
||||
+ sizeof(*pagelsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -630,7 +628,7 @@ int __ham_splitdata_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -681,7 +679,7 @@ __ham_splitdata_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tpagelsn: [%lu][%lu]\n",
|
||||
(u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -695,11 +693,12 @@ __ham_splitdata_read(recbuf, argpp)
|
||||
{
|
||||
__ham_splitdata_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_splitdata_args *)__db_malloc(sizeof(__ham_splitdata_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_splitdata_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));
|
||||
@ -756,8 +755,7 @@ int __ham_replace_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_replace;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -770,8 +768,8 @@ int __ham_replace_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(u_int32_t) + (olditem == NULL ? 0 : olditem->size)
|
||||
+ sizeof(u_int32_t) + (newitem == NULL ? 0 : newitem->size)
|
||||
+ sizeof(makedup);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -822,7 +820,7 @@ int __ham_replace_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -884,7 +882,7 @@ __ham_replace_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\n");
|
||||
printf("\tmakedup: %lu\n", (u_long)argp->makedup);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -898,11 +896,12 @@ __ham_replace_read(recbuf, argpp)
|
||||
{
|
||||
__ham_replace_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_replace_args *)__db_malloc(sizeof(__ham_replace_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_replace_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));
|
||||
@ -968,8 +967,7 @@ int __ham_newpgno_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_newpgno;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -983,8 +981,8 @@ int __ham_newpgno_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(new_type)
|
||||
+ sizeof(*pagelsn)
|
||||
+ sizeof(*metalsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -1024,7 +1022,7 @@ int __ham_newpgno_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1072,7 +1070,7 @@ __ham_newpgno_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tmetalsn: [%lu][%lu]\n",
|
||||
(u_long)argp->metalsn.file, (u_long)argp->metalsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1086,11 +1084,12 @@ __ham_newpgno_read(recbuf, argpp)
|
||||
{
|
||||
__ham_newpgno_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_newpgno_args *)__db_malloc(sizeof(__ham_newpgno_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_newpgno_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));
|
||||
@ -1149,8 +1148,7 @@ int __ham_ovfl_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_ovfl;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -1161,8 +1159,8 @@ int __ham_ovfl_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(free_pgno)
|
||||
+ sizeof(ovflpoint)
|
||||
+ sizeof(*metalsn);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -1193,7 +1191,7 @@ int __ham_ovfl_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1237,7 +1235,7 @@ __ham_ovfl_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tmetalsn: [%lu][%lu]\n",
|
||||
(u_long)argp->metalsn.file, (u_long)argp->metalsn.offset);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1251,11 +1249,12 @@ __ham_ovfl_read(recbuf, argpp)
|
||||
{
|
||||
__ham_ovfl_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_ovfl_args *)__db_malloc(sizeof(__ham_ovfl_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_ovfl_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));
|
||||
@ -1312,8 +1311,7 @@ int __ham_copypage_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_ham_copypage;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -1326,8 +1324,8 @@ int __ham_copypage_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(nnext_pgno)
|
||||
+ sizeof(*nnextlsn)
|
||||
+ sizeof(u_int32_t) + (page == NULL ? 0 : page->size);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -1376,7 +1374,7 @@ int __ham_copypage_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1432,7 +1430,7 @@ __ham_copypage_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
}
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1446,11 +1444,12 @@ __ham_copypage_read(recbuf, argpp)
|
||||
{
|
||||
__ham_copypage_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__ham_copypage_args *)__db_malloc(sizeof(__ham_copypage_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__ham_copypage_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));
|
||||
|
@ -1,92 +0,0 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* The President and Fellows of Harvard University. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jeremy Rassen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)hash_debug.c 10.6 (Sleepycat) 5/7/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* PACKAGE: hashing
|
||||
*
|
||||
* DESCRIPTION:
|
||||
* Debug routines.
|
||||
*
|
||||
* ROUTINES:
|
||||
*
|
||||
* External
|
||||
* __dump_bucket
|
||||
*/
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "hash.h"
|
||||
|
||||
/*
|
||||
* __ham_dump_bucket --
|
||||
*
|
||||
* PUBLIC: #ifdef DEBUG
|
||||
* PUBLIC: void __ham_dump_bucket __P((HTAB *, u_int32_t));
|
||||
* PUBLIC: #endif
|
||||
*/
|
||||
void
|
||||
__ham_dump_bucket(hashp, bucket)
|
||||
HTAB *hashp;
|
||||
u_int32_t bucket;
|
||||
{
|
||||
PAGE *p;
|
||||
db_pgno_t pgno;
|
||||
|
||||
for (pgno = BUCKET_TO_PAGE(hashp, bucket); pgno != PGNO_INVALID;) {
|
||||
if (memp_fget(hashp->dbp->mpf, &pgno, 0, &p) != 0)
|
||||
break;
|
||||
(void)__db_prpage(p, 1);
|
||||
pgno = p->next_pgno;
|
||||
(void)memp_fput(hashp->dbp->mpf, p, 0);
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
@ -42,7 +42,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)hash_dup.c 10.14 (Sleepycat) 5/7/98";
|
||||
static const char sccsid[] = "@(#)hash_dup.c 10.27 (Sleepycat) 12/6/98";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
@ -61,15 +61,17 @@ static const char sccsid[] = "@(#)hash_dup.c 10.14 (Sleepycat) 5/7/98";
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "db_page.h"
|
||||
#include "hash.h"
|
||||
#include "btree.h"
|
||||
|
||||
static int __ham_check_move __P((HTAB *, HASH_CURSOR *, int32_t));
|
||||
static int __ham_dup_convert __P((HTAB *, HASH_CURSOR *));
|
||||
static int __ham_check_move __P((DBC *, int32_t));
|
||||
static int __ham_dup_convert __P((DBC *));
|
||||
static int __ham_make_dup __P((const DBT *, DBT *d, void **, u_int32_t *));
|
||||
|
||||
/*
|
||||
@ -85,26 +87,29 @@ static int __ham_make_dup __P((const DBT *, DBT *d, void **, u_int32_t *));
|
||||
* Case 4: The element is large enough to push the duplicate set onto a
|
||||
* separate page.
|
||||
*
|
||||
* PUBLIC: int __ham_add_dup __P((HTAB *, HASH_CURSOR *, DBT *, u_int32_t));
|
||||
* PUBLIC: int __ham_add_dup __P((DBC *, DBT *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__ham_add_dup(hashp, hcp, nval, flags)
|
||||
HTAB *hashp;
|
||||
HASH_CURSOR *hcp;
|
||||
__ham_add_dup(dbc, nval, flags)
|
||||
DBC *dbc;
|
||||
DBT *nval;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DBT pval, tmp_val;
|
||||
DB *dbp;
|
||||
HASH_CURSOR *hcp;
|
||||
DBT dbt, pval, tmp_val;
|
||||
u_int32_t del_len, new_size;
|
||||
int ret;
|
||||
int cmp, ret;
|
||||
u_int8_t *hk;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
if (flags == DB_CURRENT && hcp->dpgno == PGNO_INVALID)
|
||||
del_len = hcp->dup_len;
|
||||
else
|
||||
del_len = 0;
|
||||
|
||||
if ((ret = __ham_check_move(hashp, hcp,
|
||||
if ((ret = __ham_check_move(dbc,
|
||||
(int32_t)DUP_SIZE(nval->size) - (int32_t)del_len)) != 0)
|
||||
return (ret);
|
||||
|
||||
@ -117,7 +122,7 @@ __ham_add_dup(hashp, hcp, nval, flags)
|
||||
*/
|
||||
hk = H_PAIRDATA(hcp->pagep, hcp->bndx);
|
||||
new_size = DUP_SIZE(nval->size) - del_len + LEN_HKEYDATA(hcp->pagep,
|
||||
hashp->hdr->pagesize, H_DATAINDEX(hcp->bndx));
|
||||
hcp->hdr->pagesize, H_DATAINDEX(hcp->bndx));
|
||||
|
||||
/*
|
||||
* We convert to off-page duplicates if the item is a big item,
|
||||
@ -125,10 +130,10 @@ __ham_add_dup(hashp, hcp, nval, flags)
|
||||
* if there isn't enough room on this page to add the next item.
|
||||
*/
|
||||
if (HPAGE_PTYPE(hk) != H_OFFDUP &&
|
||||
(HPAGE_PTYPE(hk) == H_OFFPAGE || ISBIG(hashp, new_size) ||
|
||||
(HPAGE_PTYPE(hk) == H_OFFPAGE || ISBIG(hcp, new_size) ||
|
||||
DUP_SIZE(nval->size) - del_len > P_FREESPACE(hcp->pagep))) {
|
||||
|
||||
if ((ret = __ham_dup_convert(hashp, hcp)) != 0)
|
||||
if ((ret = __ham_dup_convert(dbc)) != 0)
|
||||
return (ret);
|
||||
else
|
||||
hk = H_PAIRDATA(hcp->pagep, hcp->bndx);
|
||||
@ -140,30 +145,44 @@ __ham_add_dup(hashp, hcp, nval, flags)
|
||||
HPAGE_PTYPE(hk) = H_DUPLICATE;
|
||||
pval.flags = 0;
|
||||
pval.data = HKEYDATA_DATA(hk);
|
||||
pval.size = LEN_HDATA(hcp->pagep, hashp->hdr->pagesize,
|
||||
pval.size = LEN_HDATA(hcp->pagep, dbp->pgsize,
|
||||
hcp->bndx);
|
||||
if ((ret =
|
||||
__ham_make_dup(&pval, &tmp_val, &hcp->big_data,
|
||||
&hcp->big_datalen)) != 0 || (ret =
|
||||
__ham_replpair(hashp, hcp, &tmp_val, 1)) != 0)
|
||||
__ham_make_dup(&pval, &tmp_val, &dbc->rdata.data,
|
||||
&dbc->rdata.size)) != 0 || (ret =
|
||||
__ham_replpair(dbc, &tmp_val, 1)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Now make the new entry a duplicate. */
|
||||
if ((ret = __ham_make_dup(nval,
|
||||
&tmp_val, &hcp->big_data, &hcp->big_datalen)) != 0)
|
||||
&tmp_val, &dbc->rdata.data, &dbc->rdata.size)) != 0)
|
||||
return (ret);
|
||||
|
||||
tmp_val.dlen = 0;
|
||||
switch (flags) { /* On page. */
|
||||
case DB_KEYFIRST:
|
||||
tmp_val.doff = 0;
|
||||
break;
|
||||
case DB_KEYLAST:
|
||||
tmp_val.doff = LEN_HDATA(hcp->pagep,
|
||||
hashp->hdr->pagesize, hcp->bndx);
|
||||
if (dbp->dup_compare != NULL)
|
||||
__ham_dsearch(dbc, nval, &tmp_val.doff, &cmp);
|
||||
else if (flags == DB_KEYFIRST)
|
||||
tmp_val.doff = 0;
|
||||
else
|
||||
tmp_val.doff = LEN_HDATA(hcp->pagep,
|
||||
hcp->hdr->pagesize, hcp->bndx);
|
||||
break;
|
||||
case DB_CURRENT:
|
||||
/*
|
||||
* If we have a sort function, we need to verify that
|
||||
* the new item sorts identically to the old item.
|
||||
*/
|
||||
if (dbp->dup_compare != NULL) {
|
||||
dbt.data = HKEYDATA_DATA(H_PAIRDATA(hcp->pagep,
|
||||
hcp->bndx)) + hcp->dup_off;
|
||||
dbt.size = DUP_SIZE(hcp->dup_len);
|
||||
if (dbp->dup_compare(nval, &dbt) != 0)
|
||||
return (EINVAL);
|
||||
}
|
||||
tmp_val.doff = hcp->dup_off;
|
||||
tmp_val.dlen = DUP_SIZE(hcp->dup_len);
|
||||
break;
|
||||
@ -175,9 +194,9 @@ __ham_add_dup(hashp, hcp, nval, flags)
|
||||
break;
|
||||
}
|
||||
/* Add the duplicate. */
|
||||
ret = __ham_replpair(hashp, hcp, &tmp_val, 0);
|
||||
ret = __ham_replpair(dbc, &tmp_val, 0);
|
||||
if (ret == 0)
|
||||
ret = __ham_dirty_page(hashp, hcp->pagep);
|
||||
ret = __ham_dirty_page(dbp, hcp->pagep);
|
||||
__ham_c_update(hcp, hcp->pgno, tmp_val.size, 1, 1);
|
||||
return (ret);
|
||||
}
|
||||
@ -190,27 +209,48 @@ __ham_add_dup(hashp, hcp, nval, flags)
|
||||
|
||||
switch (flags) {
|
||||
case DB_KEYFIRST:
|
||||
if (dbp->dup_compare != NULL)
|
||||
goto sorted_dups;
|
||||
/*
|
||||
* The only way that we are already on a dup page is
|
||||
* if we just converted the on-page representation.
|
||||
* In that case, we've only got one page of duplicates.
|
||||
*/
|
||||
if (hcp->dpagep == NULL && (ret =
|
||||
__db_dend(hashp->dbp, hcp->dpgno, &hcp->dpagep)) != 0)
|
||||
__db_dend(dbc, hcp->dpgno, &hcp->dpagep)) != 0)
|
||||
return (ret);
|
||||
hcp->dndx = 0;
|
||||
break;
|
||||
case DB_KEYLAST:
|
||||
if (hcp->dpagep == NULL && (ret =
|
||||
__db_dend(hashp->dbp, hcp->dpgno, &hcp->dpagep)) != 0)
|
||||
return (ret);
|
||||
hcp->dpgno = PGNO(hcp->dpagep);
|
||||
hcp->dndx = NUM_ENT(hcp->dpagep);
|
||||
if (dbp->dup_compare != NULL) {
|
||||
sorted_dups: if ((ret = __db_dsearch(dbc, 1, nval,
|
||||
hcp->dpgno, &hcp->dndx, &hcp->dpagep, &cmp)) != 0)
|
||||
return (ret);
|
||||
if (cmp == 0)
|
||||
hcp->dpgno = PGNO(hcp->dpagep);
|
||||
} else {
|
||||
if (hcp->dpagep == NULL && (ret =
|
||||
__db_dend(dbc, hcp->dpgno, &hcp->dpagep)) != 0)
|
||||
return (ret);
|
||||
hcp->dpgno = PGNO(hcp->dpagep);
|
||||
hcp->dndx = NUM_ENT(hcp->dpagep);
|
||||
}
|
||||
break;
|
||||
case DB_CURRENT:
|
||||
if ((ret = __db_ditem(hashp->dbp, hcp->dpagep, hcp->dndx,
|
||||
BKEYDATA_SIZE(GET_BKEYDATA(hcp->dpagep, hcp->dndx)->len)))
|
||||
!= 0)
|
||||
if (dbp->dup_compare != NULL && __bam_cmp(dbp,
|
||||
nval, hcp->dpagep, hcp->dndx, dbp->dup_compare) != 0)
|
||||
return (EINVAL);
|
||||
switch (GET_BKEYDATA(hcp->dpagep, hcp->dndx)->type) {
|
||||
case B_KEYDATA:
|
||||
del_len = BKEYDATA_SIZE(GET_BKEYDATA(hcp->dpagep,
|
||||
hcp->dndx)->len);
|
||||
break;
|
||||
case B_OVERFLOW:
|
||||
del_len = BOVERFLOW_SIZE;
|
||||
break;
|
||||
}
|
||||
if ((ret =
|
||||
__db_ditem(dbc, hcp->dpagep, hcp->dndx, del_len)) != 0)
|
||||
return (ret);
|
||||
break;
|
||||
case DB_BEFORE: /* The default behavior is correct. */
|
||||
@ -220,7 +260,7 @@ __ham_add_dup(hashp, hcp, nval, flags)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = __db_dput(hashp->dbp,
|
||||
ret = __db_dput(dbc,
|
||||
nval, &hcp->dpagep, &hcp->dndx, __ham_overflow_page);
|
||||
hcp->pgno = PGNO(hcp->pagep);
|
||||
__ham_c_update(hcp, hcp->pgno, nval->size, 1, 1);
|
||||
@ -231,22 +271,25 @@ __ham_add_dup(hashp, hcp, nval, flags)
|
||||
* Convert an on-page set of duplicates to an offpage set of duplicates.
|
||||
*/
|
||||
static int
|
||||
__ham_dup_convert(hashp, hcp)
|
||||
HTAB *hashp;
|
||||
HASH_CURSOR *hcp;
|
||||
__ham_dup_convert(dbc)
|
||||
DBC *dbc;
|
||||
{
|
||||
DB *dbp;
|
||||
HASH_CURSOR *hcp;
|
||||
BOVERFLOW bo;
|
||||
DBT dbt;
|
||||
HOFFPAGE ho;
|
||||
db_indx_t dndx, len;
|
||||
db_indx_t dndx, i, len, off;
|
||||
int ret;
|
||||
u_int8_t *p, *pend;
|
||||
|
||||
/*
|
||||
* Create a new page for the duplicates.
|
||||
*/
|
||||
dbp = dbc->dbp;
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
if ((ret =
|
||||
__ham_overflow_page(hashp->dbp, P_DUPLICATE, &hcp->dpagep)) != 0)
|
||||
__ham_overflow_page(dbc, P_DUPLICATE, &hcp->dpagep)) != 0)
|
||||
return (ret);
|
||||
hcp->dpagep->type = P_DUPLICATE;
|
||||
hcp->dpgno = PGNO(hcp->dpagep);
|
||||
@ -254,67 +297,80 @@ __ham_dup_convert(hashp, hcp)
|
||||
/*
|
||||
* Now put the duplicates onto the new page.
|
||||
*/
|
||||
dndx = 0;
|
||||
dbt.flags = 0;
|
||||
switch (HPAGE_PTYPE(H_PAIRDATA(hcp->pagep, hcp->bndx))) {
|
||||
case H_KEYDATA:
|
||||
/* Simple case, one key on page; move it to dup page. */
|
||||
dndx = 0;
|
||||
dbt.size =
|
||||
LEN_HDATA(hcp->pagep, hashp->hdr->pagesize, hcp->bndx);
|
||||
LEN_HDATA(hcp->pagep, hcp->hdr->pagesize, hcp->bndx);
|
||||
dbt.data = HKEYDATA_DATA(H_PAIRDATA(hcp->pagep, hcp->bndx));
|
||||
ret = __db_pitem(hashp->dbp, hcp->dpagep,
|
||||
ret = __db_pitem(dbc, hcp->dpagep,
|
||||
(u_int32_t)dndx, BKEYDATA_SIZE(dbt.size), NULL, &dbt);
|
||||
if (ret == 0)
|
||||
__ham_dirty_page(hashp, hcp->dpagep);
|
||||
__ham_dirty_page(dbp, hcp->dpagep);
|
||||
break;
|
||||
case H_OFFPAGE:
|
||||
/* Simple case, one key on page; move it to dup page. */
|
||||
dndx = 0;
|
||||
memcpy(&ho,
|
||||
P_ENTRY(hcp->pagep, H_DATAINDEX(hcp->bndx)), HOFFPAGE_SIZE);
|
||||
UMRW(bo.unused1);
|
||||
B_TSET(bo.type, ho.type, 0);
|
||||
UMRW(bo.unused2);
|
||||
bo.pgno = ho.pgno;
|
||||
bo.tlen = ho.tlen;
|
||||
dbt.size = BOVERFLOW_SIZE;
|
||||
dbt.data = &bo;
|
||||
|
||||
ret = __db_pitem(hashp->dbp, hcp->dpagep,
|
||||
ret = __db_pitem(dbc, hcp->dpagep,
|
||||
(u_int32_t)dndx, dbt.size, &dbt, NULL);
|
||||
if (ret == 0)
|
||||
__ham_dirty_page(hashp, hcp->dpagep);
|
||||
__ham_dirty_page(dbp, hcp->dpagep);
|
||||
break;
|
||||
case H_DUPLICATE:
|
||||
p = HKEYDATA_DATA(H_PAIRDATA(hcp->pagep, hcp->bndx));
|
||||
pend = p +
|
||||
LEN_HDATA(hcp->pagep, hashp->hdr->pagesize, hcp->bndx);
|
||||
LEN_HDATA(hcp->pagep, hcp->hdr->pagesize, hcp->bndx);
|
||||
|
||||
for (dndx = 0; p < pend; dndx++) {
|
||||
/*
|
||||
* We need to maintain the duplicate cursor position.
|
||||
* Keep track of where we are in the duplicate set via
|
||||
* the offset, and when it matches the one in the cursor,
|
||||
* set the off-page duplicate cursor index to the current
|
||||
* index.
|
||||
*/
|
||||
for (off = 0, i = 0; p < pend; i++) {
|
||||
if (off == hcp->dup_off)
|
||||
dndx = i;
|
||||
memcpy(&len, p, sizeof(db_indx_t));
|
||||
dbt.size = len;
|
||||
p += sizeof(db_indx_t);
|
||||
dbt.data = p;
|
||||
p += len + sizeof(db_indx_t);
|
||||
ret = __db_dput(hashp->dbp, &dbt,
|
||||
&hcp->dpagep, &dndx, __ham_overflow_page);
|
||||
off += len + 2 * sizeof(db_indx_t);
|
||||
ret = __db_dput(dbc, &dbt,
|
||||
&hcp->dpagep, &i, __ham_overflow_page);
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = __db_pgfmt(hashp->dbp, (u_long)hcp->pgno);
|
||||
ret = __db_pgfmt(dbp, (u_long)hcp->pgno);
|
||||
break;
|
||||
}
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Now attach this to the source page in place of
|
||||
* the old duplicate item.
|
||||
*/
|
||||
__ham_move_offpage(hashp, hcp->pagep,
|
||||
__ham_move_offpage(dbc, hcp->pagep,
|
||||
(u_int32_t)H_DATAINDEX(hcp->bndx), hcp->dpgno);
|
||||
|
||||
/* Can probably just do a "put" here. */
|
||||
ret = __ham_dirty_page(hashp, hcp->pagep);
|
||||
ret = __ham_dirty_page(dbp, hcp->pagep);
|
||||
hcp->dndx = dndx;
|
||||
} else {
|
||||
(void)__ham_del_page(hashp->dbp, hcp->dpagep);
|
||||
(void)__ham_del_page(dbc, hcp->dpagep);
|
||||
hcp->dpagep = NULL;
|
||||
}
|
||||
return (ret);
|
||||
@ -354,11 +410,12 @@ __ham_make_dup(notdup, duplicate, bufp, sizep)
|
||||
}
|
||||
|
||||
static int
|
||||
__ham_check_move(hashp, hcp, add_len)
|
||||
HTAB *hashp;
|
||||
HASH_CURSOR *hcp;
|
||||
__ham_check_move(dbc, add_len)
|
||||
DBC *dbc;
|
||||
int32_t add_len;
|
||||
{
|
||||
DB *dbp;
|
||||
HASH_CURSOR *hcp;
|
||||
DBT k, d;
|
||||
DB_LSN new_lsn;
|
||||
PAGE *next_pagep;
|
||||
@ -367,6 +424,8 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
u_int8_t *hk;
|
||||
int ret;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
/*
|
||||
* Check if we can do whatever we need to on this page. If not,
|
||||
* then we'll have to move the current element to a new page.
|
||||
@ -381,7 +440,7 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
return (0);
|
||||
|
||||
old_len =
|
||||
LEN_HITEM(hcp->pagep, hashp->hdr->pagesize, H_DATAINDEX(hcp->bndx));
|
||||
LEN_HITEM(hcp->pagep, hcp->hdr->pagesize, H_DATAINDEX(hcp->bndx));
|
||||
new_datalen = old_len - HKEYDATA_SIZE(0) + add_len;
|
||||
|
||||
/*
|
||||
@ -392,11 +451,11 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
* threshold, but the new data won't fit on the page.
|
||||
* If neither of these is true, then we can return.
|
||||
*/
|
||||
if (ISBIG(hashp, new_datalen) && (old_len > HOFFDUP_SIZE ||
|
||||
if (ISBIG(hcp, new_datalen) && (old_len > HOFFDUP_SIZE ||
|
||||
HOFFDUP_SIZE - old_len <= P_FREESPACE(hcp->pagep)))
|
||||
return (0);
|
||||
|
||||
if (!ISBIG(hashp, new_datalen) &&
|
||||
if (!ISBIG(hcp, new_datalen) &&
|
||||
add_len <= (int32_t)P_FREESPACE(hcp->pagep))
|
||||
return (0);
|
||||
|
||||
@ -405,18 +464,18 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
* Check if there are more pages in the chain.
|
||||
*/
|
||||
|
||||
new_datalen = ISBIG(hashp, new_datalen) ?
|
||||
new_datalen = ISBIG(hcp, new_datalen) ?
|
||||
HOFFDUP_SIZE : HKEYDATA_SIZE(new_datalen);
|
||||
|
||||
next_pagep = NULL;
|
||||
for (next_pgno = NEXT_PGNO(hcp->pagep); next_pgno != PGNO_INVALID;
|
||||
next_pgno = NEXT_PGNO(next_pagep)) {
|
||||
if (next_pagep != NULL &&
|
||||
(ret = __ham_put_page(hashp->dbp, next_pagep, 0)) != 0)
|
||||
(ret = __ham_put_page(dbp, next_pagep, 0)) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret =
|
||||
__ham_get_page(hashp->dbp, next_pgno, &next_pagep)) != 0)
|
||||
__ham_get_page(dbp, next_pgno, &next_pagep)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (P_FREESPACE(next_pagep) >= new_datalen)
|
||||
@ -424,17 +483,17 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
}
|
||||
|
||||
/* No more pages, add one. */
|
||||
if (next_pagep == NULL &&
|
||||
(ret = __ham_add_ovflpage(hashp, hcp->pagep, 0, &next_pagep)) != 0)
|
||||
if (next_pagep == NULL && (ret = __ham_add_ovflpage(dbc,
|
||||
hcp->pagep, 0, &next_pagep)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Add new page at the end of the chain. */
|
||||
if (P_FREESPACE(next_pagep) < new_datalen &&
|
||||
(ret = __ham_add_ovflpage(hashp, next_pagep, 1, &next_pagep)) != 0)
|
||||
if (P_FREESPACE(next_pagep) < new_datalen && (ret =
|
||||
__ham_add_ovflpage(dbc, next_pagep, 1, &next_pagep)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Copy the item to the new page. */
|
||||
if (DB_LOGGING(hashp->dbp)) {
|
||||
if (DB_LOGGING(hcp->dbc)) {
|
||||
rectype = PUTPAIR;
|
||||
k.flags = 0;
|
||||
d.flags = 0;
|
||||
@ -447,7 +506,7 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
k.data =
|
||||
HKEYDATA_DATA(H_PAIRKEY(hcp->pagep, hcp->bndx));
|
||||
k.size = LEN_HKEY(hcp->pagep,
|
||||
hashp->hdr->pagesize, hcp->bndx);
|
||||
hcp->hdr->pagesize, hcp->bndx);
|
||||
}
|
||||
|
||||
if (HPAGE_PTYPE(hk) == H_OFFPAGE) {
|
||||
@ -458,13 +517,13 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
d.data =
|
||||
HKEYDATA_DATA(H_PAIRDATA(hcp->pagep, hcp->bndx));
|
||||
d.size = LEN_HDATA(hcp->pagep,
|
||||
hashp->hdr->pagesize, hcp->bndx);
|
||||
hcp->hdr->pagesize, hcp->bndx);
|
||||
}
|
||||
|
||||
|
||||
if ((ret = __ham_insdel_log(hashp->dbp->dbenv->lg_info,
|
||||
(DB_TXN *)hashp->dbp->txn, &new_lsn, 0, rectype,
|
||||
hashp->dbp->log_fileid, PGNO(next_pagep),
|
||||
if ((ret = __ham_insdel_log(dbp->dbenv->lg_info,
|
||||
dbc->txn, &new_lsn, 0, rectype,
|
||||
dbp->log_fileid, PGNO(next_pagep),
|
||||
(u_int32_t)H_NUMPAIRS(next_pagep), &LSN(next_pagep),
|
||||
&k, &d)) != 0)
|
||||
return (ret);
|
||||
@ -473,13 +532,15 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
LSN(next_pagep) = new_lsn; /* Structure assignment. */
|
||||
}
|
||||
|
||||
__ham_copy_item(hashp, hcp->pagep, H_KEYINDEX(hcp->bndx), next_pagep);
|
||||
__ham_copy_item(hashp, hcp->pagep, H_DATAINDEX(hcp->bndx), next_pagep);
|
||||
__ham_copy_item(dbp->pgsize,
|
||||
hcp->pagep, H_KEYINDEX(hcp->bndx), next_pagep);
|
||||
__ham_copy_item(dbp->pgsize,
|
||||
hcp->pagep, H_DATAINDEX(hcp->bndx), next_pagep);
|
||||
|
||||
/* Now delete the pair from the current page. */
|
||||
ret = __ham_del_pair(hashp, hcp, 0);
|
||||
ret = __ham_del_pair(dbc, 0);
|
||||
|
||||
(void)__ham_put_page(hashp->dbp, hcp->pagep, 1);
|
||||
(void)__ham_put_page(dbp, hcp->pagep, 1);
|
||||
hcp->pagep = next_pagep;
|
||||
hcp->pgno = PGNO(hcp->pagep);
|
||||
hcp->bndx = H_NUMPAIRS(hcp->pagep) - 1;
|
||||
@ -488,19 +549,25 @@ __ham_check_move(hashp, hcp, add_len)
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace an onpage set of duplicates with the OFFDUP structure that
|
||||
* references the duplicate page.
|
||||
* XXX This is really just a special case of __onpage_replace; we should
|
||||
* __ham_move_offpage --
|
||||
* Replace an onpage set of duplicates with the OFFDUP structure
|
||||
* that references the duplicate page.
|
||||
*
|
||||
* XXX
|
||||
* This is really just a special case of __onpage_replace; we should
|
||||
* probably combine them.
|
||||
* PUBLIC: void __ham_move_offpage __P((HTAB *, PAGE *, u_int32_t, db_pgno_t));
|
||||
*
|
||||
* PUBLIC: void __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t));
|
||||
*/
|
||||
void
|
||||
__ham_move_offpage(hashp, pagep, ndx, pgno)
|
||||
HTAB *hashp;
|
||||
__ham_move_offpage(dbc, pagep, ndx, pgno)
|
||||
DBC *dbc;
|
||||
PAGE *pagep;
|
||||
u_int32_t ndx;
|
||||
db_pgno_t pgno;
|
||||
{
|
||||
DB *dbp;
|
||||
HASH_CURSOR *hcp;
|
||||
DBT new_dbt;
|
||||
DBT old_dbt;
|
||||
HOFFDUP od;
|
||||
@ -508,22 +575,27 @@ __ham_move_offpage(hashp, pagep, ndx, pgno)
|
||||
int32_t shrink;
|
||||
u_int8_t *src;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
od.type = H_OFFDUP;
|
||||
UMRW(od.unused[0]);
|
||||
UMRW(od.unused[1]);
|
||||
UMRW(od.unused[2]);
|
||||
od.pgno = pgno;
|
||||
|
||||
if (DB_LOGGING(hashp->dbp)) {
|
||||
if (DB_LOGGING(dbc)) {
|
||||
new_dbt.data = &od;
|
||||
new_dbt.size = HOFFDUP_SIZE;
|
||||
old_dbt.data = P_ENTRY(pagep, ndx);
|
||||
old_dbt.size = LEN_HITEM(pagep, hashp->hdr->pagesize, ndx);
|
||||
(void)__ham_replace_log(hashp->dbp->dbenv->lg_info,
|
||||
(DB_TXN *)hashp->dbp->txn, &LSN(pagep), 0,
|
||||
hashp->dbp->log_fileid, PGNO(pagep), (u_int32_t)ndx,
|
||||
&LSN(pagep), -1, &old_dbt, &new_dbt, 0);
|
||||
old_dbt.size = LEN_HITEM(pagep, hcp->hdr->pagesize, ndx);
|
||||
(void)__ham_replace_log(dbp->dbenv->lg_info,
|
||||
dbc->txn, &LSN(pagep), 0, dbp->log_fileid,
|
||||
PGNO(pagep), (u_int32_t)ndx, &LSN(pagep), -1,
|
||||
&old_dbt, &new_dbt, 0);
|
||||
}
|
||||
|
||||
shrink =
|
||||
LEN_HITEM(pagep, hashp->hdr->pagesize, ndx) - HOFFDUP_SIZE;
|
||||
LEN_HITEM(pagep, hcp->hdr->pagesize, ndx) - HOFFDUP_SIZE;
|
||||
|
||||
if (shrink != 0) {
|
||||
/* Copy data. */
|
||||
@ -539,3 +611,46 @@ __ham_move_offpage(hashp, pagep, ndx, pgno)
|
||||
/* Now copy the offdup entry onto the page. */
|
||||
memcpy(P_ENTRY(pagep, ndx), &od, HOFFDUP_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* __ham_dsearch:
|
||||
* Locate a particular duplicate in a duplicate set.
|
||||
*
|
||||
* PUBLIC: void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *));
|
||||
*/
|
||||
void
|
||||
__ham_dsearch(dbc, dbt, offp, cmpp)
|
||||
DBC *dbc;
|
||||
DBT *dbt;
|
||||
u_int32_t *offp;
|
||||
int *cmpp;
|
||||
{
|
||||
DB *dbp;
|
||||
HASH_CURSOR *hcp;
|
||||
DBT cur;
|
||||
db_indx_t i, len;
|
||||
int (*func) __P((const DBT *, const DBT *));
|
||||
u_int8_t *data;
|
||||
|
||||
dbp = dbc->dbp;
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
if (dbp->dup_compare == NULL)
|
||||
func = __bam_defcmp;
|
||||
else
|
||||
func = dbp->dup_compare;
|
||||
|
||||
i = F_ISSET(dbc, DBC_CONTINUE) ? hcp->dup_off: 0;
|
||||
data = HKEYDATA_DATA(H_PAIRDATA(hcp->pagep, hcp->bndx)) + i;
|
||||
while (i < LEN_HDATA(hcp->pagep, hcp->hdr->pagesize, hcp->bndx)) {
|
||||
memcpy(&len, data, sizeof(db_indx_t));
|
||||
data += sizeof(db_indx_t);
|
||||
cur.data = data;
|
||||
cur.size = (u_int32_t)len;
|
||||
*cmpp = func(dbt, &cur);
|
||||
if (*cmpp == 0 || (*cmpp < 0 && dbp->dup_compare != NULL))
|
||||
break;
|
||||
i += len + 2 * sizeof(db_indx_t);
|
||||
data += len + sizeof(db_indx_t);
|
||||
}
|
||||
*offp = i;
|
||||
}
|
||||
|
1084
db2/hash/hash_page.c
1084
db2/hash/hash_page.c
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)hash_rec.c 10.19 (Sleepycat) 5/23/98";
|
||||
static const char sccsid[] = "@(#)hash_rec.c 10.22 (Sleepycat) 10/21/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -80,17 +80,19 @@ __ham_insdel_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_insdel_args *argp;
|
||||
DB *mdbp, *file_dbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
HTAB *hashp;
|
||||
PAGE *pagep;
|
||||
u_int32_t op;
|
||||
int cmp_n, cmp_p, getmeta, ret;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
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) {
|
||||
@ -101,16 +103,15 @@ __ham_insdel_recover(logp, dbtp, lsnp, redo, info)
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else if ((ret = memp_fget(mpf, &argp->pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, hcp, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
|
||||
cmp_n = log_compare(lsnp, &LSN(pagep));
|
||||
@ -144,7 +145,7 @@ __ham_insdel_recover(logp, dbtp, lsnp, redo, info)
|
||||
!redo || PAIR_ISDATABIG(argp->opcode) ?
|
||||
H_OFFPAGE : H_KEYDATA);
|
||||
} else
|
||||
(void) __ham_reputpair(pagep, hashp->hdr->pagesize,
|
||||
(void) __ham_reputpair(pagep, hcp->hdr->pagesize,
|
||||
argp->ndx, &argp->key, &argp->data);
|
||||
|
||||
LSN(pagep) = redo ? *lsnp : argp->pagelsn;
|
||||
@ -163,10 +164,11 @@ __ham_insdel_recover(logp, dbtp, lsnp, redo, info)
|
||||
goto out;
|
||||
|
||||
/* Return the previous LSN. */
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
}
|
||||
|
||||
@ -187,16 +189,18 @@ __ham_newpage_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_newpage_args *argp;
|
||||
DB *mdbp, *file_dbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
HTAB *hashp;
|
||||
PAGE *pagep;
|
||||
int cmp_n, cmp_p, change, getmeta, ret;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
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) {
|
||||
@ -214,8 +218,9 @@ __ham_newpage_recover(logp, dbtp, lsnp, redo, info)
|
||||
goto out;
|
||||
}
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
|
||||
/*
|
||||
@ -289,11 +294,13 @@ ppage: if (argp->prev_pgno != PGNO_INVALID) {
|
||||
}
|
||||
|
||||
if (!change) {
|
||||
if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
|
||||
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)
|
||||
if ((ret =
|
||||
__ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -310,9 +317,7 @@ npage: if (argp->next_pgno != PGNO_INVALID) {
|
||||
* so we would not have to undo anything. In
|
||||
* this case, don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else if ((ret =
|
||||
memp_fget(mpf, &argp->next_pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
@ -346,10 +351,11 @@ npage: if (argp->next_pgno != PGNO_INVALID) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
}
|
||||
|
||||
@ -372,19 +378,21 @@ __ham_replace_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_replace_args *argp;
|
||||
DB *mdbp, *file_dbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
DBT dbt;
|
||||
HTAB *hashp;
|
||||
PAGE *pagep;
|
||||
int32_t grow;
|
||||
int change, cmp_n, cmp_p, getmeta, ret;
|
||||
u_int8_t *hk;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
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) {
|
||||
@ -395,16 +403,15 @@ __ham_replace_recover(logp, dbtp, lsnp, redo, info)
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else if ((ret = memp_fget(mpf, &argp->pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
|
||||
cmp_n = log_compare(lsnp, &LSN(pagep));
|
||||
@ -444,10 +451,11 @@ __ham_replace_recover(logp, dbtp, lsnp, redo, info)
|
||||
if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
|
||||
goto out;
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
}
|
||||
|
||||
@ -468,19 +476,22 @@ __ham_newpgno_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_newpgno_args *argp;
|
||||
DB *mdbp, *file_dbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
HTAB *hashp;
|
||||
PAGE *pagep;
|
||||
int change, cmp_n, cmp_p, getmeta, ret;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
hcp = NULL;
|
||||
REC_PRINT(__ham_newpgno_print);
|
||||
REC_INTRO(__ham_newpgno_read);
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
|
||||
/*
|
||||
@ -488,34 +499,34 @@ __ham_newpgno_recover(logp, dbtp, lsnp, redo, info)
|
||||
* to update the meta data; then we need to update the page.
|
||||
* We'll do the meta-data first.
|
||||
*/
|
||||
cmp_n = log_compare(lsnp, &hashp->hdr->lsn);
|
||||
cmp_p = log_compare(&hashp->hdr->lsn, &argp->metalsn);
|
||||
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)) {
|
||||
/* Need to redo an allocation or undo a deletion. */
|
||||
hashp->hdr->last_freed = argp->free_pgno;
|
||||
hcp->hdr->last_freed = argp->free_pgno;
|
||||
if (redo && argp->old_pgno != 0) /* Must be ALLOCPGNO */
|
||||
hashp->hdr->spares[hashp->hdr->ovfl_point]++;
|
||||
hcp->hdr->spares[hcp->hdr->ovfl_point]++;
|
||||
change = 1;
|
||||
} else if (cmp_p == 0 && redo && argp->opcode == DELPGNO) {
|
||||
/* Need to redo a deletion */
|
||||
hashp->hdr->last_freed = argp->pgno;
|
||||
hcp->hdr->last_freed = argp->pgno;
|
||||
change = 1;
|
||||
} else if (cmp_n == 0 && !redo && argp->opcode == ALLOCPGNO) {
|
||||
/* undo an allocation. */
|
||||
if (argp->old_pgno == 0)
|
||||
hashp->hdr->last_freed = argp->pgno;
|
||||
hcp->hdr->last_freed = argp->pgno;
|
||||
else {
|
||||
hashp->hdr->spares[hashp->hdr->ovfl_point]--;
|
||||
hashp->hdr->last_freed = 0;
|
||||
hcp->hdr->spares[hcp->hdr->ovfl_point]--;
|
||||
hcp->hdr->last_freed = 0;
|
||||
}
|
||||
change = 1;
|
||||
}
|
||||
if (change) {
|
||||
hashp->hdr->lsn = redo ? *lsnp : argp->metalsn;
|
||||
F_SET(file_dbp, DB_HS_DIRTYMETA);
|
||||
hcp->hdr->lsn = redo ? *lsnp : argp->metalsn;
|
||||
F_SET(hcp, H_DIRTY);
|
||||
}
|
||||
|
||||
|
||||
@ -530,9 +541,7 @@ __ham_newpgno_recover(logp, dbtp, lsnp, redo, info)
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else if ((ret = memp_fget(mpf, &argp->pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
goto out;
|
||||
@ -565,10 +574,11 @@ __ham_newpgno_recover(logp, dbtp, lsnp, redo, info)
|
||||
if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
|
||||
goto out;
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
|
||||
}
|
||||
@ -590,19 +600,22 @@ __ham_splitmeta_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_splitmeta_args *argp;
|
||||
DB *mdbp, *file_dbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
HTAB *hashp;
|
||||
int change, cmp_n, cmp_p, getmeta, ret;
|
||||
u_int32_t pow;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
hcp = NULL;
|
||||
REC_PRINT(__ham_splitmeta_print);
|
||||
REC_INTRO(__ham_splitmeta_read);
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
|
||||
/*
|
||||
@ -610,43 +623,45 @@ __ham_splitmeta_recover(logp, dbtp, lsnp, redo, info)
|
||||
* to update the meta data; then we need to update the page.
|
||||
* We'll do the meta-data first.
|
||||
*/
|
||||
cmp_n = log_compare(lsnp, &hashp->hdr->lsn);
|
||||
cmp_p = log_compare(&hashp->hdr->lsn, &argp->metalsn);
|
||||
cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
|
||||
cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
|
||||
|
||||
change = 0;
|
||||
if (cmp_p == 0 && redo) {
|
||||
/* Need to redo the split information. */
|
||||
hashp->hdr->max_bucket = argp->bucket + 1;
|
||||
pow = __db_log2(hashp->hdr->max_bucket + 1);
|
||||
if (pow > hashp->hdr->ovfl_point) {
|
||||
hashp->hdr->spares[pow] =
|
||||
hashp->hdr->spares[hashp->hdr->ovfl_point];
|
||||
hashp->hdr->ovfl_point = pow;
|
||||
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 (hashp->hdr->max_bucket > hashp->hdr->high_mask) {
|
||||
hashp->hdr->low_mask = hashp->hdr->high_mask;
|
||||
hashp->hdr->high_mask =
|
||||
hashp->hdr->max_bucket | hashp->hdr->low_mask;
|
||||
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) {
|
||||
/* Need to undo the split information. */
|
||||
hashp->hdr->max_bucket = argp->bucket;
|
||||
hashp->hdr->ovfl_point = argp->ovflpoint;
|
||||
hashp->hdr->spares[hashp->hdr->ovfl_point] = argp->spares;
|
||||
pow = 1 << __db_log2(hashp->hdr->max_bucket + 1);
|
||||
hashp->hdr->high_mask = pow - 1;
|
||||
hashp->hdr->low_mask = (pow >> 1) - 1;
|
||||
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) {
|
||||
hashp->hdr->lsn = redo ? *lsnp : argp->metalsn;
|
||||
F_SET(file_dbp, DB_HS_DIRTYMETA);
|
||||
hcp->hdr->lsn = redo ? *lsnp : argp->metalsn;
|
||||
F_SET(hcp, H_DIRTY);
|
||||
}
|
||||
*lsnp = argp->prev_lsn;
|
||||
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
}
|
||||
|
||||
@ -665,16 +680,18 @@ __ham_splitdata_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_splitdata_args *argp;
|
||||
DB *mdbp, *file_dbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
HTAB *hashp;
|
||||
PAGE *pagep;
|
||||
int change, cmp_n, cmp_p, getmeta, ret;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
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) {
|
||||
@ -685,16 +702,15 @@ __ham_splitdata_recover(logp, dbtp, lsnp, redo, info)
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
*lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
goto out;
|
||||
goto done;
|
||||
} else if ((ret = memp_fget(mpf, &argp->pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
|
||||
cmp_n = log_compare(lsnp, &LSN(pagep));
|
||||
@ -732,10 +748,11 @@ __ham_splitdata_recover(logp, dbtp, lsnp, redo, info)
|
||||
if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
|
||||
goto out;
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
}
|
||||
|
||||
@ -755,50 +772,52 @@ __ham_ovfl_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_ovfl_args *argp;
|
||||
DB *mdbp, *file_dbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
HTAB *hashp;
|
||||
PAGE *pagep;
|
||||
db_pgno_t max_pgno, pgno;
|
||||
int cmp_n, cmp_p, getmeta, ret;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
hcp = NULL;
|
||||
REC_PRINT(__ham_ovfl_print);
|
||||
REC_INTRO(__ham_ovfl_read);
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
|
||||
cmp_n = log_compare(lsnp, &hashp->hdr->lsn);
|
||||
cmp_p = log_compare(&hashp->hdr->lsn, &argp->metalsn);
|
||||
cmp_n = log_compare(lsnp, &hcp->hdr->lsn);
|
||||
cmp_p = log_compare(&hcp->hdr->lsn, &argp->metalsn);
|
||||
|
||||
if (cmp_p == 0 && redo) {
|
||||
/* Redo the allocation. */
|
||||
hashp->hdr->last_freed = argp->start_pgno;
|
||||
hashp->hdr->spares[argp->ovflpoint] += argp->npages;
|
||||
hashp->hdr->lsn = *lsnp;
|
||||
F_SET(file_dbp, DB_HS_DIRTYMETA);
|
||||
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) {
|
||||
hashp->hdr->last_freed = argp->free_pgno;
|
||||
hashp->hdr->spares[argp->ovflpoint] -= argp->npages;
|
||||
hashp->hdr->lsn = argp->metalsn;
|
||||
F_SET(file_dbp, DB_HS_DIRTYMETA);
|
||||
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++) {
|
||||
ret = memp_fget(mpf, &pgno, 0, &pagep);
|
||||
if (ret != 0) {
|
||||
if (redo && (ret = memp_fget(mpf, &pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
goto out;
|
||||
else if (!redo) {
|
||||
(void)__ham_put_page(file_dbp, pagep, 0);
|
||||
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) {
|
||||
@ -816,9 +835,11 @@ __ham_ovfl_recover(logp, dbtp, lsnp, redo, info)
|
||||
goto out;
|
||||
}
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
}
|
||||
|
||||
@ -838,19 +859,22 @@ __ham_copypage_recover(logp, dbtp, lsnp, redo, info)
|
||||
void *info;
|
||||
{
|
||||
__ham_copypage_args *argp;
|
||||
DB *file_dbp, *mdbp;
|
||||
DB *file_dbp;
|
||||
DBC *dbc;
|
||||
HASH_CURSOR *hcp;
|
||||
DB_MPOOLFILE *mpf;
|
||||
HTAB *hashp;
|
||||
PAGE *pagep;
|
||||
int cmp_n, cmp_p, getmeta, modified, ret;
|
||||
|
||||
getmeta = 0;
|
||||
hashp = NULL; /* XXX: shut the compiler up. */
|
||||
hcp = NULL;
|
||||
REC_PRINT(__ham_copypage_print);
|
||||
REC_INTRO(__ham_copypage_read);
|
||||
hcp = (HASH_CURSOR *)dbc->internal;
|
||||
|
||||
hashp = (HTAB *)file_dbp->internal;
|
||||
GET_META(file_dbp, hashp);
|
||||
GET_META(file_dbp, (HASH_CURSOR *)dbc->internal, ret);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
getmeta = 1;
|
||||
modified = 0;
|
||||
|
||||
@ -881,7 +905,7 @@ __ham_copypage_recover(logp, dbtp, lsnp, redo, info)
|
||||
modified = 1;
|
||||
} else if (cmp_n == 0 && !redo) {
|
||||
/* Need to undo update described. */
|
||||
P_INIT(pagep, hashp->hdr->pagesize, argp->pgno, PGNO_INVALID,
|
||||
P_INIT(pagep, hcp->hdr->pagesize, argp->pgno, PGNO_INVALID,
|
||||
argp->next_pgno, 0, P_HASH);
|
||||
LSN(pagep) = argp->pagelsn;
|
||||
modified = 1;
|
||||
@ -918,10 +942,8 @@ donext: ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep);
|
||||
goto out;
|
||||
|
||||
/* Now fix up the next's next page. */
|
||||
do_nn: if (argp->nnext_pgno == PGNO_INVALID) {
|
||||
*lsnp = argp->prev_lsn;
|
||||
goto out;
|
||||
}
|
||||
do_nn: if (argp->nnext_pgno == PGNO_INVALID)
|
||||
goto done;
|
||||
|
||||
ret = memp_fget(mpf, &argp->nnext_pgno, 0, &pagep);
|
||||
if (ret != 0) {
|
||||
@ -932,9 +954,7 @@ do_nn: if (argp->nnext_pgno == PGNO_INVALID) {
|
||||
* would not have to undo anything. In this case,
|
||||
* don't bother creating a page.
|
||||
*/
|
||||
ret = 0;
|
||||
*lsnp = argp->prev_lsn;
|
||||
goto out;
|
||||
goto done;
|
||||
} else if ((ret = memp_fget(mpf, &argp->nnext_pgno,
|
||||
DB_MPOOL_CREATE, &pagep)) != 0)
|
||||
goto out;
|
||||
@ -957,9 +977,10 @@ do_nn: if (argp->nnext_pgno == PGNO_INVALID) {
|
||||
if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
|
||||
goto out;
|
||||
|
||||
*lsnp = argp->prev_lsn;
|
||||
done: *lsnp = argp->prev_lsn;
|
||||
ret = 0;
|
||||
|
||||
out: if (getmeta)
|
||||
RELEASE_META(file_dbp, hashp);
|
||||
RELEASE_META(file_dbp, hcp);
|
||||
REC_CLOSE;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)hash_stat.c 10.8 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)hash_stat.c 10.12 (Sleepycat) 12/19/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -23,35 +23,22 @@ static const char sccsid[] = "@(#)hash_stat.c 10.8 (Sleepycat) 4/26/98";
|
||||
|
||||
/*
|
||||
* __ham_stat --
|
||||
* Gather/print the hash statistics.
|
||||
* Gather/print the hash statistics
|
||||
*
|
||||
* PUBLIC: int __ham_stat __P((DB *, FILE *));
|
||||
* PUBLIC: int __ham_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
|
||||
*/
|
||||
int
|
||||
__ham_stat(dbp, fp)
|
||||
__ham_stat(dbp, spp, db_malloc, flags)
|
||||
DB *dbp;
|
||||
FILE *fp;
|
||||
void *spp;
|
||||
void *(*db_malloc) __P((size_t));
|
||||
u_int32_t flags;
|
||||
{
|
||||
HTAB *hashp;
|
||||
int i;
|
||||
COMPQUIET(spp, NULL);
|
||||
COMPQUIET(db_malloc, NULL);
|
||||
COMPQUIET(flags, 0);
|
||||
|
||||
hashp = (HTAB *)dbp->internal;
|
||||
DB_PANIC_CHECK(dbp);
|
||||
|
||||
fprintf(fp, "hash: accesses %lu collisions %lu\n",
|
||||
hashp->hash_accesses, hashp->hash_collisions);
|
||||
fprintf(fp, "hash: expansions %lu\n", hashp->hash_expansions);
|
||||
fprintf(fp, "hash: overflows %lu\n", hashp->hash_overflows);
|
||||
fprintf(fp, "hash: big key/data pages %lu\n", hashp->hash_bigpages);
|
||||
|
||||
SET_LOCKER(dbp, NULL);
|
||||
GET_META(dbp, hashp);
|
||||
fprintf(fp, "keys %lu maxp %lu\n",
|
||||
(u_long)hashp->hdr->nelem, (u_long)hashp->hdr->max_bucket);
|
||||
|
||||
for (i = 0; i < NCACHED; i++)
|
||||
fprintf(fp,
|
||||
"spares[%d] = %lu\n", i, (u_long)hashp->hdr->spares[i]);
|
||||
|
||||
RELEASE_META(dbp, hashp);
|
||||
return (0);
|
||||
return (__db_eopnotsup(dbp->dbenv));
|
||||
}
|
||||
|
@ -43,38 +43,19 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)btree.h 10.21 (Sleepycat) 5/23/98
|
||||
* @(#)btree.h 10.26 (Sleepycat) 12/16/98
|
||||
*/
|
||||
|
||||
/* Forward structure declarations. */
|
||||
struct __btree; typedef struct __btree BTREE;
|
||||
struct __cursor; typedef struct __cursor CURSOR;
|
||||
struct __epg; typedef struct __epg EPG;
|
||||
struct __rcursor; typedef struct __rcursor RCURSOR;
|
||||
struct __recno; typedef struct __recno RECNO;
|
||||
|
||||
#undef DEFMINKEYPAGE /* Minimum keys per page */
|
||||
#define DEFMINKEYPAGE (2)
|
||||
|
||||
#undef ISINTERNAL /* If an internal page. */
|
||||
#define ISINTERNAL(p) (TYPE(p) == P_IBTREE || TYPE(p) == P_IRECNO)
|
||||
#undef ISLEAF /* If a leaf page. */
|
||||
#define ISLEAF(p) (TYPE(p) == P_LBTREE || TYPE(p) == P_LRECNO)
|
||||
|
||||
/* Allocate and discard thread structures. */
|
||||
#define GETHANDLE(dbp, set_txn, dbpp, ret) { \
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) { \
|
||||
if ((ret = __db_gethandle(dbp, __bam_bdup, dbpp)) != 0) \
|
||||
return (ret); \
|
||||
} else \
|
||||
*dbpp = dbp; \
|
||||
*dbpp->txn = set_txn; \
|
||||
}
|
||||
#define PUTHANDLE(dbp) { \
|
||||
dbp->txn = NULL; \
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) \
|
||||
__db_puthandle(dbp); \
|
||||
}
|
||||
#define ISINTERNAL(p) (TYPE(p) == P_IBTREE || TYPE(p) == P_IRECNO)
|
||||
#define ISLEAF(p) (TYPE(p) == P_LBTREE || TYPE(p) == P_LRECNO)
|
||||
|
||||
/*
|
||||
* If doing transactions we have to hold the locks associated with a data item
|
||||
@ -82,15 +63,15 @@ struct __recno; typedef struct __recno RECNO;
|
||||
* locks associated with walking the tree. Distinguish between the two so that
|
||||
* we don't tie up the internal pages of the tree longer than necessary.
|
||||
*/
|
||||
#define __BT_LPUT(dbp, lock) \
|
||||
(F_ISSET((dbp), DB_AM_LOCKING) ? \
|
||||
lock_put((dbp)->dbenv->lk_info, lock) : 0)
|
||||
#define __BT_TLPUT(dbp, lock) \
|
||||
(F_ISSET((dbp), DB_AM_LOCKING) && (dbp)->txn == NULL ? \
|
||||
lock_put((dbp)->dbenv->lk_info, lock) : 0)
|
||||
#define __BT_LPUT(dbc, lock) \
|
||||
(F_ISSET((dbc)->dbp, DB_AM_LOCKING) ? \
|
||||
lock_put((dbc)->dbp->dbenv->lk_info, lock) : 0)
|
||||
#define __BT_TLPUT(dbc, lock) \
|
||||
(F_ISSET((dbc)->dbp, DB_AM_LOCKING) && (dbc)->txn == NULL ? \
|
||||
lock_put((dbc)->dbp->dbenv->lk_info, lock) : 0)
|
||||
|
||||
/*
|
||||
* Flags to __bt_search() and __rec_search().
|
||||
* Flags to __bam_search() and __bam_rsearch().
|
||||
*
|
||||
* Note, internal page searches must find the largest record less than key in
|
||||
* the tree so that descents work. Leaf page searches must find the smallest
|
||||
@ -113,22 +94,19 @@ struct __recno; typedef struct __recno RECNO;
|
||||
#define S_EXACT 0x00400 /* Exact items only. */
|
||||
#define S_PARENT 0x00800 /* Lock page pair. */
|
||||
#define S_STACK 0x01000 /* Need a complete stack. */
|
||||
#define S_PAST_EOF 0x02000 /* If doing insert search (or keyfirst
|
||||
* or keylast operations), or a split
|
||||
* on behalf of an insert, it's okay to
|
||||
* return an entry one past end-of-page.
|
||||
*/
|
||||
|
||||
#define S_DELETE (S_WRITE | S_DUPFIRST | S_DELNO | S_EXACT | S_STACK)
|
||||
#define S_FIND (S_READ | S_DUPFIRST | S_DELNO)
|
||||
#define S_INSERT (S_WRITE | S_DUPLAST | S_STACK)
|
||||
#define S_KEYFIRST (S_WRITE | S_DUPFIRST | S_STACK)
|
||||
#define S_KEYLAST (S_WRITE | S_DUPLAST | S_STACK)
|
||||
#define S_WRPAIR (S_WRITE | S_DUPLAST | S_PARENT)
|
||||
|
||||
/*
|
||||
* If doing insert search (including keyfirst or keylast operations) or a
|
||||
* split search on behalf of an insert, it's okay to return the entry one
|
||||
* past the end of the page.
|
||||
*/
|
||||
#define PAST_END_OK(f) \
|
||||
((f) == S_INSERT || \
|
||||
(f) == S_KEYFIRST || (f) == S_KEYLAST || (f) == S_WRPAIR)
|
||||
#define S_FIND_WR (S_WRITE | S_DUPFIRST | S_DELNO)
|
||||
#define S_INSERT (S_WRITE | S_DUPLAST | S_PAST_EOF | S_STACK)
|
||||
#define S_KEYFIRST (S_WRITE | S_DUPFIRST | S_PAST_EOF | S_STACK)
|
||||
#define S_KEYLAST (S_WRITE | S_DUPLAST | S_PAST_EOF | S_STACK)
|
||||
#define S_WRPAIR (S_WRITE | S_DUPLAST | S_PAST_EOF | S_PARENT)
|
||||
|
||||
/*
|
||||
* Flags to __bam_iitem().
|
||||
@ -149,23 +127,32 @@ struct __epg {
|
||||
};
|
||||
|
||||
/*
|
||||
* All cursors are queued from the master DB structure. Convert the user's
|
||||
* DB reference to the master DB reference. We lock the master DB mutex
|
||||
* so that we can walk the cursor queue. There's no race in accessing the
|
||||
* cursors, because if we're modifying a page, we have a write lock on it,
|
||||
* and therefore no other thread than the current one can have a cursor that
|
||||
* references the page.
|
||||
* We maintain a stack of the pages that we're locking in the tree. Btree's
|
||||
* (currently) only save two levels of the tree at a time, so the default
|
||||
* stack is always large enough. Recno trees have to lock the entire tree to
|
||||
* do inserts/deletes, however. Grow the stack as necessary.
|
||||
*/
|
||||
#define CURSOR_SETUP(dbp) { \
|
||||
(dbp) = (dbp)->master; \
|
||||
DB_THREAD_LOCK(dbp); \
|
||||
}
|
||||
#define CURSOR_TEARDOWN(dbp) \
|
||||
DB_THREAD_UNLOCK(dbp);
|
||||
#define BT_STK_CLR(c) \
|
||||
((c)->csp = (c)->sp)
|
||||
|
||||
#define BT_STK_ENTER(c, pagep, page_indx, lock, ret) do { \
|
||||
if ((ret = \
|
||||
(c)->csp == (c)->esp ? __bam_stkgrow(c) : 0) == 0) { \
|
||||
(c)->csp->page = pagep; \
|
||||
(c)->csp->indx = page_indx; \
|
||||
(c)->csp->lock = lock; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BT_STK_PUSH(c, pagep, page_indx, lock, ret) do { \
|
||||
BT_STK_ENTER(c, pagep, page_indx, lock, ret); \
|
||||
++(c)->csp; \
|
||||
} while (0)
|
||||
|
||||
#define BT_STK_POP(c) \
|
||||
((c)->csp == (c)->stack ? NULL : --(c)->csp)
|
||||
|
||||
/*
|
||||
* Btree cursor.
|
||||
*
|
||||
* Arguments passed to __bam_ca_replace().
|
||||
*/
|
||||
typedef enum {
|
||||
@ -173,9 +160,27 @@ typedef enum {
|
||||
REPLACE_SUCCESS,
|
||||
REPLACE_FAILED
|
||||
} ca_replace_arg;
|
||||
|
||||
/* Arguments passed to __ram_ca(). */
|
||||
typedef enum {
|
||||
CA_DELETE,
|
||||
CA_IAFTER,
|
||||
CA_IBEFORE
|
||||
} ca_recno_arg;
|
||||
|
||||
#define RECNO_OOB 0 /* Illegal record number. */
|
||||
|
||||
/* Btree/Recno cursor. */
|
||||
struct __cursor {
|
||||
DBC *dbc; /* Enclosing DBC. */
|
||||
|
||||
/* Per-thread information: shared by btree/recno. */
|
||||
EPG *sp; /* Stack pointer. */
|
||||
EPG *csp; /* Current stack entry. */
|
||||
EPG *esp; /* End stack pointer. */
|
||||
EPG stack[5];
|
||||
|
||||
/* Per-thread information: btree private. */
|
||||
PAGE *page; /* Cursor page. */
|
||||
|
||||
db_pgno_t pgno; /* Page. */
|
||||
@ -187,89 +192,24 @@ struct __cursor {
|
||||
DB_LOCK lock; /* Cursor read lock. */
|
||||
db_lockmode_t mode; /* Lock mode. */
|
||||
|
||||
/*
|
||||
* If a cursor record is deleted, the key/data pair has to remain on
|
||||
* the page so that subsequent inserts/deletes don't interrupt the
|
||||
* cursor progression through the file. This results in interesting
|
||||
* cases when "standard" operations, e.g., dbp->put() are done in the
|
||||
* context of "deleted" cursors.
|
||||
*
|
||||
* C_DELETED -- The item referenced by the cursor has been "deleted"
|
||||
* but not physically removed from the page.
|
||||
* C_REPLACE -- The "deleted" item referenced by a cursor has been
|
||||
* replaced by a dbp->put(), so the cursor is no longer
|
||||
* responsible for physical removal from the page.
|
||||
* C_REPLACE_SETUP --
|
||||
* We are about to overwrite a "deleted" item, flag any
|
||||
* cursors referencing it for transition to C_REPLACE
|
||||
* state.
|
||||
*/
|
||||
#define C_DELETED 0x0001
|
||||
#define C_REPLACE 0x0002
|
||||
#define C_REPLACE_SETUP 0x0004
|
||||
|
||||
/*
|
||||
* Internal cursor held for DB->get; don't hold locks unless involved
|
||||
* in a TXN.
|
||||
*/
|
||||
#define C_INTERNAL 0x0008
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Recno cursor.
|
||||
*
|
||||
* Arguments passed to __ram_ca().
|
||||
*/
|
||||
typedef enum {
|
||||
CA_DELETE,
|
||||
CA_IAFTER,
|
||||
CA_IBEFORE
|
||||
} ca_recno_arg;
|
||||
struct __rcursor {
|
||||
DBC *dbc; /* Enclosing DBC. */
|
||||
|
||||
/* Per-thread information: recno private. */
|
||||
db_recno_t recno; /* Current record number. */
|
||||
|
||||
/*
|
||||
* Cursors referencing "deleted" records are positioned between
|
||||
* two records, and so must be specially adjusted until they are
|
||||
* moved.
|
||||
* Btree:
|
||||
* We set a flag in the cursor structure if the underlying object has
|
||||
* been deleted. It's not strictly necessary, we could get the same
|
||||
* information by looking at the page itself.
|
||||
*
|
||||
* Recno:
|
||||
* When renumbering recno databases during deletes, cursors referencing
|
||||
* "deleted" records end up positioned between two records, and so must
|
||||
* be specially adjusted on the next operation.
|
||||
*/
|
||||
#define CR_DELETED 0x0001 /* Record deleted. */
|
||||
#define C_DELETED 0x0001 /* Record was deleted. */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* We maintain a stack of the pages that we're locking in the tree. Btree's
|
||||
* (currently) only save two levels of the tree at a time, so the default
|
||||
* stack is always large enough. Recno trees have to lock the entire tree to
|
||||
* do inserts/deletes, however. Grow the stack as necessary.
|
||||
*/
|
||||
#undef BT_STK_CLR
|
||||
#define BT_STK_CLR(t) \
|
||||
((t)->bt_csp = (t)->bt_sp)
|
||||
|
||||
#undef BT_STK_ENTER
|
||||
#define BT_STK_ENTER(t, pagep, page_indx, lock, ret) do { \
|
||||
if ((ret = \
|
||||
(t)->bt_csp == (t)->bt_esp ? __bam_stkgrow(t) : 0) == 0) { \
|
||||
(t)->bt_csp->page = pagep; \
|
||||
(t)->bt_csp->indx = page_indx; \
|
||||
(t)->bt_csp->lock = lock; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#undef BT_STK_PUSH
|
||||
#define BT_STK_PUSH(t, pagep, page_indx, lock, ret) do { \
|
||||
BT_STK_ENTER(t, pagep, page_indx, lock, ret); \
|
||||
++(t)->bt_csp; \
|
||||
} while (0)
|
||||
|
||||
#undef BT_STK_POP
|
||||
#define BT_STK_POP(t) \
|
||||
((t)->bt_csp == (t)->bt_stack ? NULL : --(t)->bt_csp)
|
||||
|
||||
/*
|
||||
* The in-memory recno data structure.
|
||||
*
|
||||
@ -278,9 +218,6 @@ struct __rcursor {
|
||||
* are no transaction semantics associated with backing files, nor is there
|
||||
* any thread protection.
|
||||
*/
|
||||
#undef RECNO_OOB
|
||||
#define RECNO_OOB 0 /* Illegal record number. */
|
||||
|
||||
struct __recno {
|
||||
int re_delim; /* Variable-length delimiting byte. */
|
||||
int re_pad; /* Fixed-length padding byte. */
|
||||
@ -294,7 +231,7 @@ struct __recno {
|
||||
void *re_emap; /* End of mapped space. */
|
||||
size_t re_msize; /* Size of mapped region. */
|
||||
/* Recno input function. */
|
||||
int (*re_irec) __P((DB *, db_recno_t));
|
||||
int (*re_irec) __P((DBC *, db_recno_t));
|
||||
|
||||
#define RECNO_EOF 0x0001 /* EOF on backing source file. */
|
||||
#define RECNO_MODIFIED 0x0002 /* Tree was modified. */
|
||||
@ -302,31 +239,11 @@ struct __recno {
|
||||
};
|
||||
|
||||
/*
|
||||
* The in-memory btree data structure.
|
||||
* The in-memory, per-tree btree data structure.
|
||||
*/
|
||||
struct __btree {
|
||||
/*
|
||||
* These fields are per-thread and are initialized when the BTREE structure
|
||||
* is created.
|
||||
*/
|
||||
db_pgno_t bt_lpgno; /* Last insert location. */
|
||||
|
||||
DBT bt_rkey; /* Returned key. */
|
||||
DBT bt_rdata; /* Returned data. */
|
||||
|
||||
EPG *bt_sp; /* Stack pointer. */
|
||||
EPG *bt_csp; /* Current stack entry. */
|
||||
EPG *bt_esp; /* End stack pointer. */
|
||||
EPG bt_stack[5];
|
||||
|
||||
RECNO *bt_recno; /* Private recno structure. */
|
||||
|
||||
DB_BTREE_LSTAT lstat; /* Btree local statistics. */
|
||||
|
||||
/*
|
||||
* These fields are copied from the original BTREE structure and never
|
||||
* change.
|
||||
*/
|
||||
db_indx_t bt_maxkey; /* Maximum keys per page. */
|
||||
db_indx_t bt_minkey; /* Minimum keys per page. */
|
||||
|
||||
@ -336,6 +253,8 @@ struct __btree {
|
||||
__P((const DBT *, const DBT *));
|
||||
|
||||
db_indx_t bt_ovflsize; /* Maximum key/data on-page size. */
|
||||
|
||||
RECNO *recno; /* Private recno structure. */
|
||||
};
|
||||
|
||||
#include "btree_auto.h"
|
||||
|
@ -1,45 +1,41 @@
|
||||
/* DO NOT EDIT: automatically built by dist/distrib. */
|
||||
#ifndef _btree_ext_h_
|
||||
#define _btree_ext_h_
|
||||
int __bam_close __P((DB *));
|
||||
int __bam_sync __P((DB *, u_int32_t));
|
||||
int __bam_cmp __P((DB *, const DBT *, EPG *));
|
||||
int __bam_cmp __P((DB *, const DBT *,
|
||||
PAGE *, u_int32_t, int (*)(const DBT *, const DBT *)));
|
||||
int __bam_defcmp __P((const DBT *, const DBT *));
|
||||
size_t __bam_defpfx __P((const DBT *, const DBT *));
|
||||
int __bam_pgin __P((db_pgno_t, void *, DBT *));
|
||||
int __bam_pgout __P((db_pgno_t, void *, DBT *));
|
||||
int __bam_mswap __P((PAGE *));
|
||||
int __bam_cursor __P((DB *, DB_TXN *, DBC **));
|
||||
int __bam_c_iclose __P((DB *, DBC *));
|
||||
int __bam_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
int __bam_ovfl_chk __P((DB *, CURSOR *, u_int32_t, int));
|
||||
int __bam_cprint __P((DB *));
|
||||
int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, CURSOR *, int));
|
||||
int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int));
|
||||
void __bam_ca_di __P((DB *, db_pgno_t, u_int32_t, int));
|
||||
void __bam_ca_dup __P((DB *,
|
||||
db_pgno_t, u_int32_t, u_int32_t, db_pgno_t, u_int32_t));
|
||||
void __bam_ca_move __P((DB *, db_pgno_t, db_pgno_t));
|
||||
void __bam_ca_replace
|
||||
__P((DB *, db_pgno_t, u_int32_t, ca_replace_arg));
|
||||
void __bam_ca_rsplit __P((DB *, db_pgno_t, db_pgno_t));
|
||||
void __bam_ca_split __P((DB *,
|
||||
db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
|
||||
int __bam_c_init __P((DBC *));
|
||||
int __bam_dup __P((DBC *, CURSOR *, u_int32_t, int));
|
||||
int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
|
||||
int __ram_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
|
||||
int __bam_ditem __P((DB *, PAGE *, u_int32_t));
|
||||
int __bam_adjindx __P((DB *, PAGE *, u_int32_t, u_int32_t, int));
|
||||
int __bam_dpage __P((DB *, const DBT *));
|
||||
int __bam_open __P((DB *, DBTYPE, DB_INFO *));
|
||||
int __bam_bdup __P((DB *, DB *));
|
||||
int __bam_new __P((DB *, u_int32_t, PAGE **));
|
||||
int __bam_free __P((DB *, PAGE *));
|
||||
int __bam_lt __P((DB *));
|
||||
int __bam_lget __P((DB *, int, db_pgno_t, db_lockmode_t, DB_LOCK *));
|
||||
int __bam_lput __P((DB *, DB_LOCK));
|
||||
int __bam_pget __P((DB *, PAGE **, db_pgno_t *, u_int32_t));
|
||||
int __bam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
int __bam_iitem __P((DB *,
|
||||
int __bam_ditem __P((DBC *, PAGE *, u_int32_t));
|
||||
int __bam_adjindx __P((DBC *, PAGE *, u_int32_t, u_int32_t, int));
|
||||
int __bam_dpage __P((DBC *, const DBT *));
|
||||
int __bam_dpages __P((DBC *));
|
||||
int __bam_open __P((DB *, DB_INFO *));
|
||||
int __bam_close __P((DB *));
|
||||
void __bam_setovflsize __P((DB *));
|
||||
int __bam_read_root __P((DB *));
|
||||
int __bam_new __P((DBC *, u_int32_t, PAGE **));
|
||||
int __bam_lput __P((DBC *, DB_LOCK));
|
||||
int __bam_free __P((DBC *, PAGE *));
|
||||
int __bam_lt __P((DBC *));
|
||||
int __bam_lget
|
||||
__P((DBC *, int, db_pgno_t, db_lockmode_t, DB_LOCK *));
|
||||
int __bam_iitem __P((DBC *,
|
||||
PAGE **, db_indx_t *, DBT *, DBT *, u_int32_t, u_int32_t));
|
||||
int __bam_ritem __P((DB *, PAGE *, u_int32_t, DBT *));
|
||||
int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *));
|
||||
int __bam_pg_alloc_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __bam_pg_free_recover
|
||||
@ -56,28 +52,24 @@ int __bam_cdel_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __bam_repl_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __ram_open __P((DB *, DBTYPE, DB_INFO *));
|
||||
int __ram_cursor __P((DB *, DB_TXN *, DBC **));
|
||||
int __ram_open __P((DB *, DB_INFO *));
|
||||
int __ram_close __P((DB *));
|
||||
int __ram_c_iclose __P((DB *, DBC *));
|
||||
int __ram_c_del __P((DBC *, u_int32_t));
|
||||
int __ram_c_get __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
void __ram_ca __P((DB *, db_recno_t, ca_recno_arg));
|
||||
int __ram_cprint __P((DB *));
|
||||
int __ram_getno __P((DB *, const DBT *, db_recno_t *, int));
|
||||
int __ram_snapshot __P((DB *));
|
||||
int __bam_rsearch __P((DB *, db_recno_t *, u_int32_t, int, int *));
|
||||
int __bam_adjust __P((DB *, BTREE *, int32_t));
|
||||
int __bam_nrecs __P((DB *, db_recno_t *));
|
||||
int __ram_getno __P((DBC *, const DBT *, db_recno_t *, int));
|
||||
int __bam_rsearch __P((DBC *, db_recno_t *, u_int32_t, int, int *));
|
||||
int __bam_adjust __P((DBC *, int32_t));
|
||||
int __bam_nrecs __P((DBC *, db_recno_t *));
|
||||
db_recno_t __bam_total __P((PAGE *));
|
||||
int __bam_search __P((DB *,
|
||||
int __bam_search __P((DBC *,
|
||||
const DBT *, u_int32_t, int, db_recno_t *, int *));
|
||||
int __bam_stkrel __P((DB *));
|
||||
int __bam_stkgrow __P((BTREE *));
|
||||
int __bam_split __P((DB *, void *));
|
||||
int __bam_broot __P((DB *, PAGE *, PAGE *, PAGE *));
|
||||
int __ram_root __P((DB *, PAGE *, PAGE *, PAGE *));
|
||||
int __bam_stkrel __P((DBC *, int));
|
||||
int __bam_stkgrow __P((CURSOR *));
|
||||
int __bam_split __P((DBC *, void *));
|
||||
int __bam_copy __P((DB *, PAGE *, PAGE *, u_int32_t, u_int32_t));
|
||||
int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
|
||||
void __bam_add_mstat __P((DB_BTREE_LSTAT *, DB_BTREE_LSTAT *));
|
||||
int __bam_pg_alloc_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, DB_LSN *, DB_LSN *, db_pgno_t,
|
||||
|
@ -37,12 +37,6 @@ void *memcpy __P((void *, const void *, size_t));
|
||||
#ifndef HAVE_MEMMOVE
|
||||
void *memmove __P((void *, const void *, size_t));
|
||||
#endif
|
||||
#ifndef HAVE_MEMCPY
|
||||
void *memcpy __P((void *, const void *, size_t));
|
||||
#endif
|
||||
#ifndef HAVE_MEMMOVE
|
||||
void *memmove __P((void *, const void *, size_t));
|
||||
#endif
|
||||
#ifndef HAVE_RAISE
|
||||
int raise __P((int));
|
||||
#endif
|
||||
|
@ -5,26 +5,18 @@ int __db_appname __P((DB_ENV *,
|
||||
APPNAME, const char *, const char *, u_int32_t, int *, char **));
|
||||
int __db_apprec __P((DB_ENV *, u_int32_t));
|
||||
int __db_byteorder __P((DB_ENV *, int));
|
||||
int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
|
||||
int __db_fcchk
|
||||
__P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
|
||||
int __db_ferr __P((const DB_ENV *, const char *, int));
|
||||
#ifdef __STDC__
|
||||
void __db_err __P((const DB_ENV *dbenv, const char *fmt, ...));
|
||||
#else
|
||||
void __db_err();
|
||||
#endif
|
||||
int __db_panic __P((DB *));
|
||||
int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
|
||||
int __db_fcchk
|
||||
__P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
|
||||
int __db_cdelchk __P((const DB *, u_int32_t, int, int));
|
||||
int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
|
||||
int __db_cputchk __P((const DB *,
|
||||
const DBT *, DBT *, u_int32_t, int, int));
|
||||
int __db_delchk __P((const DB *, DBT *, u_int32_t, int));
|
||||
int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
|
||||
int __db_putchk
|
||||
__P((const DB *, DBT *, const DBT *, u_int32_t, int, int));
|
||||
int __db_statchk __P((const DB *, u_int32_t));
|
||||
int __db_syncchk __P((const DB *, u_int32_t));
|
||||
int __db_ferr __P((const DB_ENV *, const char *, int));
|
||||
int __db_pgerr __P((DB *, db_pgno_t));
|
||||
int __db_pgfmt __P((DB *, db_pgno_t));
|
||||
int __db_panic __P((DB_ENV *, int));
|
||||
u_int32_t __db_log2 __P((u_int32_t));
|
||||
int __db_rattach __P((REGINFO *));
|
||||
int __db_rdetach __P((REGINFO *));
|
||||
|
@ -1,994 +0,0 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db.h.src 10.131 (Sleepycat) 6/2/98
|
||||
*/
|
||||
|
||||
#ifndef _DB_H_
|
||||
#define _DB_H_
|
||||
|
||||
#ifndef __NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* MacOS: ensure that Metrowerks C makes enumeration types int sized.
|
||||
*/
|
||||
#ifdef __MWERKS__
|
||||
#pragma enumsalwaysint on
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Handle function prototypes and the keyword "const". This steps on name
|
||||
* space that DB doesn't control, but all of the other solutions are worse.
|
||||
*
|
||||
* XXX
|
||||
* While Microsoft's compiler is ANSI C compliant, it doesn't have _STDC_
|
||||
* defined by default, you specify a command line flag or #pragma to turn
|
||||
* it on. Don't do that, however, because some of Microsoft's own header
|
||||
* files won't compile.
|
||||
*/
|
||||
#undef __P
|
||||
#if defined(__STDC__) || defined(__cplusplus) || defined(_MSC_VER)
|
||||
#define __P(protos) protos /* ANSI C prototypes */
|
||||
#else
|
||||
#define const
|
||||
#define __P(protos) () /* K&R C preprocessor */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* DB needs basic information about specifically sized types. If they're
|
||||
* not provided by the system, typedef them here.
|
||||
*
|
||||
* We protect them against multiple inclusion using __BIT_TYPES_DEFINED__,
|
||||
* as does BIND and Kerberos, since we don't know for sure what #include
|
||||
* files the user is using.
|
||||
*
|
||||
* !!!
|
||||
* We also provide the standard u_int, u_long etc., if they're not provided
|
||||
* by the system.
|
||||
*/
|
||||
#ifndef __BIT_TYPES_DEFINED__
|
||||
#define __BIT_TYPES_DEFINED__
|
||||
@u_int8_decl@
|
||||
@int16_decl@
|
||||
@u_int16_decl@
|
||||
@int32_decl@
|
||||
@u_int32_decl@
|
||||
#endif
|
||||
|
||||
@u_char_decl@
|
||||
@u_short_decl@
|
||||
@u_int_decl@
|
||||
@u_long_decl@
|
||||
|
||||
#define DB_VERSION_MAJOR 2
|
||||
#define DB_VERSION_MINOR 4
|
||||
#define DB_VERSION_PATCH 14
|
||||
#define DB_VERSION_STRING "Sleepycat Software: DB 2.4.14: (6/2/98)"
|
||||
|
||||
typedef u_int32_t db_pgno_t; /* Page number type. */
|
||||
typedef u_int16_t db_indx_t; /* Page offset type. */
|
||||
#define DB_MAX_PAGES 0xffffffff /* >= # of pages in a file */
|
||||
|
||||
typedef u_int32_t db_recno_t; /* Record number type. */
|
||||
typedef size_t DB_LOCK; /* Object returned by lock manager. */
|
||||
#define DB_MAX_RECORDS 0xffffffff /* >= # of records in a tree */
|
||||
|
||||
#define DB_FILE_ID_LEN 20 /* DB file ID length. */
|
||||
|
||||
/* Forward structure declarations, so applications get type checking. */
|
||||
struct __db; typedef struct __db DB;
|
||||
#ifdef DB_DBM_HSEARCH
|
||||
typedef struct __db DBM;
|
||||
#endif
|
||||
struct __db_bt_stat; typedef struct __db_bt_stat DB_BTREE_STAT;
|
||||
struct __db_dbt; typedef struct __db_dbt DBT;
|
||||
struct __db_env; typedef struct __db_env DB_ENV;
|
||||
struct __db_info; typedef struct __db_info DB_INFO;
|
||||
struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT;
|
||||
struct __db_lockregion; typedef struct __db_lockregion DB_LOCKREGION;
|
||||
struct __db_lockreq; typedef struct __db_lockreq DB_LOCKREQ;
|
||||
struct __db_locktab; typedef struct __db_locktab DB_LOCKTAB;
|
||||
struct __db_log; typedef struct __db_log DB_LOG;
|
||||
struct __db_log_stat; typedef struct __db_log_stat DB_LOG_STAT;
|
||||
struct __db_lsn; typedef struct __db_lsn DB_LSN;
|
||||
struct __db_mpool; typedef struct __db_mpool DB_MPOOL;
|
||||
struct __db_mpool_finfo;typedef struct __db_mpool_finfo DB_MPOOL_FINFO;
|
||||
struct __db_mpool_fstat;typedef struct __db_mpool_fstat DB_MPOOL_FSTAT;
|
||||
struct __db_mpool_stat; typedef struct __db_mpool_stat DB_MPOOL_STAT;
|
||||
struct __db_mpoolfile; typedef struct __db_mpoolfile DB_MPOOLFILE;
|
||||
struct __db_txn; typedef struct __db_txn DB_TXN;
|
||||
struct __db_txn_active; typedef struct __db_txn_active DB_TXN_ACTIVE;
|
||||
struct __db_txn_stat; typedef struct __db_txn_stat DB_TXN_STAT;
|
||||
struct __db_txnmgr; typedef struct __db_txnmgr DB_TXNMGR;
|
||||
struct __db_txnregion; typedef struct __db_txnregion DB_TXNREGION;
|
||||
struct __dbc; typedef struct __dbc DBC;
|
||||
|
||||
/* Key/data structure -- a Data-Base Thang. */
|
||||
struct __db_dbt {
|
||||
void *data; /* key/data */
|
||||
u_int32_t size; /* key/data length */
|
||||
u_int32_t ulen; /* RO: length of user buffer. */
|
||||
u_int32_t dlen; /* RO: get/put record length. */
|
||||
u_int32_t doff; /* RO: get/put record offset. */
|
||||
|
||||
#define DB_DBT_INTERNAL 0x01 /* Perform any mallocs using regular
|
||||
malloc, not the user's malloc. */
|
||||
#define DB_DBT_MALLOC 0x02 /* Return in allocated memory. */
|
||||
#define DB_DBT_PARTIAL 0x04 /* Partial put/get. */
|
||||
#define DB_DBT_USERMEM 0x08 /* Return in user's memory. */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* DB internal configuration.
|
||||
*
|
||||
* There are a set of functions that the application can replace with its
|
||||
* own versions, and some other knobs which can be turned at run-time.
|
||||
*/
|
||||
#define DB_FUNC_CALLOC 1 /* DELETED: ANSI C calloc. */
|
||||
#define DB_FUNC_CLOSE 2 /* POSIX 1003.1 close. */
|
||||
#define DB_FUNC_DIRFREE 3 /* DB: free directory list. */
|
||||
#define DB_FUNC_DIRLIST 4 /* DB: create directory list. */
|
||||
#define DB_FUNC_EXISTS 5 /* DB: return if file exists. */
|
||||
#define DB_FUNC_FREE 6 /* ANSI C free. */
|
||||
#define DB_FUNC_FSYNC 7 /* POSIX 1003.1 fsync. */
|
||||
#define DB_FUNC_IOINFO 8 /* DB: return file I/O information. */
|
||||
#define DB_FUNC_MALLOC 9 /* ANSI C malloc. */
|
||||
#define DB_FUNC_MAP 10 /* DB: map file into shared memory. */
|
||||
#define DB_FUNC_OPEN 11 /* POSIX 1003.1 open. */
|
||||
#define DB_FUNC_READ 12 /* POSIX 1003.1 read. */
|
||||
#define DB_FUNC_REALLOC 13 /* ANSI C realloc. */
|
||||
#define DB_FUNC_SEEK 14 /* POSIX 1003.1 lseek. */
|
||||
#define DB_FUNC_SLEEP 15 /* DB: sleep secs/usecs. */
|
||||
#define DB_FUNC_STRDUP 16 /* DELETED: DB: strdup(3). */
|
||||
#define DB_FUNC_UNLINK 17 /* POSIX 1003.1 unlink. */
|
||||
#define DB_FUNC_UNMAP 18 /* DB: unmap shared memory file. */
|
||||
#define DB_FUNC_WRITE 19 /* POSIX 1003.1 write. */
|
||||
#define DB_FUNC_YIELD 20 /* DB: yield thread to scheduler. */
|
||||
#define DB_TSL_SPINS 21 /* DB: initialize spin count. */
|
||||
#define DB_FUNC_RUNLINK 22 /* DB: remove a shared region. */
|
||||
#define DB_REGION_ANON 23 /* DB: anonymous, unnamed regions. */
|
||||
#define DB_REGION_INIT 24 /* DB: page-fault regions in create. */
|
||||
#define DB_REGION_NAME 25 /* DB: anonymous, named regions. */
|
||||
#define DB_MUTEXLOCKS 26 /* DB: turn off all mutex locks. */
|
||||
#define DB_PAGEYIELD 27 /* DB: yield the CPU on pool get. */
|
||||
|
||||
/*
|
||||
* Database configuration and initialization.
|
||||
*/
|
||||
/*
|
||||
* Flags understood by both db_open(3) and db_appinit(3).
|
||||
*/
|
||||
#define DB_CREATE 0x000001 /* O_CREAT: create file as necessary. */
|
||||
#define DB_NOMMAP 0x000002 /* Don't mmap underlying file. */
|
||||
#define DB_THREAD 0x000004 /* Free-thread DB package handles. */
|
||||
|
||||
/*
|
||||
* Flags understood by db_appinit(3).
|
||||
*/
|
||||
/* 0x000007 COMMON MASK. */
|
||||
#define DB_INIT_LOCK 0x000008 /* Initialize locking. */
|
||||
#define DB_INIT_LOG 0x000010 /* Initialize logging. */
|
||||
#define DB_INIT_MPOOL 0x000020 /* Initialize mpool. */
|
||||
#define DB_INIT_TXN 0x000040 /* Initialize transactions. */
|
||||
#define DB_MPOOL_PRIVATE 0x000080 /* Mpool: private memory pool. */
|
||||
#define __UNUSED_100 0x000100
|
||||
#define DB_RECOVER 0x000200 /* Run normal recovery. */
|
||||
#define DB_RECOVER_FATAL 0x000400 /* Run catastrophic recovery. */
|
||||
#define DB_TXN_NOSYNC 0x000800 /* Do not sync log on commit. */
|
||||
#define DB_USE_ENVIRON 0x001000 /* Use the environment. */
|
||||
#define DB_USE_ENVIRON_ROOT 0x002000 /* Use the environment if root. */
|
||||
|
||||
/* CURRENTLY UNUSED LOCK FLAGS. */
|
||||
#define DB_TXN_LOCK_2PL 0x000000 /* Two-phase locking. */
|
||||
#define DB_TXN_LOCK_OPTIMIST 0x000000 /* Optimistic locking. */
|
||||
#define DB_TXN_LOCK_MASK 0x000000 /* Lock flags mask. */
|
||||
|
||||
/* CURRENTLY UNUSED LOG FLAGS. */
|
||||
#define DB_TXN_LOG_REDO 0x000000 /* Redo-only logging. */
|
||||
#define DB_TXN_LOG_UNDO 0x000000 /* Undo-only logging. */
|
||||
#define DB_TXN_LOG_UNDOREDO 0x000000 /* Undo/redo write-ahead logging. */
|
||||
#define DB_TXN_LOG_MASK 0x000000 /* Log flags mask. */
|
||||
|
||||
/*
|
||||
* Flags understood by db_open(3).
|
||||
*
|
||||
* DB_EXCL and DB_TEMPORARY are internal only, and are not documented.
|
||||
* DB_SEQUENTIAL is currently internal, but may be exported some day.
|
||||
*/
|
||||
/* 0x000007 COMMON MASK. */
|
||||
/* 0x003fff ALREADY USED. */
|
||||
#define __UNUSED_4000 0x004000
|
||||
#define DB_EXCL 0x008000 /* O_EXCL: exclusive open. */
|
||||
#define DB_RDONLY 0x010000 /* O_RDONLY: read-only. */
|
||||
#define DB_SEQUENTIAL 0x020000 /* Indicate sequential access. */
|
||||
#define DB_TEMPORARY 0x040000 /* Remove on last close. */
|
||||
#define DB_TRUNCATE 0x080000 /* O_TRUNCATE: replace existing DB. */
|
||||
|
||||
/*
|
||||
* Deadlock detector modes; used in the DBENV structure to configure the
|
||||
* locking subsystem.
|
||||
*/
|
||||
#define DB_LOCK_NORUN 0x0
|
||||
#define DB_LOCK_DEFAULT 0x1 /* Default policy. */
|
||||
#define DB_LOCK_OLDEST 0x2 /* Abort oldest transaction. */
|
||||
#define DB_LOCK_RANDOM 0x3 /* Abort random transaction. */
|
||||
#define DB_LOCK_YOUNGEST 0x4 /* Abort youngest transaction. */
|
||||
|
||||
struct __db_env {
|
||||
int db_lorder; /* Byte order. */
|
||||
|
||||
/* Error message callback. */
|
||||
void (*db_errcall) __P((const char *, char *));
|
||||
FILE *db_errfile; /* Error message file stream. */
|
||||
const char *db_errpfx; /* Error message prefix. */
|
||||
int db_verbose; /* Generate debugging messages. */
|
||||
|
||||
/* User paths. */
|
||||
char *db_home; /* Database home. */
|
||||
char *db_log_dir; /* Database log file directory. */
|
||||
char *db_tmp_dir; /* Database tmp file directory. */
|
||||
|
||||
char **db_data_dir; /* Database data file directories. */
|
||||
int data_cnt; /* Database data file slots. */
|
||||
int data_next; /* Next Database data file slot. */
|
||||
|
||||
/* Locking. */
|
||||
DB_LOCKTAB *lk_info; /* Return from lock_open(). */
|
||||
u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */
|
||||
u_int32_t lk_modes; /* Number of lock modes in table. */
|
||||
u_int32_t lk_max; /* Maximum number of locks. */
|
||||
u_int32_t lk_detect; /* Deadlock detect on all conflicts. */
|
||||
|
||||
/* Logging. */
|
||||
DB_LOG *lg_info; /* Return from log_open(). */
|
||||
u_int32_t lg_max; /* Maximum file size. */
|
||||
|
||||
/* Memory pool. */
|
||||
DB_MPOOL *mp_info; /* Return from memp_open(). */
|
||||
size_t mp_mmapsize; /* Maximum file size for mmap. */
|
||||
size_t mp_size; /* Bytes in the mpool cache. */
|
||||
|
||||
/* Transactions. */
|
||||
DB_TXNMGR *tx_info; /* Return from txn_open(). */
|
||||
u_int32_t tx_max; /* Maximum number of transactions. */
|
||||
int (*tx_recover) /* Dispatch function for recovery. */
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
|
||||
#define DB_ENV_APPINIT 0x01 /* Paths initialized by db_appinit(). */
|
||||
#define DB_ENV_STANDALONE 0x02 /* Test: freestanding environment. */
|
||||
#define DB_ENV_THREAD 0x04 /* DB_ENV is multi-threaded. */
|
||||
u_int32_t flags; /* Flags. */
|
||||
};
|
||||
|
||||
/*******************************************************
|
||||
* Access methods.
|
||||
*******************************************************/
|
||||
/*
|
||||
* XXX
|
||||
* Changes here must be reflected in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
typedef enum {
|
||||
DB_BTREE=1, /* B+tree. */
|
||||
DB_HASH, /* Extended Linear Hashing. */
|
||||
DB_RECNO, /* Fixed and variable-length records. */
|
||||
DB_UNKNOWN /* Figure it out on open. */
|
||||
} DBTYPE;
|
||||
|
||||
#define DB_BTREEVERSION 6 /* Current btree version. */
|
||||
#define DB_BTREEOLDVER 6 /* Oldest btree version supported. */
|
||||
#define DB_BTREEMAGIC 0x053162
|
||||
|
||||
#define DB_HASHVERSION 5 /* Current hash version. */
|
||||
#define DB_HASHOLDVER 4 /* Oldest hash version supported. */
|
||||
#define DB_HASHMAGIC 0x061561
|
||||
|
||||
#define DB_LOGVERSION 2 /* Current log version. */
|
||||
#define DB_LOGOLDVER 2 /* Oldest log version supported. */
|
||||
#define DB_LOGMAGIC 0x040988
|
||||
|
||||
struct __db_info {
|
||||
int db_lorder; /* Byte order. */
|
||||
size_t db_cachesize; /* Underlying cache size. */
|
||||
size_t db_pagesize; /* Underlying page size. */
|
||||
|
||||
/* Local heap allocation. */
|
||||
void *(*db_malloc) __P((size_t));
|
||||
|
||||
/* Btree access method. */
|
||||
u_int32_t bt_maxkey; /* Maximum keys per page. */
|
||||
u_int32_t bt_minkey; /* Minimum keys per page. */
|
||||
int (*bt_compare) /* Comparison function. */
|
||||
__P((const DBT *, const DBT *));
|
||||
size_t (*bt_prefix) /* Prefix function. */
|
||||
__P((const DBT *, const DBT *));
|
||||
|
||||
/* Hash access method. */
|
||||
u_int32_t h_ffactor; /* Fill factor. */
|
||||
u_int32_t h_nelem; /* Number of elements. */
|
||||
u_int32_t (*h_hash) /* Hash function. */
|
||||
__P((const void *, u_int32_t));
|
||||
|
||||
/* Recno access method. */
|
||||
int re_pad; /* Fixed-length padding byte. */
|
||||
int re_delim; /* Variable-length delimiting byte. */
|
||||
u_int32_t re_len; /* Length for fixed-length records. */
|
||||
char *re_source; /* Source file name. */
|
||||
|
||||
#define DB_DELIMITER 0x0001 /* Recno: re_delim set. */
|
||||
#define DB_DUP 0x0002 /* Btree, Hash: duplicate keys. */
|
||||
#define DB_FIXEDLEN 0x0004 /* Recno: fixed-length records. */
|
||||
#define DB_PAD 0x0008 /* Recno: re_pad set. */
|
||||
#define DB_RECNUM 0x0010 /* Btree: record numbers. */
|
||||
#define DB_RENUMBER 0x0020 /* Recno: renumber on insert/delete. */
|
||||
#define DB_SNAPSHOT 0x0040 /* Recno: snapshot the input. */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* DB access method and cursor operation codes. These are implemented as
|
||||
* bit fields for future flexibility, but currently only a single one may
|
||||
* be specified to any function.
|
||||
*/
|
||||
#define DB_AFTER 0x000001 /* c_put() */
|
||||
#define DB_APPEND 0x000002 /* put() */
|
||||
#define DB_BEFORE 0x000004 /* c_put() */
|
||||
#define DB_CHECKPOINT 0x000008 /* log_put(), log_get() */
|
||||
#define DB_CURRENT 0x000010 /* c_get(), c_put(), log_get() */
|
||||
#define DB_FIRST 0x000020 /* c_get(), log_get() */
|
||||
#define DB_FLUSH 0x000040 /* log_put() */
|
||||
#define DB_GET_RECNO 0x000080 /* get(), c_get() */
|
||||
#define DB_KEYFIRST 0x000100 /* c_put() */
|
||||
#define DB_KEYLAST 0x000200 /* c_put() */
|
||||
#define DB_LAST 0x000400 /* c_get(), log_get() */
|
||||
#define DB_NEXT 0x000800 /* c_get(), log_get() */
|
||||
#define DB_NOOVERWRITE 0x001000 /* put() */
|
||||
#define DB_NOSYNC 0x002000 /* close() */
|
||||
#define DB_PREV 0x004000 /* c_get(), log_get() */
|
||||
#define DB_RECORDCOUNT 0x008000 /* stat() */
|
||||
#define DB_SET 0x010000 /* c_get(), log_get() */
|
||||
#define DB_SET_RANGE 0x020000 /* c_get() */
|
||||
#define DB_SET_RECNO 0x040000 /* c_get() */
|
||||
#define DB_CURLSN 0x080000 /* log_put() */
|
||||
|
||||
/*
|
||||
* DB (user visible) error return codes.
|
||||
*
|
||||
* XXX
|
||||
* Changes to any of the user visible error return codes must be reflected
|
||||
* in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
#define DB_INCOMPLETE ( -1) /* Sync didn't finish. */
|
||||
#define DB_KEYEMPTY ( -2) /* The key/data pair was deleted or
|
||||
was never created by the user. */
|
||||
#define DB_KEYEXIST ( -3) /* The key/data pair already exists. */
|
||||
#define DB_LOCK_DEADLOCK ( -4) /* Locker killed to resolve deadlock. */
|
||||
#define DB_LOCK_NOTGRANTED ( -5) /* Lock unavailable, no-wait set. */
|
||||
#define DB_LOCK_NOTHELD ( -6) /* Lock not held by locker. */
|
||||
#define DB_NOTFOUND ( -7) /* Key/data pair not found (EOF). */
|
||||
|
||||
/* DB (private) error return codes. */
|
||||
#define DB_DELETED ( -8) /* Recovery file marked deleted. */
|
||||
#define DB_NEEDSPLIT ( -9) /* Page needs to be split. */
|
||||
#define DB_REGISTERED (-10) /* Entry was previously registered. */
|
||||
#define DB_SWAPBYTES (-11) /* Database needs byte swapping. */
|
||||
#define DB_TXN_CKP (-12) /* Encountered ckp record in log. */
|
||||
|
||||
struct __db_ilock { /* Internal DB access method lock. */
|
||||
db_pgno_t pgno; /* Page being locked. */
|
||||
/* File id. */
|
||||
u_int8_t fileid[DB_FILE_ID_LEN];
|
||||
};
|
||||
|
||||
/* DB access method description structure. */
|
||||
struct __db {
|
||||
void *mutexp; /* Synchronization for free threading */
|
||||
DBTYPE type; /* DB access method. */
|
||||
DB_ENV *dbenv; /* DB_ENV structure. */
|
||||
DB_ENV *mp_dbenv; /* DB_ENV for local mpool creation. */
|
||||
|
||||
DB *master; /* Original DB created by db_open. */
|
||||
void *internal; /* Access method private. */
|
||||
|
||||
DB_MPOOL *mp; /* The access method's mpool. */
|
||||
DB_MPOOLFILE *mpf; /* The access method's mpool file. */
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Explicit representations of structures in queue.h.
|
||||
*
|
||||
* TAILQ_HEAD(curs_queue, __dbc);
|
||||
*/
|
||||
struct {
|
||||
struct __dbc *tqh_first;
|
||||
struct __dbc **tqh_last;
|
||||
} curs_queue;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Explicit representations of structures in queue.h.
|
||||
*
|
||||
* LIST_HEAD(handleq, __db);
|
||||
* LIST_ENTRY(__db);
|
||||
*/
|
||||
struct {
|
||||
struct __db *lh_first;
|
||||
} handleq; /* List of handles for this DB. */
|
||||
struct {
|
||||
struct __db *le_next;
|
||||
struct __db **le_prev;
|
||||
} links; /* Links for the handle list. */
|
||||
|
||||
u_int32_t log_fileid; /* Logging file id. */
|
||||
|
||||
DB_TXN *txn; /* Current transaction. */
|
||||
u_int32_t locker; /* Default process' locker id. */
|
||||
DBT lock_dbt; /* DBT referencing lock. */
|
||||
struct __db_ilock lock; /* Lock. */
|
||||
|
||||
size_t pgsize; /* Logical page size of file. */
|
||||
|
||||
/* Local heap allocation. */
|
||||
void *(*db_malloc) __P((size_t));
|
||||
|
||||
/* Functions. */
|
||||
int (*close) __P((DB *, u_int32_t));
|
||||
int (*cursor) __P((DB *, DB_TXN *, DBC **));
|
||||
int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t));
|
||||
int (*fd) __P((DB *, int *));
|
||||
int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
|
||||
int (*stat) __P((DB *, void *, void *(*)(size_t), u_int32_t));
|
||||
int (*sync) __P((DB *, u_int32_t));
|
||||
|
||||
#define DB_AM_DUP 0x000001 /* DB_DUP (internal). */
|
||||
#define DB_AM_INMEM 0x000002 /* In-memory; no sync on close. */
|
||||
#define DB_AM_LOCKING 0x000004 /* Perform locking. */
|
||||
#define DB_AM_LOGGING 0x000008 /* Perform logging. */
|
||||
#define DB_AM_MLOCAL 0x000010 /* Database memory pool is local. */
|
||||
#define DB_AM_PGDEF 0x000020 /* Page size was defaulted. */
|
||||
#define DB_AM_RDONLY 0x000040 /* Database is readonly. */
|
||||
#define DB_AM_RECOVER 0x000080 /* In recovery (do not log or lock). */
|
||||
#define DB_AM_SWAP 0x000100 /* Pages need to be byte-swapped. */
|
||||
#define DB_AM_THREAD 0x000200 /* DB is multi-threaded. */
|
||||
#define DB_BT_RECNUM 0x000400 /* DB_RECNUM (internal) */
|
||||
#define DB_HS_DIRTYMETA 0x000800 /* Hash: Metadata page modified. */
|
||||
#define DB_RE_DELIMITER 0x001000 /* DB_DELIMITER (internal). */
|
||||
#define DB_RE_FIXEDLEN 0x002000 /* DB_FIXEDLEN (internal). */
|
||||
#define DB_RE_PAD 0x004000 /* DB_PAD (internal). */
|
||||
#define DB_RE_RENUMBER 0x008000 /* DB_RENUMBER (internal). */
|
||||
#define DB_RE_SNAPSHOT 0x010000 /* DB_SNAPSHOT (internal). */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/* Cursor description structure. */
|
||||
struct __dbc {
|
||||
DB *dbp; /* Related DB access method. */
|
||||
DB_TXN *txn; /* Associated transaction. */
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Explicit representations of structures in queue.h.
|
||||
*
|
||||
* TAILQ_ENTRY(__dbc);
|
||||
*/
|
||||
struct {
|
||||
struct __dbc *tqe_next;
|
||||
struct __dbc **tqe_prev;
|
||||
} links;
|
||||
|
||||
void *internal; /* Access method private. */
|
||||
|
||||
int (*c_close) __P((DBC *));
|
||||
int (*c_del) __P((DBC *, u_int32_t));
|
||||
int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t));
|
||||
};
|
||||
|
||||
/* Btree/recno statistics structure. */
|
||||
struct __db_bt_stat {
|
||||
u_int32_t bt_flags; /* Open flags. */
|
||||
u_int32_t bt_maxkey; /* Maxkey value. */
|
||||
u_int32_t bt_minkey; /* Minkey value. */
|
||||
u_int32_t bt_re_len; /* Fixed-length record length. */
|
||||
u_int32_t bt_re_pad; /* Fixed-length record pad. */
|
||||
u_int32_t bt_pagesize; /* Page size. */
|
||||
u_int32_t bt_levels; /* Tree levels. */
|
||||
u_int32_t bt_nrecs; /* Number of records. */
|
||||
u_int32_t bt_int_pg; /* Internal pages. */
|
||||
u_int32_t bt_leaf_pg; /* Leaf pages. */
|
||||
u_int32_t bt_dup_pg; /* Duplicate pages. */
|
||||
u_int32_t bt_over_pg; /* Overflow pages. */
|
||||
u_int32_t bt_free; /* Pages on the free list. */
|
||||
u_int32_t bt_freed; /* Pages freed for reuse. */
|
||||
u_int32_t bt_int_pgfree; /* Bytes free in internal pages. */
|
||||
u_int32_t bt_leaf_pgfree; /* Bytes free in leaf pages. */
|
||||
u_int32_t bt_dup_pgfree; /* Bytes free in duplicate pages. */
|
||||
u_int32_t bt_over_pgfree; /* Bytes free in overflow pages. */
|
||||
u_int32_t bt_pfxsaved; /* Bytes saved by prefix compression. */
|
||||
u_int32_t bt_split; /* Total number of splits. */
|
||||
u_int32_t bt_rootsplit; /* Root page splits. */
|
||||
u_int32_t bt_fastsplit; /* Fast splits. */
|
||||
u_int32_t bt_added; /* Items added. */
|
||||
u_int32_t bt_deleted; /* Items deleted. */
|
||||
u_int32_t bt_get; /* Items retrieved. */
|
||||
u_int32_t bt_cache_hit; /* Hits in fast-insert code. */
|
||||
u_int32_t bt_cache_miss; /* Misses in fast-insert code. */
|
||||
u_int32_t bt_magic; /* Magic number. */
|
||||
u_int32_t bt_version; /* Version number. */
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int db_appinit __P((const char *, char * const *, DB_ENV *, u_int32_t));
|
||||
int db_appexit __P((DB_ENV *));
|
||||
int db_jump_set __P((void *, int));
|
||||
int db_open __P((const char *,
|
||||
DBTYPE, u_int32_t, int, DB_ENV *, DB_INFO *, DB **));
|
||||
int db_value_set __P((int, int));
|
||||
char *db_version __P((int *, int *, int *));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************
|
||||
* Locking
|
||||
*******************************************************/
|
||||
#define DB_LOCKVERSION 1
|
||||
#define DB_LOCKMAGIC 0x090193
|
||||
|
||||
/* Flag values for lock_vec(). */
|
||||
#define DB_LOCK_NOWAIT 0x01 /* Don't wait on unavailable lock. */
|
||||
|
||||
/* Flag values for lock_detect(). */
|
||||
#define DB_LOCK_CONFLICT 0x01 /* Run on any conflict. */
|
||||
|
||||
/*
|
||||
* Request types.
|
||||
*
|
||||
* XXX
|
||||
* Changes here must be reflected in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
typedef enum {
|
||||
DB_LOCK_DUMP=0, /* Display held locks. */
|
||||
DB_LOCK_GET, /* Get the lock. */
|
||||
DB_LOCK_PUT, /* Release the lock. */
|
||||
DB_LOCK_PUT_ALL, /* Release locker's locks. */
|
||||
DB_LOCK_PUT_OBJ /* Release locker's locks on obj. */
|
||||
} db_lockop_t;
|
||||
|
||||
/*
|
||||
* Simple R/W lock modes and for multi-granularity intention locking.
|
||||
*
|
||||
* XXX
|
||||
* Changes here must be reflected in java/src/com/sleepycat/db/Db.java.
|
||||
*/
|
||||
typedef enum {
|
||||
DB_LOCK_NG=0, /* Not granted. */
|
||||
DB_LOCK_READ, /* Shared/read. */
|
||||
DB_LOCK_WRITE, /* Exclusive/write. */
|
||||
DB_LOCK_IREAD, /* Intent to share/read. */
|
||||
DB_LOCK_IWRITE, /* Intent exclusive/write. */
|
||||
DB_LOCK_IWR /* Intent to read and write. */
|
||||
} db_lockmode_t;
|
||||
|
||||
/*
|
||||
* Status of a lock.
|
||||
*/
|
||||
typedef enum {
|
||||
DB_LSTAT_ABORTED, /* Lock belongs to an aborted txn. */
|
||||
DB_LSTAT_ERR, /* Lock is bad. */
|
||||
DB_LSTAT_FREE, /* Lock is unallocated. */
|
||||
DB_LSTAT_HELD, /* Lock is currently held. */
|
||||
DB_LSTAT_NOGRANT, /* Lock was not granted. */
|
||||
DB_LSTAT_PENDING, /* Lock was waiting and has been
|
||||
* promoted; waiting for the owner
|
||||
* to run and upgrade it to held. */
|
||||
DB_LSTAT_WAITING /* Lock is on the wait queue. */
|
||||
} db_status_t;
|
||||
|
||||
/* Lock request structure. */
|
||||
struct __db_lockreq {
|
||||
db_lockop_t op; /* Operation. */
|
||||
db_lockmode_t mode; /* Requested mode. */
|
||||
u_int32_t locker; /* Locker identity. */
|
||||
DBT *obj; /* Object being locked. */
|
||||
DB_LOCK lock; /* Lock returned. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Commonly used conflict matrices.
|
||||
*
|
||||
* Standard Read/Write (or exclusive/shared) locks.
|
||||
*/
|
||||
#define DB_LOCK_RW_N 3
|
||||
extern const u_int8_t db_rw_conflicts[];
|
||||
|
||||
/* Multi-granularity locking. */
|
||||
#define DB_LOCK_RIW_N 6
|
||||
extern const u_int8_t db_riw_conflicts[];
|
||||
|
||||
struct __db_lock_stat {
|
||||
u_int32_t st_magic; /* Lock file magic number. */
|
||||
u_int32_t st_version; /* Lock file version number. */
|
||||
u_int32_t st_maxlocks; /* Maximum number of locks in table. */
|
||||
u_int32_t st_nmodes; /* Number of lock modes. */
|
||||
u_int32_t st_numobjs; /* Number of objects. */
|
||||
u_int32_t st_nlockers; /* Number of lockers. */
|
||||
u_int32_t st_nconflicts; /* Number of lock conflicts. */
|
||||
u_int32_t st_nrequests; /* Number of lock gets. */
|
||||
u_int32_t st_nreleases; /* Number of lock puts. */
|
||||
u_int32_t st_ndeadlocks; /* Number of lock deadlocks. */
|
||||
u_int32_t st_region_wait; /* Region lock granted after wait. */
|
||||
u_int32_t st_region_nowait; /* Region lock granted without wait. */
|
||||
u_int32_t st_refcnt; /* Region reference count. */
|
||||
u_int32_t st_regsize; /* Region size. */
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int lock_close __P((DB_LOCKTAB *));
|
||||
int lock_detect __P((DB_LOCKTAB *, u_int32_t, u_int32_t));
|
||||
int lock_get __P((DB_LOCKTAB *,
|
||||
u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *));
|
||||
int lock_id __P((DB_LOCKTAB *, u_int32_t *));
|
||||
int lock_open __P((const char *,
|
||||
u_int32_t, int, DB_ENV *, DB_LOCKTAB **));
|
||||
int lock_put __P((DB_LOCKTAB *, DB_LOCK));
|
||||
int lock_stat __P((DB_LOCKTAB *, DB_LOCK_STAT **, void *(*)(size_t)));
|
||||
int lock_unlink __P((const char *, int, DB_ENV *));
|
||||
int lock_vec __P((DB_LOCKTAB *,
|
||||
u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************
|
||||
* Logging.
|
||||
*******************************************************/
|
||||
/* Flag values for log_archive(). */
|
||||
#define DB_ARCH_ABS 0x001 /* Absolute pathnames. */
|
||||
#define DB_ARCH_DATA 0x002 /* Data files. */
|
||||
#define DB_ARCH_LOG 0x004 /* Log files. */
|
||||
|
||||
/*
|
||||
* A DB_LSN has two parts, a fileid which identifies a specific file, and an
|
||||
* offset within that file. The fileid is an unsigned 4-byte quantity that
|
||||
* uniquely identifies a file within the log directory -- currently a simple
|
||||
* counter inside the log. The offset is also an unsigned 4-byte value. The
|
||||
* log manager guarantees the offset is never more than 4 bytes by switching
|
||||
* to a new log file before the maximum length imposed by an unsigned 4-byte
|
||||
* offset is reached.
|
||||
*/
|
||||
struct __db_lsn {
|
||||
u_int32_t file; /* File ID. */
|
||||
u_int32_t offset; /* File offset. */
|
||||
};
|
||||
|
||||
/* Log statistics structure. */
|
||||
struct __db_log_stat {
|
||||
u_int32_t st_magic; /* Log file magic number. */
|
||||
u_int32_t st_version; /* Log file version number. */
|
||||
int st_mode; /* Log file mode. */
|
||||
u_int32_t st_lg_max; /* Maximum log file size. */
|
||||
u_int32_t st_w_bytes; /* Bytes to log. */
|
||||
u_int32_t st_w_mbytes; /* Megabytes to log. */
|
||||
u_int32_t st_wc_bytes; /* Bytes to log since checkpoint. */
|
||||
u_int32_t st_wc_mbytes; /* Megabytes to log since checkpoint. */
|
||||
u_int32_t st_wcount; /* Total syncs to the log. */
|
||||
u_int32_t st_scount; /* Total writes to the log. */
|
||||
u_int32_t st_region_wait; /* Region lock granted after wait. */
|
||||
u_int32_t st_region_nowait; /* Region lock granted without wait. */
|
||||
u_int32_t st_cur_file; /* Current log file number. */
|
||||
u_int32_t st_cur_offset; /* Current log file offset. */
|
||||
u_int32_t st_refcnt; /* Region reference count. */
|
||||
u_int32_t st_regsize; /* Region size. */
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int log_archive __P((DB_LOG *, char **[], u_int32_t, void *(*)(size_t)));
|
||||
int log_close __P((DB_LOG *));
|
||||
int log_compare __P((const DB_LSN *, const DB_LSN *));
|
||||
int log_file __P((DB_LOG *, const DB_LSN *, char *, size_t));
|
||||
int log_flush __P((DB_LOG *, const DB_LSN *));
|
||||
int log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t));
|
||||
int log_open __P((const char *, u_int32_t, int, DB_ENV *, DB_LOG **));
|
||||
int log_put __P((DB_LOG *, DB_LSN *, const DBT *, u_int32_t));
|
||||
int log_register __P((DB_LOG *, DB *, const char *, DBTYPE, u_int32_t *));
|
||||
int log_stat __P((DB_LOG *, DB_LOG_STAT **, void *(*)(size_t)));
|
||||
int log_unlink __P((const char *, int, DB_ENV *));
|
||||
int log_unregister __P((DB_LOG *, u_int32_t));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************
|
||||
* Mpool
|
||||
*******************************************************/
|
||||
/* Flag values for memp_fget(). */
|
||||
#define DB_MPOOL_CREATE 0x001 /* Create a page. */
|
||||
#define DB_MPOOL_LAST 0x002 /* Return the last page. */
|
||||
#define DB_MPOOL_NEW 0x004 /* Create a new page. */
|
||||
|
||||
/* Flag values for memp_fput(), memp_fset(). */
|
||||
#define DB_MPOOL_CLEAN 0x001 /* Clear modified bit. */
|
||||
#define DB_MPOOL_DIRTY 0x002 /* Page is modified. */
|
||||
#define DB_MPOOL_DISCARD 0x004 /* Don't cache the page. */
|
||||
|
||||
/* Mpool statistics structure. */
|
||||
struct __db_mpool_stat {
|
||||
size_t st_cachesize; /* Cache size. */
|
||||
u_int32_t st_cache_hit; /* Pages found in the cache. */
|
||||
u_int32_t st_cache_miss; /* Pages not found in the cache. */
|
||||
u_int32_t st_map; /* Pages from mapped files. */
|
||||
u_int32_t st_page_create; /* Pages created in the cache. */
|
||||
u_int32_t st_page_in; /* Pages read in. */
|
||||
u_int32_t st_page_out; /* Pages written out. */
|
||||
u_int32_t st_ro_evict; /* Clean pages forced from the cache. */
|
||||
u_int32_t st_rw_evict; /* Dirty pages forced from the cache. */
|
||||
u_int32_t st_hash_buckets; /* Number of hash buckets. */
|
||||
u_int32_t st_hash_searches; /* Total hash chain searches. */
|
||||
u_int32_t st_hash_longest; /* Longest hash chain searched. */
|
||||
u_int32_t st_hash_examined; /* Total hash entries searched. */
|
||||
u_int32_t st_page_clean; /* Clean pages. */
|
||||
u_int32_t st_page_dirty; /* Dirty pages. */
|
||||
u_int32_t st_page_trickle; /* Pages written by memp_trickle. */
|
||||
u_int32_t st_region_wait; /* Region lock granted after wait. */
|
||||
u_int32_t st_region_nowait; /* Region lock granted without wait. */
|
||||
u_int32_t st_refcnt; /* Region reference count. */
|
||||
u_int32_t st_regsize; /* Region size. */
|
||||
};
|
||||
|
||||
/* Mpool file open information structure. */
|
||||
struct __db_mpool_finfo {
|
||||
int ftype; /* File type. */
|
||||
DBT *pgcookie; /* Byte-string passed to pgin/pgout. */
|
||||
u_int8_t *fileid; /* Unique file ID. */
|
||||
int32_t lsn_offset; /* LSN offset in page. */
|
||||
u_int32_t clear_len; /* Cleared length on created pages. */
|
||||
};
|
||||
|
||||
/* Mpool file statistics structure. */
|
||||
struct __db_mpool_fstat {
|
||||
char *file_name; /* File name. */
|
||||
size_t st_pagesize; /* Page size. */
|
||||
u_int32_t st_cache_hit; /* Pages found in the cache. */
|
||||
u_int32_t st_cache_miss; /* Pages not found in the cache. */
|
||||
u_int32_t st_map; /* Pages from mapped files. */
|
||||
u_int32_t st_page_create; /* Pages created in the cache. */
|
||||
u_int32_t st_page_in; /* Pages read in. */
|
||||
u_int32_t st_page_out; /* Pages written out. */
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int memp_close __P((DB_MPOOL *));
|
||||
int memp_fclose __P((DB_MPOOLFILE *));
|
||||
int memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *));
|
||||
int memp_fopen __P((DB_MPOOL *, const char *,
|
||||
u_int32_t, int, size_t, DB_MPOOL_FINFO *, DB_MPOOLFILE **));
|
||||
int memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t));
|
||||
int memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t));
|
||||
int memp_fsync __P((DB_MPOOLFILE *));
|
||||
int memp_open __P((const char *, u_int32_t, int, DB_ENV *, DB_MPOOL **));
|
||||
int memp_register __P((DB_MPOOL *, int,
|
||||
int (*)(db_pgno_t, void *, DBT *),
|
||||
int (*)(db_pgno_t, void *, DBT *)));
|
||||
int memp_stat __P((DB_MPOOL *,
|
||||
DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, void *(*)(size_t)));
|
||||
int memp_sync __P((DB_MPOOL *, DB_LSN *));
|
||||
int memp_trickle __P((DB_MPOOL *, int, int *));
|
||||
int memp_unlink __P((const char *, int, DB_ENV *));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************
|
||||
* Transactions.
|
||||
*******************************************************/
|
||||
#define DB_TXNVERSION 1
|
||||
#define DB_TXNMAGIC 0x041593
|
||||
|
||||
/* Operations values to the tx_recover() function. */
|
||||
#define DB_TXN_BACKWARD_ROLL 1 /* Read the log backwards. */
|
||||
#define DB_TXN_FORWARD_ROLL 2 /* Read the log forwards. */
|
||||
#define DB_TXN_OPENFILES 3 /* Read for open files. */
|
||||
#define DB_TXN_REDO 4 /* Redo the operation. */
|
||||
#define DB_TXN_UNDO 5 /* Undo the operation. */
|
||||
|
||||
/* Internal transaction status values. */
|
||||
|
||||
/* Transaction statistics structure. */
|
||||
struct __db_txn_active {
|
||||
u_int32_t txnid; /* Transaction ID */
|
||||
DB_LSN lsn; /* Lsn of the begin record */
|
||||
};
|
||||
|
||||
struct __db_txn_stat {
|
||||
DB_LSN st_last_ckp; /* lsn of the last checkpoint */
|
||||
DB_LSN st_pending_ckp; /* last checkpoint did not finish */
|
||||
time_t st_time_ckp; /* time of last checkpoint */
|
||||
u_int32_t st_last_txnid; /* last transaction id given out */
|
||||
u_int32_t st_maxtxns; /* maximum number of active txns */
|
||||
u_int32_t st_naborts; /* number of aborted transactions */
|
||||
u_int32_t st_nbegins; /* number of begun transactions */
|
||||
u_int32_t st_ncommits; /* number of committed transactions */
|
||||
u_int32_t st_nactive; /* number of active transactions */
|
||||
DB_TXN_ACTIVE
|
||||
*st_txnarray; /* array of active transactions */
|
||||
u_int32_t st_region_wait; /* Region lock granted after wait. */
|
||||
u_int32_t st_region_nowait; /* Region lock granted without wait. */
|
||||
u_int32_t st_refcnt; /* Region reference count. */
|
||||
u_int32_t st_regsize; /* Region size. */
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int txn_abort __P((DB_TXN *));
|
||||
int txn_begin __P((DB_TXNMGR *, DB_TXN *, DB_TXN **));
|
||||
int txn_checkpoint __P((const DB_TXNMGR *, u_int32_t, u_int32_t));
|
||||
int txn_commit __P((DB_TXN *));
|
||||
int txn_close __P((DB_TXNMGR *));
|
||||
u_int32_t txn_id __P((DB_TXN *));
|
||||
int txn_open __P((const char *, u_int32_t, int, DB_ENV *, DB_TXNMGR **));
|
||||
int txn_prepare __P((DB_TXN *));
|
||||
int txn_stat __P((DB_TXNMGR *, DB_TXN_STAT **, void *(*)(size_t)));
|
||||
int txn_unlink __P((const char *, int, DB_ENV *));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DB_DBM_HSEARCH
|
||||
#define DB_DBM_HSEARCH 0 /* No historic interfaces by default. */
|
||||
#endif
|
||||
#if DB_DBM_HSEARCH != 0
|
||||
/*******************************************************
|
||||
* Dbm/Ndbm historic interfaces.
|
||||
*******************************************************/
|
||||
#define DBM_INSERT 0 /* Flags to dbm_store(). */
|
||||
#define DBM_REPLACE 1
|
||||
|
||||
/*
|
||||
* The db(3) support for ndbm(3) always appends this suffix to the
|
||||
* file name to avoid overwriting the user's original database.
|
||||
*/
|
||||
#define DBM_SUFFIX ".db"
|
||||
|
||||
#if defined(_XPG4_2)
|
||||
typedef struct {
|
||||
char *dptr;
|
||||
size_t dsize;
|
||||
} datum;
|
||||
#else
|
||||
typedef struct {
|
||||
char *dptr;
|
||||
int dsize;
|
||||
} datum;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Translate DBM calls into DB calls so that DB doesn't step on the
|
||||
* application's name space.
|
||||
*
|
||||
* The global variables dbrdonly, dirf and pagf were not retained when
|
||||
* 4BSD replaced the dbm interface with ndbm, and are not support here.
|
||||
*/
|
||||
#define dbminit(a) __db_dbm_init(a)
|
||||
#if !defined(__cplusplus)
|
||||
#define delete(a) __db_dbm_delete(a)
|
||||
#endif
|
||||
#define fetch(a) __db_dbm_fetch(a)
|
||||
#define firstkey __db_dbm_firstkey
|
||||
#define nextkey(a) __db_dbm_nextkey(a)
|
||||
#define store(a, b) __db_dbm_store(a, b)
|
||||
|
||||
/* Prototype the DB calls. */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int __db_dbm_init __P((char *));
|
||||
int __db_dbm_delete __P((datum));
|
||||
int __db_dbm_dbrdonly __P((void));
|
||||
int __db_dbm_dirf __P((void));
|
||||
datum __db_dbm_fetch __P((datum));
|
||||
datum __db_dbm_firstkey __P((void));
|
||||
datum __db_dbm_nextkey __P((datum));
|
||||
int __db_dbm_pagf __P((void));
|
||||
int __db_dbm_store __P((datum, datum));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Translate NDBM calls into DB calls so that DB doesn't step on the
|
||||
* application's name space.
|
||||
*/
|
||||
#define dbm_clearerr(a) __db_ndbm_clearerr(a)
|
||||
#define dbm_close(a) __db_ndbm_close(a)
|
||||
#define dbm_delete(a, b) __db_ndbm_delete(a, b)
|
||||
#define dbm_dirfno(a) __db_ndbm_dirfno(a)
|
||||
#define dbm_error(a) __db_ndbm_error(a)
|
||||
#define dbm_fetch(a, b) __db_ndbm_fetch(a, b)
|
||||
#define dbm_firstkey(a) __db_ndbm_firstkey(a)
|
||||
#define dbm_nextkey(a) __db_ndbm_nextkey(a)
|
||||
#define dbm_open(a, b, c) __db_ndbm_open(a, b, c)
|
||||
#define dbm_pagfno(a) __db_ndbm_pagfno(a)
|
||||
#define dbm_rdonly(a) __db_ndbm_rdonly(a)
|
||||
#define dbm_store(a, b, c, d) __db_ndbm_store(a, b, c, d)
|
||||
|
||||
/* Prototype the DB calls. */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int __db_ndbm_clearerr __P((DBM *));
|
||||
void __db_ndbm_close __P((DBM *));
|
||||
int __db_ndbm_delete __P((DBM *, datum));
|
||||
int __db_ndbm_dirfno __P((DBM *));
|
||||
int __db_ndbm_error __P((DBM *));
|
||||
datum __db_ndbm_fetch __P((DBM *, datum));
|
||||
datum __db_ndbm_firstkey __P((DBM *));
|
||||
datum __db_ndbm_nextkey __P((DBM *));
|
||||
DBM *__db_ndbm_open __P((const char *, int, int));
|
||||
int __db_ndbm_pagfno __P((DBM *));
|
||||
int __db_ndbm_rdonly __P((DBM *));
|
||||
int __db_ndbm_store __P((DBM *, datum, datum, int));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************
|
||||
* Hsearch historic interface.
|
||||
*******************************************************/
|
||||
typedef enum {
|
||||
FIND, ENTER
|
||||
} ACTION;
|
||||
|
||||
typedef struct entry {
|
||||
char *key;
|
||||
char *data;
|
||||
} ENTRY;
|
||||
|
||||
/*
|
||||
* Translate HSEARCH calls into DB calls so that DB doesn't step on the
|
||||
* application's name space.
|
||||
*/
|
||||
#define hcreate(a) __db_hcreate(a)
|
||||
#define hdestroy __db_hdestroy
|
||||
#define hsearch(a, b) __db_hsearch(a, b)
|
||||
|
||||
/* Prototype the DB calls. */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
int __db_hcreate __P((size_t));
|
||||
void __db_hdestroy __P((void));
|
||||
ENTRY *__db_hsearch __P((ENTRY, ACTION));
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* DB_DBM_HSEARCH */
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* MacOS: Reset Metrowerks C enum sizes.
|
||||
*/
|
||||
#ifdef __MWERKS__
|
||||
#pragma enumsalwaysint reset
|
||||
#endif
|
||||
#endif /* !_DB_H_ */
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db_am.h 10.9 (Sleepycat) 4/10/98
|
||||
* @(#)db_am.h 10.15 (Sleepycat) 11/22/98
|
||||
*/
|
||||
#ifndef _DB_AM_H
|
||||
#define _DB_AM_H
|
||||
@ -16,6 +16,8 @@
|
||||
#define DB_REM_BIG 0x40
|
||||
#define DB_SPLITOLD 0x50
|
||||
#define DB_SPLITNEW 0x60
|
||||
#define DB_ADD_PAGE 0x70
|
||||
#define DB_REM_PAGE 0x80
|
||||
|
||||
/*
|
||||
* Standard initialization and shutdown macros for all recovery functions.
|
||||
@ -27,34 +29,31 @@
|
||||
* int ret;
|
||||
*/
|
||||
#define REC_INTRO(func) { \
|
||||
file_dbp = mdbp = NULL; \
|
||||
file_dbp = NULL; \
|
||||
dbc = NULL; \
|
||||
if ((ret = func(dbtp->data, &argp)) != 0) \
|
||||
goto out; \
|
||||
if ((ret = __db_fileid_to_db(logp, &mdbp, argp->fileid)) != 0) {\
|
||||
if (ret == DB_DELETED) \
|
||||
if ((ret = \
|
||||
__db_fileid_to_db(logp, &file_dbp, argp->fileid)) != 0) { \
|
||||
if (ret == DB_DELETED) { \
|
||||
ret = 0; \
|
||||
goto done; \
|
||||
} \
|
||||
goto out; \
|
||||
} \
|
||||
if (mdbp == NULL) \
|
||||
if (file_dbp == NULL) \
|
||||
goto out; \
|
||||
if (F_ISSET(mdbp, DB_AM_THREAD)) { \
|
||||
if ((ret = __db_gethandle(mdbp, \
|
||||
mdbp->type == DB_HASH ? __ham_hdup : __bam_bdup, \
|
||||
&file_dbp)) != 0) \
|
||||
goto out; \
|
||||
} else \
|
||||
file_dbp = mdbp; \
|
||||
F_SET(file_dbp, DB_AM_RECOVER); \
|
||||
if ((ret = file_dbp->cursor(file_dbp, NULL, &dbc, 0)) != 0) \
|
||||
goto out; \
|
||||
F_SET(dbc, DBC_RECOVER); \
|
||||
mpf = file_dbp->mpf; \
|
||||
}
|
||||
|
||||
#define REC_CLOSE { \
|
||||
if (argp != NULL) \
|
||||
__db_free(argp); \
|
||||
if (file_dbp != NULL) { \
|
||||
F_CLR(file_dbp, DB_AM_RECOVER); \
|
||||
if (F_ISSET(file_dbp, DB_AM_THREAD)) \
|
||||
__db_puthandle(file_dbp); \
|
||||
} \
|
||||
__os_free(argp, sizeof(*argp)); \
|
||||
if (dbc != NULL) \
|
||||
dbc->c_close(dbc); \
|
||||
return (ret); \
|
||||
}
|
||||
|
||||
@ -67,7 +66,7 @@
|
||||
}
|
||||
#define REC_NOOP_CLOSE { \
|
||||
if (argp != NULL) \
|
||||
__db_free(argp); \
|
||||
__os_free(argp, sizeof(*argp)); \
|
||||
return (ret); \
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ typedef struct _db_relink_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
u_int32_t opcode;
|
||||
u_int32_t fileid;
|
||||
db_pgno_t pgno;
|
||||
DB_LSN lsn;
|
||||
@ -107,16 +108,4 @@ typedef struct _db_debug_args {
|
||||
u_int32_t arg_flags;
|
||||
} __db_debug_args;
|
||||
|
||||
|
||||
#define DB_db_noop (DB_db_BEGIN + 8)
|
||||
|
||||
typedef struct _db_noop_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
u_int32_t fileid;
|
||||
db_pgno_t pgno;
|
||||
DB_LSN prevlsn;
|
||||
} __db_noop_args;
|
||||
|
||||
#endif
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db_cxx.h 10.17 (Sleepycat) 5/2/98
|
||||
* @(#)db_cxx.h 10.30 (Sleepycat) 11/22/98
|
||||
*/
|
||||
|
||||
#ifndef _DB_CXX_H_
|
||||
@ -49,7 +49,8 @@
|
||||
// Forward declarations
|
||||
//
|
||||
|
||||
#include "db.h"
|
||||
#include <iostream.h>
|
||||
#include <db.h>
|
||||
|
||||
class Db; // forward
|
||||
class Dbc; // forward
|
||||
@ -66,6 +67,19 @@ class Dbt; // forward
|
||||
class DbTxn; // forward
|
||||
class DbTxnMgr; // forward
|
||||
|
||||
// These classes are not defined here and should be invisible
|
||||
// to the user, but some compilers require forward references.
|
||||
// There is one for each use of the DEFINE_DB_CLASS macro.
|
||||
|
||||
class DbLockTabImp;
|
||||
class DbLogImp;
|
||||
class DbMpoolImp;
|
||||
class DbMpoolFileImp;
|
||||
class DbImp;
|
||||
class DbTxnImp;
|
||||
class DbTxnMgrImp;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@ -175,15 +189,11 @@ private:
|
||||
|
||||
class _exported DbLock
|
||||
{
|
||||
friend DbLockTab;
|
||||
friend class DbLockTab;
|
||||
|
||||
public:
|
||||
DbLock(u_int);
|
||||
DbLock();
|
||||
|
||||
u_int get_lock_id();
|
||||
void set_lock_id(u_int);
|
||||
|
||||
int put(DbLockTab *locktab);
|
||||
|
||||
DbLock(const DbLock &);
|
||||
@ -194,18 +204,21 @@ protected:
|
||||
// since its contained class is not allocated by db.
|
||||
// (see comment at top)
|
||||
|
||||
DbLock(DB_LOCK);
|
||||
DB_LOCK lock_;
|
||||
};
|
||||
|
||||
class _exported DbLockTab
|
||||
{
|
||||
friend DbEnv;
|
||||
friend class DbEnv;
|
||||
|
||||
public:
|
||||
int close();
|
||||
int detect(u_int32_t flags, int atype);
|
||||
int get(u_int32_t locker, u_int32_t flags, const Dbt *obj,
|
||||
db_lockmode_t lock_mode, DbLock *lock);
|
||||
int id(u_int32_t *idp);
|
||||
int stat(DB_LOCK_STAT **statp, void *(*db_malloc)(size_t));
|
||||
int vec(u_int32_t locker, u_int32_t flags, DB_LOCKREQ list[],
|
||||
int nlist, DB_LOCKREQ **elistp);
|
||||
|
||||
@ -244,13 +257,14 @@ private:
|
||||
|
||||
class _exported DbLsn : protected DB_LSN
|
||||
{
|
||||
friend DbLog; // friendship needed to cast to base class
|
||||
friend DbMpool;
|
||||
friend class DbLog; // friendship needed to cast to base class
|
||||
friend class DbMpool;
|
||||
};
|
||||
|
||||
class _exported DbLog
|
||||
{
|
||||
friend DbEnv;
|
||||
friend class DbEnv;
|
||||
|
||||
public:
|
||||
int archive(char **list[], u_int32_t flags, void *(*db_malloc)(size_t));
|
||||
int close();
|
||||
@ -300,7 +314,8 @@ private:
|
||||
|
||||
class _exported DbMpoolFile
|
||||
{
|
||||
friend DbEnv;
|
||||
friend class DbEnv;
|
||||
|
||||
public:
|
||||
int close();
|
||||
int get(db_pgno_t *pgnoaddr, u_int32_t flags, void *pagep);
|
||||
@ -337,7 +352,8 @@ private:
|
||||
|
||||
class _exported DbMpool
|
||||
{
|
||||
friend DbEnv;
|
||||
friend class DbEnv;
|
||||
|
||||
public:
|
||||
int close();
|
||||
|
||||
@ -388,7 +404,8 @@ private:
|
||||
|
||||
class _exported DbTxnMgr
|
||||
{
|
||||
friend DbEnv;
|
||||
friend class DbEnv;
|
||||
|
||||
public:
|
||||
int begin(DbTxn *pid, DbTxn **tid);
|
||||
int checkpoint(u_int32_t kbyte, u_int32_t min) const;
|
||||
@ -422,7 +439,8 @@ private:
|
||||
|
||||
class _exported DbTxn
|
||||
{
|
||||
friend DbTxnMgr;
|
||||
friend class DbTxnMgr;
|
||||
|
||||
public:
|
||||
int abort();
|
||||
int commit();
|
||||
@ -461,90 +479,78 @@ private:
|
||||
//
|
||||
class _exported DbInfo : protected DB_INFO
|
||||
{
|
||||
friend DbEnv;
|
||||
friend Db;
|
||||
friend class DbEnv;
|
||||
friend class Db;
|
||||
|
||||
public:
|
||||
DbInfo();
|
||||
~DbInfo();
|
||||
|
||||
// Byte order.
|
||||
int get_lorder() const;
|
||||
void set_lorder(int);
|
||||
|
||||
// Underlying cache size.
|
||||
size_t get_cachesize() const;
|
||||
void set_cachesize(size_t);
|
||||
|
||||
// Underlying page size.
|
||||
size_t get_pagesize() const;
|
||||
void set_pagesize(size_t);
|
||||
|
||||
// Local heap allocation.
|
||||
typedef void *(*db_malloc_fcn)(size_t);
|
||||
db_malloc_fcn get_malloc() const;
|
||||
void set_malloc(db_malloc_fcn);
|
||||
|
||||
// Duplicate compare function.
|
||||
typedef int (*dup_compare_fcn)(const DBT *, const DBT *);
|
||||
void set_dup_compare(dup_compare_fcn);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Btree access method.
|
||||
|
||||
// Maximum keys per page.
|
||||
int get_bt_maxkey() const;
|
||||
void set_bt_maxkey(int);
|
||||
|
||||
// Minimum keys per page.
|
||||
int get_bt_minkey() const;
|
||||
void set_bt_minkey(int);
|
||||
|
||||
// Comparison function.
|
||||
typedef int (*bt_compare_fcn)(const DBT *, const DBT *);
|
||||
bt_compare_fcn get_bt_compare() const;
|
||||
void set_bt_compare(bt_compare_fcn);
|
||||
|
||||
// Prefix function.
|
||||
typedef size_t (*bt_prefix_fcn)(const DBT *, const DBT *);
|
||||
bt_prefix_fcn get_bt_prefix() const;
|
||||
void set_bt_prefix(bt_prefix_fcn);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Hash access method.
|
||||
|
||||
// Fill factor.
|
||||
u_int32_t get_h_ffactor() const;
|
||||
void set_h_ffactor(u_int32_t);
|
||||
|
||||
// Number of elements.
|
||||
u_int32_t get_h_nelem() const;
|
||||
void set_h_nelem(u_int32_t);
|
||||
|
||||
// Hash function.
|
||||
typedef u_int32_t (*h_hash_fcn)(const void *, u_int32_t);
|
||||
h_hash_fcn get_h_hash() const;
|
||||
void set_h_hash(h_hash_fcn);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Recno access method.
|
||||
|
||||
// Fixed-length padding byte.
|
||||
int get_re_pad() const;
|
||||
void set_re_pad(int);
|
||||
|
||||
// Variable-length delimiting byte.
|
||||
int get_re_delim() const;
|
||||
void set_re_delim(int);
|
||||
|
||||
// Length for fixed-length records.
|
||||
u_int32_t get_re_len() const;
|
||||
void set_re_len(u_int32_t);
|
||||
|
||||
// Source file name.
|
||||
char *get_re_source() const;
|
||||
void set_re_source(char *);
|
||||
|
||||
// Note: some flags are set as side effects of calling
|
||||
// above "set" methods.
|
||||
//
|
||||
u_int32_t get_flags() const;
|
||||
void set_flags(u_int32_t);
|
||||
|
||||
|
||||
@ -570,11 +576,11 @@ private:
|
||||
//
|
||||
class _exported DbEnv : protected DB_ENV
|
||||
{
|
||||
friend DbTxnMgr;
|
||||
friend DbLog;
|
||||
friend DbLockTab;
|
||||
friend DbMpool;
|
||||
friend Db;
|
||||
friend class DbTxnMgr;
|
||||
friend class DbLog;
|
||||
friend class DbLockTab;
|
||||
friend class DbMpool;
|
||||
friend class Db;
|
||||
|
||||
public:
|
||||
|
||||
@ -603,6 +609,10 @@ public:
|
||||
//
|
||||
int appexit();
|
||||
|
||||
// Version information. A static method so it can be obtained anytime.
|
||||
//
|
||||
static char *version(int *major, int *minor, int *patch);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// simple get/set access methods
|
||||
//
|
||||
@ -610,54 +620,25 @@ public:
|
||||
// use the default constructor along with appinit().
|
||||
|
||||
// Byte order.
|
||||
int get_lorder() const;
|
||||
void set_lorder(int);
|
||||
|
||||
// Panic callback.
|
||||
typedef void (*db_paniccall_fcn)(DbEnv *, int);
|
||||
void set_paniccall(db_paniccall_fcn);
|
||||
|
||||
// Error message callback.
|
||||
typedef void (*db_errcall_fcn)(const char *, char *);
|
||||
db_errcall_fcn get_errcall() const;
|
||||
void set_errcall(db_errcall_fcn);
|
||||
|
||||
// Error message file stream.
|
||||
FILE *get_errfile() const;
|
||||
void set_errfile(FILE *);
|
||||
|
||||
// Error message prefix.
|
||||
const char *get_errpfx() const;
|
||||
void set_errpfx(const char *);
|
||||
|
||||
// Generate debugging messages.
|
||||
int get_verbose() const;
|
||||
void set_verbose(int);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// User paths.
|
||||
|
||||
// Database home.
|
||||
char *get_home() const;
|
||||
void set_home(char *);
|
||||
|
||||
// Database log file directory.
|
||||
char *get_log_dir() const;
|
||||
void set_log_dir(char *);
|
||||
|
||||
// Database tmp file directory.
|
||||
char *get_tmp_dir() const;
|
||||
void set_tmp_dir(char *);
|
||||
|
||||
// Database data file directories.
|
||||
char **get_data_dir() const;
|
||||
void set_data_dir(char **);
|
||||
|
||||
// Database data file slots.
|
||||
int get_data_cnt() const;
|
||||
void set_data_cnt(int);
|
||||
|
||||
// Next Database data file slot.
|
||||
int get_data_next() const;
|
||||
void set_data_next(int);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Locking.
|
||||
|
||||
@ -665,19 +646,15 @@ public:
|
||||
DbLockTab *get_lk_info() const;
|
||||
|
||||
// Two dimensional conflict matrix.
|
||||
u_int8_t *get_lk_conflicts() const;
|
||||
void set_lk_conflicts(u_int8_t *);
|
||||
|
||||
// Number of lock modes in table.
|
||||
int get_lk_modes() const;
|
||||
void set_lk_modes(int);
|
||||
|
||||
// Maximum number of locks.
|
||||
u_int32_t get_lk_max() const;
|
||||
void set_lk_max(u_int32_t);
|
||||
|
||||
// Deadlock detect on every conflict.
|
||||
u_int32_t get_lk_detect() const;
|
||||
void set_lk_detect(u_int32_t);
|
||||
|
||||
|
||||
@ -688,7 +665,6 @@ public:
|
||||
DbLog *get_lg_info() const;
|
||||
|
||||
// Maximum file size.
|
||||
u_int32_t get_lg_max() const;
|
||||
void set_lg_max(u_int32_t);
|
||||
|
||||
|
||||
@ -699,11 +675,9 @@ public:
|
||||
DbMpool *get_mp_info() const;
|
||||
|
||||
// Maximum file size for mmap.
|
||||
size_t get_mp_mmapsize() const;
|
||||
void set_mp_mmapsize(size_t);
|
||||
|
||||
// Bytes in the mpool cache.
|
||||
size_t get_mp_size() const;
|
||||
void set_mp_size(size_t);
|
||||
|
||||
|
||||
@ -714,16 +688,13 @@ public:
|
||||
DbTxnMgr *get_tx_info() const;
|
||||
|
||||
// Maximum number of transactions.
|
||||
u_int32_t get_tx_max() const;
|
||||
void set_tx_max(u_int32_t);
|
||||
|
||||
// Dispatch function for recovery.
|
||||
typedef int (*tx_recover_fcn)(DB_LOG *, DBT *, DB_LSN *, int, void *);
|
||||
tx_recover_fcn get_tx_recover() const;
|
||||
void set_tx_recover(tx_recover_fcn);
|
||||
|
||||
// Flags.
|
||||
u_int32_t get_flags() const;
|
||||
void set_flags(u_int32_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
@ -736,7 +707,6 @@ public:
|
||||
//
|
||||
enum ErrorModel { Exception, ErrorReturn };
|
||||
void set_error_model(ErrorModel);
|
||||
ErrorModel get_error_model() const;
|
||||
|
||||
// If an error is detected and the error call function
|
||||
// or stream is set, a message is dispatched or printed.
|
||||
@ -747,11 +717,11 @@ public:
|
||||
// call set_error_stream() to force all errors to a C++ stream.
|
||||
// It is unwise to mix these approaches.
|
||||
//
|
||||
class ostream* get_error_stream() const;
|
||||
void set_error_stream(class ostream*);
|
||||
|
||||
// used internally
|
||||
static int runtime_error(const char *caller, int err, int in_destructor = 0);
|
||||
static int runtime_error(const char *caller, int err,
|
||||
int in_destructor = 0, int force_throw = 0);
|
||||
|
||||
private:
|
||||
// We can add data to this class if needed
|
||||
@ -778,23 +748,27 @@ private:
|
||||
//
|
||||
class _exported Db
|
||||
{
|
||||
friend DbEnv;
|
||||
friend class DbEnv;
|
||||
|
||||
public:
|
||||
int close(u_int32_t flags);
|
||||
int cursor(DbTxn *txnid, Dbc **cursorp);
|
||||
int cursor(DbTxn *txnid, Dbc **cursorp, u_int32_t flags);
|
||||
int del(DbTxn *txnid, Dbt *key, u_int32_t flags);
|
||||
int fd(int *fdp);
|
||||
int get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
|
||||
int join(Dbc **curslist, u_int32_t flags, Dbc **dbcp);
|
||||
int put(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
|
||||
int stat(void *sp, void *(*db_malloc)(size_t), u_int32_t flags);
|
||||
int sync(u_int32_t flags);
|
||||
|
||||
int get_byteswapped() const;
|
||||
DBTYPE get_type() const;
|
||||
|
||||
static int open(const char *fname, DBTYPE type, u_int32_t flags,
|
||||
int mode, DbEnv *dbenv, DbInfo *info, Db **dbpp);
|
||||
|
||||
static int xa_open(const char *fname, DBTYPE type, u_int32_t flags,
|
||||
int mode, DbInfo *info, Db **dbpp);
|
||||
private:
|
||||
// We can add data to this class if needed
|
||||
// since it is implemented via a pointer.
|
||||
@ -817,11 +791,11 @@ private:
|
||||
//
|
||||
class _exported Dbt : private DBT
|
||||
{
|
||||
friend Dbc;
|
||||
friend Db;
|
||||
friend DbLog;
|
||||
friend DbMpoolFile;
|
||||
friend DbLockTab;
|
||||
friend class Dbc;
|
||||
friend class Db;
|
||||
friend class DbLog;
|
||||
friend class DbMpoolFile;
|
||||
friend class DbLockTab;
|
||||
|
||||
public:
|
||||
|
||||
@ -863,7 +837,7 @@ private:
|
||||
|
||||
class _exported Dbc : protected DBC
|
||||
{
|
||||
friend Db;
|
||||
friend class Db;
|
||||
|
||||
public:
|
||||
int close();
|
||||
|
@ -1,8 +1,11 @@
|
||||
/* DO NOT EDIT: automatically built by dist/distrib. */
|
||||
#ifndef _db_ext_h_
|
||||
#define _db_ext_h_
|
||||
int __db_pgerr __P((DB *, db_pgno_t));
|
||||
int __db_pgfmt __P((DB *, db_pgno_t));
|
||||
int __db_close __P((DB *, u_int32_t));
|
||||
int __db_init_wrapper __P((DB *));
|
||||
int __db_cprint __P((DB *));
|
||||
int __db_c_destroy __P((DBC *));
|
||||
int __db_sync __P((DB *, u_int32_t));
|
||||
int __db_addrem_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, u_int32_t, db_pgno_t, u_int32_t,
|
||||
@ -33,8 +36,8 @@ int __db_ovref_print
|
||||
int __db_ovref_read __P((void *, __db_ovref_args **));
|
||||
int __db_relink_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t,
|
||||
DB_LSN *, db_pgno_t, DB_LSN *));
|
||||
u_int32_t, u_int32_t, db_pgno_t, DB_LSN *,
|
||||
db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *));
|
||||
int __db_relink_print
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __db_relink_read __P((void *, __db_relink_args **));
|
||||
@ -52,12 +55,6 @@ int __db_debug_log
|
||||
int __db_debug_print
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __db_debug_read __P((void *, __db_debug_args **));
|
||||
int __db_noop_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, db_pgno_t, DB_LSN *));
|
||||
int __db_noop_print
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __db_noop_read __P((void *, __db_noop_args **));
|
||||
int __db_init_print __P((DB_ENV *));
|
||||
int __db_init_recover __P((DB_ENV *));
|
||||
int __db_pgin __P((db_pgno_t, size_t, void *));
|
||||
@ -71,23 +68,40 @@ int __db_txnlist_find __P((void *, u_int32_t));
|
||||
void __db_txnlist_end __P((void *));
|
||||
void __db_txnlist_gen __P((void *, int));
|
||||
void __db_txnlist_print __P((void *));
|
||||
int __db_dput __P((DB *,
|
||||
DBT *, PAGE **, db_indx_t *, int (*)(DB *, u_int32_t, PAGE **)));
|
||||
int __db_drem __P((DB *,
|
||||
PAGE **, u_int32_t, int (*)(DB *, PAGE *)));
|
||||
int __db_dend __P((DB *, db_pgno_t, PAGE **));
|
||||
int __db_ditem __P((DB *, PAGE *, u_int32_t, u_int32_t));
|
||||
int __db_dput __P((DBC *, DBT *,
|
||||
PAGE **, db_indx_t *, int (*)(DBC *, u_int32_t, PAGE **)));
|
||||
int __db_drem __P((DBC *,
|
||||
PAGE **, u_int32_t, int (*)(DBC *, PAGE *)));
|
||||
int __db_dend __P((DBC *, db_pgno_t, PAGE **));
|
||||
int __db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t));
|
||||
int __db_pitem
|
||||
__P((DB *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *));
|
||||
int __db_relink __P((DB *, PAGE *, PAGE **, int));
|
||||
int __db_ddup __P((DB *, db_pgno_t, int (*)(DB *, PAGE *)));
|
||||
__P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *));
|
||||
int __db_relink __P((DBC *, u_int32_t, PAGE *, PAGE **, int));
|
||||
int __db_ddup __P((DBC *, db_pgno_t, int (*)(DBC *, PAGE *)));
|
||||
int __db_dsearch __P((DBC *,
|
||||
int, DBT *, db_pgno_t, db_indx_t *, PAGE **, int *));
|
||||
int __db_cdelchk __P((const DB *, u_int32_t, int, int));
|
||||
int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
|
||||
int __db_cputchk __P((const DB *,
|
||||
const DBT *, DBT *, u_int32_t, int, int));
|
||||
int __db_closechk __P((const DB *, u_int32_t));
|
||||
int __db_delchk __P((const DB *, DBT *, u_int32_t, int));
|
||||
int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
|
||||
int __db_joinchk __P((const DB *, u_int32_t));
|
||||
int __db_putchk
|
||||
__P((const DB *, DBT *, const DBT *, u_int32_t, int, int));
|
||||
int __db_statchk __P((const DB *, u_int32_t));
|
||||
int __db_syncchk __P((const DB *, u_int32_t));
|
||||
int __db_eopnotsup __P((const DB_ENV *));
|
||||
int __db_join __P((DB *, DBC **, u_int32_t, DBC **));
|
||||
int __db_goff __P((DB *, DBT *,
|
||||
u_int32_t, db_pgno_t, void **, u_int32_t *));
|
||||
int __db_poff __P((DB *, const DBT *, db_pgno_t *,
|
||||
int (*)(DB *, u_int32_t, PAGE **)));
|
||||
int __db_ovref __P((DB *, db_pgno_t, int32_t));
|
||||
int __db_doff __P((DB *, db_pgno_t, int (*)(DB *, PAGE *)));
|
||||
int __db_moff __P((DB *, const DBT *, db_pgno_t));
|
||||
int __db_poff __P((DBC *, const DBT *, db_pgno_t *,
|
||||
int (*)(DBC *, u_int32_t, PAGE **)));
|
||||
int __db_ovref __P((DBC *, db_pgno_t, int32_t));
|
||||
int __db_doff __P((DBC *, db_pgno_t, int (*)(DBC *, PAGE *)));
|
||||
int __db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t,
|
||||
int (*)(const DBT *, const DBT *), int *));
|
||||
void __db_loadme __P((void));
|
||||
FILE *__db_prinit __P((FILE *));
|
||||
int __db_dump __P((DB *, char *, int));
|
||||
@ -111,11 +125,8 @@ int __db_relink_recover
|
||||
int __db_addpage_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __db_debug_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __db_noop_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __db_ret __P((DB *,
|
||||
PAGE *, u_int32_t, DBT *, void **, u_int32_t *));
|
||||
int __db_retcopy __P((DBT *,
|
||||
void *, u_int32_t, void **, u_int32_t *, void *(*)(size_t)));
|
||||
int __db_gethandle __P((DB *, int (*)(DB *, DB *), DB **));
|
||||
int __db_puthandle __P((DB *));
|
||||
#endif /* _db_ext_h_ */
|
||||
|
@ -1,402 +0,0 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db_int.h.src 10.62 (Sleepycat) 5/23/98
|
||||
*/
|
||||
|
||||
#ifndef _DB_INTERNAL_H_
|
||||
#define _DB_INTERNAL_H_
|
||||
|
||||
#include "db.h" /* Standard DB include file. */
|
||||
#include "queue.h"
|
||||
|
||||
/*******************************************************
|
||||
* General purpose constants and macros.
|
||||
*******************************************************/
|
||||
#define UINT16_T_MAX 0xffff /* Maximum 16 bit unsigned. */
|
||||
#define UINT32_T_MAX 0xffffffff /* Maximum 32 bit unsigned. */
|
||||
|
||||
#define DB_MIN_PGSIZE 0x000200 /* Minimum page size. */
|
||||
#define DB_MAX_PGSIZE 0x010000 /* Maximum page size. */
|
||||
|
||||
#define DB_MINCACHE 10 /* Minimum cached pages */
|
||||
|
||||
#define MEGABYTE 1048576
|
||||
|
||||
/*
|
||||
* If we are unable to determine the underlying filesystem block size, use
|
||||
* 8K on the grounds that most OS's use less than 8K as their VM page size.
|
||||
*/
|
||||
#define DB_DEF_IOSIZE (8 * 1024)
|
||||
|
||||
/*
|
||||
* Aligning items to particular sizes or in pages or memory. ALIGNP is a
|
||||
* separate macro, as we've had to cast the pointer to different integral
|
||||
* types on different architectures.
|
||||
*
|
||||
* We cast pointers into unsigned longs when manipulating them because C89
|
||||
* guarantees that u_long is the largest available integral type and further,
|
||||
* to never generate overflows. However, neither C89 or C9X requires that
|
||||
* any integer type be large enough to hold a pointer, although C9X created
|
||||
* the intptr_t type, which is guaranteed to hold a pointer but may or may
|
||||
* not exist. At some point in the future, we should test for intptr_t and
|
||||
* use it where available.
|
||||
*/
|
||||
#undef ALIGNTYPE
|
||||
#define ALIGNTYPE u_long
|
||||
#undef ALIGNP
|
||||
#define ALIGNP(value, bound) ALIGN((ALIGNTYPE)value, bound)
|
||||
#undef ALIGN
|
||||
#define ALIGN(value, bound) (((value) + (bound) - 1) & ~((bound) - 1))
|
||||
|
||||
/*
|
||||
* There are several on-page structures that are declared to have a number of
|
||||
* fields followed by a variable length array of items. The structure size
|
||||
* without including the variable length array or the address of the first of
|
||||
* those elements can be found using SSZ.
|
||||
*
|
||||
* This macro can also be used to find the offset of a structure element in a
|
||||
* structure. This is used in various places to copy structure elements from
|
||||
* unaligned memory references, e.g., pointers into a packed page.
|
||||
*
|
||||
* There are two versions because compilers object if you take the address of
|
||||
* an array.
|
||||
*/
|
||||
#undef SSZ
|
||||
#define SSZ(name, field) ((int)&(((name *)0)->field))
|
||||
|
||||
#undef SSZA
|
||||
#define SSZA(name, field) ((int)&(((name *)0)->field[0]))
|
||||
|
||||
/* Macros to return per-process address, offsets based on shared regions. */
|
||||
#define R_ADDR(base, offset) ((void *)((u_int8_t *)((base)->addr) + offset))
|
||||
#define R_OFFSET(base, p) ((u_int8_t *)(p) - (u_int8_t *)(base)->addr)
|
||||
|
||||
/* Free and free-string macros that overwrite memory. */
|
||||
#ifdef DIAGNOSTIC
|
||||
#undef FREE
|
||||
#define FREE(p, len) { \
|
||||
memset(p, 0xff, len); \
|
||||
__db_free(p); \
|
||||
}
|
||||
#undef FREES
|
||||
#define FREES(p) { \
|
||||
FREE(p, strlen(p)); \
|
||||
}
|
||||
#else
|
||||
#undef FREE
|
||||
#define FREE(p, len) { \
|
||||
__db_free(p); \
|
||||
}
|
||||
#undef FREES
|
||||
#define FREES(p) { \
|
||||
__db_free(p); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Structure used to print flag values. */
|
||||
typedef struct __fn {
|
||||
u_int32_t mask; /* Flag value. */
|
||||
const char *name; /* Flag name. */
|
||||
} FN;
|
||||
|
||||
/* Set, clear and test flags. */
|
||||
#define F_SET(p, f) (p)->flags |= (f)
|
||||
#define F_CLR(p, f) (p)->flags &= ~(f)
|
||||
#define F_ISSET(p, f) ((p)->flags & (f))
|
||||
#define LF_SET(f) (flags |= (f))
|
||||
#define LF_CLR(f) (flags &= ~(f))
|
||||
#define LF_ISSET(f) (flags & (f))
|
||||
|
||||
/* Display separator string. */
|
||||
#undef DB_LINE
|
||||
#define DB_LINE "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
|
||||
|
||||
/* Global variables. */
|
||||
typedef struct __db_globals {
|
||||
int db_mutexlocks; /* DB_MUTEXLOCKS */
|
||||
int db_region_anon; /* DB_REGION_ANON, DB_REGION_NAME */
|
||||
int db_region_init; /* DB_REGION_INIT */
|
||||
int db_tsl_spins; /* DB_TSL_SPINS */
|
||||
int db_pageyield; /* DB_PAGEYIELD */
|
||||
} DB_GLOBALS;
|
||||
extern DB_GLOBALS __db_global_values;
|
||||
#define DB_GLOBAL(v) __db_global_values.v
|
||||
|
||||
/* Unused, or not-used-yet variable. "Shut that bloody compiler up!" */
|
||||
#define COMPQUIET(n, v) (n) = (v)
|
||||
|
||||
/*
|
||||
* Win16 needs specific syntax on callback functions. Nobody else cares.
|
||||
*/
|
||||
#ifndef DB_CALLBACK
|
||||
#define DB_CALLBACK /* Nothing. */
|
||||
#endif
|
||||
|
||||
/*******************************************************
|
||||
* Files.
|
||||
*******************************************************/
|
||||
/*
|
||||
* We use 1024 as the maximum path length. It's too hard to figure out what
|
||||
* the real path length is, as it was traditionally stored in <sys/param.h>,
|
||||
* and that file isn't always available.
|
||||
*/
|
||||
#undef MAXPATHLEN
|
||||
#define MAXPATHLEN 1024
|
||||
|
||||
#define PATH_DOT "." /* Current working directory. */
|
||||
#define PATH_SEPARATOR "/" /* Path separator character. */
|
||||
|
||||
/*******************************************************
|
||||
* Mutex support.
|
||||
*******************************************************/
|
||||
@spin_line1@
|
||||
@spin_line2@
|
||||
@spin_line3@
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Various systems require different alignments for mutexes (the worst we've
|
||||
* seen so far is 16-bytes on some HP architectures). The mutex (tsl_t) must
|
||||
* be first in the db_mutex_t structure, which must itself be first in the
|
||||
* region. This ensures the alignment is as returned by mmap(2), which should
|
||||
* be sufficient. All other mutex users must ensure proper alignment locally.
|
||||
*/
|
||||
#define MUTEX_ALIGNMENT @mutex_align@
|
||||
|
||||
/*
|
||||
* The offset of a mutex in memory.
|
||||
*
|
||||
* !!!
|
||||
* Not an off_t, so backing file offsets MUST be less than 4Gb. See the
|
||||
* off field of the db_mutex_t as well.
|
||||
*/
|
||||
#define MUTEX_LOCK_OFFSET(a, b) ((u_int32_t)((u_int8_t *)b - (u_int8_t *)a))
|
||||
|
||||
typedef struct _db_mutex_t {
|
||||
#ifdef HAVE_SPINLOCKS
|
||||
tsl_t tsl_resource; /* Resource test and set. */
|
||||
#ifdef DIAGNOSTIC
|
||||
u_int32_t pid; /* Lock holder: 0 or process pid. */
|
||||
#endif
|
||||
#else
|
||||
u_int32_t off; /* Backing file offset. */
|
||||
u_int32_t pid; /* Lock holder: 0 or process pid. */
|
||||
#endif
|
||||
u_int32_t spins; /* Spins before block. */
|
||||
u_int32_t mutex_set_wait; /* Granted after wait. */
|
||||
u_int32_t mutex_set_nowait; /* Granted without waiting. */
|
||||
} db_mutex_t;
|
||||
|
||||
#include "mutex_ext.h"
|
||||
|
||||
/*******************************************************
|
||||
* Access methods.
|
||||
*******************************************************/
|
||||
/* Lock/unlock a DB thread. */
|
||||
#define DB_THREAD_LOCK(dbp) \
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) \
|
||||
(void)__db_mutex_lock((db_mutex_t *)(dbp)->mutexp, -1);
|
||||
#define DB_THREAD_UNLOCK(dbp) \
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) \
|
||||
(void)__db_mutex_unlock((db_mutex_t *)(dbp)->mutexp, -1);
|
||||
|
||||
/* Btree/recno local statistics structure. */
|
||||
struct __db_bt_lstat; typedef struct __db_bt_lstat DB_BTREE_LSTAT;
|
||||
struct __db_bt_lstat {
|
||||
u_int32_t bt_freed; /* Pages freed for reuse. */
|
||||
u_int32_t bt_pfxsaved; /* Bytes saved by prefix compression. */
|
||||
u_int32_t bt_split; /* Total number of splits. */
|
||||
u_int32_t bt_rootsplit; /* Root page splits. */
|
||||
u_int32_t bt_fastsplit; /* Fast splits. */
|
||||
u_int32_t bt_added; /* Items added. */
|
||||
u_int32_t bt_deleted; /* Items deleted. */
|
||||
u_int32_t bt_get; /* Items retrieved. */
|
||||
u_int32_t bt_cache_hit; /* Hits in fast-insert code. */
|
||||
u_int32_t bt_cache_miss; /* Misses in fast-insert code. */
|
||||
};
|
||||
|
||||
/*******************************************************
|
||||
* Environment.
|
||||
*******************************************************/
|
||||
/* Type passed to __db_appname(). */
|
||||
typedef enum {
|
||||
DB_APP_NONE=0, /* No type (region). */
|
||||
DB_APP_DATA, /* Data file. */
|
||||
DB_APP_LOG, /* Log file. */
|
||||
DB_APP_TMP /* Temporary file. */
|
||||
} APPNAME;
|
||||
|
||||
/*******************************************************
|
||||
* Shared memory regions.
|
||||
*******************************************************/
|
||||
/*
|
||||
* The shared memory regions share an initial structure so that the general
|
||||
* region code can handle races between the region being deleted and other
|
||||
* processes waiting on the region mutex.
|
||||
*
|
||||
* !!!
|
||||
* Note, the mutex must be the first entry in the region; see comment above.
|
||||
*/
|
||||
typedef struct _rlayout {
|
||||
db_mutex_t lock; /* Region mutex. */
|
||||
#define DB_REGIONMAGIC 0x120897
|
||||
u_int32_t valid; /* Valid magic number. */
|
||||
u_int32_t refcnt; /* Region reference count. */
|
||||
size_t size; /* Region length. */
|
||||
int majver; /* Major version number. */
|
||||
int minver; /* Minor version number. */
|
||||
int patch; /* Patch version number. */
|
||||
#define INVALID_SEGID -1
|
||||
int segid; /* shmget(2) ID, or Win16 segment ID. */
|
||||
|
||||
#define REGION_ANONYMOUS 0x01 /* Region is/should be in anon mem. */
|
||||
u_int32_t flags;
|
||||
} RLAYOUT;
|
||||
|
||||
/*
|
||||
* DB creates all regions on 4K boundaries out of sheer paranoia, so that
|
||||
* we don't make the underlying VM unhappy.
|
||||
*/
|
||||
#define DB_VMPAGESIZE (4 * 1024)
|
||||
#define DB_ROUNDOFF(i) { \
|
||||
(i) += DB_VMPAGESIZE - 1; \
|
||||
(i) -= (i) % DB_VMPAGESIZE; \
|
||||
}
|
||||
|
||||
/*
|
||||
* The interface to region attach is nasty, there is a lot of complex stuff
|
||||
* going on, which has to be retained between create/attach and detach. The
|
||||
* REGINFO structure keeps track of it.
|
||||
*/
|
||||
struct __db_reginfo; typedef struct __db_reginfo REGINFO;
|
||||
struct __db_reginfo {
|
||||
/* Arguments. */
|
||||
DB_ENV *dbenv; /* Region naming info. */
|
||||
APPNAME appname; /* Region naming info. */
|
||||
char *path; /* Region naming info. */
|
||||
const char *file; /* Region naming info. */
|
||||
int mode; /* Region mode, if a file. */
|
||||
size_t size; /* Region size. */
|
||||
u_int32_t dbflags; /* Region file open flags, if a file. */
|
||||
|
||||
/* Results. */
|
||||
char *name; /* Region name. */
|
||||
void *addr; /* Region address. */
|
||||
int fd; /* Fcntl(2) locking file descriptor.
|
||||
NB: this is only valid if a regular
|
||||
file is backing the shared region,
|
||||
and mmap(2) is being used to map it
|
||||
into our address space. */
|
||||
int segid; /* shmget(2) ID, or Win16 segment ID. */
|
||||
|
||||
/* Shared flags. */
|
||||
/* 0x0001 COMMON MASK with RLAYOUT structure. */
|
||||
#define REGION_CANGROW 0x0002 /* Can grow. */
|
||||
#define REGION_CREATED 0x0004 /* Created. */
|
||||
#define REGION_HOLDINGSYS 0x0008 /* Holding system resources. */
|
||||
#define REGION_LASTDETACH 0x0010 /* Delete on last detach. */
|
||||
#define REGION_MALLOC 0x0020 /* Created in malloc'd memory. */
|
||||
#define REGION_PRIVATE 0x0040 /* Private to thread/process. */
|
||||
#define REGION_REMOVED 0x0080 /* Already deleted. */
|
||||
#define REGION_SIZEDEF 0x0100 /* Use default region size if exists. */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/*******************************************************
|
||||
* Mpool.
|
||||
*******************************************************/
|
||||
/*
|
||||
* File types for DB access methods. Negative numbers are reserved to DB.
|
||||
*/
|
||||
#define DB_FTYPE_BTREE -1 /* Btree. */
|
||||
#define DB_FTYPE_HASH -2 /* Hash. */
|
||||
|
||||
/* Structure used as the DB pgin/pgout pgcookie. */
|
||||
typedef struct __dbpginfo {
|
||||
size_t db_pagesize; /* Underlying page size. */
|
||||
int needswap; /* If swapping required. */
|
||||
} DB_PGINFO;
|
||||
|
||||
/*******************************************************
|
||||
* Log.
|
||||
*******************************************************/
|
||||
/* Initialize an LSN to 'zero'. */
|
||||
#define ZERO_LSN(LSN) { \
|
||||
(LSN).file = 0; \
|
||||
(LSN).offset = 0; \
|
||||
}
|
||||
|
||||
/* Return 1 if LSN is a 'zero' lsn, otherwise return 0. */
|
||||
#define IS_ZERO_LSN(LSN) ((LSN).file == 0)
|
||||
|
||||
/* Test if we need to log a change. */
|
||||
#define DB_LOGGING(dbp) \
|
||||
(F_ISSET(dbp, DB_AM_LOGGING) && !F_ISSET(dbp, DB_AM_RECOVER))
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* Debugging macro to log operations.
|
||||
* If DEBUG_WOP is defined, log operations that modify the database.
|
||||
* If DEBUG_ROP is defined, log operations that read the database.
|
||||
*
|
||||
* D dbp
|
||||
* T txn
|
||||
* O operation (string)
|
||||
* K key
|
||||
* A data
|
||||
* F flags
|
||||
*/
|
||||
#define LOG_OP(D, T, O, K, A, F) { \
|
||||
DB_LSN _lsn; \
|
||||
DBT _op; \
|
||||
if (DB_LOGGING((D))) { \
|
||||
memset(&_op, 0, sizeof(_op)); \
|
||||
_op.data = O; \
|
||||
_op.size = strlen(O) + 1; \
|
||||
(void)__db_debug_log((D)->dbenv->lg_info, \
|
||||
T, &_lsn, 0, &_op, (D)->log_fileid, K, A, F); \
|
||||
} \
|
||||
}
|
||||
#ifdef DEBUG_ROP
|
||||
#define DEBUG_LREAD(D, T, O, K, A, F) LOG_OP(D, T, O, K, A, F)
|
||||
#else
|
||||
#define DEBUG_LREAD(D, T, O, K, A, F)
|
||||
#endif
|
||||
#ifdef DEBUG_WOP
|
||||
#define DEBUG_LWRITE(D, T, O, K, A, F) LOG_OP(D, T, O, K, A, F)
|
||||
#else
|
||||
#define DEBUG_LWRITE(D, T, O, K, A, F)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_LREAD(D, T, O, K, A, F)
|
||||
#define DEBUG_LWRITE(D, T, O, K, A, F)
|
||||
#endif /* DIAGNOSTIC */
|
||||
|
||||
/*******************************************************
|
||||
* Transactions and recovery.
|
||||
*******************************************************/
|
||||
/*
|
||||
* Out of band value for a lock. The locks are returned to callers as offsets
|
||||
* into the lock regions. Since the RLAYOUT structure begins all regions, an
|
||||
* offset of 0 is guaranteed not to be a valid lock.
|
||||
*/
|
||||
#define LOCK_INVALID 0
|
||||
|
||||
/* The structure allocated for every transaction. */
|
||||
struct __db_txn {
|
||||
DB_TXNMGR *mgrp; /* Pointer to transaction manager. */
|
||||
DB_TXN *parent; /* Pointer to transaction's parent. */
|
||||
DB_LSN last_lsn; /* Lsn of last log write. */
|
||||
u_int32_t txnid; /* Unique transaction id. */
|
||||
size_t off; /* Detail structure within region. */
|
||||
TAILQ_ENTRY(__db_txn) links;
|
||||
};
|
||||
|
||||
#include "os_func.h"
|
||||
#include "os_ext.h"
|
||||
|
||||
#endif /* !_DB_INTERNAL_H_ */
|
23
db2/include/db_join.h
Normal file
23
db2/include/db_join.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db_join.h 10.2 (Sleepycat) 10/4/98
|
||||
*/
|
||||
|
||||
#ifndef _DB_JOIN_H
|
||||
#define _DB_JOIN_H
|
||||
/*
|
||||
* Joins use a join cursor that is similar to a regular DB cursor except
|
||||
* that it only supports c_get and c_close functionality. Also, it does
|
||||
* not support the full range of flags for get.
|
||||
*/
|
||||
typedef struct __join_cursor {
|
||||
u_int32_t j_init; /* Set when cursor is initialized. */
|
||||
DBC **j_curslist; /* Array of cursors in the join. */
|
||||
DB *j_primary; /* Primary dbp. */
|
||||
DBT j_key; /* Used to do lookups. */
|
||||
} JOIN_CURSOR;
|
||||
#endif
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)db_page.h 10.15 (Sleepycat) 5/1/98
|
||||
* @(#)db_page.h 10.18 (Sleepycat) 12/2/98
|
||||
*/
|
||||
|
||||
#ifndef _DB_PAGE_H_
|
||||
@ -43,14 +43,6 @@
|
||||
|
||||
/*
|
||||
* Btree metadata page layout:
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | lsn | pgno | magic |
|
||||
* +-----------------------------------+
|
||||
* | version | pagesize | free |
|
||||
* +-----------------------------------+
|
||||
* | flags | unused ... |
|
||||
* +-----------------------------------+
|
||||
*/
|
||||
typedef struct _btmeta {
|
||||
DB_LSN lsn; /* 00-07: LSN. */
|
||||
@ -72,10 +64,6 @@ typedef struct _btmeta {
|
||||
u_int32_t re_pad; /* 44-47: Recno: fixed-length record pad. */
|
||||
/* 48-67: Unique file ID. */
|
||||
u_int8_t uid[DB_FILE_ID_LEN];
|
||||
|
||||
u_int32_t spare[13]; /* 68-123: Save some room for growth. */
|
||||
|
||||
DB_BTREE_LSTAT stat; /* 124-163: Statistics. */
|
||||
} BTMETA;
|
||||
|
||||
/************************************************************************
|
||||
@ -84,18 +72,6 @@ typedef struct _btmeta {
|
||||
|
||||
/*
|
||||
* Hash metadata page layout:
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | lsn | magic | version |
|
||||
* +-----------------------------------+
|
||||
* | pagesize | ovfl_point| last_freed|
|
||||
* +-----------------------------------+
|
||||
* | max_bucket| high_mask | low_mask |
|
||||
* +-----------------------------------+
|
||||
* | ffactor | nelem | charkey |
|
||||
* +-----------------------------------+
|
||||
* | spares[32]| flags | unused |
|
||||
* +-----------------------------------+
|
||||
*/
|
||||
/* Hash Table Information */
|
||||
typedef struct hashhdr { /* Disk resident portion */
|
||||
@ -359,10 +335,6 @@ typedef struct _hkeydata {
|
||||
|
||||
/*
|
||||
* The third type is the H_OFFPAGE, represented by the HOFFPAGE structure:
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | type | pgno_t | total len |
|
||||
* +-----------------------------------+
|
||||
*/
|
||||
typedef struct _hoffpage {
|
||||
u_int8_t type; /* 00: Page type and delete flag. */
|
||||
@ -383,10 +355,6 @@ typedef struct _hoffpage {
|
||||
|
||||
/*
|
||||
* The fourth type is H_OFFDUP represented by the HOFFDUP structure:
|
||||
*
|
||||
* +-----------------------+
|
||||
* | type | pgno_t |
|
||||
* +-----------------------+
|
||||
*/
|
||||
typedef struct _hoffdup {
|
||||
u_int8_t type; /* 00: Page type and delete flag. */
|
||||
@ -431,10 +399,6 @@ typedef struct _hoffdup {
|
||||
|
||||
/*
|
||||
* The first type is B_KEYDATA, represented by the BKEYDATA structure:
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | length | type | key/data |
|
||||
* +-----------------------------------+
|
||||
*/
|
||||
typedef struct _bkeydata {
|
||||
db_indx_t len; /* 00-01: Key/data item length. */
|
||||
@ -457,13 +421,7 @@ typedef struct _bkeydata {
|
||||
|
||||
/*
|
||||
* The second and third types are B_DUPLICATE and B_OVERFLOW, represented
|
||||
* by the BOVERFLOW structure:
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | total len | type | unused |
|
||||
* +-----------------------------------+
|
||||
* | nxt: page | nxt: off | nxt: len |
|
||||
* +-----------------------------------+
|
||||
* by the BOVERFLOW structure.
|
||||
*/
|
||||
typedef struct _boverflow {
|
||||
db_indx_t unused1; /* 00-01: Padding, unused. */
|
||||
@ -501,10 +459,6 @@ typedef struct _boverflow {
|
||||
|
||||
/*
|
||||
* Btree internal entry.
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | leaf pgno | type | data ... |
|
||||
* +-----------------------------------+
|
||||
*/
|
||||
typedef struct _binternal {
|
||||
db_indx_t len; /* 00-01: Key/data item length. */
|
||||
@ -535,12 +489,8 @@ typedef struct _binternal {
|
||||
/*
|
||||
* The recno internal entry.
|
||||
*
|
||||
* +-----------------------+
|
||||
* | leaf pgno | # of recs |
|
||||
* +-----------------------+
|
||||
*
|
||||
* XXX
|
||||
* Why not fold this into the db_indx_t structure, it's fixed length.
|
||||
* Why not fold this into the db_indx_t structure, it's fixed length?
|
||||
*/
|
||||
typedef struct _rinternal {
|
||||
db_pgno_t pgno; /* 00-03: Page number of referenced page. */
|
||||
|
@ -43,13 +43,22 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)hash.h 10.8 (Sleepycat) 4/10/98
|
||||
* @(#)hash.h 10.14 (Sleepycat) 10/4/98
|
||||
*/
|
||||
|
||||
/* Cursor structure definitions. */
|
||||
typedef struct cursor_t {
|
||||
DBC *db_cursor;
|
||||
DBC *dbc;
|
||||
|
||||
/* Per-thread information */
|
||||
DB_LOCK hlock; /* Metadata page lock. */
|
||||
HASHHDR *hdr; /* Pointer to meta-data page. */
|
||||
PAGE *split_buf; /* Temporary buffer for splits. */
|
||||
struct __db_h_stat stats; /* Hash statistics. */
|
||||
|
||||
/* Hash cursor information */
|
||||
db_pgno_t bucket; /* Bucket we are traversing. */
|
||||
db_pgno_t lbucket; /* Bucket for which we are locked. */
|
||||
DB_LOCK lock; /* Lock held on the current bucket. */
|
||||
PAGE *pagep; /* The current page. */
|
||||
db_pgno_t pgno; /* Current page number. */
|
||||
@ -62,104 +71,83 @@ typedef struct cursor_t {
|
||||
db_indx_t dup_tlen; /* Total length of duplicate entry. */
|
||||
u_int32_t seek_size; /* Number of bytes we need for add. */
|
||||
db_pgno_t seek_found_page;/* Page on which we can insert. */
|
||||
u_int32_t big_keylen; /* Length of big_key buffer. */
|
||||
void *big_key; /* Temporary buffer for big keys. */
|
||||
u_int32_t big_datalen; /* Length of big_data buffer. */
|
||||
void *big_data; /* Temporary buffer for big data. */
|
||||
#define H_OK 0x0001
|
||||
#define H_NOMORE 0x0002
|
||||
#define H_DELETED 0x0004
|
||||
#define H_ISDUP 0x0008
|
||||
#define H_EXPAND 0x0020
|
||||
u_int32_t flags; /* Is cursor inside a dup set. */
|
||||
|
||||
#define H_DELETED 0x0001 /* Cursor item is deleted. */
|
||||
#define H_DUPONLY 0x0002 /* Dups only; do not change key. */
|
||||
#define H_EXPAND 0x0004 /* Table expanded. */
|
||||
#define H_ISDUP 0x0008 /* Cursor is within duplicate set. */
|
||||
#define H_NOMORE 0x0010 /* No more entries in bucket. */
|
||||
#define H_OK 0x0020 /* Request succeeded. */
|
||||
#define H_DIRTY 0x0040 /* Meta-data page needs to be written */
|
||||
#define H_ORIGINAL 0x0080 /* Bucket lock existed on entry. */
|
||||
u_int32_t flags;
|
||||
} HASH_CURSOR;
|
||||
|
||||
#define IS_VALID(C) ((C)->bucket != BUCKET_INVALID)
|
||||
|
||||
#define SAVE_CURSOR(ORIG, COPY) { \
|
||||
F_SET((ORIG), H_ORIGINAL); \
|
||||
*(COPY) = *(ORIG); \
|
||||
}
|
||||
|
||||
typedef struct htab { /* Memory resident data structure. */
|
||||
DB *dbp; /* Pointer to parent db structure. */
|
||||
DB_LOCK hlock; /* Metadata page lock. */
|
||||
HASHHDR *hdr; /* Pointer to meta-data page. */
|
||||
u_int32_t (*hash) __P((const void *, u_int32_t)); /* Hash Function */
|
||||
PAGE *split_buf; /* Temporary buffer for splits. */
|
||||
int local_errno; /* Error Number -- for DBM compatability */
|
||||
u_long hash_accesses; /* Number of accesses to this table. */
|
||||
u_long hash_collisions; /* Number of collisions on search. */
|
||||
u_long hash_expansions; /* Number of times we added a bucket. */
|
||||
u_long hash_overflows; /* Number of overflow pages. */
|
||||
u_long hash_bigpages; /* Number of big key/data pages. */
|
||||
} HTAB;
|
||||
|
||||
/*
|
||||
* Macro used for interface functions to set the txnid in the DBP.
|
||||
*/
|
||||
#define SET_LOCKER(D, T) ((D)->txn = (T))
|
||||
#define RESTORE_CURSOR(D, ORIG, COPY, RET) { \
|
||||
if ((RET) == 0) { \
|
||||
if ((ORIG)->dbc->txn == NULL && \
|
||||
(COPY)->lock != 0 && (ORIG)->lock != (COPY)->lock) \
|
||||
(void)lock_put((D)->dbenv->lk_info, (COPY)->lock); \
|
||||
} else { \
|
||||
if ((ORIG)->dbc->txn == NULL && \
|
||||
(ORIG)->lock != 0 && (ORIG)->lock != (COPY)->lock) \
|
||||
(void)lock_put((D)->dbenv->lk_info, (ORIG)->lock); \
|
||||
*ORIG = *COPY; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* More interface macros used to get/release the meta data page.
|
||||
*/
|
||||
#define GET_META(D, H) { \
|
||||
int _r; \
|
||||
if (F_ISSET(D, DB_AM_LOCKING) && !F_ISSET(D, DB_AM_RECOVER)) { \
|
||||
(D)->lock.pgno = BUCKET_INVALID; \
|
||||
if ((_r = lock_get((D)->dbenv->lk_info, \
|
||||
(D)->txn == NULL ? (D)->locker : (D)->txn->txnid, \
|
||||
0, &(D)->lock_dbt, DB_LOCK_READ, \
|
||||
&(H)->hlock)) != 0) \
|
||||
return (_r < 0 ? EAGAIN : _r); \
|
||||
#define GET_META(D, I, R) { \
|
||||
if (F_ISSET(D, DB_AM_LOCKING) && \
|
||||
!F_ISSET((I)->dbc, DBC_RECOVER)) { \
|
||||
(I)->dbc->lock.pgno = BUCKET_INVALID; \
|
||||
(R) = lock_get((D)->dbenv->lk_info, (I)->dbc->locker, \
|
||||
0, &(I)->dbc->lock_dbt, DB_LOCK_READ, &(I)->hlock); \
|
||||
(R) = (R) < 0 ? EAGAIN : (R); \
|
||||
} \
|
||||
if ((_r = __ham_get_page(D, 0, (PAGE **)&((H)->hdr))) != 0) { \
|
||||
if ((H)->hlock) { \
|
||||
(void)lock_put((D)->dbenv->lk_info, (H)->hlock);\
|
||||
(H)->hlock = 0; \
|
||||
} \
|
||||
return (_r); \
|
||||
if ((R) == 0 && \
|
||||
((R) = __ham_get_page(D, 0, (PAGE **)&((I)->hdr))) != 0 && \
|
||||
(I)->hlock != LOCK_INVALID) { \
|
||||
(void)lock_put((D)->dbenv->lk_info, (I)->hlock); \
|
||||
(I)->hlock = LOCK_INVALID; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define RELEASE_META(D, H) { \
|
||||
if (!F_ISSET(D, DB_AM_RECOVER) && \
|
||||
(D)->txn == NULL && (H)->hlock) \
|
||||
(void)lock_put((H)->dbp->dbenv->lk_info, (H)->hlock); \
|
||||
(H)->hlock = 0; \
|
||||
if ((H)->hdr) \
|
||||
(void)__ham_put_page(D, (PAGE *)(H)->hdr, \
|
||||
F_ISSET(D, DB_HS_DIRTYMETA) ? 1 : 0); \
|
||||
(H)->hdr = NULL; \
|
||||
F_CLR(D, DB_HS_DIRTYMETA); \
|
||||
#define RELEASE_META(D, I) { \
|
||||
if ((I)->hdr) \
|
||||
(void)__ham_put_page(D, (PAGE *)(I)->hdr, \
|
||||
F_ISSET(I, H_DIRTY) ? 1 : 0); \
|
||||
(I)->hdr = NULL; \
|
||||
if (!F_ISSET((I)->dbc, DBC_RECOVER) && \
|
||||
(I)->dbc->txn == NULL && (I)->hlock) \
|
||||
(void)lock_put((D)->dbenv->lk_info, (I)->hlock); \
|
||||
(I)->hlock = LOCK_INVALID; \
|
||||
F_CLR(I, H_DIRTY); \
|
||||
}
|
||||
|
||||
#define DIRTY_META(H, R) { \
|
||||
if (F_ISSET((H)->dbp, DB_AM_LOCKING) && \
|
||||
!F_ISSET((H)->dbp, DB_AM_RECOVER)) { \
|
||||
#define DIRTY_META(D, I, R) { \
|
||||
if (F_ISSET(D, DB_AM_LOCKING) && \
|
||||
!F_ISSET((I)->dbc, DBC_RECOVER)) { \
|
||||
DB_LOCK _tmp; \
|
||||
(H)->dbp->lock.pgno = BUCKET_INVALID; \
|
||||
if (((R) = lock_get((H)->dbp->dbenv->lk_info, \
|
||||
(H)->dbp->txn ? (H)->dbp->txn->txnid : \
|
||||
(H)->dbp->locker, 0, &(H)->dbp->lock_dbt, \
|
||||
(I)->dbc->lock.pgno = BUCKET_INVALID; \
|
||||
if (((R) = lock_get((D)->dbenv->lk_info, \
|
||||
(I)->dbc->locker, 0, &(I)->dbc->lock_dbt, \
|
||||
DB_LOCK_WRITE, &_tmp)) == 0) \
|
||||
(R) = lock_put((H)->dbp->dbenv->lk_info, \
|
||||
(H)->hlock); \
|
||||
(R) = lock_put((D)->dbenv->lk_info, (I)->hlock);\
|
||||
else if ((R) < 0) \
|
||||
(R) = EAGAIN; \
|
||||
(H)->hlock = _tmp; \
|
||||
(I)->hlock = _tmp; \
|
||||
} \
|
||||
F_SET((H)->dbp, DB_HS_DIRTYMETA); \
|
||||
}
|
||||
|
||||
/* Allocate and discard thread structures. */
|
||||
#define H_GETHANDLE(dbp, dbpp, ret) \
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) \
|
||||
ret = __db_gethandle(dbp, __ham_hdup, dbpp); \
|
||||
else { \
|
||||
ret = 0; \
|
||||
*dbpp = dbp; \
|
||||
}
|
||||
|
||||
#define H_PUTHANDLE(dbp) { \
|
||||
if (F_ISSET(dbp, DB_AM_THREAD)) \
|
||||
__db_puthandle(dbp); \
|
||||
F_SET((I), H_DIRTY); \
|
||||
}
|
||||
|
||||
/* Test string. */
|
||||
@ -171,16 +159,16 @@ typedef struct htab { /* Memory resident data structure. */
|
||||
* the table, we can allocate extra pages. We keep track of how many pages
|
||||
* we've allocated at each point to calculate bucket to page number mapping.
|
||||
*/
|
||||
#define BUCKET_TO_PAGE(H, B) \
|
||||
((B) + 1 + ((B) ? (H)->hdr->spares[__db_log2((B)+1)-1] : 0))
|
||||
#define BUCKET_TO_PAGE(I, B) \
|
||||
((B) + 1 + ((B) ? (I)->hdr->spares[__db_log2((B)+1)-1] : 0))
|
||||
|
||||
#define PGNO_OF(H, S, O) (BUCKET_TO_PAGE((H), (1 << (S)) - 1) + (O))
|
||||
#define PGNO_OF(I, S, O) (BUCKET_TO_PAGE((I), (1 << (S)) - 1) + (O))
|
||||
|
||||
/* Constraints about number of pages and how much data goes on a page. */
|
||||
|
||||
#define MAX_PAGES(H) UINT32_T_MAX
|
||||
#define MINFILL 4
|
||||
#define ISBIG(H, N) (((N) > ((H)->hdr->pagesize / MINFILL)) ? 1 : 0)
|
||||
#define ISBIG(I, N) (((N) > ((I)->hdr->pagesize / MINFILL)) ? 1 : 0)
|
||||
|
||||
/* Shorthands for accessing structure */
|
||||
#define NDX_INVALID 0xFFFF
|
||||
|
@ -3,13 +3,11 @@
|
||||
#define _hash_ext_h_
|
||||
int __ham_open __P((DB *, DB_INFO *));
|
||||
int __ham_close __P((DB *));
|
||||
int __ham_c_iclose __P((DB *, DBC *));
|
||||
int __ham_expand_table __P((HTAB *));
|
||||
u_int32_t __ham_call_hash __P((HTAB *, u_int8_t *, int32_t));
|
||||
int __ham_c_init __P((DBC *));
|
||||
u_int32_t __ham_call_hash __P((HASH_CURSOR *, u_int8_t *, int32_t));
|
||||
int __ham_init_dbt __P((DBT *, u_int32_t, void **, u_int32_t *));
|
||||
void __ham_c_update
|
||||
__P((HASH_CURSOR *, db_pgno_t, u_int32_t, int, int));
|
||||
int __ham_hdup __P((DB *, DB *));
|
||||
int __ham_insdel_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, u_int32_t, db_pgno_t, u_int32_t,
|
||||
@ -72,48 +70,45 @@ int __ham_init_recover __P((DB_ENV *));
|
||||
int __ham_pgin __P((db_pgno_t, void *, DBT *));
|
||||
int __ham_pgout __P((db_pgno_t, void *, DBT *));
|
||||
int __ham_mswap __P((void *));
|
||||
#ifdef DEBUG
|
||||
void __ham_dump_bucket __P((HTAB *, u_int32_t));
|
||||
#endif
|
||||
int __ham_add_dup __P((HTAB *, HASH_CURSOR *, DBT *, u_int32_t));
|
||||
void __ham_move_offpage __P((HTAB *, PAGE *, u_int32_t, db_pgno_t));
|
||||
int __ham_add_dup __P((DBC *, DBT *, u_int32_t));
|
||||
void __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t));
|
||||
void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *));
|
||||
u_int32_t __ham_func2 __P((const void *, u_int32_t));
|
||||
u_int32_t __ham_func3 __P((const void *, u_int32_t));
|
||||
u_int32_t __ham_func4 __P((const void *, u_int32_t));
|
||||
u_int32_t __ham_func5 __P((const void *, u_int32_t));
|
||||
int __ham_item __P((HTAB *, HASH_CURSOR *, db_lockmode_t));
|
||||
int __ham_item_reset __P((HTAB *, HASH_CURSOR *));
|
||||
int __ham_item __P((DBC *, db_lockmode_t));
|
||||
int __ham_item_reset __P((DBC *));
|
||||
void __ham_item_init __P((HASH_CURSOR *));
|
||||
int __ham_item_done __P((HTAB *, HASH_CURSOR *, int));
|
||||
int __ham_item_last __P((HTAB *, HASH_CURSOR *, db_lockmode_t));
|
||||
int __ham_item_first __P((HTAB *, HASH_CURSOR *, db_lockmode_t));
|
||||
int __ham_item_prev __P((HTAB *, HASH_CURSOR *, db_lockmode_t));
|
||||
int __ham_item_next __P((HTAB *, HASH_CURSOR *, db_lockmode_t));
|
||||
int __ham_item_done __P((DBC *, int));
|
||||
int __ham_item_last __P((DBC *, db_lockmode_t));
|
||||
int __ham_item_first __P((DBC *, db_lockmode_t));
|
||||
int __ham_item_prev __P((DBC *, db_lockmode_t));
|
||||
int __ham_item_next __P((DBC *, db_lockmode_t));
|
||||
void __ham_putitem __P((PAGE *p, const DBT *, int));
|
||||
void __ham_reputpair
|
||||
__P((PAGE *p, u_int32_t, u_int32_t, const DBT *, const DBT *));
|
||||
int __ham_del_pair __P((HTAB *, HASH_CURSOR *, int));
|
||||
int __ham_replpair __P((HTAB *, HASH_CURSOR *, DBT *, u_int32_t));
|
||||
int __ham_del_pair __P((DBC *, int));
|
||||
int __ham_replpair __P((DBC *, DBT *, u_int32_t));
|
||||
void __ham_onpage_replace __P((PAGE *, size_t, u_int32_t, int32_t,
|
||||
int32_t, DBT *));
|
||||
int __ham_split_page __P((HTAB *, u_int32_t, u_int32_t));
|
||||
int __ham_add_el
|
||||
__P((HTAB *, HASH_CURSOR *, const DBT *, const DBT *, int));
|
||||
void __ham_copy_item __P((HTAB *, PAGE *, u_int32_t, PAGE *));
|
||||
int __ham_add_ovflpage __P((HTAB *, PAGE *, int, PAGE **));
|
||||
int __ham_new_page __P((HTAB *, u_int32_t, u_int32_t, PAGE **));
|
||||
int __ham_del_page __P((DB *, PAGE *));
|
||||
int __ham_split_page __P((DBC *, u_int32_t, u_int32_t));
|
||||
int __ham_add_el __P((DBC *, const DBT *, const DBT *, int));
|
||||
void __ham_copy_item __P((size_t, PAGE *, u_int32_t, PAGE *));
|
||||
int __ham_add_ovflpage __P((DBC *, PAGE *, int, PAGE **));
|
||||
int __ham_new_page __P((DB *, u_int32_t, u_int32_t, PAGE **));
|
||||
int __ham_del_page __P((DBC *, PAGE *));
|
||||
int __ham_put_page __P((DB *, PAGE *, int32_t));
|
||||
int __ham_dirty_page __P((HTAB *, PAGE *));
|
||||
int __ham_dirty_page __P((DB *, PAGE *));
|
||||
int __ham_get_page __P((DB *, db_pgno_t, PAGE **));
|
||||
int __ham_overflow_page __P((DB *, u_int32_t, PAGE **));
|
||||
int __ham_overflow_page
|
||||
__P((DBC *, u_int32_t, PAGE **));
|
||||
#ifdef DEBUG
|
||||
db_pgno_t __bucket_to_page __P((HTAB *, db_pgno_t));
|
||||
db_pgno_t __bucket_to_page __P((HASH_CURSOR *, db_pgno_t));
|
||||
#endif
|
||||
void __ham_init_ovflpages __P((HTAB *));
|
||||
int __ham_get_cpage __P((HTAB *, HASH_CURSOR *, db_lockmode_t));
|
||||
int __ham_next_cpage
|
||||
__P((HTAB *, HASH_CURSOR *, db_pgno_t, int, u_int32_t));
|
||||
void __ham_init_ovflpages __P((DBC *));
|
||||
int __ham_get_cpage __P((DBC *, db_lockmode_t));
|
||||
int __ham_next_cpage __P((DBC *, db_pgno_t, int, u_int32_t));
|
||||
void __ham_dpair __P((DB *, PAGE *, u_int32_t));
|
||||
int __ham_insdel_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
@ -131,5 +126,5 @@ int __ham_ovfl_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __ham_copypage_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __ham_stat __P((DB *, FILE *));
|
||||
int __ham_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
|
||||
#endif /* _hash_ext_h_ */
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)lock.h 10.15 (Sleepycat) 5/10/98
|
||||
* @(#)lock.h 10.17 (Sleepycat) 1/3/99
|
||||
*/
|
||||
|
||||
typedef struct __db_lockobj DB_LOCKOBJ;
|
||||
@ -22,6 +22,12 @@ typedef struct __db_lockobj DB_LOCKOBJ;
|
||||
*/
|
||||
#define DB_LOCK_MAXID 0x7fffffff
|
||||
|
||||
/* Check for region catastrophic shutdown. */
|
||||
#define LOCK_PANIC_CHECK(lt) { \
|
||||
if ((lt)->region->hdr.panic) \
|
||||
return (DB_RUNRECOVERY); \
|
||||
}
|
||||
|
||||
/*
|
||||
* The lock region consists of:
|
||||
* The DB_LOCKREGION structure (sizeof(DB_LOCKREGION)).
|
||||
@ -135,9 +141,23 @@ struct __db_lock {
|
||||
u_int32_t refcount; /* Reference count the lock. */
|
||||
db_lockmode_t mode; /* What sort of lock. */
|
||||
ssize_t obj; /* Relative offset of object struct. */
|
||||
size_t txnoff; /* Offset of holding transaction. */
|
||||
db_status_t status; /* Status of this lock. */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a serious layering violation. To support nested transactions, we
|
||||
* need to be able to tell that a lock is held by a transaction (as opposed to
|
||||
* some other locker) and to be able to traverse the parent/descendent chain.
|
||||
* In order to do this, each lock held by a transaction maintains a reference
|
||||
* to the shared memory transaction structure so it can be accessed during lock
|
||||
* promotion. As the structure is in shared memory, we cannot store a pointer
|
||||
* to it, so we use the offset within the region. As nothing lives at region
|
||||
* offset 0, we use that to indicate that there is no transaction associated
|
||||
* with the current lock.
|
||||
*/
|
||||
#define TXN_IS_HOLDING(L) ((L)->txnoff != 0 /* INVALID_REG_OFFSET */)
|
||||
|
||||
/*
|
||||
* We cannot return pointers to the user (else we cannot easily grow regions),
|
||||
* so we return offsets in the region. These must be converted to and from
|
||||
|
@ -6,6 +6,9 @@ int __lock_is_locked
|
||||
void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int));
|
||||
int __lock_getobj __P((DB_LOCKTAB *,
|
||||
u_int32_t, const DBT *, u_int32_t type, DB_LOCKOBJ **));
|
||||
int __lock_downgrade __P((DB_LOCKTAB *,
|
||||
DB_LOCK, db_lockmode_t, u_int32_t));
|
||||
void __lock_panic __P((DB_ENV *));
|
||||
int __lock_validate_region __P((DB_LOCKTAB *));
|
||||
int __lock_grow_region __P((DB_LOCKTAB *, int, size_t));
|
||||
void __lock_dump_region __P((DB_LOCKTAB *, char *, FILE *));
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)log.h 10.25 (Sleepycat) 4/10/98
|
||||
* @(#)log.h 10.30 (Sleepycat) 10/11/98
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H_
|
||||
@ -16,8 +16,10 @@ struct __log; typedef struct __log LOG;
|
||||
struct __log_persist; typedef struct __log_persist LOGP;
|
||||
|
||||
#ifndef MAXLFNAME
|
||||
#define MAXLFNAME 99999 /* Maximum log file name. */
|
||||
#define LFNAME "log.%05d" /* Log file name template. */
|
||||
#define LFPREFIX "log." /* Log file name prefix. */
|
||||
#define LFNAME "log.%010d" /* Log file name template. */
|
||||
#define LFNAME_V1 "log.%05d" /* Log file name template, rev 1. */
|
||||
#define MAXLFNAME 2000000000 /* Maximum log file name. */
|
||||
#endif
|
||||
/* Default log name. */
|
||||
#define DB_DEFAULT_LOG_FILE "__db_log.share"
|
||||
@ -38,6 +40,12 @@ struct __log_persist; typedef struct __log_persist LOGP;
|
||||
(void)__db_mutex_unlock(&((RLAYOUT *)(dblp)->lp)->lock, \
|
||||
(dblp)->reginfo.fd)
|
||||
|
||||
/* Check for region catastrophic shutdown. */
|
||||
#define LOG_PANIC_CHECK(dblp) { \
|
||||
if ((dblp)->lp->rlayout.panic) \
|
||||
return (DB_RUNRECOVERY); \
|
||||
}
|
||||
|
||||
/*
|
||||
* The per-process table that maps log file-id's to DB structures.
|
||||
*/
|
||||
@ -84,7 +92,28 @@ struct __db_log {
|
||||
|
||||
char *dir; /* Directory argument. */
|
||||
|
||||
u_int32_t flags; /* Support the DB_AM_XXX flags. */
|
||||
/*
|
||||
* These fields are used by XA; since XA forbids threaded execution, these
|
||||
* do not have to be protected.
|
||||
*/
|
||||
void *xa_info; /* Committed transaction list that
|
||||
* has to be carried between calls
|
||||
* to xa_recover. */
|
||||
DB_LSN xa_lsn; /* Position of an XA recovery scan. */
|
||||
DB_LSN xa_first; /* LSN to which we need to roll back
|
||||
for this XA recovery scan. */
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Currently used to hold:
|
||||
* DB_AM_THREAD (a DB flag)
|
||||
* DBC_RECOVER (a DBC flag)
|
||||
* If they are ever the same bits, we're in serious trouble.
|
||||
*/
|
||||
#if DB_AM_THREAD == DBC_RECOVER
|
||||
DB_AM_THREAD, DBC_RECOVER, FLAG MISMATCH
|
||||
#endif
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1,8 +1,9 @@
|
||||
/* DO NOT EDIT: automatically built by dist/distrib. */
|
||||
#ifndef _log_ext_h_
|
||||
#define _log_ext_h_
|
||||
void __log_panic __P((DB_ENV *));
|
||||
int __log_find __P((DB_LOG *, int, int *));
|
||||
int __log_valid __P((DB_LOG *, LOG *, int));
|
||||
int __log_valid __P((DB_LOG *, u_int32_t, int));
|
||||
int __log_register_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, const DBT *, const DBT *, u_int32_t,
|
||||
@ -15,7 +16,7 @@ int __log_init_recover __P((DB_ENV *));
|
||||
int __log_findckp __P((DB_LOG *, DB_LSN *));
|
||||
int __log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t, int));
|
||||
int __log_put __P((DB_LOG *, DB_LSN *, const DBT *, u_int32_t));
|
||||
int __log_name __P((DB_LOG *, int, char **));
|
||||
int __log_name __P((DB_LOG *, u_int32_t, char **, int *, u_int32_t));
|
||||
int __log_register_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __log_add_logid __P((DB_LOG *, DB *, u_int32_t));
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)mp.h 10.33 (Sleepycat) 5/4/98
|
||||
* @(#)mp.h 10.37 (Sleepycat) 1/1/99
|
||||
*/
|
||||
|
||||
struct __bh; typedef struct __bh BH;
|
||||
@ -16,11 +16,11 @@ struct __mpoolfile; typedef struct __mpoolfile MPOOLFILE;
|
||||
#define DB_DEFAULT_MPOOL_FILE "__db_mpool.share"
|
||||
|
||||
/*
|
||||
* We default to 128K (16 8K pages) if the user doesn't specify, and
|
||||
* We default to 256K (32 8K pages) if the user doesn't specify, and
|
||||
* require a minimum of 20K.
|
||||
*/
|
||||
#ifndef DB_CACHESIZE_DEF
|
||||
#define DB_CACHESIZE_DEF (128 * 1024)
|
||||
#define DB_CACHESIZE_DEF (256 * 1024)
|
||||
#endif
|
||||
#define DB_CACHESIZE_MIN ( 20 * 1024)
|
||||
|
||||
@ -106,6 +106,12 @@ struct __mpoolfile; typedef struct __mpoolfile MPOOLFILE;
|
||||
if (F_ISSET(dbmp, MP_LOCKREGION)) \
|
||||
(void)__db_mutex_unlock(&(bhp)->mutex, (dbmp)->reginfo.fd)
|
||||
|
||||
/* Check for region catastrophic shutdown. */
|
||||
#define MP_PANIC_CHECK(dbmp) { \
|
||||
if ((dbmp)->mp->rlayout.panic) \
|
||||
return (DB_RUNRECOVERY); \
|
||||
}
|
||||
|
||||
/*
|
||||
* DB_MPOOL --
|
||||
* Per-process memory pool structure.
|
||||
@ -158,6 +164,18 @@ struct __db_mpoolfile {
|
||||
|
||||
int fd; /* Underlying file descriptor. */
|
||||
|
||||
u_int32_t ref; /* Reference count. */
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* This field is a special case -- it's protected by the region lock
|
||||
* NOT the thread lock. The reason for this is that we always have
|
||||
* the region lock immediately before or after we modify the field,
|
||||
* and we don't want to use the structure lock to protect it because
|
||||
* then I/O (which is done with the structure lock held because of
|
||||
* the race between the seek and write of the file descriptor) will
|
||||
* block any other put/get calls using this DB_MPOOLFILE structure.
|
||||
*/
|
||||
u_int32_t pinref; /* Pinned block reference count. */
|
||||
|
||||
/* These fields are not protected. */
|
||||
|
@ -9,10 +9,12 @@ int __memp_pg __P((DB_MPOOLFILE *, BH *, int));
|
||||
void __memp_bhfree __P((DB_MPOOL *, MPOOLFILE *, BH *, int));
|
||||
int __memp_fopen __P((DB_MPOOL *, MPOOLFILE *, const char *,
|
||||
u_int32_t, int, size_t, int, DB_MPOOL_FINFO *, DB_MPOOLFILE **));
|
||||
void __memp_panic __P((DB_ENV *));
|
||||
char * __memp_fn __P((DB_MPOOLFILE *));
|
||||
char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *));
|
||||
void __memp_dump_region __P((DB_MPOOL *, char *, FILE *));
|
||||
int __memp_ralloc __P((DB_MPOOL *, size_t, size_t *, void *));
|
||||
int __memp_reg_alloc __P((DB_MPOOL *, size_t, size_t *, void *));
|
||||
int __memp_alloc __P((DB_MPOOL *, size_t, size_t *, void *));
|
||||
int __memp_ropen
|
||||
__P((DB_MPOOL *, const char *, size_t, int, int, u_int32_t));
|
||||
int __mp_xxx_fd __P((DB_MPOOLFILE *, int *));
|
||||
|
24
db2/include/os.h
Normal file
24
db2/include/os.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)os.h 10.11 (Sleepycat) 10/12/98
|
||||
*/
|
||||
|
||||
/*
|
||||
* We group seek/write calls into a single function so that we can use
|
||||
* pread(2)/pwrite(2) where they're available.
|
||||
*/
|
||||
#define DB_IO_READ 1
|
||||
#define DB_IO_WRITE 2
|
||||
typedef struct __io {
|
||||
int fd_io; /* I/O file descriptor. */
|
||||
int fd_lock; /* Locking file descriptor. */
|
||||
db_mutex_t *mutexp; /* Mutex to lock. */
|
||||
size_t pagesize; /* Page size. */
|
||||
db_pgno_t pgno; /* Page number. */
|
||||
u_int8_t *buf; /* Buffer. */
|
||||
size_t bytes; /* Bytes read/written. */
|
||||
} DB_IO;
|
@ -1,15 +1,17 @@
|
||||
/* DO NOT EDIT: automatically built by dist/distrib. */
|
||||
#ifndef _os_ext_h_
|
||||
#define _os_ext_h_
|
||||
int __db_abspath __P((const char *));
|
||||
char *__db_strdup __P((const char *));
|
||||
void *__db_calloc __P((size_t, size_t));
|
||||
void *__db_malloc __P((size_t));
|
||||
void *__db_realloc __P((void *, size_t));
|
||||
int __os_abspath __P((const char *));
|
||||
int __os_strdup __P((const char *, void *));
|
||||
int __os_calloc __P((size_t, size_t, void *));
|
||||
int __os_malloc __P((size_t, void *(*)(size_t), void *));
|
||||
int __os_realloc __P((void *, size_t));
|
||||
void __os_free __P((void *, size_t));
|
||||
void __os_freestr __P((void *));
|
||||
int __os_dirlist __P((const char *, char ***, int *));
|
||||
void __os_dirfree __P((char **, int));
|
||||
int __db_fileid __P((DB_ENV *, const char *, int, u_int8_t *));
|
||||
int __db_fsync __P((int));
|
||||
int __os_fileid __P((DB_ENV *, const char *, int, u_int8_t *));
|
||||
int __os_fsync __P((int));
|
||||
int __db_mapanon_ok __P((int));
|
||||
int __db_mapinit __P((void));
|
||||
int __db_mapregion __P((char *, REGINFO *));
|
||||
@ -20,15 +22,19 @@ int __db_unmapfile __P((void *, size_t));
|
||||
u_int32_t __db_oflags __P((int));
|
||||
int __db_omode __P((const char *));
|
||||
int __db_open __P((const char *, u_int32_t, u_int32_t, int, int *));
|
||||
int __db_close __P((int));
|
||||
int __os_open __P((const char *, int, int, int *));
|
||||
int __os_close __P((int));
|
||||
char *__db_rpath __P((const char *));
|
||||
int __db_read __P((int, void *, size_t, ssize_t *));
|
||||
int __db_write __P((int, void *, size_t, ssize_t *));
|
||||
int __os_io __P((DB_IO *, int, ssize_t *));
|
||||
int __os_read __P((int, void *, size_t, ssize_t *));
|
||||
int __os_write __P((int, const void *, size_t, ssize_t *));
|
||||
int __os_seek __P((int, size_t, db_pgno_t, u_int32_t, int, int));
|
||||
int __os_sleep __P((u_long, u_long));
|
||||
int __os_spin __P((void));
|
||||
void __os_yield __P((u_long));
|
||||
int __os_exists __P((const char *, int *));
|
||||
int __os_ioinfo
|
||||
__P((const char *, int, u_int32_t *, u_int32_t *, u_int32_t *));
|
||||
int __db_unlink __P((const char *));
|
||||
int __os_tmpdir __P((DB_ENV *, u_int32_t));
|
||||
int __os_unlink __P((const char *));
|
||||
#endif /* _os_ext_h_ */
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)os_func.h 10.8 (Sleepycat) 4/19/98
|
||||
* @(#)os_jump.h 10.1 (Sleepycat) 10/17/98
|
||||
*/
|
||||
|
||||
/* Calls which can be replaced by the application. */
|
||||
@ -38,32 +38,3 @@ struct __db_jumptab {
|
||||
};
|
||||
|
||||
extern struct __db_jumptab __db_jump;
|
||||
|
||||
/*
|
||||
* Names used by DB to call through the jump table.
|
||||
*
|
||||
* The naming scheme goes like this: if the functionality the application can
|
||||
* replace is the same as the DB functionality, e.g., malloc, or dirlist, then
|
||||
* we use the name __db_XXX, and the application is expected to replace the
|
||||
* complete functionality, which may or may not map directly to an ANSI C or
|
||||
* POSIX 1003.1 interface. If the functionality that the aplication replaces
|
||||
* only underlies what the DB os directory exports to other parts of DB, e.g.,
|
||||
* read, then the name __os_XXX is used, and the application can only replace
|
||||
* the underlying functionality. Under most circumstances, the os directory
|
||||
* part of DB is the only code that should use the __os_XXX names, all other
|
||||
* parts of DB should be calling __db_XXX functions.
|
||||
*/
|
||||
#define __os_close __db_jump.j_close /* __db_close is a wrapper. */
|
||||
#define __db_dirfree __db_jump.j_dirfree
|
||||
#define __db_dirlist __db_jump.j_dirlist
|
||||
#define __db_exists __db_jump.j_exists
|
||||
#define __db_free __db_jump.j_free
|
||||
#define __os_fsync __db_jump.j_fsync /* __db_fsync is a wrapper. */
|
||||
#define __db_ioinfo __db_jump.j_ioinfo
|
||||
#define __os_open __db_jump.j_open /* __db_open is a wrapper. */
|
||||
#define __os_read __db_jump.j_read /* __db_read is a wrapper. */
|
||||
#define __db_seek __db_jump.j_seek
|
||||
#define __db_sleep __db_jump.j_sleep
|
||||
#define __os_unlink __db_jump.j_unlink /* __db_unlink is a wrapper. */
|
||||
#define __os_write __db_jump.j_write /* __db_write is a wrapper. */
|
||||
#define __db_yield __db_jump.j_yield
|
@ -4,11 +4,13 @@
|
||||
* Copyright (c) 1996, 1997, 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)txn.h 10.15 (Sleepycat) 4/21/98
|
||||
* @(#)txn.h 10.18 (Sleepycat) 1/3/99
|
||||
*/
|
||||
#ifndef _TXN_H_
|
||||
#define _TXN_H_
|
||||
|
||||
#include "xa.h"
|
||||
|
||||
/*
|
||||
* The name of the transaction shared memory region is DEFAULT_TXN_FILE and
|
||||
* the region is always created group RW of the group owning the directory.
|
||||
@ -25,6 +27,8 @@
|
||||
/*
|
||||
* Internal data maintained in shared memory for each transaction.
|
||||
*/
|
||||
typedef char DB_XID[XIDDATASIZE];
|
||||
|
||||
typedef struct __txn_detail {
|
||||
u_int32_t txnid; /* current transaction id
|
||||
used to link free list also */
|
||||
@ -32,12 +36,31 @@ typedef struct __txn_detail {
|
||||
DB_LSN begin_lsn; /* lsn of begin record */
|
||||
size_t last_lock; /* offset in lock region of last lock
|
||||
for this transaction. */
|
||||
size_t parent; /* Offset of transaction's parent. */
|
||||
#define TXN_UNALLOC 0
|
||||
#define TXN_RUNNING 1
|
||||
#define TXN_ABORTED 2
|
||||
#define TXN_PREPARED 3
|
||||
#define TXN_COMMITTED 4
|
||||
u_int32_t status; /* status of the transaction */
|
||||
SH_TAILQ_ENTRY links; /* free/active list */
|
||||
|
||||
#define TXN_XA_ABORTED 1
|
||||
#define TXN_XA_DEADLOCKED 2
|
||||
#define TXN_XA_ENDED 3
|
||||
#define TXN_XA_PREPARED 4
|
||||
#define TXN_XA_STARTED 5
|
||||
#define TXN_XA_SUSPENDED 6
|
||||
u_int32_t xa_status; /* XA status */
|
||||
|
||||
/*
|
||||
* XID (xid_t) structure: because these fields are logged, the
|
||||
* sizes have to be explicit.
|
||||
*/
|
||||
DB_XID xid; /* XA global transaction id */
|
||||
u_int32_t bqual; /* bqual_length from XID */
|
||||
u_int32_t gtrid; /* gtrid_length from XID */
|
||||
int32_t format; /* XA format */
|
||||
} TXN_DETAIL;
|
||||
|
||||
/*
|
||||
@ -105,6 +128,12 @@ struct __db_txnregion {
|
||||
#define UNLOCK_TXNREGION(tmgrp) \
|
||||
(void)__db_mutex_unlock(&(tmgrp)->region->hdr.lock, (tmgrp)->reginfo.fd)
|
||||
|
||||
/* Check for region catastrophic shutdown. */
|
||||
#define TXN_PANIC_CHECK(tmgrp) { \
|
||||
if ((tmgrp)->region->hdr.panic) \
|
||||
return (DB_RUNRECOVERY); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Log record types.
|
||||
*/
|
||||
@ -114,4 +143,6 @@ struct __db_txnregion {
|
||||
|
||||
#include "txn_auto.h"
|
||||
#include "txn_ext.h"
|
||||
|
||||
#include "xa_ext.h"
|
||||
#endif /* !_TXN_H_ */
|
||||
|
@ -22,4 +22,30 @@ typedef struct _txn_ckp_args {
|
||||
DB_LSN last_ckp;
|
||||
} __txn_ckp_args;
|
||||
|
||||
|
||||
#define DB_txn_xa_regop (DB_txn_BEGIN + 3)
|
||||
|
||||
typedef struct _txn_xa_regop_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
u_int32_t opcode;
|
||||
DBT xid;
|
||||
int32_t formatID;
|
||||
u_int32_t gtrid;
|
||||
u_int32_t bqual;
|
||||
DB_LSN begin_lsn;
|
||||
} __txn_xa_regop_args;
|
||||
|
||||
|
||||
#define DB_txn_child (DB_txn_BEGIN + 4)
|
||||
|
||||
typedef struct _txn_child_args {
|
||||
u_int32_t type;
|
||||
DB_TXN *txnid;
|
||||
DB_LSN prev_lsn;
|
||||
u_int32_t opcode;
|
||||
u_int32_t parent;
|
||||
} __txn_child_args;
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,9 @@
|
||||
/* DO NOT EDIT: automatically built by dist/distrib. */
|
||||
#ifndef _txn_ext_h_
|
||||
#define _txn_ext_h_
|
||||
void __txn_panic __P((DB_ENV *));
|
||||
int __txn_xa_begin __P((DB_ENV *, DB_TXN *));
|
||||
int __txn_is_ancestor __P((DB_TXNMGR *, size_t, size_t));
|
||||
int __txn_regop_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t));
|
||||
@ -13,9 +16,26 @@ int __txn_ckp_log
|
||||
int __txn_ckp_print
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __txn_ckp_read __P((void *, __txn_ckp_args **));
|
||||
int __txn_xa_regop_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, const DBT *, int32_t, u_int32_t,
|
||||
u_int32_t, DB_LSN *));
|
||||
int __txn_xa_regop_print
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __txn_xa_regop_read __P((void *, __txn_xa_regop_args **));
|
||||
int __txn_child_log
|
||||
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
|
||||
u_int32_t, u_int32_t));
|
||||
int __txn_child_print
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __txn_child_read __P((void *, __txn_child_args **));
|
||||
int __txn_init_print __P((DB_ENV *));
|
||||
int __txn_init_recover __P((DB_ENV *));
|
||||
int __txn_regop_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __txn_xa_regop_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __txn_ckp_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
int __txn_child_recover
|
||||
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
|
||||
#endif /* _txn_ext_h_ */
|
||||
|
179
db2/include/xa.h
Normal file
179
db2/include/xa.h
Normal file
@ -0,0 +1,179 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1998
|
||||
* Sleepycat Software. All rights reserved.
|
||||
*
|
||||
* @(#)xa.h 10.1 (Sleepycat) 6/22/98
|
||||
*/
|
||||
/*
|
||||
* Start of xa.h header
|
||||
*
|
||||
* Define a symbol to prevent multiple inclusions of this header file
|
||||
*/
|
||||
#ifndef XA_H
|
||||
#define XA_H
|
||||
|
||||
/*
|
||||
* Transaction branch identification: XID and NULLXID:
|
||||
*/
|
||||
#define XIDDATASIZE 128 /* size in bytes */
|
||||
#define MAXGTRIDSIZE 64 /* maximum size in bytes of gtrid */
|
||||
#define MAXBQUALSIZE 64 /* maximum size in bytes of bqual */
|
||||
|
||||
struct xid_t {
|
||||
long formatID; /* format identifier */
|
||||
long gtrid_length; /* value from 1 through 64 */
|
||||
long bqual_length; /* value from 1 through 64 */
|
||||
char data[XIDDATASIZE];
|
||||
};
|
||||
typedef struct xid_t XID;
|
||||
/*
|
||||
* A value of -1 in formatID means that the XID is null.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Declarations of routines by which RMs call TMs:
|
||||
*/
|
||||
extern int ax_reg __P((int, XID *, long));
|
||||
extern int ax_unreg __P((int, long));
|
||||
|
||||
/*
|
||||
* XA Switch Data Structure
|
||||
*/
|
||||
#define RMNAMESZ 32 /* length of resource manager name, */
|
||||
/* including the null terminator */
|
||||
#define MAXINFOSIZE 256 /* maximum size in bytes of xa_info */
|
||||
/* strings, including the null
|
||||
terminator */
|
||||
struct xa_switch_t {
|
||||
char name[RMNAMESZ]; /* name of resource manager */
|
||||
long flags; /* resource manager specific options */
|
||||
long version; /* must be 0 */
|
||||
int (*xa_open_entry) /* xa_open function pointer */
|
||||
__P((char *, int, long));
|
||||
int (*xa_close_entry) /* xa_close function pointer */
|
||||
__P((char *, int, long));
|
||||
int (*xa_start_entry) /* xa_start function pointer */
|
||||
__P((XID *, int, long));
|
||||
int (*xa_end_entry) /* xa_end function pointer */
|
||||
__P((XID *, int, long));
|
||||
int (*xa_rollback_entry) /* xa_rollback function pointer */
|
||||
__P((XID *, int, long));
|
||||
int (*xa_prepare_entry) /* xa_prepare function pointer */
|
||||
__P((XID *, int, long));
|
||||
int (*xa_commit_entry) /* xa_commit function pointer */
|
||||
__P((XID *, int, long));
|
||||
int (*xa_recover_entry) /* xa_recover function pointer */
|
||||
__P((XID *, long, int, long));
|
||||
int (*xa_forget_entry) /* xa_forget function pointer */
|
||||
__P((XID *, int, long));
|
||||
int (*xa_complete_entry) /* xa_complete function pointer */
|
||||
__P((int *, int *, int, long));
|
||||
};
|
||||
|
||||
/*
|
||||
* Flag definitions for the RM switch
|
||||
*/
|
||||
#define TMNOFLAGS 0x00000000L /* no resource manager features
|
||||
selected */
|
||||
#define TMREGISTER 0x00000001L /* resource manager dynamically
|
||||
registers */
|
||||
#define TMNOMIGRATE 0x00000002L /* resource manager does not support
|
||||
association migration */
|
||||
#define TMUSEASYNC 0x00000004L /* resource manager supports
|
||||
asynchronous operations */
|
||||
/*
|
||||
* Flag definitions for xa_ and ax_ routines
|
||||
*/
|
||||
/* use TMNOFLAGGS, defined above, when not specifying other flags */
|
||||
#define TMASYNC 0x80000000L /* perform routine asynchronously */
|
||||
#define TMONEPHASE 0x40000000L /* caller is using one-phase commit
|
||||
optimisation */
|
||||
#define TMFAIL 0x20000000L /* dissociates caller and marks
|
||||
transaction branch rollback-only */
|
||||
#define TMNOWAIT 0x10000000L /* return if blocking condition
|
||||
exists */
|
||||
#define TMRESUME 0x08000000L /* caller is resuming association with
|
||||
suspended transaction branch */
|
||||
#define TMSUCCESS 0x04000000L /* dissociate caller from transaction
|
||||
branch */
|
||||
#define TMSUSPEND 0x02000000L /* caller is suspending, not ending,
|
||||
association */
|
||||
#define TMSTARTRSCAN 0x01000000L /* start a recovery scan */
|
||||
#define TMENDRSCAN 0x00800000L /* end a recovery scan */
|
||||
#define TMMULTIPLE 0x00400000L /* wait for any asynchronous
|
||||
operation */
|
||||
#define TMJOIN 0x00200000L /* caller is joining existing
|
||||
transaction branch */
|
||||
#define TMMIGRATE 0x00100000L /* caller intends to perform
|
||||
migration */
|
||||
|
||||
/*
|
||||
* ax_() return codes (transaction manager reports to resource manager)
|
||||
*/
|
||||
#define TM_JOIN 2 /* caller is joining existing
|
||||
transaction branch */
|
||||
#define TM_RESUME 1 /* caller is resuming association with
|
||||
suspended transaction branch */
|
||||
#define TM_OK 0 /* normal execution */
|
||||
#define TMER_TMERR -1 /* an error occurred in the transaction
|
||||
manager */
|
||||
#define TMER_INVAL -2 /* invalid arguments were given */
|
||||
#define TMER_PROTO -3 /* routine invoked in an improper
|
||||
context */
|
||||
|
||||
/*
|
||||
* xa_() return codes (resource manager reports to transaction manager)
|
||||
*/
|
||||
#define XA_RBBASE 100 /* The inclusive lower bound of the
|
||||
rollback codes */
|
||||
#define XA_RBROLLBACK XA_RBBASE /* The rollback was caused by an
|
||||
unspecified reason */
|
||||
#define XA_RBCOMMFAIL XA_RBBASE+1 /* The rollback was caused by a
|
||||
communication failure */
|
||||
#define XA_RBDEADLOCK XA_RBBASE+2 /* A deadlock was detected */
|
||||
#define XA_RBINTEGRITY XA_RBBASE+3 /* A condition that violates the
|
||||
integrity of the resources was
|
||||
detected */
|
||||
#define XA_RBOTHER XA_RBBASE+4 /* The resource manager rolled back the
|
||||
transaction branch for a reason not
|
||||
on this list */
|
||||
#define XA_RBPROTO XA_RBBASE+5 /* A protocol error occurred in the
|
||||
resource manager */
|
||||
#define XA_RBTIMEOUT XA_RBBASE+6 /* A transaction branch took too long */
|
||||
#define XA_RBTRANSIENT XA_RBBASE+7 /* May retry the transaction branch */
|
||||
#define XA_RBEND XA_RBTRANSIENT /* The inclusive upper bound of the
|
||||
rollback codes */
|
||||
#define XA_NOMIGRATE 9 /* resumption must occur where
|
||||
suspension occurred */
|
||||
#define XA_HEURHAZ 8 /* the transaction branch may have
|
||||
been heuristically completed */
|
||||
#define XA_HEURCOM 7 /* the transaction branch has been
|
||||
heuristically committed */
|
||||
#define XA_HEURRB 6 /* the transaction branch has been
|
||||
heuristically rolled back */
|
||||
#define XA_HEURMIX 5 /* the transaction branch has been
|
||||
heuristically committed and rolled
|
||||
back */
|
||||
#define XA_RETRY 4 /* routine returned with no effect and
|
||||
may be re-issued */
|
||||
#define XA_RDONLY 3 /* the transaction branch was read-only
|
||||
and has been committed */
|
||||
#define XA_OK 0 /* normal execution */
|
||||
#define XAER_ASYNC -2 /* asynchronous operation already
|
||||
outstanding */
|
||||
#define XAER_RMERR -3 /* a resource manager error occurred in
|
||||
the transaction branch */
|
||||
#define XAER_NOTA -4 /* the XID is not valid */
|
||||
#define XAER_INVAL -5 /* invalid arguments were given */
|
||||
#define XAER_PROTO -6 /* routine invoked in an improper
|
||||
context */
|
||||
#define XAER_RMFAIL -7 /* resource manager unavailable */
|
||||
#define XAER_DUPID -8 /* the XID already exists */
|
||||
#define XAER_OUTSIDE -9 /* resource manager doing work outside
|
||||
transaction */
|
||||
#endif /* ifndef XA_H */
|
||||
/*
|
||||
* End of xa.h header
|
||||
*/
|
13
db2/include/xa_ext.h
Normal file
13
db2/include/xa_ext.h
Normal file
@ -0,0 +1,13 @@
|
||||
/* DO NOT EDIT: automatically built by dist/distrib. */
|
||||
#ifndef _xa_ext_h_
|
||||
#define _xa_ext_h_
|
||||
int __db_rmid_to_env __P((int rmid, DB_ENV **envp, int open_ok));
|
||||
int __db_xid_to_txn __P((DB_ENV *, XID *, size_t *));
|
||||
int __db_map_rmid __P((int, DB_ENV *));
|
||||
int __db_unmap_rmid __P((int));
|
||||
int __db_map_xid __P((DB_ENV *, XID *, size_t));
|
||||
void __db_unmap_xid __P((DB_ENV *, XID *, size_t));
|
||||
int __db_map_rmid_name __P((int, char *));
|
||||
int __db_rmid_to_name __P((int, char **));
|
||||
void __db_unmap_rmid_name __P((int));
|
||||
#endif /* _xa_ext_h_ */
|
386
db2/lock/lock.c
386
db2/lock/lock.c
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)lock.c 10.52 (Sleepycat) 5/10/98";
|
||||
static const char sccsid[] = "@(#)lock.c 10.61 (Sleepycat) 1/3/99";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -23,16 +23,22 @@ static const char sccsid[] = "@(#)lock.c 10.52 (Sleepycat) 5/10/98";
|
||||
#include "db_page.h"
|
||||
#include "db_shash.h"
|
||||
#include "lock.h"
|
||||
#include "common_ext.h"
|
||||
#include "db_am.h"
|
||||
#include "txn_auto.h"
|
||||
#include "txn_ext.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
static void __lock_checklocker __P((DB_LOCKTAB *, struct __db_lock *, int));
|
||||
static void __lock_freeobj __P((DB_LOCKTAB *, DB_LOCKOBJ *));
|
||||
static int __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, u_int32_t,
|
||||
const DBT *, db_lockmode_t, struct __db_lock **));
|
||||
static int __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, DB_TXN *,
|
||||
u_int32_t, const DBT *, db_lockmode_t, struct __db_lock **));
|
||||
static int __lock_is_parent __P((u_int32_t, DB_TXN *));
|
||||
static int __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *));
|
||||
static int __lock_put_internal __P((DB_LOCKTAB *, struct __db_lock *, int));
|
||||
static void __lock_remove_waiter
|
||||
__P((DB_LOCKTAB *, DB_LOCKOBJ *, struct __db_lock *, db_status_t));
|
||||
static int __lock_vec_internal __P((DB_LOCKTAB *, u_int32_t, DB_TXN *,
|
||||
u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **elistp));
|
||||
|
||||
int
|
||||
lock_id(lt, idp)
|
||||
@ -41,6 +47,8 @@ lock_id(lt, idp)
|
||||
{
|
||||
u_int32_t id;
|
||||
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
LOCK_LOCKREGION(lt);
|
||||
if (lt->region->id >= DB_LOCK_MAXID)
|
||||
lt->region->id = 0;
|
||||
@ -57,11 +65,38 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
|
||||
u_int32_t locker, flags;
|
||||
int nlist;
|
||||
DB_LOCKREQ *list, **elistp;
|
||||
{
|
||||
return (__lock_vec_internal(lt,
|
||||
locker, NULL, flags, list, nlist, elistp));
|
||||
}
|
||||
|
||||
int
|
||||
lock_tvec(lt, txn, flags, list, nlist, elistp)
|
||||
DB_LOCKTAB *lt;
|
||||
DB_TXN *txn;
|
||||
u_int32_t flags;
|
||||
int nlist;
|
||||
DB_LOCKREQ *list, **elistp;
|
||||
{
|
||||
return (__lock_vec_internal(lt,
|
||||
txn->txnid, txn, flags, list, nlist, elistp));
|
||||
}
|
||||
|
||||
static int
|
||||
__lock_vec_internal(lt, locker, txn, flags, list, nlist, elistp)
|
||||
DB_LOCKTAB *lt;
|
||||
u_int32_t locker;
|
||||
DB_TXN *txn;
|
||||
u_int32_t flags;
|
||||
int nlist;
|
||||
DB_LOCKREQ *list, **elistp;
|
||||
{
|
||||
struct __db_lock *lp;
|
||||
DB_LOCKOBJ *sh_obj, *sh_locker;
|
||||
DB_LOCKOBJ *sh_obj, *sh_locker, *sh_parent;
|
||||
int i, ret, run_dd;
|
||||
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((ret =
|
||||
__db_fchk(lt->dbenv, "lock_vec", flags, DB_LOCK_NOWAIT)) != 0)
|
||||
@ -78,13 +113,43 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
|
||||
for (i = 0; i < nlist && ret == 0; i++) {
|
||||
switch (list[i].op) {
|
||||
case DB_LOCK_GET:
|
||||
ret = __lock_get_internal(lt, locker, flags,
|
||||
ret = __lock_get_internal(lt, locker, txn, flags,
|
||||
list[i].obj, list[i].mode, &lp);
|
||||
if (ret == 0) {
|
||||
list[i].lock = LOCK_TO_OFFSET(lt, lp);
|
||||
lt->region->nrequests++;
|
||||
}
|
||||
break;
|
||||
case DB_LOCK_INHERIT:
|
||||
/* Find the locker. */
|
||||
if ((ret = __lock_getobj(lt, locker,
|
||||
NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
|
||||
break;
|
||||
if (txn == NULL || txn->parent == NULL) {
|
||||
ret = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ret = __lock_getobj(lt, txn->parent->txnid,
|
||||
NULL, DB_LOCK_LOCKER, &sh_parent)) != 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Traverse all the locks held by this locker. Remove
|
||||
* the locks from the locker's list and put them on the
|
||||
* parent's list.
|
||||
*/
|
||||
for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
|
||||
lp != NULL;
|
||||
lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) {
|
||||
SH_LIST_REMOVE(lp, locker_links, __db_lock);
|
||||
SH_LIST_INSERT_HEAD(&sh_parent->heldby, lp,
|
||||
locker_links, __db_lock);
|
||||
lp->holder = txn->parent->txnid;
|
||||
}
|
||||
__lock_freeobj(lt, sh_locker);
|
||||
lt->region->nlockers--;
|
||||
break;
|
||||
case DB_LOCK_PUT:
|
||||
lp = OFFSET_TO_LOCK(lt, list[i].lock);
|
||||
if (lp->holder != locker) {
|
||||
@ -93,8 +158,8 @@ lock_vec(lt, locker, flags, list, nlist, elistp)
|
||||
}
|
||||
list[i].mode = lp->mode;
|
||||
|
||||
/* XXX Need to copy the object. ??? */
|
||||
ret = __lock_put_internal(lt, lp, 0);
|
||||
__lock_checklocker(lt, lp, 0);
|
||||
break;
|
||||
case DB_LOCK_PUT_ALL:
|
||||
/* Find the locker. */
|
||||
@ -204,24 +269,67 @@ lock_get(lt, locker, flags, obj, lock_mode, lock)
|
||||
struct __db_lock *lockp;
|
||||
int ret;
|
||||
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((ret =
|
||||
__db_fchk(lt->dbenv, "lock_get", flags, DB_LOCK_NOWAIT)) != 0)
|
||||
if ((ret = __db_fchk(lt->dbenv,
|
||||
"lock_get", flags, DB_LOCK_NOWAIT | DB_LOCK_UPGRADE)) != 0)
|
||||
return (ret);
|
||||
|
||||
LOCK_LOCKREGION(lt);
|
||||
|
||||
ret = __lock_validate_region(lt);
|
||||
if (ret == 0 && (ret = __lock_get_internal(lt,
|
||||
locker, flags, obj, lock_mode, &lockp)) == 0) {
|
||||
*lock = LOCK_TO_OFFSET(lt, lockp);
|
||||
lt->region->nrequests++;
|
||||
if ((ret = __lock_validate_region(lt)) == 0) {
|
||||
if (LF_ISSET(DB_LOCK_UPGRADE))
|
||||
lockp = OFFSET_TO_LOCK(lt, *lock);
|
||||
|
||||
if ((ret = __lock_get_internal(lt,
|
||||
locker, NULL, flags, obj, lock_mode, &lockp)) == 0) {
|
||||
if (!LF_ISSET(DB_LOCK_UPGRADE))
|
||||
*lock = LOCK_TO_OFFSET(lt, lockp);
|
||||
lt->region->nrequests++;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK_LOCKREGION(lt);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
lock_tget(lt, txn, flags, obj, lock_mode, lock)
|
||||
DB_LOCKTAB *lt;
|
||||
DB_TXN *txn;
|
||||
u_int32_t flags;
|
||||
const DBT *obj;
|
||||
db_lockmode_t lock_mode;
|
||||
DB_LOCK *lock;
|
||||
{
|
||||
struct __db_lock *lockp;
|
||||
int ret;
|
||||
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((ret = __db_fchk(lt->dbenv,
|
||||
"lock_get", flags, DB_LOCK_NOWAIT | DB_LOCK_UPGRADE)) != 0)
|
||||
return (ret);
|
||||
|
||||
LOCK_LOCKREGION(lt);
|
||||
|
||||
if ((ret = __lock_validate_region(lt)) == 0) {
|
||||
if (LF_ISSET(DB_LOCK_UPGRADE))
|
||||
lockp = OFFSET_TO_LOCK(lt, *lock);
|
||||
|
||||
if ((ret = __lock_get_internal(lt,
|
||||
txn->txnid, txn, flags, obj, lock_mode, &lockp)) == 0) {
|
||||
if (!LF_ISSET(DB_LOCK_UPGRADE))
|
||||
*lock = LOCK_TO_OFFSET(lt, lockp);
|
||||
lt->region->nrequests++;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK_LOCKREGION(lt);
|
||||
return (ret);
|
||||
}
|
||||
int
|
||||
lock_put(lt, lock)
|
||||
DB_LOCKTAB *lt;
|
||||
@ -230,6 +338,8 @@ lock_put(lt, lock)
|
||||
struct __db_lock *lockp;
|
||||
int ret, run_dd;
|
||||
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
LOCK_LOCKREGION(lt);
|
||||
|
||||
if ((ret = __lock_validate_region(lt)) != 0)
|
||||
@ -261,7 +371,6 @@ __lock_put_internal(lt, lockp, do_all)
|
||||
struct __db_lock *lockp;
|
||||
int do_all;
|
||||
{
|
||||
struct __db_lock *lp_w, *lp_h, *next_waiter;
|
||||
DB_LOCKOBJ *sh_obj;
|
||||
int state_changed;
|
||||
|
||||
@ -293,39 +402,7 @@ __lock_put_internal(lt, lockp, do_all)
|
||||
else
|
||||
SH_TAILQ_REMOVE(&sh_obj->holders, lockp, links, __db_lock);
|
||||
|
||||
/*
|
||||
* We need to do lock promotion. We also need to determine if
|
||||
* we're going to need to run the deadlock detector again. If
|
||||
* we release locks, and there are waiters, but no one gets promoted,
|
||||
* then we haven't fundamentally changed the lockmgr state, so
|
||||
* we may still have a deadlock and we have to run again. However,
|
||||
* if there were no waiters, or we actually promoted someone, then
|
||||
* we are OK and we don't have to run it immediately.
|
||||
*/
|
||||
for (lp_w = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock),
|
||||
state_changed = lp_w == NULL;
|
||||
lp_w != NULL;
|
||||
lp_w = next_waiter) {
|
||||
next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock);
|
||||
for (lp_h = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
|
||||
lp_h != NULL;
|
||||
lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) {
|
||||
if (CONFLICTS(lt, lp_h->mode, lp_w->mode) &&
|
||||
lp_h->holder != lp_w->holder)
|
||||
break;
|
||||
}
|
||||
if (lp_h != NULL) /* Found a conflict. */
|
||||
break;
|
||||
|
||||
/* No conflict, promote the waiting lock. */
|
||||
SH_TAILQ_REMOVE(&sh_obj->waiters, lp_w, links, __db_lock);
|
||||
lp_w->status = DB_LSTAT_PENDING;
|
||||
SH_TAILQ_INSERT_TAIL(&sh_obj->holders, lp_w, links);
|
||||
|
||||
/* Wake up waiter. */
|
||||
(void)__db_mutex_unlock(&lp_w->mutex, lt->reginfo.fd);
|
||||
state_changed = 1;
|
||||
}
|
||||
state_changed = __lock_promote(lt, sh_obj);
|
||||
|
||||
/* Check if object should be reclaimed. */
|
||||
if (SH_TAILQ_FIRST(&sh_obj->holders, __db_lock) == NULL) {
|
||||
@ -354,9 +431,10 @@ __lock_put_internal(lt, lockp, do_all)
|
||||
}
|
||||
|
||||
static int
|
||||
__lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
|
||||
__lock_get_internal(lt, locker, txn, flags, obj, lock_mode, lockp)
|
||||
DB_LOCKTAB *lt;
|
||||
u_int32_t locker, flags;
|
||||
DB_TXN *txn;
|
||||
const DBT *obj;
|
||||
db_lockmode_t lock_mode;
|
||||
struct __db_lock **lockp;
|
||||
@ -365,13 +443,13 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
|
||||
DB_LOCKOBJ *sh_obj, *sh_locker;
|
||||
DB_LOCKREGION *lrp;
|
||||
size_t newl_off;
|
||||
int ihold, ret;
|
||||
int ihold, no_dd, ret;
|
||||
|
||||
no_dd = ret = 0;
|
||||
|
||||
ret = 0;
|
||||
/*
|
||||
* Check that lock mode is valid.
|
||||
*/
|
||||
|
||||
lrp = lt->region;
|
||||
if ((u_int32_t)lock_mode >= lrp->nmodes) {
|
||||
__db_err(lt->dbenv,
|
||||
@ -423,20 +501,28 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
|
||||
* lock, then we guarantee deadlock.
|
||||
*
|
||||
* In case of conflict, we put the new lock on the end of the waiters
|
||||
* list.
|
||||
* list, unless we are upgrading in which case the locker goes on the
|
||||
* front of the list.
|
||||
*/
|
||||
ihold = 0;
|
||||
for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
|
||||
lp != NULL;
|
||||
lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
|
||||
if (locker == lp->holder) {
|
||||
if (locker == lp->holder ||
|
||||
__lock_is_parent(lp->holder, txn)) {
|
||||
if (lp->mode == lock_mode &&
|
||||
lp->status == DB_LSTAT_HELD) {
|
||||
/* Lock is held, just inc the ref count. */
|
||||
if (LF_ISSET(DB_LOCK_UPGRADE))
|
||||
goto upgrade;
|
||||
|
||||
/*
|
||||
* Lock is held, so we can increment the
|
||||
* reference count and return this lock.
|
||||
*/
|
||||
lp->refcount++;
|
||||
*lockp = lp;
|
||||
SH_TAILQ_INSERT_HEAD(&lrp->free_locks,
|
||||
newl, links, __db_lock);
|
||||
*lockp = lp;
|
||||
return (0);
|
||||
} else
|
||||
ihold = 1;
|
||||
@ -444,6 +530,21 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are upgrading, then there are two scenarios. Either
|
||||
* we had no conflicts, so we can do the upgrade. Or, there
|
||||
* is a conflict and we should wait at the HEAD of the waiters
|
||||
* list.
|
||||
*/
|
||||
if (LF_ISSET(DB_LOCK_UPGRADE)) {
|
||||
if (lp == NULL)
|
||||
goto upgrade;
|
||||
|
||||
/* There was a conflict, wait. */
|
||||
SH_TAILQ_INSERT_HEAD(&sh_obj->waiters, newl, links, __db_lock);
|
||||
goto wait;
|
||||
}
|
||||
|
||||
if (lp == NULL && !ihold)
|
||||
for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock);
|
||||
lp != NULL;
|
||||
@ -464,31 +565,35 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
|
||||
}
|
||||
|
||||
/*
|
||||
* This is really a blocker for the process, so initialize it
|
||||
* set. That way the current process will block when it tries
|
||||
* to get it and the waking process will release it.
|
||||
*/
|
||||
(void)__db_mutex_init(&newl->mutex,
|
||||
MUTEX_LOCK_OFFSET(lt->region, &newl->mutex));
|
||||
(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
|
||||
|
||||
/*
|
||||
* Now, insert the lock onto its locker's list.
|
||||
* Now, insert the lock onto its locker's list. If the locker does
|
||||
* not currently hold any locks, there's no reason to run a deadlock
|
||||
* detector, save that information.
|
||||
*/
|
||||
if ((ret =
|
||||
__lock_getobj(lt, locker, NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
|
||||
return (ret);
|
||||
no_dd = SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL;
|
||||
|
||||
lrp = lt->region;
|
||||
SH_LIST_INSERT_HEAD(&sh_locker->heldby, newl, locker_links, __db_lock);
|
||||
|
||||
if (lp != NULL) {
|
||||
/*
|
||||
* This is really a blocker for the process, so initialize it
|
||||
* set. That way the current process will block when it tries
|
||||
* to get it and the waking process will release it.
|
||||
*/
|
||||
wait: (void)__db_mutex_init(&newl->mutex,
|
||||
MUTEX_LOCK_OFFSET(lt->region, &newl->mutex));
|
||||
(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
|
||||
|
||||
newl->status = DB_LSTAT_WAITING;
|
||||
lrp->nconflicts++;
|
||||
|
||||
/*
|
||||
* We are about to wait; must release the region mutex.
|
||||
* Then, when we wakeup, we need to reacquire the region
|
||||
* mutex before continuing.
|
||||
* We are about to wait; must release the region mutex. Then,
|
||||
* when we wakeup, we need to reacquire the region mutex before
|
||||
* continuing.
|
||||
*/
|
||||
if (lrp->detect == DB_LOCK_NORUN)
|
||||
lt->region->need_dd = 1;
|
||||
@ -498,13 +603,19 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
|
||||
* We are about to wait; before waiting, see if the deadlock
|
||||
* detector should be run.
|
||||
*/
|
||||
if (lrp->detect != DB_LOCK_NORUN)
|
||||
ret = lock_detect(lt, 0, lrp->detect);
|
||||
if (lrp->detect != DB_LOCK_NORUN && !no_dd)
|
||||
(void)lock_detect(lt, 0, lrp->detect);
|
||||
|
||||
(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
|
||||
|
||||
LOCK_LOCKREGION(lt);
|
||||
if (newl->status != DB_LSTAT_PENDING) {
|
||||
/*
|
||||
* If this lock errored due to a deadlock, then
|
||||
* we have waiters that require promotion.
|
||||
*/
|
||||
if (newl->status == DB_LSTAT_ABORTED)
|
||||
(void)__lock_promote(lt, sh_obj);
|
||||
/* Return to free list. */
|
||||
__lock_checklocker(lt, newl, 0);
|
||||
SH_TAILQ_INSERT_HEAD(&lrp->free_locks, newl, links,
|
||||
@ -522,12 +633,31 @@ __lock_get_internal(lt, locker, flags, obj, lock_mode, lockp)
|
||||
}
|
||||
newl->status = DB_LSTAT_FREE;
|
||||
newl = NULL;
|
||||
} else if (LF_ISSET(DB_LOCK_UPGRADE)) {
|
||||
/*
|
||||
* The lock that was just granted got put on the
|
||||
* holders list. Since we're upgrading some other
|
||||
* lock, we've got to remove it here.
|
||||
*/
|
||||
SH_TAILQ_REMOVE(&sh_obj->holders,
|
||||
newl, links, __db_lock);
|
||||
goto upgrade;
|
||||
} else
|
||||
newl->status = DB_LSTAT_HELD;
|
||||
}
|
||||
|
||||
*lockp = newl;
|
||||
return (ret);
|
||||
|
||||
upgrade:
|
||||
/*
|
||||
* This was an upgrade, so return the new lock to the free list and
|
||||
* upgrade the mode.
|
||||
*/
|
||||
(*lockp)->mode = lock_mode;
|
||||
newl->status = DB_LSTAT_FREE;
|
||||
SH_TAILQ_INSERT_HEAD(&lrp->free_locks, newl, links, __db_lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -788,3 +918,117 @@ __lock_freeobj(lt, obj)
|
||||
__db_shalloc_free(lt->mem, SH_DBT_PTR(&obj->lockobj));
|
||||
SH_TAILQ_INSERT_HEAD(<->region->free_objs, obj, links, __db_lockobj);
|
||||
}
|
||||
|
||||
/*
|
||||
* __lock_downgrade --
|
||||
* Used by the concurrent access product to downgrade write locks
|
||||
* back to iwrite locks.
|
||||
*
|
||||
* PUBLIC: int __lock_downgrade __P((DB_LOCKTAB *,
|
||||
* PUBLIC: DB_LOCK, db_lockmode_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__lock_downgrade(lt, lock, new_mode, flags)
|
||||
DB_LOCKTAB *lt;
|
||||
DB_LOCK lock;
|
||||
db_lockmode_t new_mode;
|
||||
u_int32_t flags;
|
||||
{
|
||||
struct __db_lock *lockp;
|
||||
DB_LOCKOBJ *obj;
|
||||
int ret;
|
||||
|
||||
COMPQUIET(flags, 0);
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
LOCK_LOCKREGION(lt);
|
||||
|
||||
if ((ret = __lock_validate_region(lt)) == 0) {
|
||||
lockp = OFFSET_TO_LOCK(lt, lock);
|
||||
lockp->mode = new_mode;
|
||||
|
||||
/* Get the object associated with this lock. */
|
||||
obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
|
||||
(void)__lock_promote(lt, obj);
|
||||
++lt->region->nreleases;
|
||||
}
|
||||
|
||||
UNLOCK_LOCKREGION(lt);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __lock_promote --
|
||||
*
|
||||
* Look through the waiters and holders lists and decide which (if any)
|
||||
* locks can be promoted. Promote any that are eligible.
|
||||
*/
|
||||
static int
|
||||
__lock_promote(lt, obj)
|
||||
DB_LOCKTAB *lt;
|
||||
DB_LOCKOBJ *obj;
|
||||
{
|
||||
struct __db_lock *lp_w, *lp_h, *next_waiter;
|
||||
int state_changed, waiter_is_txn;
|
||||
|
||||
/*
|
||||
* We need to do lock promotion. We also need to determine if
|
||||
* we're going to need to run the deadlock detector again. If
|
||||
* we release locks, and there are waiters, but no one gets promoted,
|
||||
* then we haven't fundamentally changed the lockmgr state, so
|
||||
* we may still have a deadlock and we have to run again. However,
|
||||
* if there were no waiters, or we actually promoted someone, then
|
||||
* we are OK and we don't have to run it immediately.
|
||||
*
|
||||
* During promotion, we look for state changes so we can return
|
||||
* this information to the caller.
|
||||
*/
|
||||
for (lp_w = SH_TAILQ_FIRST(&obj->waiters, __db_lock),
|
||||
state_changed = lp_w == NULL;
|
||||
lp_w != NULL;
|
||||
lp_w = next_waiter) {
|
||||
waiter_is_txn = TXN_IS_HOLDING(lp_w);
|
||||
next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock);
|
||||
for (lp_h = SH_TAILQ_FIRST(&obj->holders, __db_lock);
|
||||
lp_h != NULL;
|
||||
lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) {
|
||||
if (CONFLICTS(lt, lp_h->mode, lp_w->mode) &&
|
||||
lp_h->holder != lp_w->holder &&
|
||||
!(waiter_is_txn &&
|
||||
TXN_IS_HOLDING(lp_h) &&
|
||||
__txn_is_ancestor(lt->dbenv->tx_info,
|
||||
lp_h->txnoff, lp_w->txnoff)))
|
||||
break;
|
||||
}
|
||||
if (lp_h != NULL) /* Found a conflict. */
|
||||
break;
|
||||
|
||||
/* No conflict, promote the waiting lock. */
|
||||
SH_TAILQ_REMOVE(&obj->waiters, lp_w, links, __db_lock);
|
||||
lp_w->status = DB_LSTAT_PENDING;
|
||||
SH_TAILQ_INSERT_TAIL(&obj->holders, lp_w, links);
|
||||
|
||||
/* Wake up waiter. */
|
||||
(void)__db_mutex_unlock(&lp_w->mutex, lt->reginfo.fd);
|
||||
state_changed = 1;
|
||||
}
|
||||
|
||||
return (state_changed);
|
||||
}
|
||||
|
||||
static int
|
||||
__lock_is_parent(locker, txn)
|
||||
u_int32_t locker;
|
||||
DB_TXN *txn;
|
||||
{
|
||||
DB_TXN *t;
|
||||
|
||||
if (txn == NULL)
|
||||
return (0);
|
||||
|
||||
for (t = txn->parent; t != NULL; t = t->parent)
|
||||
if (t->txnid == locker)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)lock_conflict.c 10.3 (Sleepycat) 4/10/98";
|
||||
static const char sccsid[] = "@(#)lock_conflict.c 10.4 (Sleepycat) 11/20/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -29,11 +29,11 @@ const u_int8_t db_rw_conflicts[] = {
|
||||
};
|
||||
|
||||
const u_int8_t db_riw_conflicts[] = {
|
||||
/* N S X IS IX SIX */
|
||||
/* N S X IX IS SIX */
|
||||
/* N */ 0, 0, 0, 0, 0, 0,
|
||||
/* S */ 0, 0, 1, 0, 1, 1,
|
||||
/* S */ 0, 0, 1, 1, 0, 1,
|
||||
/* X */ 1, 1, 1, 1, 1, 1,
|
||||
/* IS */ 0, 0, 1, 0, 0, 0,
|
||||
/* IX */ 0, 1, 1, 0, 0, 0,
|
||||
/* IS */ 0, 0, 1, 0, 0, 0,
|
||||
/* SIX */ 0, 1, 1, 0, 0, 0
|
||||
};
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)lock_deadlock.c 10.32 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)lock_deadlock.c 10.37 (Sleepycat) 10/4/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -69,6 +69,8 @@ lock_detect(lt, flags, atype)
|
||||
u_int32_t *bitmap, *deadlock, i, killid, nentries, nlockers;
|
||||
int do_pass, ret;
|
||||
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((ret =
|
||||
__db_fchk(lt->dbenv, "lock_detect", flags, DB_LOCK_CONFLICT)) != 0)
|
||||
@ -176,8 +178,8 @@ lock_detect(lt, flags, atype)
|
||||
"warning: unable to abort locker %lx",
|
||||
(u_long)idmap[killid].id);
|
||||
}
|
||||
__db_free(bitmap);
|
||||
__db_free(idmap);
|
||||
__os_free(bitmap, 0);
|
||||
__os_free(idmap, 0);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -198,7 +200,7 @@ __dd_build(dbenv, bmp, nlockers, idmap)
|
||||
u_int8_t *pptr;
|
||||
locker_info *id_array;
|
||||
u_int32_t *bitmap, count, *entryp, i, id, nentries, *tmpmap;
|
||||
int is_first;
|
||||
int is_first, ret;
|
||||
|
||||
lt = dbenv->lk_info;
|
||||
|
||||
@ -230,25 +232,20 @@ retry: count = lt->region->nlockers;
|
||||
* We can probably save the malloc's between iterations just
|
||||
* reallocing if necessary because count grew by too much.
|
||||
*/
|
||||
if ((bitmap = (u_int32_t *)__db_calloc((size_t)count,
|
||||
sizeof(u_int32_t) * nentries)) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_calloc((size_t)count,
|
||||
sizeof(u_int32_t) * nentries, &bitmap)) != 0)
|
||||
return (ret);
|
||||
|
||||
if ((ret = __os_calloc(sizeof(u_int32_t), nentries, &tmpmap)) != 0) {
|
||||
__os_free(bitmap, sizeof(u_int32_t) * nentries);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if ((tmpmap =
|
||||
(u_int32_t *)__db_calloc(sizeof(u_int32_t), nentries)) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
__db_free(bitmap);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
if ((id_array = (locker_info *)__db_calloc((size_t)count,
|
||||
sizeof(locker_info))) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
__db_free(bitmap);
|
||||
__db_free(tmpmap);
|
||||
return (ENOMEM);
|
||||
if ((ret =
|
||||
__os_calloc((size_t)count, sizeof(locker_info), &id_array)) != 0) {
|
||||
__os_free(bitmap, count * sizeof(u_int32_t) * nentries);
|
||||
__os_free(tmpmap, sizeof(u_int32_t) * nentries);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -256,9 +253,9 @@ retry: count = lt->region->nlockers;
|
||||
*/
|
||||
LOCK_LOCKREGION(lt);
|
||||
if (lt->region->nlockers > count) {
|
||||
__db_free(bitmap);
|
||||
__db_free(tmpmap);
|
||||
__db_free(id_array);
|
||||
__os_free(bitmap, count * sizeof(u_int32_t) * nentries);
|
||||
__os_free(tmpmap, sizeof(u_int32_t) * nentries);
|
||||
__os_free(id_array, count * sizeof(locker_info));
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@ -383,7 +380,7 @@ retry: count = lt->region->nlockers;
|
||||
*nlockers = id;
|
||||
*idmap = id_array;
|
||||
*bmp = bitmap;
|
||||
__db_free(tmpmap);
|
||||
__os_free(tmpmap, sizeof(u_int32_t) * nentries);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -434,8 +431,21 @@ __dd_abort(dbenv, info)
|
||||
goto out;
|
||||
|
||||
lockp = SH_LIST_FIRST(&lockerp->heldby, __db_lock);
|
||||
if (LOCK_TO_OFFSET(lt, lockp) != info->last_lock ||
|
||||
lockp == NULL || lockp->status != DB_LSTAT_WAITING)
|
||||
|
||||
/*
|
||||
* It's possible that this locker was already aborted.
|
||||
* If that's the case, make sure that we remove its
|
||||
* locker from the hash table.
|
||||
*/
|
||||
if (lockp == NULL) {
|
||||
HASHREMOVE_EL(lt->hashtab, __db_lockobj,
|
||||
links, lockerp, lt->region->table_size, __lock_lhash);
|
||||
SH_TAILQ_INSERT_HEAD(<->region->free_objs,
|
||||
lockerp, links, __db_lockobj);
|
||||
lt->region->nlockers--;
|
||||
goto out;
|
||||
} else if (LOCK_TO_OFFSET(lt, lockp) != info->last_lock ||
|
||||
lockp->status != DB_LSTAT_WAITING)
|
||||
goto out;
|
||||
|
||||
/* Abort lock, take it off list, and wake up this lock. */
|
||||
@ -460,17 +470,17 @@ __dd_debug(dbenv, idmap, bitmap, nlockers)
|
||||
u_int32_t *bitmap, nlockers;
|
||||
{
|
||||
u_int32_t i, j, *mymap, nentries;
|
||||
int ret;
|
||||
char *msgbuf;
|
||||
|
||||
__db_err(dbenv, "Waitsfor array");
|
||||
__db_err(dbenv, "waiter\twaiting on");
|
||||
/*
|
||||
* Allocate space to print 10 bytes per item waited on.
|
||||
*/
|
||||
if ((msgbuf = (char *)__db_malloc((nlockers + 1) * 10 + 64)) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
|
||||
/* Allocate space to print 10 bytes per item waited on. */
|
||||
#undef MSGBUF_LEN
|
||||
#define MSGBUF_LEN ((nlockers + 1) * 10 + 64)
|
||||
if ((ret = __os_malloc(MSGBUF_LEN, NULL, &msgbuf)) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
nentries = ALIGN(nlockers, 32) / 32;
|
||||
for (mymap = bitmap, i = 0; i < nlockers; i++, mymap += nentries) {
|
||||
@ -487,6 +497,6 @@ __dd_debug(dbenv, idmap, bitmap, nlockers)
|
||||
__db_err(dbenv, msgbuf);
|
||||
}
|
||||
|
||||
__db_free(msgbuf);
|
||||
__os_free(msgbuf, MSGBUF_LEN);
|
||||
}
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)lock_region.c 10.15 (Sleepycat) 6/2/98";
|
||||
static const char sccsid[] = "@(#)lock_region.c 10.21 (Sleepycat) 10/19/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -29,7 +29,8 @@ static u_int32_t __lock_count_locks __P((DB_LOCKREGION *));
|
||||
static u_int32_t __lock_count_objs __P((DB_LOCKREGION *));
|
||||
static void __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
|
||||
static void __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
|
||||
static const char *__lock_dump_status __P((db_status_t));
|
||||
static const char *
|
||||
__lock_dump_status __P((db_status_t));
|
||||
static void __lock_reset_region __P((DB_LOCKTAB *));
|
||||
static int __lock_tabinit __P((DB_ENV *, DB_LOCKREGION *));
|
||||
|
||||
@ -55,10 +56,8 @@ lock_open(path, flags, mode, dbenv, ltp)
|
||||
return (ret);
|
||||
|
||||
/* Create the lock table structure. */
|
||||
if ((lt = (DB_LOCKTAB *)__db_calloc(1, sizeof(DB_LOCKTAB))) == NULL) {
|
||||
__db_err(dbenv, "%s", strerror(ENOMEM));
|
||||
return (ENOMEM);
|
||||
}
|
||||
if ((ret = __os_calloc(1, sizeof(DB_LOCKTAB), <)) != 0)
|
||||
return (ret);
|
||||
lt->dbenv = dbenv;
|
||||
|
||||
/* Grab the values that we need to compute the region size. */
|
||||
@ -82,7 +81,7 @@ lock_open(path, flags, mode, dbenv, ltp)
|
||||
if (path == NULL)
|
||||
lt->reginfo.path = NULL;
|
||||
else
|
||||
if ((lt->reginfo.path = (char *)__db_strdup(path)) == NULL)
|
||||
if ((ret = __os_strdup(path, <->reginfo.path)) != 0)
|
||||
goto err;
|
||||
lt->reginfo.file = DB_DEFAULT_LOCK_FILE;
|
||||
lt->reginfo.mode = mode;
|
||||
@ -147,11 +146,26 @@ err: if (lt->reginfo.addr != NULL) {
|
||||
}
|
||||
|
||||
if (lt->reginfo.path != NULL)
|
||||
FREES(lt->reginfo.path);
|
||||
FREE(lt, sizeof(*lt));
|
||||
__os_freestr(lt->reginfo.path);
|
||||
__os_free(lt, sizeof(*lt));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __lock_panic --
|
||||
* Panic a lock region.
|
||||
*
|
||||
* PUBLIC: void __lock_panic __P((DB_ENV *));
|
||||
*/
|
||||
void
|
||||
__lock_panic(dbenv)
|
||||
DB_ENV *dbenv;
|
||||
{
|
||||
if (dbenv->lk_info != NULL)
|
||||
dbenv->lk_info->region->hdr.panic = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* __lock_tabinit --
|
||||
* Initialize the lock region.
|
||||
@ -254,12 +268,14 @@ lock_close(lt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
if ((ret = __db_rdetach(<->reginfo)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (lt->reginfo.path != NULL)
|
||||
FREES(lt->reginfo.path);
|
||||
FREE(lt, sizeof(*lt));
|
||||
__os_freestr(lt->reginfo.path);
|
||||
__os_free(lt, sizeof(*lt));
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -276,12 +292,12 @@ lock_unlink(path, force, dbenv)
|
||||
memset(®info, 0, sizeof(reginfo));
|
||||
reginfo.dbenv = dbenv;
|
||||
reginfo.appname = DB_APP_NONE;
|
||||
if (path != NULL && (reginfo.path = (char *)__db_strdup(path)) == NULL)
|
||||
return (ENOMEM);
|
||||
if (path != NULL && (ret = __os_strdup(path, ®info.path)) != 0)
|
||||
return (ret);
|
||||
reginfo.file = DB_DEFAULT_LOCK_FILE;
|
||||
ret = __db_runlink(®info, force);
|
||||
if (reginfo.path != NULL)
|
||||
FREES(reginfo.path);
|
||||
__os_freestr(reginfo.path);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -463,13 +479,14 @@ lock_stat(lt, gspp, db_malloc)
|
||||
void *(*db_malloc) __P((size_t));
|
||||
{
|
||||
DB_LOCKREGION *rp;
|
||||
int ret;
|
||||
|
||||
*gspp = NULL;
|
||||
|
||||
if ((*gspp = db_malloc == NULL ?
|
||||
(DB_LOCK_STAT *)__db_malloc(sizeof(**gspp)) :
|
||||
(DB_LOCK_STAT *)db_malloc(sizeof(**gspp))) == NULL)
|
||||
return (ENOMEM);
|
||||
LOCK_PANIC_CHECK(lt);
|
||||
|
||||
if ((ret = __os_malloc(sizeof(**gspp), db_malloc, gspp)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Copy out the global statistics. */
|
||||
LOCK_LOCKREGION(lt);
|
||||
@ -632,15 +649,15 @@ __lock_dump_region(lt, area, fp)
|
||||
for (lp = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
|
||||
lp != NULL;
|
||||
lp = SH_TAILQ_NEXT(lp, links, __db_lock))
|
||||
fprintf(fp, "0x%x: %lu\t%lu\t%s\t0x%x\n", (u_int)lp,
|
||||
fprintf(fp, "0x%lx: %lu\t%lu\t%s\t0x%lx\n", (u_long)lp,
|
||||
(u_long)lp->holder, (u_long)lp->mode,
|
||||
__lock_dump_status(lp->status), (u_int)lp->obj);
|
||||
__lock_dump_status(lp->status), (u_long)lp->obj);
|
||||
|
||||
fprintf(fp, "%s\nObject free list\n", DB_LINE);
|
||||
for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
|
||||
op != NULL;
|
||||
op = SH_TAILQ_NEXT(op, links, __db_lockobj))
|
||||
fprintf(fp, "0x%x\n", (u_int)op);
|
||||
fprintf(fp, "0x%lx\n", (u_long)op);
|
||||
}
|
||||
|
||||
if (LF_ISSET(LOCK_DUMP_MEM))
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)lock_util.c 10.9 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)lock_util.c 10.10 (Sleepycat) 9/20/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -75,7 +75,7 @@ __lock_locker_cmp(locker, lock_obj)
|
||||
* fast path the case where we think we are doing a hash on a DB page/fileid
|
||||
* pair. If the size is right, then we do the fast hash.
|
||||
*
|
||||
* We know that DB uses struct __db_ilocks for its lock objects. The first
|
||||
* We know that DB uses DB_LOCK_ILOCK types for its lock objects. The first
|
||||
* four bytes are the 4-byte page number and the next DB_FILE_ID_LEN bytes
|
||||
* are a unique file id, where the first 4 bytes on UNIX systems are the file
|
||||
* inode number, and the first 4 bytes on Windows systems are the FileIndexLow
|
||||
@ -107,7 +107,7 @@ u_int32_t
|
||||
__lock_ohash(dbt)
|
||||
const DBT *dbt;
|
||||
{
|
||||
if (dbt->size == sizeof(struct __db_ilock))
|
||||
if (dbt->size == sizeof(DB_LOCK_ILOCK))
|
||||
FAST_HASH(dbt->data);
|
||||
|
||||
return (__ham_func5(dbt->data, dbt->size));
|
||||
@ -131,7 +131,7 @@ __lock_lhash(lock_obj)
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
if (lock_obj->lockobj.size == sizeof(struct __db_ilock))
|
||||
if (lock_obj->lockobj.size == sizeof(DB_LOCK_ILOCK))
|
||||
FAST_HASH(obj_data);
|
||||
|
||||
return (__ham_func5(obj_data, lock_obj->lockobj.size));
|
||||
|
194
db2/log/log.c
194
db2/log/log.c
@ -7,13 +7,14 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)log.c 10.54 (Sleepycat) 5/31/98";
|
||||
static const char sccsid[] = "@(#)log.c 10.63 (Sleepycat) 10/10/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <shqueue.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -23,6 +24,7 @@ static const char sccsid[] = "@(#)log.c 10.54 (Sleepycat) 5/31/98";
|
||||
#include "shqueue.h"
|
||||
#include "log.h"
|
||||
#include "db_dispatch.h"
|
||||
#include "txn.h"
|
||||
#include "txn_auto.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
@ -54,13 +56,11 @@ log_open(path, flags, mode, dbenv, lpp)
|
||||
return (ret);
|
||||
|
||||
/* Create and initialize the DB_LOG structure. */
|
||||
if ((dblp = (DB_LOG *)__db_calloc(1, sizeof(DB_LOG))) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_calloc(1, sizeof(DB_LOG), &dblp)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (path != NULL && (dblp->dir = __db_strdup(path)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if (path != NULL && (ret = __os_strdup(path, &dblp->dir)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dblp->dbenv = dbenv;
|
||||
dblp->lfd = -1;
|
||||
@ -80,7 +80,7 @@ log_open(path, flags, mode, dbenv, lpp)
|
||||
if (path == NULL)
|
||||
dblp->reginfo.path = NULL;
|
||||
else
|
||||
if ((dblp->reginfo.path = __db_strdup(path)) == NULL)
|
||||
if ((ret = __os_strdup(path, &dblp->reginfo.path)) != 0)
|
||||
goto err;
|
||||
dblp->reginfo.file = DB_DEFAULT_LOG_FILE;
|
||||
dblp->reginfo.mode = mode;
|
||||
@ -122,7 +122,7 @@ log_open(path, flags, mode, dbenv, lpp)
|
||||
if ((ret = __db_shalloc(dblp->addr,
|
||||
sizeof(db_mutex_t), MUTEX_ALIGNMENT, &dblp->mutexp)) != 0)
|
||||
goto err;
|
||||
(void)__db_mutex_init(dblp->mutexp, -1);
|
||||
(void)__db_mutex_init(dblp->mutexp, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -148,13 +148,27 @@ err: if (dblp->reginfo.addr != NULL) {
|
||||
}
|
||||
|
||||
if (dblp->reginfo.path != NULL)
|
||||
FREES(dblp->reginfo.path);
|
||||
__os_freestr(dblp->reginfo.path);
|
||||
if (dblp->dir != NULL)
|
||||
FREES(dblp->dir);
|
||||
FREE(dblp, sizeof(*dblp));
|
||||
__os_freestr(dblp->dir);
|
||||
__os_free(dblp, sizeof(*dblp));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __log_panic --
|
||||
* Panic a log.
|
||||
*
|
||||
* PUBLIC: void __log_panic __P((DB_ENV *));
|
||||
*/
|
||||
void
|
||||
__log_panic(dbenv)
|
||||
DB_ENV *dbenv;
|
||||
{
|
||||
if (dbenv->lg_info != NULL)
|
||||
dbenv->lg_info->lp->rlayout.panic = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* __log_recover --
|
||||
* Recover a log.
|
||||
@ -212,12 +226,12 @@ __log_recover(dblp)
|
||||
}
|
||||
|
||||
/*
|
||||
* We know where the end of the log is. Since that record is on disk,
|
||||
* it's also the last-synced LSN.
|
||||
* We now know where the end of the log is. Set the first LSN that
|
||||
* we want to return to an application and the LSN of the last known
|
||||
* record on disk.
|
||||
*/
|
||||
lp->lsn = lsn;
|
||||
lp->lsn = lp->s_lsn = lsn;
|
||||
lp->lsn.offset += dblp->c_len;
|
||||
lp->s_lsn = lp->lsn;
|
||||
|
||||
/* Set up the current buffer information, too. */
|
||||
lp->len = dblp->c_len;
|
||||
@ -250,13 +264,23 @@ __log_recover(dblp)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Reset the cursor lsn to the beginning of the log, so that an
|
||||
* initial call to DB_NEXT does the right thing.
|
||||
*/
|
||||
ZERO_LSN(dblp->c_lsn);
|
||||
|
||||
/* If we never find a checkpoint, that's okay, just 0 it out. */
|
||||
if (!found_checkpoint)
|
||||
ZERO_LSN(lp->chkpt_lsn);
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* The test suite explicitly looks for this string -- don't change
|
||||
* it here unless you also change it there.
|
||||
*/
|
||||
__db_err(dblp->dbenv,
|
||||
"Recovering the log: last valid LSN: file: %lu offset %lu",
|
||||
"Finding last valid log LSN: file: %lu offset %lu",
|
||||
(u_long)lp->lsn.file, (u_long)lp->lsn.offset);
|
||||
|
||||
return (0);
|
||||
@ -275,14 +299,15 @@ __log_find(dblp, find_first, valp)
|
||||
DB_LOG *dblp;
|
||||
int find_first, *valp;
|
||||
{
|
||||
int cnt, fcnt, logval, ret;
|
||||
u_int32_t clv, logval;
|
||||
int cnt, fcnt, ret;
|
||||
const char *dir;
|
||||
char **names, *p, *q;
|
||||
|
||||
*valp = 0;
|
||||
|
||||
/* Find the directory name. */
|
||||
if ((ret = __log_name(dblp, 1, &p)) != 0)
|
||||
if ((ret = __log_name(dblp, 1, &p, NULL, 0)) != 0)
|
||||
return (ret);
|
||||
if ((q = __db_rpath(p)) == NULL)
|
||||
dir = PATH_DOT;
|
||||
@ -292,8 +317,8 @@ __log_find(dblp, find_first, valp)
|
||||
}
|
||||
|
||||
/* Get the list of file names. */
|
||||
ret = __db_dirlist(dir, &names, &fcnt);
|
||||
FREES(p);
|
||||
ret = __os_dirlist(dir, &names, &fcnt);
|
||||
__os_freestr(p);
|
||||
if (ret != 0) {
|
||||
__db_err(dblp->dbenv, "%s: %s", dir, strerror(ret));
|
||||
return (ret);
|
||||
@ -302,28 +327,30 @@ __log_find(dblp, find_first, valp)
|
||||
/*
|
||||
* Search for a valid log file name, return a value of 0 on
|
||||
* failure.
|
||||
*
|
||||
* XXX
|
||||
* Assumes that atoi(3) returns a 32-bit number.
|
||||
*/
|
||||
for (cnt = fcnt, logval = 0; --cnt >= 0;)
|
||||
if (strncmp(names[cnt], "log.", sizeof("log.") - 1) == 0) {
|
||||
logval = atoi(names[cnt] + 4);
|
||||
if (logval != 0 &&
|
||||
__log_valid(dblp, dblp->lp, logval) == 0)
|
||||
break;
|
||||
}
|
||||
for (cnt = fcnt, clv = logval = 0; --cnt >= 0;) {
|
||||
if (strncmp(names[cnt], LFPREFIX, sizeof(LFPREFIX) - 1) != 0)
|
||||
continue;
|
||||
|
||||
clv = atoi(names[cnt] + (sizeof(LFPREFIX) - 1));
|
||||
if (find_first) {
|
||||
if (logval != 0 && clv > logval)
|
||||
continue;
|
||||
} else
|
||||
if (logval != 0 && clv < logval)
|
||||
continue;
|
||||
|
||||
if (__log_valid(dblp, clv, 1) == 0)
|
||||
logval = clv;
|
||||
}
|
||||
|
||||
*valp = logval;
|
||||
|
||||
/* Discard the list. */
|
||||
__db_dirfree(names, fcnt);
|
||||
|
||||
/* We have a valid log file, find either the first or last one. */
|
||||
if (find_first) {
|
||||
for (; logval > 0; --logval)
|
||||
if (__log_valid(dblp, dblp->lp, logval - 1) != 0)
|
||||
break;
|
||||
} else
|
||||
for (; logval < MAXLFNAME; ++logval)
|
||||
if (__log_valid(dblp, dblp->lp, logval + 1) != 0)
|
||||
break;
|
||||
*valp = logval;
|
||||
__os_dirfree(names, fcnt);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -332,62 +359,68 @@ __log_find(dblp, find_first, valp)
|
||||
* log_valid --
|
||||
* Validate a log file.
|
||||
*
|
||||
* PUBLIC: int __log_valid __P((DB_LOG *, LOG *, int));
|
||||
* PUBLIC: int __log_valid __P((DB_LOG *, u_int32_t, int));
|
||||
*/
|
||||
int
|
||||
__log_valid(dblp, lp, cnt)
|
||||
__log_valid(dblp, number, set_persist)
|
||||
DB_LOG *dblp;
|
||||
LOG *lp;
|
||||
int cnt;
|
||||
u_int32_t number;
|
||||
int set_persist;
|
||||
{
|
||||
LOGP persist;
|
||||
ssize_t nw;
|
||||
char *fname;
|
||||
int fd, ret;
|
||||
char *p;
|
||||
|
||||
if ((ret = __log_name(dblp, cnt, &p)) != 0)
|
||||
/* Try to open the log file. */
|
||||
if ((ret = __log_name(dblp,
|
||||
number, &fname, &fd, DB_RDONLY | DB_SEQUENTIAL)) != 0) {
|
||||
__os_freestr(fname);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
if ((ret = __db_open(p,
|
||||
DB_RDONLY | DB_SEQUENTIAL,
|
||||
DB_RDONLY | DB_SEQUENTIAL, 0, &fd)) != 0 ||
|
||||
(ret = __db_seek(fd, 0, 0, sizeof(HDR), 0, SEEK_SET)) != 0 ||
|
||||
(ret = __db_read(fd, &persist, sizeof(LOGP), &nw)) != 0 ||
|
||||
/* Try to read the header. */
|
||||
if ((ret = __os_seek(fd, 0, 0, sizeof(HDR), 0, SEEK_SET)) != 0 ||
|
||||
(ret = __os_read(fd, &persist, sizeof(LOGP), &nw)) != 0 ||
|
||||
nw != sizeof(LOGP)) {
|
||||
if (ret == 0)
|
||||
ret = EIO;
|
||||
if (fd != -1) {
|
||||
(void)__db_close(fd);
|
||||
__db_err(dblp->dbenv,
|
||||
"Ignoring log file: %s: %s", p, strerror(ret));
|
||||
}
|
||||
|
||||
(void)__os_close(fd);
|
||||
|
||||
__db_err(dblp->dbenv,
|
||||
"Ignoring log file: %s: %s", fname, strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
(void)__db_close(fd);
|
||||
(void)__os_close(fd);
|
||||
|
||||
/* Validate the header. */
|
||||
if (persist.magic != DB_LOGMAGIC) {
|
||||
__db_err(dblp->dbenv,
|
||||
"Ignoring log file: %s: magic number %lx, not %lx",
|
||||
p, (u_long)persist.magic, (u_long)DB_LOGMAGIC);
|
||||
fname, (u_long)persist.magic, (u_long)DB_LOGMAGIC);
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if (persist.version < DB_LOGOLDVER || persist.version > DB_LOGVERSION) {
|
||||
__db_err(dblp->dbenv,
|
||||
"Ignoring log file: %s: unsupported log version %lu",
|
||||
p, (u_long)persist.version);
|
||||
fname, (u_long)persist.version);
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (lp != NULL) {
|
||||
lp->persist.lg_max = persist.lg_max;
|
||||
lp->persist.mode = persist.mode;
|
||||
/*
|
||||
* If we're going to use this log file, set the region's persistent
|
||||
* information based on the headers.
|
||||
*/
|
||||
if (set_persist) {
|
||||
dblp->lp->persist.lg_max = persist.lg_max;
|
||||
dblp->lp->persist.mode = persist.mode;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
err: FREES(p);
|
||||
err: __os_freestr(fname);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -401,6 +434,11 @@ log_close(dblp)
|
||||
{
|
||||
int ret, t_ret;
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
/* We may have opened files as part of XA; if so, close them. */
|
||||
__log_close_files(dblp);
|
||||
|
||||
/* Discard the per-thread pointer. */
|
||||
if (dblp->mutexp != NULL) {
|
||||
LOCK_LOGREGION(dblp);
|
||||
@ -412,21 +450,22 @@ log_close(dblp)
|
||||
ret = __db_rdetach(&dblp->reginfo);
|
||||
|
||||
/* Close open files, release allocated memory. */
|
||||
if (dblp->lfd != -1 && (t_ret = __db_close(dblp->lfd)) != 0 && ret == 0)
|
||||
if (dblp->lfd != -1 && (t_ret = __os_close(dblp->lfd)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
if (dblp->c_dbt.data != NULL)
|
||||
FREE(dblp->c_dbt.data, dblp->c_dbt.ulen);
|
||||
__os_free(dblp->c_dbt.data, dblp->c_dbt.ulen);
|
||||
if (dblp->c_fd != -1 &&
|
||||
(t_ret = __db_close(dblp->c_fd)) != 0 && ret == 0)
|
||||
(t_ret = __os_close(dblp->c_fd)) != 0 && ret == 0)
|
||||
ret = t_ret;
|
||||
if (dblp->dbentry != NULL)
|
||||
FREE(dblp->dbentry, (dblp->dbentry_cnt * sizeof(DB_ENTRY)));
|
||||
__os_free(dblp->dbentry,
|
||||
(dblp->dbentry_cnt * sizeof(DB_ENTRY)));
|
||||
if (dblp->dir != NULL)
|
||||
FREES(dblp->dir);
|
||||
__os_freestr(dblp->dir);
|
||||
|
||||
if (dblp->reginfo.path != NULL)
|
||||
FREES(dblp->reginfo.path);
|
||||
FREE(dblp, sizeof(*dblp));
|
||||
__os_freestr(dblp->reginfo.path);
|
||||
__os_free(dblp, sizeof(*dblp));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -447,12 +486,12 @@ log_unlink(path, force, dbenv)
|
||||
memset(®info, 0, sizeof(reginfo));
|
||||
reginfo.dbenv = dbenv;
|
||||
reginfo.appname = DB_APP_LOG;
|
||||
if (path != NULL && (reginfo.path = __db_strdup(path)) == NULL)
|
||||
return (ENOMEM);
|
||||
if (path != NULL && (ret = __os_strdup(path, ®info.path)) != 0)
|
||||
return (ret);
|
||||
reginfo.file = DB_DEFAULT_LOG_FILE;
|
||||
ret = __db_runlink(®info, force);
|
||||
if (reginfo.path != NULL)
|
||||
FREES(reginfo.path);
|
||||
__os_freestr(reginfo.path);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -467,14 +506,15 @@ log_stat(dblp, gspp, db_malloc)
|
||||
void *(*db_malloc) __P((size_t));
|
||||
{
|
||||
LOG *lp;
|
||||
int ret;
|
||||
|
||||
*gspp = NULL;
|
||||
lp = dblp->lp;
|
||||
|
||||
if ((*gspp = db_malloc == NULL ?
|
||||
(DB_LOG_STAT *)__db_malloc(sizeof(**gspp)) :
|
||||
(DB_LOG_STAT *)db_malloc(sizeof(**gspp))) == NULL)
|
||||
return (ENOMEM);
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
if ((ret = __os_malloc(sizeof(**gspp), db_malloc, gspp)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Copy out the global statistics. */
|
||||
LOCK_LOGREGION(dblp);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)log_archive.c 10.37 (Sleepycat) 5/3/98";
|
||||
static const char sccsid[] = "@(#)log_archive.c 10.44 (Sleepycat) 10/9/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -49,8 +49,11 @@ log_archive(dblp, listp, flags, db_malloc)
|
||||
int array_size, n, ret;
|
||||
char **array, **arrayp, *name, *p, *pref, buf[MAXPATHLEN];
|
||||
|
||||
name = NULL;
|
||||
COMPQUIET(fnum, 0);
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
#define OKFLAGS (DB_ARCH_ABS | DB_ARCH_DATA | DB_ARCH_LOG)
|
||||
if (flags != 0) {
|
||||
if ((ret =
|
||||
@ -84,7 +87,7 @@ log_archive(dblp, listp, flags, db_malloc)
|
||||
if ((ret = log_get(dblp, &stable_lsn, &rec, DB_LAST)) != 0)
|
||||
return (ret);
|
||||
if (F_ISSET(dblp, DB_AM_THREAD))
|
||||
__db_free(rec.data);
|
||||
__os_free(rec.data, rec.size);
|
||||
fnum = stable_lsn.file;
|
||||
break;
|
||||
case 0:
|
||||
@ -106,40 +109,40 @@ log_archive(dblp, listp, flags, db_malloc)
|
||||
|
||||
#define LIST_INCREMENT 64
|
||||
/* Get some initial space. */
|
||||
if ((array =
|
||||
(char **)__db_malloc(sizeof(char *) * (array_size = 10))) == NULL)
|
||||
return (ENOMEM);
|
||||
array_size = 10;
|
||||
if ((ret = __os_malloc(sizeof(char *) * array_size, NULL, &array)) != 0)
|
||||
return (ret);
|
||||
array[0] = NULL;
|
||||
|
||||
/* Build an array of the file names. */
|
||||
for (n = 0; fnum > 0; --fnum) {
|
||||
if ((ret = __log_name(dblp, fnum, &name)) != 0)
|
||||
if ((ret = __log_name(dblp, fnum, &name, NULL, 0)) != 0)
|
||||
goto err;
|
||||
if (__db_exists(name, NULL) != 0)
|
||||
if (__os_exists(name, NULL) != 0) {
|
||||
__os_freestr(name);
|
||||
name = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n >= array_size - 1) {
|
||||
array_size += LIST_INCREMENT;
|
||||
if ((array = (char **)__db_realloc(array,
|
||||
sizeof(char *) * array_size)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_realloc(&array,
|
||||
sizeof(char *) * array_size)) != 0)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (LF_ISSET(DB_ARCH_ABS)) {
|
||||
if ((ret = __absname(pref, name, &array[n])) != 0)
|
||||
goto err;
|
||||
FREES(name);
|
||||
__os_freestr(name);
|
||||
} else if ((p = __db_rpath(name)) != NULL) {
|
||||
if ((array[n] = (char *)__db_strdup(p + 1)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_strdup(p + 1, &array[n])) != 0)
|
||||
goto err;
|
||||
}
|
||||
FREES(name);
|
||||
__os_freestr(name);
|
||||
} else
|
||||
array[n] = name;
|
||||
|
||||
name = NULL;
|
||||
array[++n] = NULL;
|
||||
}
|
||||
|
||||
@ -162,9 +165,11 @@ log_archive(dblp, listp, flags, db_malloc)
|
||||
|
||||
err: if (array != NULL) {
|
||||
for (arrayp = array; *arrayp != NULL; ++arrayp)
|
||||
FREES(*arrayp);
|
||||
__db_free(array);
|
||||
__os_freestr(*arrayp);
|
||||
__os_free(array, sizeof(char *) * array_size);
|
||||
}
|
||||
if (name != NULL)
|
||||
__os_freestr(name);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -186,9 +191,9 @@ __build_data(dblp, pref, listp, db_malloc)
|
||||
char **array, **arrayp, *p, *real_name;
|
||||
|
||||
/* Get some initial space. */
|
||||
if ((array =
|
||||
(char **)__db_malloc(sizeof(char *) * (array_size = 10))) == NULL)
|
||||
return (ENOMEM);
|
||||
array_size = 10;
|
||||
if ((ret = __os_malloc(sizeof(char *) * array_size, NULL, &array)) != 0)
|
||||
return (ret);
|
||||
array[0] = NULL;
|
||||
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
@ -205,7 +210,7 @@ __build_data(dblp, pref, listp, db_malloc)
|
||||
memcpy(&rectype, rec.data, sizeof(rectype));
|
||||
if (rectype != DB_log_register) {
|
||||
if (F_ISSET(dblp, DB_AM_THREAD)) {
|
||||
__db_free(rec.data);
|
||||
__os_free(rec.data, rec.size);
|
||||
rec.data = NULL;
|
||||
}
|
||||
continue;
|
||||
@ -219,25 +224,22 @@ __build_data(dblp, pref, listp, db_malloc)
|
||||
|
||||
if (n >= array_size - 1) {
|
||||
array_size += LIST_INCREMENT;
|
||||
if ((array = (char **)__db_realloc(array,
|
||||
sizeof(char *) * array_size)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_realloc(&array,
|
||||
sizeof(char *) * array_size)) != 0)
|
||||
goto lg_free;
|
||||
}
|
||||
}
|
||||
|
||||
if ((array[n] = (char *)__db_strdup(argp->name.data)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_strdup(argp->name.data, &array[n])) != 0) {
|
||||
lg_free: if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL)
|
||||
__db_free(rec.data);
|
||||
__os_free(rec.data, rec.size);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
array[++n] = NULL;
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
|
||||
if (F_ISSET(dblp, DB_AM_THREAD)) {
|
||||
__db_free(rec.data);
|
||||
__os_free(rec.data, rec.size);
|
||||
rec.data = NULL;
|
||||
}
|
||||
}
|
||||
@ -268,7 +270,7 @@ lg_free: if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL)
|
||||
}
|
||||
for (++nxt; nxt < n &&
|
||||
strcmp(array[last], array[nxt]) == 0; ++nxt) {
|
||||
FREES(array[nxt]);
|
||||
__os_freestr(array[nxt]);
|
||||
array[nxt] = NULL;
|
||||
}
|
||||
|
||||
@ -278,25 +280,25 @@ lg_free: if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL)
|
||||
goto err2;
|
||||
|
||||
/* If the file doesn't exist, ignore it. */
|
||||
if (__db_exists(real_name, NULL) != 0) {
|
||||
FREES(real_name);
|
||||
FREES(array[last]);
|
||||
if (__os_exists(real_name, NULL) != 0) {
|
||||
__os_freestr(real_name);
|
||||
__os_freestr(array[last]);
|
||||
array[last] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Rework the name as requested by the user. */
|
||||
FREES(array[last]);
|
||||
__os_freestr(array[last]);
|
||||
array[last] = NULL;
|
||||
if (pref != NULL) {
|
||||
ret = __absname(pref, real_name, &array[last]);
|
||||
FREES(real_name);
|
||||
__os_freestr(real_name);
|
||||
if (ret != 0)
|
||||
goto err2;
|
||||
} else if ((p = __db_rpath(real_name)) != NULL) {
|
||||
array[last] = (char *)__db_strdup(p + 1);
|
||||
FREES(real_name);
|
||||
if (array[last] == NULL)
|
||||
ret = __os_strdup(p + 1, &array[last]);
|
||||
__os_freestr(real_name);
|
||||
if (ret != 0)
|
||||
goto err2;
|
||||
} else
|
||||
array[last] = real_name;
|
||||
@ -320,13 +322,13 @@ err2: /*
|
||||
*/
|
||||
if (array != NULL)
|
||||
for (; nxt < n; ++nxt)
|
||||
FREES(array[nxt]);
|
||||
__os_freestr(array[nxt]);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
err1: if (array != NULL) {
|
||||
for (arrayp = array; *arrayp != NULL; ++arrayp)
|
||||
FREES(*arrayp);
|
||||
__db_free(array);
|
||||
__os_freestr(*arrayp);
|
||||
__os_free(array, array_size * sizeof(char *));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
@ -340,17 +342,17 @@ __absname(pref, name, newnamep)
|
||||
char *pref, *name, **newnamep;
|
||||
{
|
||||
size_t l_pref, l_name;
|
||||
int isabspath;
|
||||
int isabspath, ret;
|
||||
char *newname;
|
||||
|
||||
l_name = strlen(name);
|
||||
isabspath = __db_abspath(name);
|
||||
isabspath = __os_abspath(name);
|
||||
l_pref = isabspath ? 0 : strlen(pref);
|
||||
|
||||
/* Malloc space for concatenating the two. */
|
||||
if ((*newnamep =
|
||||
newname = (char *)__db_malloc(l_pref + l_name + 2)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(l_pref + l_name + 2, NULL, &newname)) != 0)
|
||||
return (ret);
|
||||
*newnamep = newname;
|
||||
|
||||
/* Build the name. If `name' is an absolute path, ignore any prefix. */
|
||||
if (!isabspath) {
|
||||
@ -369,11 +371,12 @@ __absname(pref, name, newnamep)
|
||||
* If the user has their own malloc routine, use it.
|
||||
*/
|
||||
static int
|
||||
__usermem(listp, cmpfunc)
|
||||
__usermem(listp, db_malloc)
|
||||
char ***listp;
|
||||
void *(*cmpfunc) __P((size_t));
|
||||
void *(*db_malloc) __P((size_t));
|
||||
{
|
||||
size_t len;
|
||||
int ret;
|
||||
char **array, **arrayp, **orig, *strp;
|
||||
|
||||
/* Find out how much space we need. */
|
||||
@ -381,18 +384,10 @@ __usermem(listp, cmpfunc)
|
||||
len += sizeof(char *) + strlen(*orig) + 1;
|
||||
len += sizeof(char *);
|
||||
|
||||
/*
|
||||
* Allocate it and set up the pointers.
|
||||
*
|
||||
* XXX
|
||||
* Don't simplify this expression, SunOS compilers don't like it.
|
||||
*/
|
||||
if (cmpfunc == NULL)
|
||||
array = (char **)__db_malloc(len);
|
||||
else
|
||||
array = (char **)cmpfunc(len);
|
||||
if (array == NULL)
|
||||
return (ENOMEM);
|
||||
/* Allocate it and set up the pointers. */
|
||||
if ((ret = __os_malloc(len, db_malloc, &array)) != 0)
|
||||
return (ret);
|
||||
|
||||
strp = (char *)(array + (orig - *listp) + 1);
|
||||
|
||||
/* Copy the original information into the new memory. */
|
||||
@ -402,13 +397,13 @@ __usermem(listp, cmpfunc)
|
||||
*arrayp = strp;
|
||||
strp += len + 1;
|
||||
|
||||
FREES(*orig);
|
||||
__os_freestr(*orig);
|
||||
}
|
||||
|
||||
/* NULL-terminate the list. */
|
||||
*arrayp = NULL;
|
||||
|
||||
__db_free(*listp);
|
||||
__os_free(*listp, 0);
|
||||
*listp = array;
|
||||
|
||||
return (0);
|
||||
|
@ -10,7 +10,6 @@
|
||||
#endif
|
||||
|
||||
#include "db_int.h"
|
||||
#include "shqueue.h"
|
||||
#include "db_page.h"
|
||||
#include "db_dispatch.h"
|
||||
#include "log.h"
|
||||
@ -43,8 +42,7 @@ int __log_register_log(logp, txnid, ret_lsnp, flags,
|
||||
rectype = DB_log_register;
|
||||
txn_num = txnid == NULL ? 0 : txnid->txnid;
|
||||
if (txnid == NULL) {
|
||||
null_lsn.file = 0;
|
||||
null_lsn.offset = 0;
|
||||
ZERO_LSN(null_lsn);
|
||||
lsnp = &null_lsn;
|
||||
} else
|
||||
lsnp = &txnid->last_lsn;
|
||||
@ -54,8 +52,8 @@ int __log_register_log(logp, txnid, ret_lsnp, flags,
|
||||
+ sizeof(u_int32_t) + (uid == NULL ? 0 : uid->size)
|
||||
+ sizeof(id)
|
||||
+ sizeof(ftype);
|
||||
if ((logrec.data = (void *)__db_malloc(logrec.size)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(logrec.size, NULL, &logrec.data)) != 0)
|
||||
return (ret);
|
||||
|
||||
bp = logrec.data;
|
||||
memcpy(bp, &rectype, sizeof(rectype));
|
||||
@ -97,7 +95,7 @@ int __log_register_log(logp, txnid, ret_lsnp, flags,
|
||||
ret = __log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
|
||||
if (txnid != NULL)
|
||||
txnid->last_lsn = *ret_lsnp;
|
||||
__db_free(logrec.data);
|
||||
__os_free(logrec.data, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -155,7 +153,7 @@ __log_register_print(notused1, dbtp, lsnp, notused2, notused3)
|
||||
printf("\tid: %lu\n", (u_long)argp->id);
|
||||
printf("\tftype: 0x%lx\n", (u_long)argp->ftype);
|
||||
printf("\n");
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -169,11 +167,12 @@ __log_register_read(recbuf, argpp)
|
||||
{
|
||||
__log_register_args *argp;
|
||||
u_int8_t *bp;
|
||||
int ret;
|
||||
|
||||
argp = (__log_register_args *)__db_malloc(sizeof(__log_register_args) +
|
||||
sizeof(DB_TXN));
|
||||
if (argp == NULL)
|
||||
return (ENOMEM);
|
||||
ret = __os_malloc(sizeof(__log_register_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));
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)log_findckp.c 10.15 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)log_findckp.c 10.17 (Sleepycat) 9/17/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -28,7 +28,10 @@ static const char sccsid[] = "@(#)log_findckp.c 10.15 (Sleepycat) 4/26/98";
|
||||
* __log_findckp --
|
||||
*
|
||||
* Looks for the most recent checkpoint that occurs before the most recent
|
||||
* checkpoint LSN. This is the point from which recovery can start and the
|
||||
* checkpoint LSN, subject to the constraint that there must be at least two
|
||||
* checkpoints. The reason you need two checkpoints is that you might have
|
||||
* crashed during the most recent one and may not have a copy of all the
|
||||
* open files. This is the point from which recovery can start and the
|
||||
* point up to which archival/truncation can take place. Checkpoints in
|
||||
* the log look like:
|
||||
*
|
||||
@ -56,7 +59,7 @@ __log_findckp(lp, lsnp)
|
||||
DB_LSN *lsnp;
|
||||
{
|
||||
DBT data;
|
||||
DB_LSN ckp_lsn, last_ckp, next_lsn;
|
||||
DB_LSN ckp_lsn, final_ckp, last_ckp, next_lsn;
|
||||
__txn_ckp_args *ckp_args;
|
||||
int ret, verbose;
|
||||
|
||||
@ -77,16 +80,17 @@ __log_findckp(lp, lsnp)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
final_ckp = last_ckp;
|
||||
next_lsn = last_ckp;
|
||||
do {
|
||||
if (F_ISSET(lp, DB_AM_THREAD))
|
||||
__db_free(data.data);
|
||||
__os_free(data.data, data.size);
|
||||
|
||||
if ((ret = log_get(lp, &next_lsn, &data, DB_SET)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __txn_ckp_read(data.data, &ckp_args)) != 0) {
|
||||
if (F_ISSET(lp, DB_AM_THREAD))
|
||||
__db_free(data.data);
|
||||
__os_free(data.data, data.size);
|
||||
return (ret);
|
||||
}
|
||||
if (IS_ZERO_LSN(ckp_lsn))
|
||||
@ -103,12 +107,19 @@ __log_findckp(lp, lsnp)
|
||||
}
|
||||
last_ckp = next_lsn;
|
||||
next_lsn = ckp_args->last_ckp;
|
||||
__db_free(ckp_args);
|
||||
__os_free(ckp_args, sizeof(*ckp_args));
|
||||
|
||||
/*
|
||||
* Keep looping until either you 1) run out of checkpoints,
|
||||
* 2) you've found a checkpoint before the most recent
|
||||
* checkpoint's LSN and you have at least 2 checkpoints.
|
||||
*/
|
||||
} while (!IS_ZERO_LSN(next_lsn) &&
|
||||
log_compare(&last_ckp, &ckp_lsn) > 0);
|
||||
(log_compare(&last_ckp, &ckp_lsn) > 0 ||
|
||||
log_compare(&final_ckp, &last_ckp) == 0));
|
||||
|
||||
if (F_ISSET(lp, DB_AM_THREAD))
|
||||
__db_free(data.data);
|
||||
__os_free(data.data, data.size);
|
||||
|
||||
/*
|
||||
* At this point, either, next_lsn is ZERO or ckp_lsn is the
|
||||
@ -117,11 +128,12 @@ __log_findckp(lp, lsnp)
|
||||
* next_lsn must be 0 and we need to roll forward from the
|
||||
* beginning of the log.
|
||||
*/
|
||||
if (log_compare(&last_ckp, &ckp_lsn) > 0) {
|
||||
if (log_compare(&last_ckp, &ckp_lsn) > 0 ||
|
||||
log_compare(&final_ckp, &last_ckp) == 0) {
|
||||
get_first: if ((ret = log_get(lp, &last_ckp, &data, DB_FIRST)) != 0)
|
||||
return (ret);
|
||||
if (F_ISSET(lp, DB_AM_THREAD))
|
||||
__db_free(data.data);
|
||||
__os_free(data.data, data.size);
|
||||
}
|
||||
*lsnp = last_ckp;
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)log_get.c 10.32 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)log_get.c 10.38 (Sleepycat) 10/3/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -38,26 +38,16 @@ log_get(dblp, alsn, dbt, flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
/* Validate arguments. */
|
||||
#define OKFLAGS (DB_CHECKPOINT | \
|
||||
DB_CURRENT | DB_FIRST | DB_LAST | DB_NEXT | DB_PREV | DB_SET)
|
||||
if ((ret = __db_fchk(dblp->dbenv, "log_get", flags, OKFLAGS)) != 0)
|
||||
return (ret);
|
||||
switch (flags) {
|
||||
case DB_CHECKPOINT:
|
||||
case DB_CURRENT:
|
||||
case DB_FIRST:
|
||||
case DB_LAST:
|
||||
case DB_NEXT:
|
||||
case DB_PREV:
|
||||
case DB_SET:
|
||||
break;
|
||||
default:
|
||||
if (flags != DB_CHECKPOINT && flags != DB_CURRENT &&
|
||||
flags != DB_FIRST && flags != DB_LAST &&
|
||||
flags != DB_NEXT && flags != DB_PREV && flags != DB_SET)
|
||||
return (__db_ferr(dblp->dbenv, "log_get", 1));
|
||||
}
|
||||
|
||||
if (F_ISSET(dblp, DB_AM_THREAD)) {
|
||||
if (LF_ISSET(DB_NEXT | DB_PREV | DB_CURRENT))
|
||||
if (flags == DB_NEXT || flags == DB_PREV || flags == DB_CURRENT)
|
||||
return (__db_ferr(dblp->dbenv, "log_get", 1));
|
||||
if (!F_ISSET(dbt, DB_DBT_USERMEM | DB_DBT_MALLOC))
|
||||
return (__db_ferr(dblp->dbenv, "threaded data", 1));
|
||||
@ -156,7 +146,7 @@ __log_get(dblp, alsn, dbt, flags, silent)
|
||||
/* If at start-of-file, move to the previous file. */
|
||||
if (nlsn.offset == 0) {
|
||||
if (nlsn.file == 1 ||
|
||||
__log_valid(dblp, NULL, nlsn.file - 1) != 0)
|
||||
__log_valid(dblp, nlsn.file - 1, 0) != 0)
|
||||
return (DB_NOTFOUND);
|
||||
|
||||
--nlsn.file;
|
||||
@ -183,7 +173,7 @@ retry:
|
||||
|
||||
/* If we've switched files, discard the current fd. */
|
||||
if (dblp->c_lsn.file != nlsn.file && dblp->c_fd != -1) {
|
||||
(void)__db_close(dblp->c_fd);
|
||||
(void)__os_close(dblp->c_fd);
|
||||
dblp->c_fd = -1;
|
||||
}
|
||||
|
||||
@ -203,24 +193,22 @@ retry:
|
||||
|
||||
/* Acquire a file descriptor. */
|
||||
if (dblp->c_fd == -1) {
|
||||
if ((ret = __log_name(dblp, nlsn.file, &np)) != 0)
|
||||
goto err1;
|
||||
if ((ret = __db_open(np, DB_RDONLY | DB_SEQUENTIAL,
|
||||
DB_RDONLY | DB_SEQUENTIAL, 0, &dblp->c_fd)) != 0) {
|
||||
if ((ret = __log_name(dblp, nlsn.file,
|
||||
&np, &dblp->c_fd, DB_RDONLY | DB_SEQUENTIAL)) != 0) {
|
||||
fail = np;
|
||||
goto err1;
|
||||
}
|
||||
__db_free(np);
|
||||
__os_freestr(np);
|
||||
np = NULL;
|
||||
}
|
||||
|
||||
/* Seek to the header offset and read the header. */
|
||||
if ((ret =
|
||||
__db_seek(dblp->c_fd, 0, 0, nlsn.offset, 0, SEEK_SET)) != 0) {
|
||||
__os_seek(dblp->c_fd, 0, 0, nlsn.offset, 0, SEEK_SET)) != 0) {
|
||||
fail = "seek";
|
||||
goto err1;
|
||||
}
|
||||
if ((ret = __db_read(dblp->c_fd, &hdr, sizeof(HDR), &nr)) != 0) {
|
||||
if ((ret = __os_read(dblp->c_fd, &hdr, sizeof(HDR), &nr)) != 0) {
|
||||
fail = "read";
|
||||
goto err1;
|
||||
}
|
||||
@ -276,10 +264,8 @@ retry:
|
||||
* We're calling malloc(3) with a region locked. This isn't
|
||||
* a good idea.
|
||||
*/
|
||||
if ((tbuf = (char *)__db_malloc(len)) == NULL) {
|
||||
ret = ENOMEM;
|
||||
if ((ret = __os_malloc(len, NULL, &tbuf)) != 0)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the record into the buffer. If read returns a short count,
|
||||
@ -287,7 +273,7 @@ retry:
|
||||
* buffer. Note, the information may be garbage if we're in recovery,
|
||||
* so don't read past the end of the buffer's memory.
|
||||
*/
|
||||
if ((ret = __db_read(dblp->c_fd, tbuf, len, &nr)) != 0) {
|
||||
if ((ret = __os_read(dblp->c_fd, tbuf, len, &nr)) != 0) {
|
||||
fail = "read";
|
||||
goto err1;
|
||||
}
|
||||
@ -305,7 +291,7 @@ retry:
|
||||
if ((ret = __db_retcopy(dbt, tbuf, len,
|
||||
&dblp->c_dbt.data, &dblp->c_dbt.ulen, NULL)) != 0)
|
||||
goto err1;
|
||||
__db_free(tbuf);
|
||||
__os_free(tbuf, 0);
|
||||
tbuf = NULL;
|
||||
|
||||
cksum: if (hdr.cksum != __ham_func4(dbt->data, dbt->size)) {
|
||||
@ -329,7 +315,7 @@ corrupt:/*
|
||||
ret = EIO;
|
||||
fail = "read";
|
||||
|
||||
err1: if (!silent) {
|
||||
err1: if (!silent) {
|
||||
if (fail == NULL)
|
||||
__db_err(dblp->dbenv, "log_get: %s", strerror(ret));
|
||||
else
|
||||
@ -337,8 +323,8 @@ corrupt:/*
|
||||
"log_get: %s: %s", fail, strerror(ret));
|
||||
}
|
||||
err2: if (np != NULL)
|
||||
__db_free(np);
|
||||
__os_freestr(np);
|
||||
if (tbuf != NULL)
|
||||
__db_free(tbuf);
|
||||
__os_free(tbuf, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -7,13 +7,14 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)log_put.c 10.35 (Sleepycat) 5/6/98";
|
||||
static const char sccsid[] = "@(#)log_put.c 10.44 (Sleepycat) 11/3/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@ -24,6 +25,7 @@ static const char sccsid[] = "@(#)log_put.c 10.35 (Sleepycat) 5/6/98";
|
||||
#include "db_page.h"
|
||||
#include "log.h"
|
||||
#include "hash.h"
|
||||
#include "clib_ext.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
static int __log_fill __P((DB_LOG *, DB_LSN *, void *, u_int32_t));
|
||||
@ -45,22 +47,12 @@ log_put(dblp, lsn, dbt, flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
/* Validate arguments. */
|
||||
#define OKFLAGS (DB_CHECKPOINT | DB_FLUSH | DB_CURLSN)
|
||||
if (flags != 0) {
|
||||
if ((ret =
|
||||
__db_fchk(dblp->dbenv, "log_put", flags, OKFLAGS)) != 0)
|
||||
return (ret);
|
||||
switch (flags) {
|
||||
case DB_CHECKPOINT:
|
||||
case DB_CURLSN:
|
||||
case DB_FLUSH:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (__db_ferr(dblp->dbenv, "log_put", 1));
|
||||
}
|
||||
}
|
||||
if (flags != 0 && flags != DB_CHECKPOINT &&
|
||||
flags != DB_CURLSN && flags != DB_FLUSH)
|
||||
return (__db_ferr(dblp->dbenv, "log_put", 0));
|
||||
|
||||
LOCK_LOGREGION(dblp);
|
||||
ret = __log_put(dblp, lsn, dbt, flags);
|
||||
@ -95,7 +87,7 @@ __log_put(dblp, lsn, dbt, flags)
|
||||
* the information. Currently used by the transaction manager
|
||||
* to avoid writing TXN_begin records.
|
||||
*/
|
||||
if (LF_ISSET(DB_CURLSN)) {
|
||||
if (flags == DB_CURLSN) {
|
||||
lsn->file = lp->lsn.file;
|
||||
lsn->offset = lp->lsn.offset;
|
||||
return (0);
|
||||
@ -165,6 +157,8 @@ __log_put(dblp, lsn, dbt, flags)
|
||||
|
||||
for (fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
|
||||
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
|
||||
if (fnp->ref == 0) /* Entry not in use. */
|
||||
continue;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.data = R_ADDR(dblp, fnp->name_off);
|
||||
t.size = strlen(t.data) + 1;
|
||||
@ -248,6 +242,8 @@ log_flush(dblp, lsn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
LOCK_LOGREGION(dblp);
|
||||
ret = __log_flush(dblp, lsn);
|
||||
UNLOCK_LOGREGION(dblp);
|
||||
@ -304,8 +300,7 @@ __log_flush(dblp, lsn)
|
||||
* buffer's starting LSN.
|
||||
*/
|
||||
current = 0;
|
||||
if (lp->b_off != 0 &&
|
||||
lsn->file >= lp->f_lsn.file && lsn->offset >= lp->f_lsn.offset) {
|
||||
if (lp->b_off != 0 && log_compare(lsn, &lp->f_lsn) >= 0) {
|
||||
if ((ret = __log_write(dblp, lp->buf, lp->b_off)) != 0)
|
||||
return (ret);
|
||||
|
||||
@ -322,8 +317,10 @@ __log_flush(dblp, lsn)
|
||||
return (ret);
|
||||
|
||||
/* Sync all writes to disk. */
|
||||
if ((ret = __db_fsync(dblp->lfd)) != 0)
|
||||
if ((ret = __os_fsync(dblp->lfd)) != 0) {
|
||||
__db_panic(dblp->dbenv, ret);
|
||||
return (ret);
|
||||
}
|
||||
++lp->stat.st_scount;
|
||||
|
||||
/*
|
||||
@ -331,9 +328,16 @@ __log_flush(dblp, lsn)
|
||||
* the current buffer was flushed, we know the LSN of the first byte
|
||||
* of the buffer is on disk, otherwise, we only know that the LSN of
|
||||
* the record before the one beginning the current buffer is on disk.
|
||||
*
|
||||
* XXX
|
||||
* Check to make sure that the saved lsn isn't 0 before we go making
|
||||
* this change. If DB_CHECKPOINT was called before we actually wrote
|
||||
* something, you can end up here without ever having written anything
|
||||
* to a log file, and decrementing either s_lsn.file or s_lsn.offset
|
||||
* will cause much sadness later on.
|
||||
*/
|
||||
lp->s_lsn = lp->f_lsn;
|
||||
if (!current) {
|
||||
if (!current && lp->s_lsn.file != 0) {
|
||||
if (lp->s_lsn.offset == 0) {
|
||||
--lp->s_lsn.file;
|
||||
lp->s_lsn.offset = lp->persist.lg_max;
|
||||
@ -431,10 +435,11 @@ __log_write(dblp, addr, len)
|
||||
* Seek to the offset in the file (someone may have written it
|
||||
* since we last did).
|
||||
*/
|
||||
if ((ret = __db_seek(dblp->lfd, 0, 0, lp->w_off, 0, SEEK_SET)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_write(dblp->lfd, addr, len, &nw)) != 0)
|
||||
if ((ret = __os_seek(dblp->lfd, 0, 0, lp->w_off, 0, SEEK_SET)) != 0 ||
|
||||
(ret = __os_write(dblp->lfd, addr, len, &nw)) != 0) {
|
||||
__db_panic(dblp->dbenv, ret);
|
||||
return (ret);
|
||||
}
|
||||
if (nw != (int32_t)len)
|
||||
return (EIO);
|
||||
|
||||
@ -467,21 +472,23 @@ log_file(dblp, lsn, namep, len)
|
||||
size_t len;
|
||||
{
|
||||
int ret;
|
||||
char *p;
|
||||
char *name;
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
LOCK_LOGREGION(dblp);
|
||||
ret = __log_name(dblp, lsn->file, &p);
|
||||
ret = __log_name(dblp, lsn->file, &name, NULL, 0);
|
||||
UNLOCK_LOGREGION(dblp);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
/* Check to make sure there's enough room and copy the name. */
|
||||
if (len < strlen(p) + 1) {
|
||||
if (len < strlen(name) + 1) {
|
||||
*namep = '\0';
|
||||
return (ENOMEM);
|
||||
}
|
||||
(void)strcpy(namep, p);
|
||||
__db_free(p);
|
||||
(void)strcpy(namep, name);
|
||||
__os_freestr(name);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -495,43 +502,102 @@ __log_newfd(dblp)
|
||||
DB_LOG *dblp;
|
||||
{
|
||||
int ret;
|
||||
char *p;
|
||||
char *name;
|
||||
|
||||
/* Close any previous file descriptor. */
|
||||
if (dblp->lfd != -1) {
|
||||
(void)__db_close(dblp->lfd);
|
||||
(void)__os_close(dblp->lfd);
|
||||
dblp->lfd = -1;
|
||||
}
|
||||
|
||||
/* Get the path of the new file and open it. */
|
||||
dblp->lfname = dblp->lp->lsn.file;
|
||||
if ((ret = __log_name(dblp, dblp->lfname, &p)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __db_open(p,
|
||||
DB_CREATE | DB_SEQUENTIAL,
|
||||
DB_CREATE | DB_SEQUENTIAL,
|
||||
dblp->lp->persist.mode, &dblp->lfd)) != 0)
|
||||
__db_err(dblp->dbenv,
|
||||
"log_put: %s: %s", p, strerror(ret));
|
||||
FREES(p);
|
||||
if ((ret = __log_name(dblp,
|
||||
dblp->lfname, &name, &dblp->lfd, DB_CREATE | DB_SEQUENTIAL)) != 0)
|
||||
__db_err(dblp->dbenv, "log_put: %s: %s", name, strerror(ret));
|
||||
|
||||
__os_freestr(name);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __log_name --
|
||||
* Return the log name for a particular file.
|
||||
* Return the log name for a particular file, and optionally open it.
|
||||
*
|
||||
* PUBLIC: int __log_name __P((DB_LOG *, int, char **));
|
||||
* PUBLIC: int __log_name __P((DB_LOG *, u_int32_t, char **, int *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__log_name(dblp, filenumber, namep)
|
||||
__log_name(dblp, filenumber, namep, fdp, flags)
|
||||
DB_LOG *dblp;
|
||||
u_int32_t filenumber, flags;
|
||||
char **namep;
|
||||
int filenumber;
|
||||
int *fdp;
|
||||
{
|
||||
char name[sizeof(LFNAME) + 10];
|
||||
int ret;
|
||||
char *oname;
|
||||
char old[sizeof(LFPREFIX) + 5 + 20], new[sizeof(LFPREFIX) + 10 + 20];
|
||||
|
||||
(void)snprintf(name, sizeof(name), LFNAME, filenumber);
|
||||
return (__db_appname(dblp->dbenv,
|
||||
DB_APP_LOG, dblp->dir, name, 0, NULL, namep));
|
||||
/*
|
||||
* !!!
|
||||
* The semantics of this routine are bizarre.
|
||||
*
|
||||
* The reason for all of this is that we need a place where we can
|
||||
* intercept requests for log files, and, if appropriate, check for
|
||||
* both the old-style and new-style log file names. The trick is
|
||||
* that all callers of this routine that are opening the log file
|
||||
* read-only want to use an old-style file name if they can't find
|
||||
* a match using a new-style name. The only down-side is that some
|
||||
* callers may check for the old-style when they really don't need
|
||||
* to, but that shouldn't mess up anything, and we only check for
|
||||
* the old-style name when we've already failed to find a new-style
|
||||
* one.
|
||||
*
|
||||
* Create a new-style file name, and if we're not going to open the
|
||||
* file, return regardless.
|
||||
*/
|
||||
(void)snprintf(new, sizeof(new), LFNAME, filenumber);
|
||||
if ((ret = __db_appname(dblp->dbenv,
|
||||
DB_APP_LOG, dblp->dir, new, 0, NULL, namep)) != 0 || fdp == NULL)
|
||||
return (ret);
|
||||
|
||||
/* Open the new-style file -- if we succeed, we're done. */
|
||||
if ((ret = __db_open(*namep,
|
||||
flags, flags, dblp->lp->persist.mode, fdp)) == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* The open failed... if the DB_RDONLY flag isn't set, we're done,
|
||||
* the caller isn't interested in old-style files.
|
||||
*/
|
||||
if (!LF_ISSET(DB_RDONLY))
|
||||
return (ret);
|
||||
|
||||
/* Create an old-style file name. */
|
||||
(void)snprintf(old, sizeof(old), LFNAME_V1, filenumber);
|
||||
if ((ret = __db_appname(dblp->dbenv,
|
||||
DB_APP_LOG, dblp->dir, old, 0, NULL, &oname)) != 0)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Open the old-style file -- if we succeed, we're done. Free the
|
||||
* space allocated for the new-style name and return the old-style
|
||||
* name to the caller.
|
||||
*/
|
||||
if ((ret = __db_open(oname,
|
||||
flags, flags, dblp->lp->persist.mode, fdp)) == 0) {
|
||||
__os_freestr(*namep);
|
||||
*namep = oname;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Couldn't find either style of name -- return the new-style name
|
||||
* for the caller's error message. If it's an old-style name that's
|
||||
* actually missing we're going to confuse the user with the error
|
||||
* message, but that implies that not only were we looking for an
|
||||
* old-style name, but we expected it to exist and we weren't just
|
||||
* looking for any log file. That's not a likely error.
|
||||
*/
|
||||
err: __os_freestr(oname);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -40,7 +40,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)log_rec.c 10.20 (Sleepycat) 4/28/98";
|
||||
static const char sccsid[] = "@(#)log_rec.c 10.26 (Sleepycat) 10/21/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -56,8 +56,10 @@ static const char sccsid[] = "@(#)log_rec.c 10.20 (Sleepycat) 4/28/98";
|
||||
#include "db_dispatch.h"
|
||||
#include "common_ext.h"
|
||||
|
||||
static int __log_open_file __P((DB_LOG *,
|
||||
static int __log_do_open __P((DB_LOG *,
|
||||
u_int8_t *, char *, DBTYPE, u_int32_t));
|
||||
static int __log_lid_to_fname __P((DB_LOG *, u_int32_t, FNAME **));
|
||||
static int __log_open_file __P((DB_LOG *, __log_register_args *));
|
||||
|
||||
/*
|
||||
* PUBLIC: int __log_register_recover
|
||||
@ -80,7 +82,7 @@ __log_register_recover(logp, dbtp, lsnp, redo, info)
|
||||
COMPQUIET(info, NULL);
|
||||
COMPQUIET(lsnp, NULL);
|
||||
|
||||
F_SET(logp, DB_AM_RECOVER);
|
||||
F_SET(logp, DBC_RECOVER);
|
||||
|
||||
if ((ret = __log_register_read(dbtp->data, &argp)) != 0)
|
||||
goto out;
|
||||
@ -95,13 +97,11 @@ __log_register_recover(logp, dbtp, lsnp, redo, info)
|
||||
* If we are redoing an open or undoing a close, then we need
|
||||
* to open a file.
|
||||
*/
|
||||
ret = __log_open_file(logp,
|
||||
argp->uid.data, argp->name.data, argp->ftype, argp->id);
|
||||
ret = __log_open_file(logp, argp);
|
||||
if (ret == ENOENT) {
|
||||
if (redo == TXN_OPENFILES)
|
||||
__db_err(logp->dbenv,
|
||||
"warning: file %s not found",
|
||||
argp->name.data);
|
||||
__db_err(logp->dbenv, "warning: %s: %s",
|
||||
argp->name.data, strerror(ENOENT));
|
||||
ret = 0;
|
||||
}
|
||||
} else if (argp->opcode != LOG_CHECKPOINT) {
|
||||
@ -109,26 +109,42 @@ __log_register_recover(logp, dbtp, lsnp, redo, info)
|
||||
* If we are redoing a close or undoing an open, then we need
|
||||
* to close the file.
|
||||
*
|
||||
* If the file is deleted, then we can just ignore this close.
|
||||
* Otherwise, we'd better have a valid dbp that we should either
|
||||
* close or whose reference count should be decremented.
|
||||
* If the file is deleted, then we can just ignore this close.
|
||||
* Otherwise, we should usually have a valid dbp we should
|
||||
* close or whose reference count should be decremented.
|
||||
* However, if we shut down without closing a file, we
|
||||
* may, in fact, not have the file open, and that's OK.
|
||||
*/
|
||||
LOCK_LOGTHREAD(logp);
|
||||
if (logp->dbentry[argp->id].dbp == NULL) {
|
||||
if (!logp->dbentry[argp->id].deleted)
|
||||
ret = EINVAL;
|
||||
} else if (--logp->dbentry[argp->id].refcount == 0) {
|
||||
F_SET(logp->dbentry[argp->id].dbp, DB_AM_RECOVER);
|
||||
if (logp->dbentry[argp->id].dbp != NULL &&
|
||||
--logp->dbentry[argp->id].refcount == 0) {
|
||||
ret = logp->dbentry[argp->id].dbp->close(
|
||||
logp->dbentry[argp->id].dbp, 0);
|
||||
logp->dbentry[argp->id].dbp = NULL;
|
||||
}
|
||||
UNLOCK_LOGTHREAD(logp);
|
||||
} else if (redo == TXN_UNDO &&
|
||||
(argp->id >= logp->dbentry_cnt ||
|
||||
(!logp->dbentry[argp->id].deleted &&
|
||||
logp->dbentry[argp->id].dbp == NULL))) {
|
||||
/*
|
||||
* It's a checkpoint and we are rolling backward. It
|
||||
* is possible that the system was shut down and thus
|
||||
* ended with a stable checkpoint; this file was never
|
||||
* closed and has therefore not been reopened yet. If
|
||||
* so, we need to try to open it.
|
||||
*/
|
||||
ret = __log_open_file(logp, argp);
|
||||
if (ret == ENOENT) {
|
||||
__db_err(logp->dbenv, "warning: %s: %s",
|
||||
argp->name.data, strerror(ENOENT));
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
out: F_CLR(logp, DB_AM_RECOVER);
|
||||
out: F_CLR(logp, DBC_RECOVER);
|
||||
if (argp != NULL)
|
||||
__db_free(argp);
|
||||
__os_free(argp, 0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -140,7 +156,33 @@ out: F_CLR(logp, DB_AM_RECOVER);
|
||||
* Returns 0 on success, non-zero on error.
|
||||
*/
|
||||
static int
|
||||
__log_open_file(lp, uid, name, ftype, ndx)
|
||||
__log_open_file(lp, argp)
|
||||
DB_LOG *lp;
|
||||
__log_register_args *argp;
|
||||
{
|
||||
LOCK_LOGTHREAD(lp);
|
||||
if (argp->id < lp->dbentry_cnt &&
|
||||
(lp->dbentry[argp->id].deleted == 1 ||
|
||||
lp->dbentry[argp->id].dbp != NULL)) {
|
||||
if (argp->opcode != LOG_CHECKPOINT)
|
||||
lp->dbentry[argp->id].refcount++;
|
||||
|
||||
UNLOCK_LOGTHREAD(lp);
|
||||
return (0);
|
||||
}
|
||||
UNLOCK_LOGTHREAD(lp);
|
||||
return (__log_do_open(lp,
|
||||
argp->uid.data, argp->name.data, argp->ftype, argp->id));
|
||||
}
|
||||
|
||||
/*
|
||||
* __log_do_open --
|
||||
* Open files referenced in the log. This is the part of the open that
|
||||
* is not protected by the thread mutex.
|
||||
*/
|
||||
|
||||
static int
|
||||
__log_do_open(lp, uid, name, ftype, ndx)
|
||||
DB_LOG *lp;
|
||||
u_int8_t *uid;
|
||||
char *name;
|
||||
@ -150,24 +192,13 @@ __log_open_file(lp, uid, name, ftype, ndx)
|
||||
DB *dbp;
|
||||
int ret;
|
||||
|
||||
LOCK_LOGTHREAD(lp);
|
||||
if (ndx < lp->dbentry_cnt &&
|
||||
(lp->dbentry[ndx].deleted == 1 || lp->dbentry[ndx].dbp != NULL)) {
|
||||
lp->dbentry[ndx].refcount++;
|
||||
|
||||
UNLOCK_LOGTHREAD(lp);
|
||||
return (0);
|
||||
}
|
||||
UNLOCK_LOGTHREAD(lp);
|
||||
|
||||
/* Need to open file. */
|
||||
dbp = NULL;
|
||||
if ((ret = db_open(name, ftype, 0, 0, lp->dbenv, NULL, &dbp)) == 0) {
|
||||
/*
|
||||
* Verify that we are opening the same file that we were
|
||||
* referring to when we wrote this log record.
|
||||
*/
|
||||
if (memcmp(uid, dbp->lock.fileid, DB_FILE_ID_LEN) != 0) {
|
||||
if (memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0) {
|
||||
(void)dbp->close(dbp, 0);
|
||||
dbp = NULL;
|
||||
ret = ENOENT;
|
||||
@ -181,10 +212,9 @@ __log_open_file(lp, uid, name, ftype, ndx)
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns:
|
||||
* 0 SUCCESS (the entry was not previously set and is now set or the
|
||||
* entry was previously set and we just inced the ref count.
|
||||
* >0 on system error (returns errno value).
|
||||
* __log_add_logid --
|
||||
* Adds a DB entry to the log's DB entry table.
|
||||
*
|
||||
* PUBLIC: int __log_add_logid __P((DB_LOG *, DB *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
@ -193,43 +223,30 @@ __log_add_logid(logp, dbp, ndx)
|
||||
DB *dbp;
|
||||
u_int32_t ndx;
|
||||
{
|
||||
DB_ENTRY *temp_entryp;
|
||||
u_int32_t i;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
|
||||
LOCK_LOGTHREAD(logp);
|
||||
|
||||
/*
|
||||
* Check if we need to grow the table.
|
||||
* Check if we need to grow the table. Note, ndx is 0-based (the
|
||||
* index into the DB entry table) an dbentry_cnt is 1-based, the
|
||||
* number of available slots.
|
||||
*/
|
||||
if (logp->dbentry_cnt <= ndx) {
|
||||
if (logp->dbentry_cnt == 0) {
|
||||
logp->dbentry = (DB_ENTRY *)
|
||||
__db_malloc(DB_GROW_SIZE * sizeof(DB_ENTRY));
|
||||
if (logp->dbentry == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
temp_entryp = (DB_ENTRY *)__db_realloc(logp->dbentry,
|
||||
(DB_GROW_SIZE + logp->dbentry_cnt) *
|
||||
sizeof(DB_ENTRY));
|
||||
if (temp_entryp == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
logp->dbentry = temp_entryp;
|
||||
if ((ret = __os_realloc(&logp->dbentry,
|
||||
(ndx + DB_GROW_SIZE) * sizeof(DB_ENTRY))) != 0)
|
||||
goto err;
|
||||
|
||||
}
|
||||
/* Initialize the new entries. */
|
||||
for (i = logp->dbentry_cnt;
|
||||
i < logp->dbentry_cnt + DB_GROW_SIZE; i++) {
|
||||
for (i = logp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) {
|
||||
logp->dbentry[i].dbp = NULL;
|
||||
logp->dbentry[i].deleted = 0;
|
||||
}
|
||||
|
||||
logp->dbentry_cnt += DB_GROW_SIZE;
|
||||
logp->dbentry_cnt = i;
|
||||
}
|
||||
|
||||
if (logp->dbentry[ndx].deleted == 0 && logp->dbentry[ndx].dbp == NULL) {
|
||||
@ -257,10 +274,46 @@ __db_fileid_to_db(logp, dbpp, ndx)
|
||||
u_int32_t ndx;
|
||||
{
|
||||
int ret;
|
||||
char *name;
|
||||
FNAME *fname;
|
||||
|
||||
ret = 0;
|
||||
LOCK_LOGTHREAD(logp);
|
||||
|
||||
/*
|
||||
* Under XA, a process different than the one issuing DB
|
||||
* operations may abort a transaction. In this case,
|
||||
* recovery routines are run by a process that does not
|
||||
* necessarily have the file open. In this case, we must
|
||||
* open the file explicitly.
|
||||
*/
|
||||
if (ndx >= logp->dbentry_cnt ||
|
||||
(!logp->dbentry[ndx].deleted && logp->dbentry[ndx].dbp == NULL)) {
|
||||
if (__log_lid_to_fname(logp, ndx, &fname) != 0) {
|
||||
/* Couldn't find entry; this is a fatal error. */
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
name = R_ADDR(logp, fname->name_off);
|
||||
/*
|
||||
* __log_do_open is called without protection of the
|
||||
* log thread lock.
|
||||
*/
|
||||
UNLOCK_LOGTHREAD(logp);
|
||||
/*
|
||||
* At this point, we are not holding the thread lock, so
|
||||
* exit directly instead of going through the exit code
|
||||
* at the bottom. If the __log_do_open succeeded, then
|
||||
* we don't need to do any of the remaining error checking
|
||||
* at the end of this routine.
|
||||
*/
|
||||
if ((ret = __log_do_open(logp,
|
||||
fname->ufid, name, fname->s_type, ndx)) != 0)
|
||||
return (ret);
|
||||
*dbpp = logp->dbentry[ndx].dbp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return DB_DELETED if the file has been deleted
|
||||
* (it's not an error).
|
||||
@ -294,8 +347,12 @@ __log_close_files(logp)
|
||||
|
||||
LOCK_LOGTHREAD(logp);
|
||||
for (i = 0; i < logp->dbentry_cnt; i++)
|
||||
if (logp->dbentry[i].dbp)
|
||||
if (logp->dbentry[i].dbp) {
|
||||
logp->dbentry[i].dbp->close(logp->dbentry[i].dbp, 0);
|
||||
logp->dbentry[i].dbp = NULL;
|
||||
logp->dbentry[i].deleted = 0;
|
||||
}
|
||||
F_CLR(logp, DBC_RECOVER);
|
||||
UNLOCK_LOGTHREAD(logp);
|
||||
}
|
||||
|
||||
@ -314,3 +371,28 @@ __log_rem_logid(logp, ndx)
|
||||
}
|
||||
UNLOCK_LOGTHREAD(logp);
|
||||
}
|
||||
|
||||
/*
|
||||
* __log_lid_to_fname --
|
||||
* Traverse the shared-memory region looking for the entry that
|
||||
* matches the passed log fileid. Returns 0 on success; -1 on error.
|
||||
*/
|
||||
static int
|
||||
__log_lid_to_fname(dblp, lid, fnamep)
|
||||
DB_LOG *dblp;
|
||||
u_int32_t lid;
|
||||
FNAME **fnamep;
|
||||
{
|
||||
FNAME *fnp;
|
||||
|
||||
for (fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
|
||||
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
|
||||
if (fnp->ref == 0) /* Entry not in use. */
|
||||
continue;
|
||||
if (fnp->id == lid) {
|
||||
*fnamep = fnp;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)log_register.c 10.18 (Sleepycat) 5/3/98";
|
||||
static const char sccsid[] = "@(#)log_register.c 10.22 (Sleepycat) 9/27/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -36,17 +36,18 @@ log_register(dblp, dbp, name, type, idp)
|
||||
{
|
||||
DBT fid_dbt, r_name;
|
||||
DB_LSN r_unused;
|
||||
FNAME *fnp;
|
||||
FNAME *fnp, *reuse_fnp;
|
||||
size_t len;
|
||||
u_int32_t fid;
|
||||
u_int32_t maxid;
|
||||
int inserted, ret;
|
||||
char *fullname;
|
||||
void *namep;
|
||||
|
||||
fid = 0;
|
||||
inserted = 0;
|
||||
fullname = NULL;
|
||||
fnp = namep = NULL;
|
||||
fnp = namep = reuse_fnp = NULL;
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
/* Check the arguments. */
|
||||
if (type != DB_BTREE && type != DB_HASH && type != DB_RECNO) {
|
||||
@ -63,26 +64,37 @@ log_register(dblp, dbp, name, type, idp)
|
||||
|
||||
/*
|
||||
* See if we've already got this file in the log, finding the
|
||||
* next-to-lowest file id currently in use as we do it.
|
||||
* (maximum+1) in-use file id and some available file id (if we
|
||||
* find an available fid, we'll use it, else we'll have to allocate
|
||||
* one after the maximum that we found).
|
||||
*/
|
||||
for (fid = 1, fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
|
||||
for (maxid = 0, fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname);
|
||||
fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
|
||||
if (fid <= fnp->id)
|
||||
fid = fnp->id + 1;
|
||||
if (!memcmp(dbp->lock.fileid, fnp->ufid, DB_FILE_ID_LEN)) {
|
||||
if (fnp->ref == 0) { /* Entry is not in use. */
|
||||
if (reuse_fnp == NULL)
|
||||
reuse_fnp = fnp;
|
||||
continue;
|
||||
}
|
||||
if (!memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN)) {
|
||||
++fnp->ref;
|
||||
fid = fnp->id;
|
||||
goto found;
|
||||
}
|
||||
if (maxid <= fnp->id)
|
||||
maxid = fnp->id + 1;
|
||||
}
|
||||
|
||||
/* Allocate a new file name structure. */
|
||||
if ((ret = __db_shalloc(dblp->addr, sizeof(FNAME), 0, &fnp)) != 0)
|
||||
/* Fill in fnp structure. */
|
||||
|
||||
if (reuse_fnp != NULL) /* Reuse existing one. */
|
||||
fnp = reuse_fnp;
|
||||
else if ((ret = __db_shalloc(dblp->addr, sizeof(FNAME), 0, &fnp)) != 0)
|
||||
goto err;
|
||||
else /* Allocate a new one. */
|
||||
fnp->id = maxid;
|
||||
|
||||
fnp->ref = 1;
|
||||
fnp->id = fid;
|
||||
fnp->s_type = type;
|
||||
memcpy(fnp->ufid, dbp->lock.fileid, DB_FILE_ID_LEN);
|
||||
memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN);
|
||||
|
||||
len = strlen(name) + 1;
|
||||
if ((ret = __db_shalloc(dblp->addr, len, 0, &namep)) != 0)
|
||||
@ -90,20 +102,22 @@ log_register(dblp, dbp, name, type, idp)
|
||||
fnp->name_off = R_OFFSET(dblp, namep);
|
||||
memcpy(namep, name, len);
|
||||
|
||||
SH_TAILQ_INSERT_HEAD(&dblp->lp->fq, fnp, q, __fname);
|
||||
/* Only do the insert if we allocated a new fnp. */
|
||||
if (reuse_fnp == NULL)
|
||||
SH_TAILQ_INSERT_HEAD(&dblp->lp->fq, fnp, q, __fname);
|
||||
inserted = 1;
|
||||
|
||||
found: /* Log the registry. */
|
||||
if (!F_ISSET(dblp, DB_AM_RECOVER)) {
|
||||
if (!F_ISSET(dblp, DBC_RECOVER)) {
|
||||
r_name.data = (void *)name; /* XXX: Yuck! */
|
||||
r_name.size = strlen(name) + 1;
|
||||
memset(&fid_dbt, 0, sizeof(fid_dbt));
|
||||
fid_dbt.data = dbp->lock.fileid;
|
||||
fid_dbt.data = dbp->fileid;
|
||||
fid_dbt.size = DB_FILE_ID_LEN;
|
||||
if ((ret = __log_register_log(dblp, NULL, &r_unused,
|
||||
0, LOG_OPEN, &r_name, &fid_dbt, fid, type)) != 0)
|
||||
0, LOG_OPEN, &r_name, &fid_dbt, fnp->id, type)) != 0)
|
||||
goto err;
|
||||
if ((ret = __log_add_logid(dblp, dbp, fid)) != 0)
|
||||
if ((ret = __log_add_logid(dblp, dbp, fnp->id)) != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -120,13 +134,13 @@ err: /*
|
||||
__db_shalloc_free(dblp->addr, fnp);
|
||||
}
|
||||
|
||||
if (idp != NULL)
|
||||
*idp = fnp->id;
|
||||
UNLOCK_LOGREGION(dblp);
|
||||
|
||||
if (fullname != NULL)
|
||||
FREES(fullname);
|
||||
__os_freestr(fullname);
|
||||
|
||||
if (idp != NULL)
|
||||
*idp = fid;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -144,6 +158,8 @@ log_unregister(dblp, fid)
|
||||
FNAME *fnp;
|
||||
int ret;
|
||||
|
||||
LOG_PANIC_CHECK(dblp);
|
||||
|
||||
ret = 0;
|
||||
LOCK_LOGREGION(dblp);
|
||||
|
||||
@ -159,7 +175,7 @@ log_unregister(dblp, fid)
|
||||
}
|
||||
|
||||
/* Unlog the registry. */
|
||||
if (!F_ISSET(dblp, DB_AM_RECOVER)) {
|
||||
if (!F_ISSET(dblp, DBC_RECOVER)) {
|
||||
memset(&r_name, 0, sizeof(r_name));
|
||||
r_name.data = R_ADDR(dblp, fnp->name_off);
|
||||
r_name.size = strlen(r_name.data) + 1;
|
||||
@ -173,22 +189,18 @@ log_unregister(dblp, fid)
|
||||
|
||||
/*
|
||||
* If more than 1 reference, just decrement the reference and return.
|
||||
* Otherwise, free the unique file information, name and structure.
|
||||
* Otherwise, free the name.
|
||||
*/
|
||||
if (fnp->ref > 1)
|
||||
--fnp->ref;
|
||||
else {
|
||||
--fnp->ref;
|
||||
if (fnp->ref == 0)
|
||||
__db_shalloc_free(dblp->addr, R_ADDR(dblp, fnp->name_off));
|
||||
SH_TAILQ_REMOVE(&dblp->lp->fq, fnp, q, __fname);
|
||||
__db_shalloc_free(dblp->addr, fnp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove from the process local table. If this operation is taking
|
||||
* place during recovery, then the logid was never added to the table,
|
||||
* so do not remove it.
|
||||
*/
|
||||
if (!F_ISSET(dblp, DB_AM_RECOVER))
|
||||
if (!F_ISSET(dblp, DBC_RECOVER))
|
||||
__log_rem_logid(dblp, fid);
|
||||
|
||||
ret1: UNLOCK_LOGREGION(dblp);
|
||||
|
176
db2/mp/mp_bh.c
176
db2/mp/mp_bh.c
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_bh.c 10.38 (Sleepycat) 5/20/98";
|
||||
static const char sccsid[] = "@(#)mp_bh.c 10.45 (Sleepycat) 11/25/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -42,11 +42,13 @@ __memp_bhwrite(dbmp, mfp, bhp, restartp, wrotep)
|
||||
{
|
||||
DB_MPOOLFILE *dbmfp;
|
||||
DB_MPREG *mpreg;
|
||||
int incremented, ret;
|
||||
|
||||
if (restartp != NULL)
|
||||
*restartp = 0;
|
||||
if (wrotep != NULL)
|
||||
*wrotep = 0;
|
||||
incremented = 0;
|
||||
|
||||
/*
|
||||
* Walk the process' DB_MPOOLFILE list and find a file descriptor for
|
||||
@ -63,6 +65,13 @@ __memp_bhwrite(dbmp, mfp, bhp, restartp, wrotep)
|
||||
UNLOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment the reference count -- see the comment in
|
||||
* memp_fclose().
|
||||
*/
|
||||
++dbmfp->ref;
|
||||
incremented = 1;
|
||||
break;
|
||||
}
|
||||
UNLOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
@ -117,7 +126,15 @@ __memp_bhwrite(dbmp, mfp, bhp, restartp, wrotep)
|
||||
0, 0, mfp->stat.st_pagesize, 0, NULL, &dbmfp) != 0)
|
||||
return (0);
|
||||
|
||||
found: return (__memp_pgwrite(dbmfp, bhp, restartp, wrotep));
|
||||
found: ret = __memp_pgwrite(dbmfp, bhp, restartp, wrotep);
|
||||
|
||||
if (incremented) {
|
||||
LOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
--dbmfp->ref;
|
||||
UNLOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -132,11 +149,12 @@ __memp_pgread(dbmfp, bhp, can_create)
|
||||
BH *bhp;
|
||||
int can_create;
|
||||
{
|
||||
DB_IO db_io;
|
||||
DB_MPOOL *dbmp;
|
||||
MPOOLFILE *mfp;
|
||||
size_t pagesize;
|
||||
size_t len, pagesize;
|
||||
ssize_t nr;
|
||||
int ret;
|
||||
int created, ret;
|
||||
|
||||
dbmp = dbmfp->dbmp;
|
||||
mfp = dbmfp->mfp;
|
||||
@ -147,70 +165,63 @@ __memp_pgread(dbmfp, bhp, can_create)
|
||||
UNLOCKREGION(dbmp);
|
||||
|
||||
/*
|
||||
* Temporary files may not yet have been created.
|
||||
*
|
||||
* Seek to the page location.
|
||||
* Temporary files may not yet have been created. We don't create
|
||||
* them now, we create them when the pages have to be flushed.
|
||||
*/
|
||||
ret = 0;
|
||||
LOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
if (dbmfp->fd == -1 || (ret =
|
||||
__db_seek(dbmfp->fd, pagesize, bhp->pgno, 0, 0, SEEK_SET)) != 0) {
|
||||
if (!can_create) {
|
||||
if (dbmfp->fd == -1)
|
||||
ret = EINVAL;
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
nr = 0;
|
||||
if (dbmfp->fd == -1)
|
||||
ret = 0;
|
||||
else {
|
||||
/*
|
||||
* Ignore read errors if we have permission to create the page.
|
||||
* Assume that the page doesn't exist, and that we'll create it
|
||||
* when we write it out.
|
||||
*/
|
||||
db_io.fd_io = dbmfp->fd;
|
||||
db_io.fd_lock = dbmp->reginfo.fd;
|
||||
db_io.mutexp =
|
||||
F_ISSET(dbmp, MP_LOCKHANDLE) ? dbmfp->mutexp : NULL;
|
||||
db_io.pagesize = db_io.bytes = pagesize;
|
||||
db_io.pgno = bhp->pgno;
|
||||
db_io.buf = bhp->buf;
|
||||
|
||||
ret = __os_io(&db_io, DB_IO_READ, &nr);
|
||||
}
|
||||
|
||||
created = 0;
|
||||
if (nr < (ssize_t)pagesize) {
|
||||
if (can_create)
|
||||
created = 1;
|
||||
else {
|
||||
/* If we had a short read, ret may be 0. */
|
||||
if (ret == 0)
|
||||
ret = EIO;
|
||||
__db_err(dbmp->dbenv,
|
||||
"%s: page %lu doesn't exist, create flag not set",
|
||||
__memp_fn(dbmfp), (u_long)bhp->pgno);
|
||||
goto err;
|
||||
}
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
|
||||
/* Clear the created page. */
|
||||
if (mfp->clear_len == 0)
|
||||
memset(bhp->buf, 0, pagesize);
|
||||
else {
|
||||
memset(bhp->buf, 0, mfp->clear_len);
|
||||
#ifdef DIAGNOSTIC
|
||||
memset(bhp->buf + mfp->clear_len,
|
||||
0xff, pagesize - mfp->clear_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
goto pgin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the page; short reads are treated like creates, although
|
||||
* any valid data is preserved.
|
||||
* Clear any bytes we didn't read that need to be cleared. If we're
|
||||
* running in diagnostic mode, smash any bytes on the page that are
|
||||
* unknown quantities for the caller.
|
||||
*/
|
||||
ret = __db_read(dbmfp->fd, bhp->buf, pagesize, &nr);
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
if (nr == (ssize_t)pagesize)
|
||||
can_create = 0;
|
||||
else {
|
||||
if (!can_create) {
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't fail until we tried the read, don't clear the
|
||||
* whole page, it wouldn't be insane for a filesystem to just
|
||||
* always behave that way. Else, clear any uninitialized data.
|
||||
*/
|
||||
if (nr == 0)
|
||||
memset(bhp->buf, 0,
|
||||
mfp->clear_len == 0 ? pagesize : mfp->clear_len);
|
||||
else
|
||||
memset(bhp->buf + nr, 0, pagesize - nr);
|
||||
if (nr != (ssize_t)pagesize) {
|
||||
len = mfp->clear_len == 0 ? pagesize : mfp->clear_len;
|
||||
if (nr < (ssize_t)len)
|
||||
memset(bhp->buf + nr, 0, len - nr);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (nr > (ssize_t)len)
|
||||
len = nr;
|
||||
if (len < pagesize)
|
||||
memset(bhp->buf + len, 0xdb, pagesize - len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Call any pgin function. */
|
||||
pgin: ret = mfp->ftype == 0 ? 0 : __memp_pg(dbmfp, bhp, 1);
|
||||
ret = mfp->ftype == 0 ? 0 : __memp_pg(dbmfp, bhp, 1);
|
||||
|
||||
/* Unlock the buffer and reacquire the region lock. */
|
||||
err: UNLOCKBUFFER(dbmp, bhp);
|
||||
@ -225,7 +236,7 @@ err: UNLOCKBUFFER(dbmp, bhp);
|
||||
F_CLR(bhp, BH_TRASH);
|
||||
|
||||
/* Update the statistics. */
|
||||
if (can_create) {
|
||||
if (created) {
|
||||
++dbmp->mp->stat.st_page_create;
|
||||
++mfp->stat.st_page_create;
|
||||
} else {
|
||||
@ -250,12 +261,12 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
|
||||
int *restartp, *wrotep;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
DB_IO db_io;
|
||||
DB_LOG *lg_info;
|
||||
DB_LSN lsn;
|
||||
DB_MPOOL *dbmp;
|
||||
MPOOL *mp;
|
||||
MPOOLFILE *mfp;
|
||||
size_t pagesize;
|
||||
ssize_t nw;
|
||||
int callpgin, ret, syncfail;
|
||||
const char *fail;
|
||||
@ -270,7 +281,6 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
|
||||
if (wrotep != NULL)
|
||||
*wrotep = 0;
|
||||
callpgin = 0;
|
||||
pagesize = mfp->stat.st_pagesize;
|
||||
|
||||
/*
|
||||
* Check the dirty bit -- this buffer may have been written since we
|
||||
@ -326,34 +336,32 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
|
||||
}
|
||||
|
||||
/* Temporary files may not yet have been created. */
|
||||
LOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
if (dbmfp->fd == -1 &&
|
||||
((ret = __db_appname(dbenv, DB_APP_TMP, NULL, NULL,
|
||||
DB_CREATE | DB_EXCL | DB_TEMPORARY, &dbmfp->fd, NULL)) != 0 ||
|
||||
dbmfp->fd == -1)) {
|
||||
if (dbmfp->fd == -1) {
|
||||
LOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
if (dbmfp->fd == -1 && ((ret = __db_appname(dbenv,
|
||||
DB_APP_TMP, NULL, NULL, DB_CREATE | DB_EXCL | DB_TEMPORARY,
|
||||
&dbmfp->fd, NULL)) != 0 || dbmfp->fd == -1)) {
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
__db_err(dbenv,
|
||||
"unable to create temporary backing file");
|
||||
goto err;
|
||||
}
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
__db_err(dbenv, "unable to create temporary backing file");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the page out.
|
||||
*
|
||||
* XXX
|
||||
* Shut the compiler up; it doesn't understand the correlation between
|
||||
* the failing clauses to __db_lseek and __db_write and this ret != 0.
|
||||
*/
|
||||
COMPQUIET(fail, NULL);
|
||||
if ((ret =
|
||||
__db_seek(dbmfp->fd, pagesize, bhp->pgno, 0, 0, SEEK_SET)) != 0)
|
||||
fail = "seek";
|
||||
else if ((ret = __db_write(dbmfp->fd, bhp->buf, pagesize, &nw)) != 0)
|
||||
/* Write the page. */
|
||||
db_io.fd_io = dbmfp->fd;
|
||||
db_io.fd_lock = dbmp->reginfo.fd;
|
||||
db_io.mutexp = F_ISSET(dbmp, MP_LOCKHANDLE) ? dbmfp->mutexp : NULL;
|
||||
db_io.pagesize = db_io.bytes = mfp->stat.st_pagesize;
|
||||
db_io.pgno = bhp->pgno;
|
||||
db_io.buf = bhp->buf;
|
||||
if ((ret = __os_io(&db_io, DB_IO_WRITE, &nw)) != 0) {
|
||||
__db_panic(dbenv, ret);
|
||||
fail = "write";
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
if (ret != 0)
|
||||
goto syserr;
|
||||
|
||||
if (nw != (ssize_t)pagesize) {
|
||||
}
|
||||
if (nw != (ssize_t)mfp->stat.st_pagesize) {
|
||||
ret = EIO;
|
||||
fail = "write";
|
||||
goto syserr;
|
||||
@ -394,7 +402,7 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
|
||||
if (F_ISSET(bhp, BH_WRITE)) {
|
||||
if (mfp->lsn_cnt == 1) {
|
||||
UNLOCKREGION(dbmp);
|
||||
syncfail = __db_fsync(dbmfp->fd) != 0;
|
||||
syncfail = __os_fsync(dbmfp->fd) != 0;
|
||||
LOCKREGION(dbmp);
|
||||
if (syncfail)
|
||||
F_SET(mp, MP_LSN_RETRY);
|
||||
@ -574,11 +582,11 @@ __memp_upgrade(dbmp, dbmfp, mfp)
|
||||
ret = 1;
|
||||
} else {
|
||||
/* Swap the descriptors and set the upgrade flag. */
|
||||
(void)__db_close(dbmfp->fd);
|
||||
(void)__os_close(dbmfp->fd);
|
||||
dbmfp->fd = fd;
|
||||
F_SET(dbmfp, MP_UPGRADE);
|
||||
ret = 0;
|
||||
}
|
||||
FREES(rpath);
|
||||
__os_freestr(rpath);
|
||||
return (ret);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_fget.c 10.48 (Sleepycat) 6/2/98";
|
||||
static const char sccsid[] = "@(#)mp_fget.c 10.53 (Sleepycat) 11/16/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -46,6 +46,8 @@ memp_fget(dbmfp, pgnoaddr, flags, addrp)
|
||||
mp = dbmp->mp;
|
||||
mfp = dbmfp->mfp;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
/*
|
||||
* Validate arguments.
|
||||
*
|
||||
@ -79,12 +81,11 @@ memp_fget(dbmfp, pgnoaddr, flags, addrp)
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* XXX
|
||||
* We want to switch threads as often as possible. Sleep every time
|
||||
* we get a new page to make it more likely.
|
||||
* We want to switch threads as often as possible. Yield every time
|
||||
* we get a new page to ensure contention.
|
||||
*/
|
||||
if (DB_GLOBAL(db_pageyield) &&
|
||||
(__db_yield == NULL || __db_yield() != 0))
|
||||
__db_sleep(0, 1);
|
||||
if (DB_GLOBAL(db_pageyield))
|
||||
__os_yield(1);
|
||||
#endif
|
||||
|
||||
/* Initialize remaining local variables. */
|
||||
@ -205,8 +206,8 @@ memp_fget(dbmfp, pgnoaddr, flags, addrp)
|
||||
* up running to the end of our CPU quantum as we will
|
||||
* simply be swapping between the two locks.
|
||||
*/
|
||||
if (!first && (__db_yield == NULL || __db_yield() != 0))
|
||||
__db_sleep(0, 1);
|
||||
if (!first)
|
||||
__os_yield(1);
|
||||
|
||||
LOCKBUFFER(dbmp, bhp);
|
||||
/* Wait for I/O to finish... */
|
||||
@ -240,7 +241,7 @@ memp_fget(dbmfp, pgnoaddr, flags, addrp)
|
||||
}
|
||||
|
||||
alloc: /* Allocate new buffer header and data space. */
|
||||
if ((ret = __memp_ralloc(dbmp, sizeof(BH) -
|
||||
if ((ret = __memp_alloc(dbmp, sizeof(BH) -
|
||||
sizeof(u_int8_t) + mfp->stat.st_pagesize, NULL, &bhp)) != 0)
|
||||
goto err;
|
||||
|
||||
@ -285,7 +286,7 @@ alloc: /* Allocate new buffer header and data space. */
|
||||
else {
|
||||
memset(bhp->buf, 0, mfp->clear_len);
|
||||
#ifdef DIAGNOSTIC
|
||||
memset(bhp->buf + mfp->clear_len, 0xff,
|
||||
memset(bhp->buf + mfp->clear_len, 0xdb,
|
||||
mfp->stat.st_pagesize - mfp->clear_len);
|
||||
#endif
|
||||
}
|
||||
@ -335,11 +336,9 @@ done: /* Update the chain search statistics. */
|
||||
mp->stat.st_hash_examined += st_hsearch;
|
||||
}
|
||||
|
||||
UNLOCKREGION(dbmp);
|
||||
|
||||
LOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
++dbmfp->pinref;
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
|
||||
UNLOCKREGION(dbmp);
|
||||
|
||||
return (0);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_fopen.c 10.47 (Sleepycat) 5/4/98";
|
||||
static const char sccsid[] = "@(#)mp_fopen.c 10.60 (Sleepycat) 1/1/99";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -43,6 +43,8 @@ memp_fopen(dbmp, path, flags, mode, pagesize, finfop, retp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((ret = __db_fchk(dbmp->dbenv,
|
||||
"memp_fopen", flags, DB_CREATE | DB_NOMMAP | DB_RDONLY)) != 0)
|
||||
@ -53,6 +55,8 @@ memp_fopen(dbmp, path, flags, mode, pagesize, finfop, retp)
|
||||
__db_err(dbmp->dbenv, "memp_fopen: pagesize not specified");
|
||||
return (EINVAL);
|
||||
}
|
||||
if (finfop != NULL && finfop->clear_len > pagesize)
|
||||
return (EINVAL);
|
||||
|
||||
return (__memp_fopen(dbmp,
|
||||
NULL, path, flags, mode, pagesize, 1, finfop, retp));
|
||||
@ -80,7 +84,7 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
DB_MPOOLFILE *dbmfp;
|
||||
DB_MPOOL_FINFO finfo;
|
||||
db_pgno_t last_pgno;
|
||||
size_t size;
|
||||
size_t maxmap;
|
||||
u_int32_t mbytes, bytes;
|
||||
int ret;
|
||||
u_int8_t idbuf[DB_FILE_ID_LEN];
|
||||
@ -115,13 +119,11 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
}
|
||||
|
||||
/* Allocate and initialize the per-process structure. */
|
||||
if ((dbmfp =
|
||||
(DB_MPOOLFILE *)__db_calloc(1, sizeof(DB_MPOOLFILE))) == NULL) {
|
||||
__db_err(dbenv, "memp_fopen: %s", strerror(ENOMEM));
|
||||
return (ENOMEM);
|
||||
}
|
||||
if ((ret = __os_calloc(1, sizeof(DB_MPOOLFILE), &dbmfp)) != 0)
|
||||
return (ret);
|
||||
dbmfp->dbmp = dbmp;
|
||||
dbmfp->fd = -1;
|
||||
dbmfp->ref = 1;
|
||||
if (LF_ISSET(DB_RDONLY))
|
||||
F_SET(dbmfp, MP_READONLY);
|
||||
|
||||
@ -132,7 +134,6 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
size = 0;
|
||||
last_pgno = 0;
|
||||
} else {
|
||||
/* Get the real name for this file and open it. */
|
||||
@ -146,21 +147,40 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Don't permit files that aren't a multiple of the pagesize. */
|
||||
if ((ret = __db_ioinfo(rpath,
|
||||
/*
|
||||
* Don't permit files that aren't a multiple of the pagesize,
|
||||
* and find the number of the last page in the file, all the
|
||||
* time being careful not to overflow 32 bits.
|
||||
*
|
||||
* !!!
|
||||
* We can't use off_t's here, or in any code in the mainline
|
||||
* library for that matter. (We have to use them in the os
|
||||
* stubs, of course, as there are system calls that take them
|
||||
* as arguments.) The reason is that some customers build in
|
||||
* environments where an off_t is 32-bits, but still run where
|
||||
* offsets are 64-bits, and they pay us a lot of money.
|
||||
*/
|
||||
if ((ret = __os_ioinfo(rpath,
|
||||
dbmfp->fd, &mbytes, &bytes, NULL)) != 0) {
|
||||
__db_err(dbenv, "%s: %s", rpath, strerror(ret));
|
||||
goto err;
|
||||
}
|
||||
if (bytes % pagesize) {
|
||||
|
||||
/* Page sizes have to be a power-of-two, ignore mbytes. */
|
||||
if (bytes % pagesize != 0) {
|
||||
__db_err(dbenv,
|
||||
"%s: file size not a multiple of the pagesize",
|
||||
rpath);
|
||||
ret = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
size = mbytes * MEGABYTE + bytes;
|
||||
last_pgno = size == 0 ? 0 : (size - 1) / pagesize;
|
||||
|
||||
last_pgno = mbytes * (MEGABYTE / pagesize);
|
||||
last_pgno += bytes / pagesize;
|
||||
|
||||
/* Correction: page numbers are zero-based, not 1-based. */
|
||||
if (last_pgno != 0)
|
||||
--last_pgno;
|
||||
|
||||
/*
|
||||
* Get the file id if we weren't given one. Generated file id's
|
||||
@ -168,7 +188,7 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
* other process joining the party.
|
||||
*/
|
||||
if (finfop->fileid == NULL) {
|
||||
if ((ret = __db_fileid(dbenv, rpath, 0, idbuf)) != 0)
|
||||
if ((ret = __os_fileid(dbenv, rpath, 0, idbuf)) != 0)
|
||||
goto err;
|
||||
finfop->fileid = idbuf;
|
||||
}
|
||||
@ -191,7 +211,7 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
}
|
||||
if (ret == 0 &&
|
||||
F_ISSET(dbmp, MP_LOCKHANDLE) && (ret =
|
||||
__memp_ralloc(dbmp, sizeof(db_mutex_t), NULL, &dbmfp->mutexp)) == 0)
|
||||
__memp_alloc(dbmp, sizeof(db_mutex_t), NULL, &dbmfp->mutexp)) == 0)
|
||||
LOCKINIT(dbmp, dbmfp->mutexp);
|
||||
|
||||
if (needlock)
|
||||
@ -232,13 +252,15 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
F_CLR(mfp, MP_CAN_MMAP);
|
||||
if (LF_ISSET(DB_NOMMAP))
|
||||
F_CLR(mfp, MP_CAN_MMAP);
|
||||
if (size > (dbenv == NULL || dbenv->mp_mmapsize == 0 ?
|
||||
DB_MAXMMAPSIZE : dbenv->mp_mmapsize))
|
||||
maxmap = dbenv == NULL || dbenv->mp_mmapsize == 0 ?
|
||||
DB_MAXMMAPSIZE : dbenv->mp_mmapsize;
|
||||
if (mbytes > maxmap / MEGABYTE ||
|
||||
(mbytes == maxmap / MEGABYTE && bytes >= maxmap % MEGABYTE))
|
||||
F_CLR(mfp, MP_CAN_MMAP);
|
||||
}
|
||||
dbmfp->addr = NULL;
|
||||
if (F_ISSET(mfp, MP_CAN_MMAP)) {
|
||||
dbmfp->len = size;
|
||||
dbmfp->len = (size_t)mbytes * MEGABYTE + bytes;
|
||||
if (__db_mapfile(rpath,
|
||||
dbmfp->fd, dbmfp->len, 1, &dbmfp->addr) != 0) {
|
||||
dbmfp->addr = NULL;
|
||||
@ -246,7 +268,7 @@ __memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp)
|
||||
}
|
||||
}
|
||||
if (rpath != NULL)
|
||||
FREES(rpath);
|
||||
__os_freestr(rpath);
|
||||
|
||||
LOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
TAILQ_INSERT_TAIL(&dbmp->dbmfq, dbmfp, q);
|
||||
@ -260,11 +282,11 @@ err: /*
|
||||
* never get to here after we have successfully allocated it.
|
||||
*/
|
||||
if (rpath != NULL)
|
||||
FREES(rpath);
|
||||
__os_freestr(rpath);
|
||||
if (dbmfp->fd != -1)
|
||||
(void)__db_close(dbmfp->fd);
|
||||
(void)__os_close(dbmfp->fd);
|
||||
if (dbmfp != NULL)
|
||||
FREE(dbmfp, sizeof(DB_MPOOLFILE));
|
||||
__os_free(dbmfp, sizeof(DB_MPOOLFILE));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -315,7 +337,7 @@ __memp_mf_open(dbmp, path, pagesize, last_pgno, finfop, retp)
|
||||
}
|
||||
|
||||
/* Allocate a new MPOOLFILE. */
|
||||
if ((ret = __memp_ralloc(dbmp, sizeof(MPOOLFILE), NULL, &mfp)) != 0)
|
||||
if ((ret = __memp_alloc(dbmp, sizeof(MPOOLFILE), NULL, &mfp)) != 0)
|
||||
return (ret);
|
||||
*retp = mfp;
|
||||
|
||||
@ -334,21 +356,22 @@ __memp_mf_open(dbmp, path, pagesize, last_pgno, finfop, retp)
|
||||
mfp->stat.st_pagesize = pagesize;
|
||||
mfp->orig_last_pgno = mfp->last_pgno = last_pgno;
|
||||
|
||||
F_SET(mfp, MP_CAN_MMAP);
|
||||
if (ISTEMPORARY)
|
||||
F_SET(mfp, MP_TEMP);
|
||||
else {
|
||||
/* Copy the file path into shared memory. */
|
||||
if ((ret = __memp_ralloc(dbmp,
|
||||
if ((ret = __memp_alloc(dbmp,
|
||||
strlen(path) + 1, &mfp->path_off, &p)) != 0)
|
||||
goto err;
|
||||
memcpy(p, path, strlen(path) + 1);
|
||||
|
||||
/* Copy the file identification string into shared memory. */
|
||||
if ((ret = __memp_ralloc(dbmp,
|
||||
if ((ret = __memp_alloc(dbmp,
|
||||
DB_FILE_ID_LEN, &mfp->fileid_off, &p)) != 0)
|
||||
goto err;
|
||||
memcpy(p, finfop->fileid, DB_FILE_ID_LEN);
|
||||
|
||||
F_SET(mfp, MP_CAN_MMAP);
|
||||
}
|
||||
|
||||
/* Copy the page cookie into shared memory. */
|
||||
@ -356,7 +379,7 @@ __memp_mf_open(dbmp, path, pagesize, last_pgno, finfop, retp)
|
||||
mfp->pgcookie_len = 0;
|
||||
mfp->pgcookie_off = 0;
|
||||
} else {
|
||||
if ((ret = __memp_ralloc(dbmp,
|
||||
if ((ret = __memp_alloc(dbmp,
|
||||
finfop->pgcookie->size, &mfp->pgcookie_off, &p)) != 0)
|
||||
goto err;
|
||||
memcpy(p, finfop->pgcookie->data, finfop->pgcookie->size);
|
||||
@ -394,16 +417,48 @@ memp_fclose(dbmfp)
|
||||
dbmp = dbmfp->dbmp;
|
||||
ret = 0;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
for (;;) {
|
||||
LOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
|
||||
/*
|
||||
* We have to reference count DB_MPOOLFILE structures as other
|
||||
* threads may be using them. The problem only happens if the
|
||||
* application makes a bad design choice. Here's the path:
|
||||
*
|
||||
* Thread A opens a database.
|
||||
* Thread B uses thread A's DB_MPOOLFILE to write a buffer
|
||||
* in order to free up memory in the mpool cache.
|
||||
* Thread A closes the database while thread B is using the
|
||||
* DB_MPOOLFILE structure.
|
||||
*
|
||||
* By opening all databases before creating the threads, and
|
||||
* closing them after the threads have exited, applications
|
||||
* get better performance and avoid the problem path entirely.
|
||||
*
|
||||
* Regardless, holding the DB_MPOOLFILE to flush a dirty buffer
|
||||
* is a short-term lock, even in worst case, since we better be
|
||||
* the only thread of control using the DB_MPOOLFILE structure
|
||||
* to read pages *into* the cache. Wait until we're the only
|
||||
* reference holder and remove the DB_MPOOLFILE structure from
|
||||
* the list, so nobody else can even find it.
|
||||
*/
|
||||
if (dbmfp->ref == 1) {
|
||||
TAILQ_REMOVE(&dbmp->dbmfq, dbmfp, q);
|
||||
break;
|
||||
}
|
||||
UNLOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
|
||||
(void)__os_sleep(1, 0);
|
||||
}
|
||||
UNLOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
|
||||
/* Complain if pinned blocks never returned. */
|
||||
if (dbmfp->pinref != 0)
|
||||
__db_err(dbmp->dbenv, "%s: close: %lu blocks left pinned",
|
||||
__memp_fn(dbmfp), (u_long)dbmfp->pinref);
|
||||
|
||||
/* Remove the DB_MPOOLFILE structure from the list. */
|
||||
LOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
TAILQ_REMOVE(&dbmp->dbmfq, dbmfp, q);
|
||||
UNLOCKHANDLE(dbmp, dbmp->mutexp);
|
||||
|
||||
/* Close the underlying MPOOLFILE. */
|
||||
(void)__memp_mf_close(dbmp, dbmfp);
|
||||
|
||||
@ -414,7 +469,7 @@ memp_fclose(dbmfp)
|
||||
"%s: %s", __memp_fn(dbmfp), strerror(ret));
|
||||
|
||||
/* Close the file; temporary files may not yet have been created. */
|
||||
if (dbmfp->fd != -1 && (t_ret = __db_close(dbmfp->fd)) != 0) {
|
||||
if (dbmfp->fd != -1 && (t_ret = __os_close(dbmfp->fd)) != 0) {
|
||||
__db_err(dbmp->dbenv,
|
||||
"%s: %s", __memp_fn(dbmfp), strerror(t_ret));
|
||||
if (ret != 0)
|
||||
@ -429,7 +484,7 @@ memp_fclose(dbmfp)
|
||||
}
|
||||
|
||||
/* Discard the DB_MPOOLFILE structure. */
|
||||
FREE(dbmfp, sizeof(DB_MPOOLFILE));
|
||||
__os_free(dbmfp, sizeof(DB_MPOOLFILE));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_fput.c 10.22 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)mp_fput.c 10.24 (Sleepycat) 9/27/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -40,6 +40,8 @@ memp_fput(dbmfp, pgaddr, flags)
|
||||
dbmp = dbmfp->dbmp;
|
||||
mp = dbmp->mp;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
/* Validate arguments. */
|
||||
if (flags) {
|
||||
if ((ret = __db_fchk(dbmp->dbenv, "memp_fput", flags,
|
||||
@ -57,15 +59,15 @@ memp_fput(dbmfp, pgaddr, flags)
|
||||
}
|
||||
}
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
|
||||
/* Decrement the pinned reference count. */
|
||||
LOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
if (dbmfp->pinref == 0)
|
||||
__db_err(dbmp->dbenv,
|
||||
"%s: put: more blocks returned than retrieved",
|
||||
__memp_fn(dbmfp));
|
||||
else
|
||||
--dbmfp->pinref;
|
||||
UNLOCKHANDLE(dbmp, dbmfp->mutexp);
|
||||
|
||||
/*
|
||||
* If we're mapping the file, there's nothing to do. Because we can
|
||||
@ -74,14 +76,14 @@ memp_fput(dbmfp, pgaddr, flags)
|
||||
* region.
|
||||
*/
|
||||
if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr &&
|
||||
(u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len)
|
||||
(u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len) {
|
||||
UNLOCKREGION(dbmp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Convert the page address to a buffer header. */
|
||||
bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
|
||||
/* Set/clear the page bits. */
|
||||
if (LF_ISSET(DB_MPOOL_CLEAN) && F_ISSET(bhp, BH_DIRTY)) {
|
||||
++mp->stat.st_page_clean;
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_fset.c 10.15 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)mp_fset.c 10.16 (Sleepycat) 9/27/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -40,6 +40,8 @@ memp_fset(dbmfp, pgaddr, flags)
|
||||
dbmp = dbmfp->dbmp;
|
||||
mp = dbmp->mp;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
/* Validate arguments. */
|
||||
if (flags == 0)
|
||||
return (__db_ferr(dbmp->dbenv, "memp_fset", 1));
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_open.c 10.23 (Sleepycat) 5/3/98";
|
||||
static const char sccsid[] = "@(#)mp_open.c 10.27 (Sleepycat) 10/1/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -52,8 +52,8 @@ memp_open(path, flags, mode, dbenv, retp)
|
||||
cachesize = dbenv == NULL ? 0 : dbenv->mp_size;
|
||||
|
||||
/* Create and initialize the DB_MPOOL structure. */
|
||||
if ((dbmp = (DB_MPOOL *)__db_calloc(1, sizeof(DB_MPOOL))) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_calloc(1, sizeof(DB_MPOOL), &dbmp)) != 0)
|
||||
return (ret);
|
||||
LIST_INIT(&dbmp->dbregq);
|
||||
TAILQ_INIT(&dbmp->dbmfq);
|
||||
|
||||
@ -83,7 +83,7 @@ memp_open(path, flags, mode, dbenv, retp)
|
||||
if (LF_ISSET(DB_THREAD)) {
|
||||
F_SET(dbmp, MP_LOCKHANDLE | MP_LOCKREGION);
|
||||
LOCKREGION(dbmp);
|
||||
ret = __memp_ralloc(dbmp,
|
||||
ret = __memp_alloc(dbmp,
|
||||
sizeof(db_mutex_t), NULL, &dbmp->mutexp);
|
||||
UNLOCKREGION(dbmp);
|
||||
if (ret != 0) {
|
||||
@ -97,7 +97,7 @@ memp_open(path, flags, mode, dbenv, retp)
|
||||
return (0);
|
||||
|
||||
err: if (dbmp != NULL)
|
||||
FREE(dbmp, sizeof(DB_MPOOL));
|
||||
__os_free(dbmp, sizeof(DB_MPOOL));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -115,10 +115,12 @@ memp_close(dbmp)
|
||||
|
||||
ret = 0;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
/* Discard DB_MPREGs. */
|
||||
while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) {
|
||||
LIST_REMOVE(mpreg, q);
|
||||
FREE(mpreg, sizeof(DB_MPREG));
|
||||
__os_free(mpreg, sizeof(DB_MPREG));
|
||||
}
|
||||
|
||||
/* Discard DB_MPOOLFILEs. */
|
||||
@ -138,12 +140,26 @@ memp_close(dbmp)
|
||||
ret = t_ret;
|
||||
|
||||
if (dbmp->reginfo.path != NULL)
|
||||
FREES(dbmp->reginfo.path);
|
||||
FREE(dbmp, sizeof(DB_MPOOL));
|
||||
__os_freestr(dbmp->reginfo.path);
|
||||
__os_free(dbmp, sizeof(DB_MPOOL));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __memp_panic --
|
||||
* Panic a memory pool.
|
||||
*
|
||||
* PUBLIC: void __memp_panic __P((DB_ENV *));
|
||||
*/
|
||||
void
|
||||
__memp_panic(dbenv)
|
||||
DB_ENV *dbenv;
|
||||
{
|
||||
if (dbenv->mp_info != NULL)
|
||||
dbenv->mp_info->mp->rlayout.panic = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* memp_unlink --
|
||||
* Exit a memory pool.
|
||||
@ -160,12 +176,12 @@ memp_unlink(path, force, dbenv)
|
||||
memset(®info, 0, sizeof(reginfo));
|
||||
reginfo.dbenv = dbenv;
|
||||
reginfo.appname = DB_APP_NONE;
|
||||
if (path != NULL && (reginfo.path = __db_strdup(path)) == NULL)
|
||||
return (ENOMEM);
|
||||
if (path != NULL && (ret = __os_strdup(path, ®info.path)) != 0)
|
||||
return (ret);
|
||||
reginfo.file = DB_DEFAULT_MPOOL_FILE;
|
||||
ret = __db_runlink(®info, force);
|
||||
if (reginfo.path != NULL)
|
||||
FREES(reginfo.path);
|
||||
__os_freestr(reginfo.path);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -181,9 +197,12 @@ memp_register(dbmp, ftype, pgin, pgout)
|
||||
int (*pgout) __P((db_pgno_t, void *, DBT *));
|
||||
{
|
||||
DB_MPREG *mpr;
|
||||
int ret;
|
||||
|
||||
if ((mpr = (DB_MPREG *)__db_malloc(sizeof(DB_MPREG))) == NULL)
|
||||
return (ENOMEM);
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
if ((ret = __os_malloc(sizeof(DB_MPREG), NULL, &mpr)) != 0)
|
||||
return (ret);
|
||||
|
||||
mpr->ftype = ftype;
|
||||
mpr->pgin = pgin;
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_pr.c 10.26 (Sleepycat) 5/23/98";
|
||||
static const char sccsid[] = "@(#)mp_pr.c 10.30 (Sleepycat) 10/1/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -44,16 +44,17 @@ memp_stat(dbmp, gspp, fspp, db_malloc)
|
||||
DB_MPOOL_FSTAT **tfsp;
|
||||
MPOOLFILE *mfp;
|
||||
size_t len, nlen;
|
||||
int ret;
|
||||
char *name;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
/* Allocate space for the global statistics. */
|
||||
if (gspp != NULL) {
|
||||
*gspp = NULL;
|
||||
|
||||
if ((*gspp = db_malloc == NULL ?
|
||||
(DB_MPOOL_STAT *)__db_malloc(sizeof(**gspp)) :
|
||||
(DB_MPOOL_STAT *)db_malloc(sizeof(**gspp))) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(sizeof(**gspp), db_malloc, gspp)) != 0)
|
||||
return (ret);
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
|
||||
@ -89,10 +90,8 @@ memp_stat(dbmp, gspp, fspp, db_malloc)
|
||||
|
||||
/* Allocate space for the pointers. */
|
||||
len = (len + 1) * sizeof(DB_MPOOL_FSTAT *);
|
||||
if ((*fspp = db_malloc == NULL ?
|
||||
(DB_MPOOL_FSTAT **)__db_malloc(len) :
|
||||
(DB_MPOOL_FSTAT **)db_malloc(len)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(len, db_malloc, fspp)) != 0)
|
||||
return (ret);
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
|
||||
@ -104,10 +103,8 @@ memp_stat(dbmp, gspp, fspp, db_malloc)
|
||||
name = __memp_fns(dbmp, mfp);
|
||||
nlen = strlen(name);
|
||||
len = sizeof(DB_MPOOL_FSTAT) + nlen + 1;
|
||||
if ((*tfsp = db_malloc == NULL ?
|
||||
(DB_MPOOL_FSTAT *)__db_malloc(len) :
|
||||
(DB_MPOOL_FSTAT *)db_malloc(len)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_malloc(len, db_malloc, tfsp)) != 0)
|
||||
return (ret);
|
||||
**tfsp = mfp->stat;
|
||||
(*tfsp)->file_name = (char *)
|
||||
(u_int8_t *)*tfsp + sizeof(DB_MPOOL_FSTAT);
|
||||
@ -212,8 +209,9 @@ __memp_dump_region(dbmp, area, fp)
|
||||
cnt = 0;
|
||||
for (mfp = SH_TAILQ_FIRST(&dbmp->mp->mpfq, __mpoolfile);
|
||||
mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile), ++cnt) {
|
||||
(void)fprintf(fp, "file #%d: %s: %lu references: %s\n",
|
||||
(void)fprintf(fp, "file #%d: %s: refs %lu, type %ld, %s\n",
|
||||
cnt + 1, __memp_fns(dbmp, mfp), (u_long)mfp->ref,
|
||||
(long)mfp->ftype,
|
||||
F_ISSET(mfp, MP_CAN_MMAP) ? "mmap" : "read/write");
|
||||
if (cnt < FMAP_ENTRIES)
|
||||
fmap[cnt] = R_OFFSET(dbmp, mfp);
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_region.c 10.30 (Sleepycat) 5/31/98";
|
||||
static const char sccsid[] = "@(#)mp_region.c 10.35 (Sleepycat) 12/11/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -24,13 +24,33 @@ static const char sccsid[] = "@(#)mp_region.c 10.30 (Sleepycat) 5/31/98";
|
||||
#include "common_ext.h"
|
||||
|
||||
/*
|
||||
* __memp_ralloc --
|
||||
* Allocate some space in the mpool region.
|
||||
* __memp_reg_alloc --
|
||||
* Allocate some space in the mpool region, with locking.
|
||||
*
|
||||
* PUBLIC: int __memp_ralloc __P((DB_MPOOL *, size_t, size_t *, void *));
|
||||
* PUBLIC: int __memp_reg_alloc __P((DB_MPOOL *, size_t, size_t *, void *));
|
||||
*/
|
||||
int
|
||||
__memp_ralloc(dbmp, len, offsetp, retp)
|
||||
__memp_reg_alloc(dbmp, len, offsetp, retp)
|
||||
DB_MPOOL *dbmp;
|
||||
size_t len, *offsetp;
|
||||
void *retp;
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
ret = __memp_alloc(dbmp, len, offsetp, retp);
|
||||
UNLOCKREGION(dbmp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __memp_alloc --
|
||||
* Allocate some space in the mpool region.
|
||||
*
|
||||
* PUBLIC: int __memp_alloc __P((DB_MPOOL *, size_t, size_t *, void *));
|
||||
*/
|
||||
int
|
||||
__memp_alloc(dbmp, len, offsetp, retp)
|
||||
DB_MPOOL *dbmp;
|
||||
size_t len, *offsetp;
|
||||
void *retp;
|
||||
@ -52,7 +72,9 @@ alloc: if ((ret = __db_shalloc(dbmp->addr, len, MUTEX_ALIGNMENT, &p)) == 0) {
|
||||
return (0);
|
||||
}
|
||||
if (nomore) {
|
||||
__db_err(dbmp->dbenv, "%s", strerror(ret));
|
||||
__db_err(dbmp->dbenv,
|
||||
"Unable to allocate %lu bytes from mpool shared region: %s\n",
|
||||
(u_long)len, strerror(ret));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -91,7 +113,7 @@ alloc: if ((ret = __db_shalloc(dbmp->addr, len, MUTEX_ALIGNMENT, &p)) == 0) {
|
||||
}
|
||||
|
||||
retry: /* Find a buffer we can flush; pure LRU. */
|
||||
total = 0;
|
||||
restart = total = 0;
|
||||
for (bhp =
|
||||
SH_TAILQ_FIRST(&mp->bhq, __bh); bhp != NULL; bhp = nbhp) {
|
||||
nbhp = SH_TAILQ_NEXT(bhp, q, __bh);
|
||||
@ -222,8 +244,8 @@ __memp_ropen(dbmp, path, cachesize, mode, is_private, flags)
|
||||
if (path == NULL)
|
||||
dbmp->reginfo.path = NULL;
|
||||
else
|
||||
if ((dbmp->reginfo.path = __db_strdup(path)) == NULL)
|
||||
return (ENOMEM);
|
||||
if ((ret = __os_strdup(path, &dbmp->reginfo.path)) != 0)
|
||||
return (ret);
|
||||
dbmp->reginfo.file = DB_DEFAULT_MPOOL_FILE;
|
||||
dbmp->reginfo.mode = mode;
|
||||
dbmp->reginfo.size = rlen;
|
||||
@ -244,7 +266,7 @@ __memp_ropen(dbmp, path, cachesize, mode, is_private, flags)
|
||||
|
||||
if ((ret = __db_rattach(&dbmp->reginfo)) != 0) {
|
||||
if (dbmp->reginfo.path != NULL)
|
||||
FREES(dbmp->reginfo.path);
|
||||
__os_freestr(dbmp->reginfo.path);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -303,6 +325,6 @@ err: UNLOCKREGION(dbmp);
|
||||
(void)memp_unlink(path, 1, dbmp->dbenv);
|
||||
|
||||
if (dbmp->reginfo.path != NULL)
|
||||
FREES(dbmp->reginfo.path);
|
||||
__os_freestr(dbmp->reginfo.path);
|
||||
return (ret);
|
||||
}
|
||||
|
166
db2/mp/mp_sync.c
166
db2/mp/mp_sync.c
@ -7,7 +7,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)mp_sync.c 10.25 (Sleepycat) 4/26/98";
|
||||
static const char sccsid[] = "@(#)mp_sync.c 10.31 (Sleepycat) 12/11/98";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef NO_SYSTEM_INCLUDES
|
||||
@ -39,9 +39,12 @@ memp_sync(dbmp, lsnp)
|
||||
DB_ENV *dbenv;
|
||||
MPOOL *mp;
|
||||
MPOOLFILE *mfp;
|
||||
int ar_cnt, cnt, nalloc, next, ret, wrote;
|
||||
int ar_cnt, nalloc, next, maxpin, ret, wrote;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
dbenv = dbmp->dbenv;
|
||||
mp = dbmp->mp;
|
||||
|
||||
if (dbenv->lg_info == NULL) {
|
||||
__db_err(dbenv, "memp_sync: requires logging");
|
||||
@ -49,16 +52,19 @@ memp_sync(dbmp, lsnp)
|
||||
}
|
||||
|
||||
/*
|
||||
* We try and write the buffers in page order so that the underlying
|
||||
* filesystem doesn't have to seek and can write contiguous blocks,
|
||||
* plus, we don't want to hold the region lock while we write the
|
||||
* buffers. Get memory to hold the buffer pointers. Get a good-size
|
||||
* block, too, because we realloc while holding the region lock if we
|
||||
* run out.
|
||||
* We try and write the buffers in page order: it should reduce seeks
|
||||
* by the underlying filesystem and possibly reduce the actual number
|
||||
* of writes. We don't want to hold the region lock while we write
|
||||
* the buffers, so only hold it lock while we create a list. Get a
|
||||
* good-size block of memory to hold buffer pointers, we don't want
|
||||
* to run out.
|
||||
*/
|
||||
if ((bharray =
|
||||
(BH **)__db_malloc((nalloc = 1024) * sizeof(BH *))) == NULL)
|
||||
return (ENOMEM);
|
||||
LOCKREGION(dbmp);
|
||||
nalloc = mp->stat.st_page_dirty + mp->stat.st_page_dirty / 2 + 10;
|
||||
UNLOCKREGION(dbmp);
|
||||
|
||||
if ((ret = __os_malloc(nalloc * sizeof(BH *), NULL, &bharray)) != 0)
|
||||
return (ret);
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
|
||||
@ -70,7 +76,6 @@ memp_sync(dbmp, lsnp)
|
||||
* we've already handled or are currently handling, then we return a
|
||||
* result based on the count for the larger LSN.
|
||||
*/
|
||||
mp = dbmp->mp;
|
||||
if (!F_ISSET(mp, MP_LSN_RETRY) && log_compare(lsnp, &mp->lsn) <= 0) {
|
||||
if (mp->lsn_cnt == 0) {
|
||||
*lsnp = mp->lsn;
|
||||
@ -114,10 +119,15 @@ memp_sync(dbmp, lsnp)
|
||||
* finish. Since the application may have restarted the sync, clear
|
||||
* any BH_WRITE flags that appear to be left over from previous calls.
|
||||
*
|
||||
* We don't want to pin down the entire buffer cache, otherwise we'll
|
||||
* starve threads needing new pages. Don't pin down more than 80% of
|
||||
* the cache.
|
||||
*
|
||||
* Keep a count of the total number of buffers we need to write in
|
||||
* MPOOL->lsn_cnt, and for each file, in MPOOLFILE->lsn_count.
|
||||
*/
|
||||
ar_cnt = 0;
|
||||
maxpin = ((mp->stat.st_page_dirty + mp->stat.st_page_clean) * 8) / 10;
|
||||
for (bhp = SH_TAILQ_FIRST(&mp->bhq, __bh);
|
||||
bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh))
|
||||
if (F_ISSET(bhp, BH_DIRTY) || bhp->ref != 0) {
|
||||
@ -130,19 +140,27 @@ memp_sync(dbmp, lsnp)
|
||||
|
||||
/*
|
||||
* If the buffer isn't in use, we should be able to
|
||||
* write it immediately, so save a reference to it.
|
||||
* write it immediately, so increment the reference
|
||||
* count to lock it and its contents down, and then
|
||||
* save a reference to it.
|
||||
*
|
||||
* If we've run out space to store buffer references,
|
||||
* we're screwed. We don't want to realloc the array
|
||||
* while holding a region lock, so we set the flag to
|
||||
* force the checkpoint to be done again, from scratch,
|
||||
* later.
|
||||
*
|
||||
* If we've pinned down too much of the cache stop, and
|
||||
* set a flag to force the checkpoint to be tried again
|
||||
* later.
|
||||
*/
|
||||
if (bhp->ref == 0) {
|
||||
if (ar_cnt == nalloc) {
|
||||
nalloc *= 2;
|
||||
if ((bharray =
|
||||
(BH **)__db_realloc(bharray,
|
||||
nalloc * sizeof(BH *))) == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
++bhp->ref;
|
||||
bharray[ar_cnt] = bhp;
|
||||
if (++ar_cnt >= nalloc || ar_cnt >= maxpin) {
|
||||
F_SET(mp, MP_LSN_RETRY);
|
||||
break;
|
||||
}
|
||||
bharray[ar_cnt++] = bhp;
|
||||
}
|
||||
} else
|
||||
if (F_ISSET(bhp, BH_WRITE))
|
||||
@ -154,10 +172,6 @@ memp_sync(dbmp, lsnp)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Lock down the buffers and their contents. */
|
||||
for (cnt = 0; cnt < ar_cnt; ++cnt)
|
||||
++bharray[cnt]->ref;
|
||||
|
||||
UNLOCKREGION(dbmp);
|
||||
|
||||
/* Sort the buffers we're going to write. */
|
||||
@ -205,7 +219,8 @@ memp_sync(dbmp, lsnp)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
ret = mp->lsn_cnt ? DB_INCOMPLETE : 0;
|
||||
ret = mp->lsn_cnt != 0 ||
|
||||
F_ISSET(mp, MP_LSN_RETRY) ? DB_INCOMPLETE : 0;
|
||||
|
||||
done:
|
||||
if (0) {
|
||||
@ -224,7 +239,7 @@ err: /*
|
||||
F_CLR(bhp, BH_WRITE);
|
||||
}
|
||||
UNLOCKREGION(dbmp);
|
||||
__db_free(bharray);
|
||||
__os_free(bharray, nalloc * sizeof(BH *));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -241,6 +256,8 @@ memp_fsync(dbmfp)
|
||||
|
||||
dbmp = dbmfp->dbmp;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
/*
|
||||
* If this handle doesn't have a file descriptor that's open for
|
||||
* writing, or if the file is a temporary, there's no reason to
|
||||
@ -300,25 +317,29 @@ __memp_fsync(dbmfp)
|
||||
{
|
||||
BH *bhp, **bharray;
|
||||
DB_MPOOL *dbmp;
|
||||
MPOOL *mp;
|
||||
size_t mf_offset;
|
||||
int ar_cnt, cnt, nalloc, next, pincnt, ret, wrote;
|
||||
int ar_cnt, incomplete, nalloc, next, ret, wrote;
|
||||
|
||||
ret = 0;
|
||||
dbmp = dbmfp->dbmp;
|
||||
mp = dbmp->mp;
|
||||
mf_offset = R_OFFSET(dbmp, dbmfp->mfp);
|
||||
|
||||
/*
|
||||
* We try and write the buffers in page order so that the underlying
|
||||
* filesystem doesn't have to seek and can write contiguous blocks,
|
||||
* plus, we don't want to hold the region lock while we write the
|
||||
* buffers. Get memory to hold the buffer pointers. Get a good-size
|
||||
* block, too, because we realloc while holding the region lock if we
|
||||
* run out.
|
||||
* We try and write the buffers in page order: it should reduce seeks
|
||||
* by the underlying filesystem and possibly reduce the actual number
|
||||
* of writes. We don't want to hold the region lock while we write
|
||||
* the buffers, so only hold it lock while we create a list. Get a
|
||||
* good-size block of memory to hold buffer pointers, we don't want
|
||||
* to run out.
|
||||
*/
|
||||
nalloc = 1024;
|
||||
if ((bharray =
|
||||
(BH **)__db_malloc((size_t)nalloc * sizeof(BH *))) == NULL)
|
||||
return (ENOMEM);
|
||||
LOCKREGION(dbmp);
|
||||
nalloc = mp->stat.st_page_dirty + mp->stat.st_page_dirty / 2 + 10;
|
||||
UNLOCKREGION(dbmp);
|
||||
|
||||
if ((ret = __os_malloc(nalloc * sizeof(BH *), NULL, &bharray)) != 0)
|
||||
return (ret);
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
|
||||
@ -326,36 +347,37 @@ __memp_fsync(dbmfp)
|
||||
* Walk the LRU list of buffer headers, and get a list of buffers to
|
||||
* write for this MPOOLFILE.
|
||||
*/
|
||||
ar_cnt = pincnt = 0;
|
||||
for (bhp = SH_TAILQ_FIRST(&dbmp->mp->bhq, __bh);
|
||||
ar_cnt = incomplete = 0;
|
||||
for (bhp = SH_TAILQ_FIRST(&mp->bhq, __bh);
|
||||
bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) {
|
||||
if (!F_ISSET(bhp, BH_DIRTY) || bhp->mf_offset != mf_offset)
|
||||
continue;
|
||||
if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED)) {
|
||||
++pincnt;
|
||||
incomplete = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ar_cnt == nalloc) {
|
||||
nalloc *= 2;
|
||||
if ((bharray = (BH **)__db_realloc(bharray,
|
||||
nalloc * sizeof(BH *))) == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
++bhp->ref;
|
||||
bharray[ar_cnt] = bhp;
|
||||
|
||||
/*
|
||||
* If we've run out space to store buffer references, we're
|
||||
* screwed, as we don't want to realloc the array holding a
|
||||
* region lock. Set the incomplete flag -- the only way we
|
||||
* can get here is if the file is active in the buffer cache,
|
||||
* which is the same thing as finding pinned buffers.
|
||||
*/
|
||||
if (++ar_cnt >= nalloc) {
|
||||
incomplete = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
bharray[ar_cnt++] = bhp;
|
||||
}
|
||||
|
||||
/* Lock down the buffers and their contents. */
|
||||
for (cnt = 0; cnt < ar_cnt; ++cnt)
|
||||
++bharray[cnt]->ref;
|
||||
|
||||
UNLOCKREGION(dbmp);
|
||||
|
||||
/* Sort the buffers we're going to write. */
|
||||
qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp);
|
||||
if (ar_cnt != 0)
|
||||
qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp);
|
||||
|
||||
LOCKREGION(dbmp);
|
||||
|
||||
@ -365,11 +387,10 @@ __memp_fsync(dbmfp)
|
||||
* It's possible for a thread to have gotten the buffer since
|
||||
* we listed it for writing. If the reference count is still
|
||||
* 1, we're the only ones using the buffer, go ahead and write.
|
||||
* If it's >1, then skip the buffer and assume that it will be
|
||||
* written when it's returned to the cache.
|
||||
* If it's >1, then skip the buffer.
|
||||
*/
|
||||
if (bharray[next]->ref > 1) {
|
||||
++pincnt;
|
||||
incomplete = 1;
|
||||
|
||||
--bharray[next]->ref;
|
||||
continue;
|
||||
@ -387,13 +408,18 @@ __memp_fsync(dbmfp)
|
||||
--bharray[next]->ref;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't write the buffer for some reason, don't return
|
||||
* success.
|
||||
*/
|
||||
if (!wrote)
|
||||
++pincnt;
|
||||
incomplete = 1;
|
||||
}
|
||||
|
||||
err: UNLOCKREGION(dbmp);
|
||||
|
||||
__db_free(bharray);
|
||||
__os_free(bharray, nalloc * sizeof(BH *));
|
||||
|
||||
/*
|
||||
* Sync the underlying file as the last thing we do, so that the OS
|
||||
@ -404,7 +430,7 @@ err: UNLOCKREGION(dbmp);
|
||||
* issues.
|
||||
*/
|
||||
if (ret == 0)
|
||||
return (pincnt == 0 ? __db_fsync(dbmfp->fd) : DB_INCOMPLETE);
|
||||
return (incomplete ? DB_INCOMPLETE : __os_fsync(dbmfp->fd));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -423,6 +449,8 @@ memp_trickle(dbmp, pct, nwrotep)
|
||||
u_long total;
|
||||
int ret, wrote;
|
||||
|
||||
MP_PANIC_CHECK(dbmp);
|
||||
|
||||
mp = dbmp->mp;
|
||||
if (nwrotep != NULL)
|
||||
*nwrotep = 0;
|
||||
@ -487,7 +515,7 @@ loop: total = mp->stat.st_page_clean + mp->stat.st_page_dirty;
|
||||
}
|
||||
|
||||
/* No more buffers to write. */
|
||||
return (0);
|
||||
ret = 0;
|
||||
|
||||
err: UNLOCKREGION(dbmp);
|
||||
return (ret);
|
||||
@ -508,6 +536,14 @@ __bhcmp(p1, p2)
|
||||
if (bhp1->mf_offset > bhp2->mf_offset)
|
||||
return (1);
|
||||
|
||||
/* Sort by page in file. */
|
||||
return (bhp1->pgno < bhp2->pgno ? -1 : 1);
|
||||
/*
|
||||
* !!!
|
||||
* Defend against badly written quicksort code calling the comparison
|
||||
* function with two identical pointers (e.g., WATCOM C++ (Power++)).
|
||||
*/
|
||||
if (bhp1->pgno < bhp2->pgno)
|
||||
return (-1);
|
||||
if (bhp1->pgno > bhp2->pgno)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* @(#)alpha.dec 8.3 (Sleepycat Software) 1/18/97
|
||||
*
|
||||
* The DEC C asm acts as a pseudo-call. The first argument is the assembly
|
||||
* code, and the remaining arguments are assigned as in a procedure call, to
|
||||
* r16, r17, etc. (represented in asm as %a0, %a1, and so forth).
|
||||
*
|
||||
* From: Dave Butenhof.
|
||||
*/
|
||||
|
||||
#include <c_asm.h>
|
||||
|
||||
#define TSL_SET(tsl) (asm ("mb; \
|
||||
10: ldl_l %v0,(%a0) ; \
|
||||
bne %v0,30f ; \
|
||||
or %v0,1,%r1 ; \
|
||||
stl_c %r1,(%a0) ; \
|
||||
beq %r1,20f ; \
|
||||
mb ; \
|
||||
br %r31,30f ; \
|
||||
20: br %r31,10b ; \
|
||||
30: ", (tsl)))
|
||||
|
||||
THIS WAS NOT CONVERTED TO TAKE A POINTER AS AN ARGUMENT...
|
||||
#define TSL_UNSET(tsl) (asm ("mb"), *(tsl) = 0)
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* @(#)alpha.gcc 10.1 (Sleepycat) 4/12/97
|
||||
*
|
||||
* The code appearing below is taken from Richard L. Sites, ed. "Alpha
|
||||
* Architecture Reference Manual", Digital Press, 1992, page 5-7 and 5-8.
|
||||
* There are 2 modifications:
|
||||
*
|
||||
* 1. The jump from blbs __r1,30f to !__r1, which is dictated by the way the
|
||||
* TSL_SET macro is used. The code suggested in Sites includes the main loop
|
||||
* of the spin lock, whereas in this code the rest the loop is specified in C.
|
||||
* The generated code might be suboptimal if the compiler generates a forward
|
||||
* branch for the usual case in which the mutex is uncontested.
|
||||
*
|
||||
* 2. At label 20, Sites suggests including code for testing for an excessive
|
||||
* number of _processor_ lock conflicts. (The seq_c instruction stores its
|
||||
* first argument provided that no other processor has written to a byte range
|
||||
* including its memory-location argument.) Absent such checking the code
|
||||
* below could conceivably stall silently on a multiprocessor alpha, depending
|
||||
* on how often processor/processor conflicts occur in a particular byte range.
|
||||
*
|
||||
* Note that the mb ("memory-barrier") instruction in TSL_UNSET is critical to
|
||||
* correct operation in a multiprocessor alpha (as is, of course, the mb in
|
||||
* the TSL_SET macro). Without the mb, changes to shared memory that occurred
|
||||
* inside the critical section (before the TSL_UNSET) might reach shared memory
|
||||
* _after_ the change of tsl to 0, thereby permitting another processor to see
|
||||
* an inconsistent view of the data protected by the mutex.
|
||||
*
|
||||
* For gcc/alpha, 0 is clear, 1 is set.
|
||||
*/
|
||||
#define TSL_SET(tsl) ({ \
|
||||
register tsl_t *__l = (tsl); \
|
||||
register tsl_t __r1, __r2; \
|
||||
__asm__ volatile(" \n\
|
||||
10: ldq_l %0,(%2) \n\
|
||||
blbs %0,30f \n\
|
||||
or %0,1,%1 \n\
|
||||
stq_c %1,(%2) \n\
|
||||
beq %1,20f \n\
|
||||
mb \n\
|
||||
br 30f \n\
|
||||
20: br 10b \n\
|
||||
30: " \
|
||||
: "=&r" (__r1), "=&r" (__r2) \
|
||||
: "r" (__l)); \
|
||||
!__r1; \
|
||||
})
|
||||
|
||||
#define TSL_UNSET(tsl) ({ \
|
||||
register tsl_t *__l = (tsl); \
|
||||
__asm__ volatile("mb; stq $31,(%0);" : : "r" (__l)); \
|
||||
})
|
||||
#define TSL_INIT(tsl) TSL_UNSET(tsl)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user