summary refs log tree commit diff
path: root/db2/mp/mp_bh.c
diff options
context:
space:
mode:
Diffstat (limited to 'db2/mp/mp_bh.c')
-rw-r--r--db2/mp/mp_bh.c131
1 files changed, 89 insertions, 42 deletions
diff --git a/db2/mp/mp_bh.c b/db2/mp/mp_bh.c
index 578abedcb6..c23abdda24 100644
--- a/db2/mp/mp_bh.c
+++ b/db2/mp/mp_bh.c
@@ -7,7 +7,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)mp_bh.c	10.23 (Sleepycat) 11/26/97";
+static const char sccsid[] = "@(#)mp_bh.c	10.28 (Sleepycat) 1/8/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -193,30 +193,28 @@ __memp_pgread(dbmfp, bhp, can_create)
 	/* Call any pgin function. */
 pgin:	ret = mfp->ftype == 0 ? 0 : __memp_pg(dbmfp, bhp, 1);
 
-	/* Reacquire the region lock. */
+	/* Unlock the buffer and reacquire the region lock. */
+err:	UNLOCKBUFFER(dbmp, bhp);
 	LOCKREGION(dbmp);
 
-	/* If the pgin function succeeded, the data is now valid. */
-	if (ret == 0)
+	/*
+	 * If no errors occurred, the data is now valid, clear the BH_TRASH
+	 * flag; regardless, clear the lock bit and let other threads proceed.
+	 */
+	F_CLR(bhp, BH_LOCKED);
+	if (ret == 0) {
 		F_CLR(bhp, BH_TRASH);
 
-	/* Update the statistics. */
-	if (can_create) {
-		++dbmp->mp->stat.st_page_create;
-		++mfp->stat.st_page_create;
-	} else {
-		++dbmp->mp->stat.st_page_in;
-		++mfp->stat.st_page_in;
-	}
-
-	if (0) {
-err:		LOCKREGION(dbmp);
+		/* Update the statistics. */
+		if (can_create) {
+			++dbmp->mp->stat.st_page_create;
+			++mfp->stat.st_page_create;
+		} else {
+			++dbmp->mp->stat.st_page_in;
+			++mfp->stat.st_page_in;
+		}
 	}
 
-	/* Release the buffer. */
-	F_CLR(bhp, BH_LOCKED);
-	UNLOCKBUFFER(dbmp, bhp);
-
 	return (ret);
 }
 
@@ -240,7 +238,7 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
 	MPOOLFILE *mfp;
 	size_t pagesize;
 	ssize_t nw;
-	int callpgin, ret;
+	int callpgin, ret, syncfail;
 	const char *fail;
 
 	dbmp = dbmfp->dbmp;
@@ -255,8 +253,32 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
 	callpgin = 0;
 	pagesize = mfp->stat.st_pagesize;
 
-	F_SET(bhp, BH_LOCKED);
+	/*
+	 * Check the dirty bit -- this buffer may have been written since we
+	 * decided to write it.
+	 */
+	if (!F_ISSET(bhp, BH_DIRTY)) {
+		if (wrotep != NULL)
+			*wrotep = 1;
+		return (0);
+	}
+
 	LOCKBUFFER(dbmp, bhp);
+
+	/*
+	 * If there were two writers, we may have just been waiting while the
+	 * other writer completed I/O on this buffer.  Check the dirty bit one
+	 * more time.
+	 */
+	if (!F_ISSET(bhp, BH_DIRTY)) {
+		UNLOCKBUFFER(dbmp, bhp);
+
+		if (wrotep != NULL)
+			*wrotep = 1;
+		return (0);
+	}
+
+	F_SET(bhp, BH_LOCKED);
 	UNLOCKREGION(dbmp);
 
 	if (restartp != NULL)
@@ -272,8 +294,9 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
 		goto err;
 
 	/*
-	 * Call any pgout function.  We set the callpgin flag so that on
-	 * error we flag that the contents of the buffer may be trash.
+	 * Call any pgout function.  We set the callpgin flag so that we flag
+	 * that the contents of the buffer will need to be passed through pgin
+	 * before they are reused.
 	 */
 	if (mfp->ftype == 0)
 		ret = 0;
