Loading...
db/mpool/mpool.c Libc-320 Libc-262.3.2
--- Libc/Libc-320/db/mpool/mpool.c
+++ Libc/Libc-262.3.2/db/mpool/mpool.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -22,8 +22,8 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-/*-
- * Copyright (c) 1990, 1993, 1994
+/*
+ * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,13 +55,8 @@
  * SUCH DAMAGE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)mpool.c	8.5 (Berkeley) 7/26/94";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
 
 #include <sys/param.h>
-#include <sys/queue.h>
 #include <sys/stat.h>
 
 #include <errno.h>
@@ -71,21 +66,31 @@
 #include <unistd.h>
 
 #include <db.h>
-
 #define	__MPOOLINTERFACE_PRIVATE
-#include <mpool.h>
-
-static BKT *mpool_bkt(MPOOL *);
-static BKT *mpool_look(MPOOL *, pgno_t);
-static int  mpool_write(MPOOL *, BKT *);
-
-/*
- * mpool_open --
- *	Initialize a memory pool.
+#include "mpool.h"
+
+static BKT *mpool_bkt __P((MPOOL *));
+static BKT *mpool_look __P((MPOOL *, pgno_t));
+static int  mpool_write __P((MPOOL *, BKT *));
+#ifdef DEBUG
+static void __mpoolerr __P((const char *fmt, ...));
+#endif
+
+/*
+ * MPOOL_OPEN -- initialize a memory pool.
+ *
+ * Parameters:
+ *	key:		Shared buffer key.
+ *	fd:		File descriptor.
+ *	pagesize:	File page size.
+ *	maxcache:	Max number of cached pages.
+ *
+ * Returns:
+ *	MPOOL pointer, NULL on error.
  */
 MPOOL *
 mpool_open(key, fd, pagesize, maxcache)
-	void *key;
+	DBT *key;
 	int fd;
 	pgno_t pagesize, maxcache;
 {
@@ -93,41 +98,55 @@
 	MPOOL *mp;
 	int entry;
 
-	/*
-	 * Get information about the file.
-	 *
-	 * XXX
-	 * We don't currently handle pipes, although we should.
+	if (fstat(fd, &sb))
+		return (NULL);
+	/* XXX
+	 * We should only set st_size to 0 for pipes -- 4.4BSD has the fix so
+	 * that stat(2) returns true for ISSOCK on pipes.  Until then, this is
+	 * fairly close.
 	 */
-	if (fstat(fd, &sb))
-		return (NULL);
 	if (!S_ISREG(sb.st_mode)) {
 		errno = ESPIPE;
 		return (NULL);
 	}
 
-	/* Allocate and initialize the MPOOL cookie. */
-	if ((mp = (MPOOL *)calloc(1, sizeof(MPOOL))) == NULL)
-		return (NULL);
-	TAILQ_INIT(&mp->lqh);
+	if ((mp = (MPOOL *)malloc(sizeof(MPOOL))) == NULL)
+		return (NULL);
+	mp->free.cnext = mp->free.cprev = (BKT *)&mp->free;
+	mp->lru.cnext = mp->lru.cprev = (BKT *)&mp->lru;
 	for (entry = 0; entry < HASHSIZE; ++entry)
-		TAILQ_INIT(&mp->hqh[entry]);
+		mp->hashtable[entry].hnext = mp->hashtable[entry].hprev = 
+		    mp->hashtable[entry].cnext = mp->hashtable[entry].cprev =
+		    (BKT *)&mp->hashtable[entry];
+	mp->curcache = 0;
 	mp->maxcache = maxcache;
+	mp->pagesize = pagesize;
 	mp->npages = sb.st_size / pagesize;
-	mp->pagesize = pagesize;
 	mp->fd = fd;
+	mp->pgcookie = NULL;
+	mp->pgin = mp->pgout = NULL;
+
+#ifdef STATISTICS
+	mp->cachehit = mp->cachemiss = mp->pagealloc = mp->pageflush = 
+	    mp->pageget = mp->pagenew = mp->pageput = mp->pageread = 
+	    mp->pagewrite = 0;
+#endif
 	return (mp);
 }
 
 /*
- * mpool_filter --
- *	Initialize input/output filters.
+ * MPOOL_FILTER -- initialize input/output filters.
+ *
+ * Parameters:
+ *	pgin:		Page in conversion routine.
+ *	pgout:		Page out conversion routine.
+ *	pgcookie:	Cookie for page in/out routines.
  */
 void
 mpool_filter(mp, pgin, pgout, pgcookie)
 	MPOOL *mp;
