summaryrefslogtreecommitdiff
path: root/bdb/hash/hash_stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'bdb/hash/hash_stat.c')
-rw-r--r--bdb/hash/hash_stat.c137
1 files changed, 90 insertions, 47 deletions
diff --git a/bdb/hash/hash_stat.c b/bdb/hash/hash_stat.c
index ed64bbc68bd..f9ee1d099cb 100644
--- a/bdb/hash/hash_stat.c
+++ b/bdb/hash/hash_stat.c
@@ -1,14 +1,14 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Copyright (c) 1996-2002
* Sleepycat Software. All rights reserved.
*/
#include "db_config.h"
#ifndef lint
-static const char revid[] = "$Id: hash_stat.c,v 11.24 2000/12/21 21:54:35 margo Exp $";
+static const char revid[] = "$Id: hash_stat.c,v 11.48 2002/08/06 06:11:28 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -18,11 +18,9 @@ static const char revid[] = "$Id: hash_stat.c,v 11.24 2000/12/21 21:54:35 margo
#endif
#include "db_int.h"
-#include "db_page.h"
-#include "db_shash.h"
-#include "btree.h"
-#include "hash.h"
-#include "lock.h"
+#include "dbinc/db_page.h"
+#include "dbinc/btree.h"
+#include "dbinc/hash.h"
static int __ham_stat_callback __P((DB *, PAGE *, void *, int *));
@@ -30,24 +28,29 @@ static int __ham_stat_callback __P((DB *, PAGE *, void *, int *));
* __ham_stat --
* Gather/print the hash statistics
*
- * PUBLIC: int __ham_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
+ * PUBLIC: int __ham_stat __P((DB *, void *, u_int32_t));
*/
int
-__ham_stat(dbp, spp, db_malloc, flags)
+__ham_stat(dbp, spp, flags)
DB *dbp;
- void *spp, *(*db_malloc) __P((size_t));
+ void *spp;
u_int32_t flags;
{
+ DBC *dbc;
+ DB_ENV *dbenv;
DB_HASH_STAT *sp;
+ DB_MPOOLFILE *mpf;
HASH_CURSOR *hcp;
- DBC *dbc;
PAGE *h;
db_pgno_t pgno;
int ret;
- PANIC_CHECK(dbp->dbenv);
+ dbenv = dbp->dbenv;
+
+ PANIC_CHECK(dbenv);
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
+ mpf = dbp->mpf;
sp = NULL;
/* Check for invalid flags. */
@@ -62,39 +65,39 @@ __ham_stat(dbp, spp, db_malloc, flags)
goto err;
/* Allocate and clear the structure. */
- if ((ret = __os_malloc(dbp->dbenv, sizeof(*sp), db_malloc, &sp)) != 0)
+ if ((ret = __os_umalloc(dbenv, sizeof(*sp), &sp)) != 0)
goto err;
memset(sp, 0, sizeof(*sp));
- if (flags == DB_CACHED_COUNTS) {
- sp->hash_nkeys = hcp->hdr->dbmeta.key_count;
- sp->hash_ndata = hcp->hdr->dbmeta.record_count;
- goto done;
- }
-
/* Copy the fields that we have. */
+ sp->hash_nkeys = hcp->hdr->dbmeta.key_count;
+ sp->hash_ndata = hcp->hdr->dbmeta.record_count;
sp->hash_pagesize = dbp->pgsize;
sp->hash_buckets = hcp->hdr->max_bucket + 1;
sp->hash_magic = hcp->hdr->dbmeta.magic;
sp->hash_version = hcp->hdr->dbmeta.version;
sp->hash_metaflags = hcp->hdr->dbmeta.flags;
- sp->hash_nelem = hcp->hdr->nelem;
sp->hash_ffactor = hcp->hdr->ffactor;
+ if (flags == DB_FAST_STAT || flags == DB_CACHED_COUNTS)
+ goto done;
+
/* Walk the free list, counting pages. */
for (sp->hash_free = 0, pgno = hcp->hdr->dbmeta.free;
pgno != PGNO_INVALID;) {
++sp->hash_free;
- if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
+ if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
goto err;
pgno = h->next_pgno;
- (void)memp_fput(dbp->mpf, h, 0);
+ (void)mpf->put(mpf, h, 0);
}
/* Now traverse the rest of the table. */
- if ((ret = __ham_traverse(dbp,
- dbc, DB_LOCK_READ, __ham_stat_callback, sp)) != 0)
+ sp->hash_nkeys = 0;
+ sp->hash_ndata = 0;
+ if ((ret = __ham_traverse(dbc,
+ DB_LOCK_READ, __ham_stat_callback, sp, 0)) != 0)
goto err;
if (!F_ISSET(dbp, DB_AM_RDONLY)) {
@@ -114,7 +117,7 @@ done:
return (0);
err: if (sp != NULL)
- __os_free(sp, sizeof(*sp));
+ __os_ufree(dbenv, sp);
if (hcp->hdr != NULL)
(void)__ham_release_meta(dbc);
(void)dbc->c_close(dbc);
@@ -127,26 +130,30 @@ err: if (sp != NULL)
* Traverse an entire hash table. We use the callback so that we
* can use this both for stat collection and for deallocation.
*
- * PUBLIC: int __ham_traverse __P((DB *, DBC *, db_lockmode_t,
- * PUBLIC: int (*)(DB *, PAGE *, void *, int *), void *));
+ * PUBLIC: int __ham_traverse __P((DBC *, db_lockmode_t,
+ * PUBLIC: int (*)(DB *, PAGE *, void *, int *), void *, int));
*/
int
-__ham_traverse(dbp, dbc, mode, callback, cookie)
- DB *dbp;
+__ham_traverse(dbc, mode, callback, cookie, look_past_max)
DBC *dbc;
db_lockmode_t mode;
int (*callback) __P((DB *, PAGE *, void *, int *));
void *cookie;
+ int look_past_max;
{
+ DB *dbp;
+ DBC *opd;
+ DB_MPOOLFILE *mpf;
HASH_CURSOR *hcp;
HKEYDATA *hk;
- DBC *opd;
db_pgno_t pgno, opgno;
- u_int32_t bucket;
int did_put, i, ret, t_ret;
+ u_int32_t bucket, spares_entry;
- hcp = (HASH_CURSOR *)dbc->internal;
+ dbp = dbc->dbp;
opd = NULL;
+ mpf = dbp->mpf;
+ hcp = (HASH_CURSOR *)dbc->internal;
ret = 0;
/*
@@ -156,12 +163,47 @@ __ham_traverse(dbp, dbc, mode, callback, cookie)
* locking easy, makes this a pain in the butt. We have to traverse
* duplicate, overflow and big pages from the bucket so that we
* don't access anything that isn't properly locked.
+ *
*/
- for (bucket = 0; bucket <= hcp->hdr->max_bucket; bucket++) {
+ for (bucket = 0;; bucket++) {
+ /*
+ * We put the loop exit condition check here, because
+ * it made for a really vile extended ?: that made SCO's
+ * compiler drop core.
+ *
+ * If look_past_max is not set, we can stop at max_bucket;
+ * if it is set, we need to include pages that are part of
+ * the current doubling but beyond the highest bucket we've
+ * split into, as well as pages from a "future" doubling
+ * that may have been created within an aborted
+ * transaction. To do this, keep looping (and incrementing
+ * bucket) until the corresponding spares array entries
+ * cease to be defined.
+ */
+ if (look_past_max) {
+ spares_entry = __db_log2(bucket + 1);
+ if (spares_entry >= NCACHED ||
+ hcp->hdr->spares[spares_entry] == 0)
+ break;
+ } else {
+ if (bucket > hcp->hdr->max_bucket)
+ break;
+ }
+
hcp->bucket = bucket;
hcp->pgno = pgno = BUCKET_TO_PAGE(hcp, bucket);
for (ret = __ham_get_cpage(dbc, mode); ret == 0;
ret = __ham_next_cpage(dbc, pgno, 0)) {
+
+ /*
+ * If we are cleaning up pages past the max_bucket,
+ * then they may be on the free list and have their
+ * next pointers set, but the should be ignored. In
+ * fact, we really ought to just skip anybody who is
+ * not a valid page.
+ */
+ if (TYPE(hcp->page) == P_INVALID)
+ break;
pgno = NEXT_PGNO(hcp->page);
/*
@@ -171,17 +213,17 @@ __ham_traverse(dbp, dbc, mode, callback, cookie)
* case we have to count those pages).
*/
for (i = 0; i < NUM_ENT(hcp->page); i++) {
- hk = (HKEYDATA *)P_ENTRY(hcp->page, i);
+ hk = (HKEYDATA *)P_ENTRY(dbp, hcp->page, i);
switch (HPAGE_PTYPE(hk)) {
case H_OFFDUP:
memcpy(&opgno, HOFFDUP_PGNO(hk),
sizeof(db_pgno_t));
if ((ret = __db_c_newopd(dbc,
- opgno, &opd)) != 0)
+ opgno, NULL, &opd)) != 0)
return (ret);
if ((ret = __bam_traverse(opd,
DB_LOCK_READ, opgno,
- __ham_stat_callback, cookie))
+ callback, cookie))
!= 0)
goto err;
if ((ret = opd->c_close(opd)) != 0)
@@ -221,10 +263,10 @@ __ham_traverse(dbp, dbc, mode, callback, cookie)
goto err;
if (STD_LOCKING(dbc))
- (void)lock_put(dbp->dbenv, &hcp->lock);
+ (void)dbp->dbenv->lock_put(dbp->dbenv, &hcp->lock);
if (hcp->page != NULL) {
- if ((ret = memp_fput(dbc->dbp->mpf, hcp->page, 0)) != 0)
+ if ((ret = mpf->put(mpf, hcp->page, 0)) != 0)
return (ret);
hcp->page = NULL;
}
@@ -247,6 +289,7 @@ __ham_stat_callback(dbp, pagep, cookie, putp)
DB_BTREE_STAT bstat;
db_indx_t indx, len, off, tlen, top;
u_int8_t *hk;
+ int ret;
*putp = 0;
sp = cookie;
@@ -266,15 +309,15 @@ __ham_stat_callback(dbp, pagep, cookie, putp)
* is a bucket.
*/
if (PREV_PGNO(pagep) == PGNO_INVALID)
- sp->hash_bfree += P_FREESPACE(pagep);
+ sp->hash_bfree += P_FREESPACE(dbp, pagep);
else {
sp->hash_overflows++;
- sp->hash_ovfl_free += P_FREESPACE(pagep);
+ sp->hash_ovfl_free += P_FREESPACE(dbp, pagep);
}
top = NUM_ENT(pagep);
/* Correct for on-page duplicates and deleted items. */
for (indx = 0; indx < top; indx += P_INDX) {
- switch (*H_PAIRDATA(pagep, indx)) {
+ switch (*H_PAIRDATA(dbp, pagep, indx)) {
case H_OFFDUP:
case H_OFFPAGE:
break;
@@ -282,8 +325,8 @@ __ham_stat_callback(dbp, pagep, cookie, putp)
sp->hash_ndata++;
break;
case H_DUPLICATE:
- tlen = LEN_HDATA(pagep, 0, indx);
- hk = H_PAIRDATA(pagep, indx);
+ tlen = LEN_HDATA(dbp, pagep, 0, indx);
+ hk = H_PAIRDATA(dbp, pagep, indx);
for (off = 0; off < tlen;
off += len + 2 * sizeof (db_indx_t)) {
sp->hash_ndata++;
@@ -310,7 +353,8 @@ __ham_stat_callback(dbp, pagep, cookie, putp)
bstat.bt_int_pgfree = 0;
bstat.bt_leaf_pgfree = 0;
bstat.bt_ndata = 0;
- __bam_stat_callback(dbp, pagep, &bstat, putp);
+ if ((ret = __bam_stat_callback(dbp, pagep, &bstat, putp)) != 0)
+ return (ret);
sp->hash_dup++;
sp->hash_dup_free += bstat.bt_leaf_pgfree +
bstat.bt_dup_pgfree + bstat.bt_int_pgfree;
@@ -318,11 +362,10 @@ __ham_stat_callback(dbp, pagep, cookie, putp)
break;
case P_OVERFLOW:
sp->hash_bigpages++;
- sp->hash_big_bfree += P_OVFLSPACE(dbp->pgsize, pagep);
+ sp->hash_big_bfree += P_OVFLSPACE(dbp, dbp->pgsize, pagep);
break;
default:
- return (__db_unknown_type(dbp->dbenv,
- "__ham_stat_callback", pagep->type));
+ return (__db_pgfmt(dbp->dbenv, pagep->pgno));
}
return (0);