summaryrefslogtreecommitdiffstats
path: root/debian/htdig/htdig-3.2.0b6/db/hash_stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/htdig/htdig-3.2.0b6/db/hash_stat.c')
-rw-r--r--debian/htdig/htdig-3.2.0b6/db/hash_stat.c249
1 files changed, 249 insertions, 0 deletions
diff --git a/debian/htdig/htdig-3.2.0b6/db/hash_stat.c b/debian/htdig/htdig-3.2.0b6/db/hash_stat.c
new file mode 100644
index 00000000..192ab2ec
--- /dev/null
+++ b/debian/htdig/htdig-3.2.0b6/db/hash_stat.c
@@ -0,0 +1,249 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997, 1998, 1999
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "db_config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)hash_stat.c 11.5 (Sleepycat) 9/10/99";
+#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_shash.h"
+#include "hash.h"
+#include "lock.h"
+
+static int CDB___ham_stat_callback __P((DB *, PAGE *, void *, int *));
+
+/*
+ * CDB___ham_stat --
+ * Gather/print the hash statistics
+ *
+ * PUBLIC: int CDB___ham_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
+ */
+int
+CDB___ham_stat(dbp, spp, db_malloc, flags)
+ DB *dbp;
+ void *spp, *(*db_malloc) __P((size_t));
+ u_int32_t flags;
+{
+ DB_HASH_STAT *sp;
+ HASH_CURSOR *hcp;
+ DBC *dbc;
+ PAGE *h;
+ db_pgno_t pgno;
+ int ret;
+
+ PANIC_CHECK(dbp->dbenv);
+ DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
+
+ sp = NULL;
+
+ /* Check for invalid flags. */
+ if ((ret = CDB___db_statchk(dbp, flags)) != 0)
+ return (ret);
+
+ if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
+ return (ret);
+ hcp = (HASH_CURSOR *)dbc->internal;
+
+ if ((ret = CDB___ham_get_meta(dbc)) != 0)
+ goto err;
+
+ /* Allocate and clear the structure. */
+ if ((ret = CDB___os_malloc(sizeof(*sp), db_malloc, &sp)) != 0)
+ goto err;
+ memset(sp, 0, sizeof(*sp));
+
+ /* Copy the fields that we have. */
+ 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;
+
+ /* Walk the free list, counting pages. */
+ for (sp->hash_free = 0, pgno = hcp->hdr->dbmeta.free;
+ pgno != PGNO_INVALID;) {
+ ++sp->hash_free;
+
+ if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
+ goto err;
+
+ pgno = h->next_pgno;
+ (void)CDB_memp_fput(dbp->mpf, h, 0);
+ }
+
+ /* Now traverse the rest of the table. */
+ if ((ret = CDB___ham_traverse(dbp,
+ dbc, DB_LOCK_READ, CDB___ham_stat_callback, sp)) != 0)
+ goto err;
+ if ((ret = dbc->c_close(dbc)) != 0)
+ goto err;
+ if ((ret = CDB___ham_release_meta(dbc)) != 0)
+ goto err;
+
+ *(DB_HASH_STAT **)spp = sp;
+ return (0);
+
+err: if (sp != NULL)
+ CDB___os_free(sp, sizeof(*sp));
+ if (hcp->hdr != NULL)
+ (void)CDB___ham_release_meta(dbc);
+ (void)dbc->c_close(dbc);
+ return (ret);
+
+}
+
+/*
+ * CDB___ham_traverse
+ * Traverse an entire hash table. We use the callback so that we
+ * can use this both for stat collection and for deallocation.
+ *
+ * PUBLIC: int CDB___ham_traverse __P((DB *, DBC *, db_lockmode_t,
+ * PUBLIC: int (*)(DB *, PAGE *, void *, int *), void *));
+ */
+int
+CDB___ham_traverse(dbp, dbc, mode, callback, cookie)
+ DB *dbp;
+ DBC *dbc;
+ db_lockmode_t mode;
+ int (*callback) __P((DB *, PAGE *, void *, int *));
+ void *cookie;
+{
+ HASH_CURSOR *hcp;
+ HKEYDATA *hk;
+ db_pgno_t pgno, opgno;
+ u_int32_t bucket;
+ int did_put, i, ret;
+
+ hcp = (HASH_CURSOR *)dbc->internal;
+
+ /*
+ * In a perfect world, we could simply read each page in the file
+ * and look at its page type to tally the information necessary.
+ * Unfortunately, the bucket locking that hash tables do to make
+ * 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++) {
+ hcp->bucket = bucket;
+ pgno = CDB___bucket_to_page(hcp, bucket);
+ for (ret = CDB___ham_get_cpage(dbc, mode); ret == 0;
+ ret = CDB___ham_next_cpage(dbc, pgno, 0, 0)) {
+ pgno = NEXT_PGNO(hcp->pagep);
+
+ /*
+ * Go through each item on the page checking for
+ * duplicates (in which case we have to count the
+ * duplicate pages) or big key/data items (in which
+ * case we have to count those pages).
+ */
+ for (i = 0; i < NUM_ENT(hcp->pagep); i++) {
+ hk = (HKEYDATA *)P_ENTRY(hcp->pagep, i);
+ switch (HPAGE_PTYPE(hk)) {
+ case H_OFFDUP:
+ memcpy(&opgno, HOFFDUP_PGNO(hk),
+ sizeof(db_pgno_t));
+ if ((ret = CDB___db_traverse_dup(dbp,
+ opgno, callback, cookie))
+ != 0)
+ return (ret);
+ break;
+ case H_OFFPAGE:
+ /*
+ * We are about to get a big page
+ * which will use the same spot that
+ * the current page uses, so we need
+ * to restore the current page before
+ * looking at it again.
+ */
+ memcpy(&opgno, HOFFPAGE_PGNO(hk),
+ sizeof(db_pgno_t));
+ ret = CDB___db_traverse_big(dbp,
+ opgno, callback, cookie);
+ if (ret != 0)
+ return (ret);
+ break;
+ case H_DUPLICATE:
+ case H_KEYDATA:
+ break;
+ }
+ }
+
+ /* Call the callback on main pages. */
+ if ((ret = callback(dbp,
+ hcp->pagep, cookie, &did_put)) != 0)
+ return (ret);
+
+ if (did_put)
+ hcp->pagep = NULL;
+ if (pgno == PGNO_INVALID)
+ break;
+ }
+ if (ret != 0)
+ return (ret);
+
+ if (F_ISSET(dbp->dbenv, DB_ENV_LOCKING))
+ (void)CDB_lock_put(dbp->dbenv, &hcp->lock);
+ }
+
+ return (0);
+}
+
+static int
+CDB___ham_stat_callback(dbp, pagep, cookie, putp)
+ DB *dbp;
+ PAGE *pagep;
+ void *cookie;
+ int *putp;
+{
+ DB_HASH_STAT *sp;
+
+ *putp = 0;
+ sp = cookie;
+
+ switch (pagep->type) {
+ case P_DUPLICATE:
+ sp->hash_dup++;
+ sp->hash_dup_free += P_FREESPACE(pagep);
+ break;
+ case P_OVERFLOW:
+ sp->hash_bigpages++;
+ sp->hash_big_bfree += P_OVFLSPACE(dbp->pgsize, pagep);
+ break;
+ case P_HASH:
+ /*
+ * We count the buckets and the overflow pages
+ * separately and tally their bytes separately
+ * as well. We need to figure out if this page
+ * is a bucket.
+ */
+ if (PREV_PGNO(pagep) == PGNO_INVALID)
+ sp->hash_bfree += P_FREESPACE(pagep);
+ else {
+ sp->hash_overflows++;
+ sp->hash_ovfl_free += P_FREESPACE(pagep);
+ }
+ sp->hash_nrecs += H_NUMPAIRS(pagep);
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}