-	void (*pgin)(void *, pgno_t, void *);
-	void (*pgout)(void *, pgno_t, void *);
+	void (*pgin) __P((void *, pgno_t, void *));
+	void (*pgout) __P((void *, pgno_t, void *));
 	void *pgcookie;
 {
 	mp->pgin = pgin;
@@ -136,128 +155,124 @@
 }
 	
 /*
- * mpool_new --
- *	Get a new page of memory.
+ * MPOOL_NEW -- get a new page
+ *
+ * Parameters:
+ *	mp:		mpool cookie
+ *	pgnoadddr:	place to store new page number
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
  */
 void *
 mpool_new(mp, pgnoaddr)
 	MPOOL *mp;
 	pgno_t *pgnoaddr;
 {
-	struct _hqh *head;
-	BKT *bp;
-
-	if (mp->npages == MAX_PAGE_NUMBER) {
-		(void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
-		abort();
-	}
+	BKT *b;
+	BKTHDR *hp;
+
 #ifdef STATISTICS
 	++mp->pagenew;
 #endif
 	/*
-	 * Get a BKT from the cache.  Assign a new page number, attach
-	 * it to the head of the hash chain, the tail of the lru chain,
-	 * and return.
+	 * Get a BKT from the cache.  Assign a new page number, attach it to
+	 * the hash and lru chains and return.
 	 */
-	if ((bp = mpool_bkt(mp)) == NULL)
-		return (NULL);
-	*pgnoaddr = bp->pgno = mp->npages++;
-	bp->flags = MPOOL_PINNED;
-
-	head = &mp->hqh[HASHKEY(bp->pgno)];
-	TAILQ_INSERT_HEAD(head, bp, hq);
-	TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
-	return (bp->page);
-}
-
-/*
- * mpool_get
- *	Get a page.
+	if ((b = mpool_bkt(mp)) == NULL)
+		return (NULL);
+	*pgnoaddr = b->pgno = mp->npages++;
+	b->flags = MPOOL_PINNED;
+	inshash(b, b->pgno);
+	inschain(b, &mp->lru);
+	return (b->page);
+}
+
+/*
+ * MPOOL_GET -- get a page from the pool
+ *
+ * Parameters:
+ *	mp:	mpool cookie
+ *	pgno:	page number
+ *	flags:	not used
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
  */
 void *
 mpool_get(mp, pgno, flags)
 	MPOOL *mp;
 	pgno_t pgno;
-	u_int flags;				/* XXX not used? */
-{
-	struct _hqh *head;
-	BKT *bp;
+	u_int flags;		/* XXX not used? */
+{
+	BKT *b;
+	BKTHDR *hp;
 	off_t off;
 	int nr;
 
-	/* Check for attempt to retrieve a non-existent page. */
+	/*
+	 * If asking for a specific page that is already in the cache, find
+	 * it and return it.
+	 */
+	if (b = mpool_look(mp, pgno)) {
+#ifdef STATISTICS
+		++mp->pageget;
+#endif
+#ifdef DEBUG
+		if (b->flags & MPOOL_PINNED)
+			__mpoolerr("mpool_get: page %d already pinned",
+			    b->pgno);
+#endif
+		rmchain(b);
+		inschain(b, &mp->lru);
+		b->flags |= MPOOL_PINNED;
+		return (b->page);
+	}
+
+	/* Not allowed to retrieve a non-existent page. */
 	if (pgno >= mp->npages) {
 		errno = EINVAL;
 		return (NULL);
 	}
 
-#ifdef STATISTICS
-	++mp->pageget;
-#endif
-
-	/* Check for a page that is cached. */
-	if ((bp = mpool_look(mp, pgno)) != NULL) {
-#ifdef DEBUG
-		if (bp->flags & MPOOL_PINNED) {
-			(void)fprintf(stderr,
-			    "mpool_get: page %d already pinned\n", bp->pgno);
-			abort();
-		}
-#endif
-		/*
-		 * Move the page to the head of the hash chain and the tail
-		 * of the lru chain.
-		 */
-		head = &mp->hqh[HASHKEY(bp->pgno)];
-		TAILQ_REMOVE(head, bp, hq);
-		TAILQ_INSERT_HEAD(head, bp, hq);
-		TAILQ_REMOVE(&mp->lqh, bp, q);
-		TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
-
-		/* Return a pinned page. */
-		bp->flags |= MPOOL_PINNED;
-		return (bp->page);
-	}
-
 	/* Get a page from the cache. */
-	if ((bp = mpool_bkt(mp)) == NULL)
-		return (NULL);
-
+	if ((b = mpool_bkt(mp)) == NULL)
+		return (NULL);
+	b->pgno = pgno;
+	b->flags = MPOOL_PINNED;
+
+#ifdef STATISTICS
+	++mp->pageread;
+#endif
 	/* Read in the contents. */
-#ifdef STATISTICS
-	++mp->pageread;
-#endif
 	off = mp->pagesize * pgno;
 	if (lseek(mp->fd, off, SEEK_SET) != off)
 		return (NULL);
-	if ((nr = read(mp->fd, bp->page, mp->pagesize)) != mp->pagesize) {
+	if ((nr = read(mp->fd, b->page, mp->pagesize)) != mp->pagesize) {
 		if (nr >= 0)
 			errno = EFTYPE;
 		return (NULL);
 	}
-
-	/* Set the page number, pin the page. */
-	bp->pgno = pgno;
-	bp->flags = MPOOL_PINNED;
-
-	/*
-	 * Add the page to the head of the hash chain and the tail
-	 * of the lru chain.
-	 */
-	head = &mp->hqh[HASHKEY(bp->pgno)];
-	TAILQ_INSERT_HEAD(head, bp, hq);
-	TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
-
-	/* Run through the user's filter. */
-	if (mp->pgin != NULL)
-		(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
-
-	return (bp->page);
-}
-
-/*
- * mpool_put
- *	Return a page.
+	if (mp->pgin)
+		(mp->pgin)(mp->pgcookie, b->pgno, b->page);
+
+	inshash(b, b->pgno);
+	inschain(b, &mp->lru);
+#ifdef STATISTICS
+	++mp->pageget;
+#endif
+	return (b->page);
+}
+
+/*
+ * MPOOL_PUT -- return a page to the pool
+ *
+ * Parameters:
+ *	mp:	mpool cookie
+ *	page:	page pointer
+ *	pgno:	page number
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
  */
 int
 mpool_put(mp, page, flags)
@@ -265,171 +280,193 @@
 	void *page;
 	u_int flags;
 {
-	BKT *bp;
+	BKT *baddr;
+#ifdef DEBUG
+	BKT *b;
+#endif
 
 #ifdef STATISTICS
 	++mp->pageput;
 #endif
-	bp = (BKT *)((char *)page - sizeof(BKT));
-#ifdef DEBUG
-	if (!(bp->flags & MPOOL_PINNED)) {
-		(void)fprintf(stderr,
-		    "mpool_put: page %d not pinned\n", bp->pgno);
-		abort();
-	}
-#endif
-	bp->flags &= ~MPOOL_PINNED;
-	bp->flags |= flags & MPOOL_DIRTY;
+	baddr = (BKT *)((char *)page - sizeof(BKT));
+#ifdef DEBUG
+	if (!(baddr->flags & MPOOL_PINNED))
+		__mpoolerr("mpool_put: page %d not pinned", b->pgno);
+	for (b = mp->lru.cnext; b != (BKT *)&mp->lru; b = b->cnext) {
+		if (b == (BKT *)&mp->lru)
+			__mpoolerr("mpool_put: %0x: bad address", baddr);
+		if (b == baddr)
+			break;
+	}
+#endif
+	baddr->flags &= ~MPOOL_PINNED;
+	baddr->flags |= flags & MPOOL_DIRTY;
 	return (RET_SUCCESS);
 }
 
 /*
- * mpool_close
- *	Close the buffer pool.
+ * MPOOL_CLOSE -- close the buffer pool
+ *
+ * Parameters:
+ *	mp:	mpool cookie
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
  */
 int
 mpool_close(mp)
 	MPOOL *mp;
 {
-	BKT *bp;
+	BKT *b, *next;
 
 	/* Free up any space allocated to the lru pages. */
-	while (!TAILQ_EMPTY(&mp->lqh)) {
-		bp = TAILQ_FIRST(&mp->lqh);
-		TAILQ_REMOVE(&mp->lqh, bp, q);
-		free(bp);
-	}
-
-	/* Free the MPOOL cookie. */
+	for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = next) {
+		next = b->cprev;
+		free(b);
+	}
 	free(mp);
 	return (RET_SUCCESS);
 }
 
 /*
- * mpool_sync
- *	Sync the pool to disk.
+ * MPOOL_SYNC -- sync the file to disk.
+ *
+ * Parameters:
+ *	mp:	mpool cookie
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
  */
 int
 mpool_sync(mp)
 	MPOOL *mp;
 {
-	BKT *bp;
-
-	/* Walk the lru chain, flushing any dirty pages to disk. */
-	TAILQ_FOREACH(bp, &mp->lqh, q)
-		if (bp->flags & MPOOL_DIRTY &&
-		    mpool_write(mp, bp) == RET_ERROR)
+	BKT *b;
+
+	for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = b->cprev)
+		if (b->flags & MPOOL_DIRTY && mpool_write(mp, b) == RET_ERROR)
 			return (RET_ERROR);
-
-	/* Sync the file descriptor. */
 	return (fsync(mp->fd) ? RET_ERROR : RET_SUCCESS);
 }
 
 /*
- * mpool_bkt
- *	Get a page from the cache (or create one).
+ * MPOOL_BKT -- get/create a BKT from the cache
+ *
+ * Parameters:
+ *	mp:	mpool cookie
+ *
+ * Returns:
+ *	NULL on failure and a pointer to the BKT on success	
  */
 static BKT *
 mpool_bkt(mp)
 	MPOOL *mp;
 {
-	struct _hqh *head;
-	BKT *bp;
-
-	/* If under the max cached, always create a new page. */
+	BKT *b;
+
 	if (mp->curcache < mp->maxcache)
 		goto new;
 
 	/*
-	 * If the cache is max'd out, walk the lru list for a buffer we
-	 * can flush.  If we find one, write it (if necessary) and take it
-	 * off any lists.  If we don't find anything we grow the cache anyway.
+	 * If the cache is maxxed out, search the lru list for a buffer we
+	 * can flush.  If we find one, write it if necessary and take it off
+	 * any lists.  If we don't find anything we grow the cache anyway.
 	 * The cache never shrinks.
 	 */
-	TAILQ_FOREACH(bp, &mp->lqh, q)
-		if (!(bp->flags & MPOOL_PINNED)) {
-			/* Flush if dirty. */
-			if (bp->flags & MPOOL_DIRTY &&
-			    mpool_write(mp, bp) == RET_ERROR)
+	for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = b->cprev)
+		if (!(b->flags & MPOOL_PINNED)) {
+			if (b->flags & MPOOL_DIRTY &&
+			    mpool_write(mp, b) == RET_ERROR)
 				return (NULL);
+			rmhash(b);
+			rmchain(b);
 #ifdef STATISTICS
 			++mp->pageflush;
 #endif
-			/* Remove from the hash and lru queues. */
-			head = &mp->hqh[HASHKEY(bp->pgno)];
-			TAILQ_REMOVE(head, bp, hq);
-			TAILQ_REMOVE(&mp->lqh, bp, q);
-#ifdef DEBUG
-			{ void *spage;
-				spage = bp->page;
-				memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
-				bp->page = spage;
+#ifdef DEBUG
+			{
+				void *spage;
+				spage = b->page;
+				memset(b, 0xff, sizeof(BKT) + mp->pagesize);
+				b->page = spage;
 			}
 #endif
-			return (bp);
+			return (b);
 		}
 
-new:	if ((bp = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL)
+new:	if ((b = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL)
 		return (NULL);
 #ifdef STATISTICS
 	++mp->pagealloc;
 #endif
-#if defined(DEBUG) || defined(PURIFY)
-	memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
-#endif
-	bp->page = (char *)bp + sizeof(BKT);
+#ifdef DEBUG
+	memset(b, 0xff, sizeof(BKT) + mp->pagesize);
+#endif
+	b->page = (char *)b + sizeof(BKT);
 	++mp->curcache;
-	return (bp);
-}
-
-/*
- * mpool_write
- *	Write a page to disk.
+	return (b);
+}
+
+/*
+ * MPOOL_WRITE -- sync a page to disk
+ *
+ * Parameters:
+ *	mp:	mpool cookie
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
  */
 static int
-mpool_write(mp, bp)
-	MPOOL *mp;
-	BKT *bp;
+mpool_write(mp, b)
+	MPOOL *mp;
+	BKT *b;
 {
 	off_t off;
 
+	if (mp->pgout)
+		(mp->pgout)(mp->pgcookie, b->pgno, b->page);
+
 #ifdef STATISTICS
 	++mp->pagewrite;
 #endif
-
-	/* Run through the user's filter. */
-	if (mp->pgout)
-		(mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
-
-	off = mp->pagesize * bp->pgno;
+	off = mp->pagesize * b->pgno;
 	if (lseek(mp->fd, off, SEEK_SET) != off)
 		return (RET_ERROR);
-	if (write(mp->fd, bp->page, mp->pagesize) != mp->pagesize)
+	if (write(mp->fd, b->page, mp->pagesize) != mp->pagesize)
 		return (RET_ERROR);
-
-	bp->flags &= ~MPOOL_DIRTY;
+	b->flags &= ~MPOOL_DIRTY;
 	return (RET_SUCCESS);
 }
 
 /*
- * mpool_look
- *	Lookup a page in the cache.
+ * MPOOL_LOOK -- lookup a page
+ *
+ * Parameters:
+ *	mp:	mpool cookie
+ *	pgno:	page number
+ *
+ * Returns:
+ *	NULL on failure and a pointer to the BKT on success
  */
 static BKT *
 mpool_look(mp, pgno)
 	MPOOL *mp;
 	pgno_t pgno;
 {
-	struct _hqh *head;
-	BKT *bp;
-
-	head = &mp->hqh[HASHKEY(pgno)];
-	TAILQ_FOREACH(bp, head, hq)
-		if (bp->pgno == pgno) {
+	register BKT *b;
+	register BKTHDR *tb;
+
+	/* XXX
+	 * If find the buffer, put it first on the hash chain so can
+	 * find it again quickly.
+	 */
+	tb = &mp->hashtable[HASHKEY(pgno)];
+	for (b = tb->hnext; b != (BKT *)tb; b = b->hnext)
+		if (b->pgno == pgno) {
 #ifdef STATISTICS
 			++mp->cachehit;
 #endif
-			return (bp);
+			return (b);
 		}
 #ifdef STATISTICS
 	++mp->cachemiss;
@@ -439,14 +476,16 @@
 
 #ifdef STATISTICS
 /*
- * mpool_stat
- *	Print out cache statistics.
+ * MPOOL_STAT -- cache statistics
+ *
+ * Parameters:
+ *	mp:	mpool cookie
  */
 void
 mpool_stat(mp)
 	MPOOL *mp;
 {
-	BKT *bp;
+	BKT *b;
 	int cnt;
 	char *sep;
 
@@ -468,11 +507,11 @@
 
 	sep = "";
 	cnt = 0;
-	TAILQ_FOREACH(bp, &mp->lqh, q) {
-		(void)fprintf(stderr, "%s%d", sep, bp->pgno);
-		if (bp->flags & MPOOL_DIRTY)
+	for (b = mp->lru.cnext; b != (BKT *)&mp->lru; b = b->cnext) {
+		(void)fprintf(stderr, "%s%d", sep, b->pgno);
+		if (b->flags & MPOOL_DIRTY)
 			(void)fprintf(stderr, "d");
-		if (bp->flags & MPOOL_PINNED)
+		if (b->flags & MPOOL_PINNED)
 			(void)fprintf(stderr, "P");
 		if (++cnt == 10) {
 			sep = "\n";
@@ -484,3 +523,33 @@
 	(void)fprintf(stderr, "\n");
 }
 #endif
+
+#ifdef DEBUG
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static void
+#if __STDC__
+__mpoolerr(const char *fmt, ...)
+#else
+__mpoolerr(fmt, va_alist)
+	char *fmt;
+	va_dcl
+#endif
+{
+	va_list ap;
+#if __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	(void)vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	(void)fprintf(stderr, "\n");
+	abort();
+	/* NOTREACHED */
+}
+#endif