@@ -307,7 +330,7 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
 		 * between the failing clauses to __db_lseek and __db_write and
 		 * this ret != 0.
 		 */
-		fail = NULL;
+		COMPQUIET(fail, NULL);
 		goto syserr;
 	}
 
@@ -320,18 +343,20 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
 	if (wrotep != NULL)
 		*wrotep = 1;
 
-	/* Reacquire the region lock. */
+	/* Unlock the buffer and reacquire the region lock. */
+	UNLOCKBUFFER(dbmp, bhp);
 	LOCKREGION(dbmp);
 
-	/* Clean up the flags based on a successful write. */
-	F_SET(bhp, BH_CALLPGIN);
+	/*
+	 * Clean up the flags based on a successful write.
+	 *
+	 * If we rewrote the page, it will need processing by the pgin
+	 * routine before reuse.
+	 */
+	if (callpgin)
+		F_SET(bhp, BH_CALLPGIN);
 	F_CLR(bhp, BH_DIRTY | BH_LOCKED);
 
-	++mp->stat.st_page_clean;
-	--mp->stat.st_page_dirty;
-
-	UNLOCKBUFFER(dbmp, bhp);
-
 	/*
 	 * If we write a buffer for which a checkpoint is waiting, update
 	 * the count of pending buffers (both in the mpool as a whole and
@@ -344,23 +369,36 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
 	 *
 	 * XXX:
 	 * We ignore errors from the sync -- it makes no sense to return an
-	 * error to the calling process, so set a flag causing the sync to
-	 * be retried later.
-	 *
-	 * If the buffer we wrote has a LSN larger than the current largest
-	 * we've written for this checkpoint, update the saved value.
+	 * error to the calling process, so set a flag causing the checkpoint
+	 * to be retried later.
 	 */
 	if (F_ISSET(bhp, BH_WRITE)) {
+		if (mfp->lsn_cnt == 1) {
+			UNLOCKREGION(dbmp);
+			syncfail = __db_fsync(dbmfp->fd) != 0;
+			LOCKREGION(dbmp);
+			if (syncfail)
+				F_SET(mp, MP_LSN_RETRY);
+
+		}
+
+		F_CLR(bhp, BH_WRITE);
+
+		/*
+		 * If the buffer just written has a larger LSN than the current
+		 * max LSN written for this checkpoint, update the saved value.
+		 */
 		if (log_compare(&lsn, &mp->lsn) > 0)
 			mp->lsn = lsn;
-		F_CLR(bhp, BH_WRITE);
 
 		--mp->lsn_cnt;
-
-		if (--mfp->lsn_cnt == 0 && __db_fsync(dbmfp->fd) != 0)
-			F_SET(mp, MP_LSN_RETRY);
+		--mfp->lsn_cnt;
 	}
 
+	/* Update the page clean/dirty statistics. */
+	++mp->stat.st_page_clean;
+	--mp->stat.st_page_dirty;
+
 	/* Update I/O statistics. */
 	++mp->stat.st_page_out;
 	++mfp->stat.st_page_out;
@@ -370,11 +408,20 @@ __memp_pgwrite(dbmfp, bhp, restartp, wrotep)
 syserr:	__db_err(dbenv, "%s: %s failed for page %lu",
 	    __memp_fn(dbmfp), fail, (u_long)bhp->pgno);
 
-err:	UNLOCKBUFFER(dbmp, bhp);
+err:	/* Unlock the buffer and reacquire the region lock. */
+	UNLOCKBUFFER(dbmp, bhp);
 	LOCKREGION(dbmp);
+
+	/*
+	 * Clean up the flags based on a failure.
+	 *
+	 * The page remains dirty but we remove our lock.  If we rewrote the
+	 * page, it will need processing by the pgin routine before reuse.
+	 */
 	if (callpgin)
 		F_SET(bhp, BH_CALLPGIN);
 	F_CLR(bhp, BH_LOCKED);
+
 	return (ret);
 }