Patches for Berkeley DB version 2.6.6

  1. If there are a sufficient number of threads competing for limited numbers of pages, it's possible to split Btree pages too many times, and cause a core dump.
  2. Apply the following patch to the db-2.6.6 btree/bt_split.c file.  
    *** btree/bt_split.c.orig	Wed Apr 14 18:23:16 1999
    --- btree/bt_split.c	Wed Apr 14 18:23:16 1999
    ***************
    *** 77,82 ****
    --- 79,85 ----
      	DBC *dbc;
      	void *arg;
      {
    + 	BTREE *t;
      	CURSOR *cp;
      	DB *dbp;
      	enum { UP, DOWN } dir;
    ***************
    *** 112,117 ****
    --- 115,121 ----
      	 * split.  This would be an easy change for this code, but I have no
      	 * numbers that indicate it's worthwhile.
      	 */
    + 	t = dbp->internal;
      	for (dir = UP, level = LEAFLEVEL;; dir == UP ? ++level : --level) {
      		/*
      		 * Acquire a page and its parent, locked.
    ***************
    *** 122,128 ****
      		        (db_recno_t *)arg, S_WRPAIR, level, &exact))) != 0)
      			return (ret);
      
    ! 		/* Split the page. */
      		ret = cp->csp[0].page->pgno == PGNO_ROOT ?
      		    __bam_root(dbc, &cp->csp[0]) :
      		    __bam_page(dbc, &cp->csp[-1], &cp->csp[0]);
    --- 126,142 ----
      		        (db_recno_t *)arg, S_WRPAIR, level, &exact))) != 0)
      			return (ret);
      
    ! 		/*
    ! 		 * Split the page if it still needs it (it's possible another
    ! 		 * thread of control has already split the page).  If we are
    ! 		 * guaranteed that two items will fit on the page, the split
    ! 		 * is no longer necessary.
    ! 		 */
    ! 		if (t->bt_ovflsize * 2 <=
    ! 		    (db_indx_t)P_FREESPACE(cp->csp[0].page)) {
    ! 			__bam_stkrel(dbc, 1);
    ! 			return (0);
    ! 		}
      		ret = cp->csp[0].page->pgno == PGNO_ROOT ?
      		    __bam_root(dbc, &cp->csp[0]) :
      		    __bam_page(dbc, &cp->csp[-1], &cp->csp[0]);
    

  3. Under some circumstances, lockers could be left on locker chains. No incorrect behavior could occur but resources could be leaked.
  4. Apply the following patch to the db-2.6.6 lock/lock_deadlock.c file.  
    *** lock/lock_deadlock.c.orig	Fri Dec 11 13:10:22 1998
    --- lock/lock_deadlock.c	Mon Apr 12 23:03:16 1999
    ***************
    *** 431,438 ****
      		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)
      		goto out;
      
      	/* Abort lock, take it off list, and wake up this lock. */
    --- 431,451 ----
      		goto out;
      
      	lockp = SH_LIST_FIRST(&lockerp->heldby, __db_lock);
    ! 
    ! 	/*
    ! 	 * 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. */
    

  5. Fix potential races in updating checkpoint buffer counts that can cause checkpoint calls to never finish.
  6. Apply the following patch to the db-2.6.6 mp/mp_bh.c file.  
    *** mp/mp_bh.c.orig	Wed Nov 25 10:46:58 1998
    --- mp/mp_bh.c	Thu Apr 15 21:19:17 1999
    ***************
    *** 267,273 ****
      	MPOOL *mp;
      	MPOOLFILE *mfp;
      	ssize_t nw;
    ! 	int callpgin, ret, syncfail;
      	const char *fail;
      
      	dbmp = dbmfp->dbmp;
    --- 267,273 ----
      	MPOOL *mp;
      	MPOOLFILE *mfp;
      	ssize_t nw;
    ! 	int callpgin, dosync, ret, syncfail;
      	const char *fail;
      
      	dbmp = dbmfp->dbmp;
    ***************
    *** 386,425 ****
      	/*
      	 * 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
    ! 	 * for this file).  If the count for this file goes to zero, flush
    ! 	 * the writes.
    ! 	 *
    ! 	 * XXX:
    ! 	 * Don't lock the region around the sync, fsync(2) has no atomicity
    ! 	 * issues.
    ! 	 *
    ! 	 * 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 checkpoint
    ! 	 * to be retried later.
      	 */
      	if (F_ISSET(bhp, BH_WRITE)) {
    - 		if (mfp->lsn_cnt == 1) {
    - 			UNLOCKREGION(dbmp);
    - 			syncfail = __os_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;
    - 
      		--mp->lsn_cnt;
    ! 		--mfp->lsn_cnt;
    ! 	}
      
      	/* Update the page clean/dirty statistics. */
      	++mp->stat.st_page_clean;
    --- 386,401 ----
      	/*
      	 * 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
    ! 	 * for this file).  If the count for this file goes to zero, set a
    ! 	 * flag so we flush the writes.
      	 */
      	if (F_ISSET(bhp, BH_WRITE)) {
      		F_CLR(bhp, BH_WRITE);
      
      		--mp->lsn_cnt;
    ! 		dosync = --mfp->lsn_cnt == 0 ? 1 : 0;
    ! 	} else
    ! 		dosync = 0;
      
      	/* Update the page clean/dirty statistics. */
      	++mp->stat.st_page_clean;
    ***************
    *** 428,433 ****
    --- 404,432 ----
      	/* Update I/O statistics. */
      	++mp->stat.st_page_out;
      	++mfp->stat.st_page_out;
    + 
    + 	/*
    + 	 * Do the sync after everything else has been updated, so any incoming
    + 	 * checkpoint doesn't see inconsistent information.
    + 	 *
    + 	 * XXX:
    + 	 * Don't lock the region around the sync, fsync(2) has no atomicity
    + 	 * issues.
    + 	 *
    + 	 * 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 checkpoint
    + 	 * to be retried later.  There is a possibility, of course, that a
    + 	 * subsequent checkpoint was started and that we're going to force it
    + 	 * to fail.  That should be unlikely, and fixing it would be difficult.
    + 	 */
    + 	if (dosync) {
    + 		UNLOCKREGION(dbmp);
    + 		syncfail = __os_fsync(dbmfp->fd) != 0;
    + 		LOCKREGION(dbmp);
    + 		if (syncfail)
    + 			F_SET(mp, MP_LSN_RETRY);
    + 	}
      
      	return (0);
    

  7. Fix a potential NULL pointer dereference in the database delete-by-key interface.
  8. Apply the following patch to the db-2.6.6 btree/bt_delete.c file.  
    *** btree/bt_delete.c.orig	Fri Apr  9 21:50:28 1999
    --- btree/bt_delete.c	Sun Apr 18 20:32:01 1999
    ***************
    *** 103,109 ****
      	/* If locking, set read-modify-write flag. */
      	f_init = DB_SET;
      	f_next = DB_NEXT_DUP;
    ! 	if (dbp->dbenv->lk_info != NULL) {
      		f_init |= DB_RMW;
      		f_next |= DB_RMW;
      	}
    --- 103,109 ----
      	/* 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;
      	}
    

  9. Fix a case where it was possible for EAGAIN to not be returned from the database get-by-key interface.
  10. Apply the following patch to the db-2.6.6 db/db_am.c file.  
    *** db/db_am.c.orig	Tue May 18 14:09:25 1999
    --- db/db_am.c	Fri May 21 11:14:09 1999
    ***************
    *** 388,394 ****
      		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)
    --- 388,394 ----
      		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 if (ret == DB_NOTFOUND)
      			ret = 0;
      	}
      	if (ret == 0)
    

  11. Ignore log records not involved in transactions so that actions taken outside of transactions are not undone during recovery.
  12. Apply the following patch to the db-2.6.6 db/db_dispatch.c file.  
    *** db/db_dispatch.orig	Mon May 24 21:37:48 1999
    --- db/db_dispatch.c	Mon May 24 21:40:43 1999
    ***************
    *** 117,123 ****
      		 * in "abort mode".
      		 */
      		if (rectype == DB_log_register || rectype == DB_txn_ckp ||
    ! 		    __db_txnlist_find(info, txnid) == DB_NOTFOUND)
      			return ((dispatch_table[rectype])(logp,
      			    db, lsnp, TXN_UNDO, info));
      		break;
    --- 117,124 ----
      		 * in "abort mode".
      		 */
      		if (rectype == DB_log_register || rectype == DB_txn_ckp ||
    ! 		    (__db_txnlist_find(info, txnid) == DB_NOTFOUND &&
    ! 		    txnid != 0))
      			return ((dispatch_table[rectype])(logp,
      			    db, lsnp, TXN_UNDO, info));
      		break;
    

  13. Fix a recovery bug when database files are opened/closed multiple times in the same session.
  14. Apply the following patches to the db-2.6.6 log/{log,log_rec,log_register}.c and include/{log,log_ext}.h files.  
    *** include/log.h.orig	Tue Nov 10 11:50:03 1998
    --- include/log.h	Wed Aug 11 16:00:34 1999
    ***************
    *** 51,56 ****
    --- 51,57 ----
       */
      typedef	struct __db_entry {
      	DB	 *dbp;			/* Associated DB structure. */
    + 	char 	 *name;			/* File name. */
      	u_int32_t refcount;		/* Reference counted. */
      	int	  deleted;		/* File was not found during open. */
      } DB_ENTRY;
    *** include/log_ext.h.orig	Wed Aug 11 16:04:02 1999
    --- include/log_ext.h	Wed Aug 11 16:05:44 1999
    ***************
    *** 19,25 ****
      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));
      int __db_fileid_to_db __P((DB_LOG *, DB **, u_int32_t));
      void __log_close_files __P((DB_LOG *));
      void __log_rem_logid __P((DB_LOG *, u_int32_t));
    --- 19,25 ----
      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 *, const char *, u_int32_t));
      int __db_fileid_to_db __P((DB_LOG *, DB **, u_int32_t));
      void __log_close_files __P((DB_LOG *));
      void __log_rem_logid __P((DB_LOG *, u_int32_t));
    *** log/log.c.orig	Mon Mar 15 18:13:58 1999
    --- log/log.c	Wed Aug 11 15:21:01 1999
    ***************
    *** 432,437 ****
    --- 432,438 ----
      log_close(dblp)
      	DB_LOG *dblp;
      {
    + 	u_int32_t i;
      	int ret, t_ret;
      
      	LOG_PANIC_CHECK(dblp);
    ***************
    *** 454,462 ****
      	if (dblp->c_fd != -1 &&
      	    (t_ret = __os_close(dblp->c_fd)) != 0 && ret == 0)
      		ret = t_ret;
    ! 	if (dblp->dbentry != NULL)
      		__os_free(dblp->dbentry,
      		    (dblp->dbentry_cnt * sizeof(DB_ENTRY)));
      	if (dblp->dir != NULL)
      		__os_freestr(dblp->dir);
      
    --- 455,468 ----
      	if (dblp->c_fd != -1 &&
      	    (t_ret = __os_close(dblp->c_fd)) != 0 && ret == 0)
      		ret = t_ret;
    ! 	if (dblp->dbentry != NULL) {
    ! 		for (i = 0; i < dblp->dbentry_cnt; i++)
    ! 			if (dblp->dbentry[i].name != NULL)
    ! 				__os_freestr(dblp->dbentry[i].name);
      		__os_free(dblp->dbentry,
      		    (dblp->dbentry_cnt * sizeof(DB_ENTRY)));
    + 	}
    + 
      	if (dblp->dir != NULL)
      		__os_freestr(dblp->dir);
      
    *** log/log_rec.c.orig	Mon Mar 15 18:13:58 1999
    --- log/log_rec.c	Fri Aug 13 16:30:31 1999
    ***************
    *** 70,75 ****
    --- 70,76 ----
      	int redo;
      	void *info;
      {
    + 	DB_ENTRY *dbe;
      	__log_register_args *argp;
      	int ret;
      
    ***************
    *** 101,110 ****
      				    argp->name.data, strerror(ENOENT));
      			ret = 0;
      		}
    ! 	} else if (argp->opcode != LOG_CHECKPOINT) {
      		/*
    ! 		 * 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 should usually have a valid dbp we should
    --- 102,117 ----
      				    argp->name.data, strerror(ENOENT));
      			ret = 0;
      		}
    ! 	} else if (argp->opcode != LOG_CHECKPOINT &&
    ! 	    argp->opcode != LOG_CLOSE) {
      		/*
    ! 		 * If we are undoing an open, then we need to close the file.
    ! 		 * Note that we do *not* close the file if we are redoing a
    ! 		 * close, because we do not log the reference counts on log
    ! 		 * files and we may have had the file open multiple times,
    ! 		 * and therefore, this close should just dec a reference
    ! 		 * count.  However, since we only do one open during a
    ! 		 * checkpoint, this will inadvertently close the file.
      		 *
        		 * If the file is deleted, then we can just ignore this close.
       		 * Otherwise, we should usually have a valid dbp we should
    ***************
    *** 113,126 ****
      		 * may, in fact, not have the file open, and that's OK.
      		 */
      		LOCK_LOGTHREAD(logp);
    ! 		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))) {
    --- 120,138 ----
      		 * may, in fact, not have the file open, and that's OK.
      		 */
      		LOCK_LOGTHREAD(logp);
    ! 		if (argp->id < logp->dbentry_cnt) {
    ! 			dbe = &logp->dbentry[argp->id];
    ! 			if (dbe->dbp != NULL && --dbe->refcount == 0) {
    ! 				ret = dbe->dbp->close(dbe->dbp, 0);
    ! 				if (dbe->name != NULL) {
    ! 					__os_freestr(dbe->name);
    ! 					dbe->name = NULL;
    ! 				}
    ! 				(void)__log_rem_logid(logp, argp->id);
    ! 			}
      		}
      		UNLOCK_LOGTHREAD(logp);
    !  	} else if (argp->opcode == LOG_CHECKPOINT && redo == TXN_UNDO &&
       	    (argp->id >= logp->dbentry_cnt ||
       	    (!logp->dbentry[argp->id].deleted &&
       	    logp->dbentry[argp->id].dbp == NULL))) {
    ***************
    *** 158,178 ****
      	__log_register_args *argp;
      {
      	DB *dbp;
      	int ret;
      
    ! 	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);
      
      	/* Need to open file. */
      	dbp = NULL;
      	if ((ret = db_open(argp->name.data,
      	    argp->ftype, 0, 0, lp->dbenv, NULL, &dbp)) == 0) {
    --- 170,213 ----
      	__log_register_args *argp;
      {
      	DB *dbp;
    + 	DB_ENTRY *dbe;
      	int ret;
      
    ! 	if (argp->name.size == 0)
    ! 		return(0);
      
    + 	/*
    + 	 * Because of reference counting, we cannot automatically close files
    + 	 * during recovery, so when we're opening, we have to check that the
    + 	 * name we are opening is what we expect.  If it's not, then we close
    + 	 * the old file and open the new one.
    + 	 */
    + 	LOCK_LOGTHREAD(lp);
    + 	if (argp->id < lp->dbentry_cnt)
    + 		dbe = &lp->dbentry[argp->id];
    + 	else
    + 		dbe = NULL;
    + 
    + 	if (dbe != NULL && (dbe->deleted == 1 || dbe->dbp != NULL) &&
    + 	    dbe->name != NULL && argp->name.data != NULL &&
    + 	    strncmp(argp->name.data, dbe->name, argp->name.size) == 0) {
    +   
    + 		dbe->refcount++;
      		UNLOCK_LOGTHREAD(lp);
    !   		return (0);
    !   	}
    ! 
      	UNLOCK_LOGTHREAD(lp);
      
      	/* Need to open file. */
    + 	if (dbe != NULL && dbe->dbp != NULL) {
    +                 (void)dbe->dbp->close(dbe->dbp, 0);
    + 		if (dbe->name != NULL)
    + 			__os_freestr(dbe->name);
    +                 dbe->name = NULL;
    + 		(void)__log_rem_logid(lp, argp->id);
    +         }
    + 
      	dbp = NULL;
      	if ((ret = db_open(argp->name.data,
      	    argp->ftype, 0, 0, lp->dbenv, NULL, &dbp)) == 0) {
    ***************
    *** 188,194 ****
      	}
      
      	if (ret == 0 || ret == ENOENT)
    ! 		(void)__log_add_logid(lp, dbp, argp->id);
      
      	return (ret);
      }
    --- 223,229 ----
      	}
      
      	if (ret == 0 || ret == ENOENT)
    ! 		(void)__log_add_logid(lp, dbp, argp->name.data, argp->id);
      
      	return (ret);
      }
    ***************
    *** 197,208 ****
       * __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
    ! __log_add_logid(logp, dbp, ndx)
      	DB_LOG *logp;
      	DB *dbp;
      	u_int32_t ndx;
      {
      	u_int32_t i;
    --- 232,244 ----
       * __log_add_logid --
       *	Adds a DB entry to the log's DB entry table.
       *
    !  * PUBLIC: int __log_add_logid __P((DB_LOG *, DB *, const char *, u_int32_t));
       */
      int
    ! __log_add_logid(logp, dbp, name, ndx)
      	DB_LOG *logp;
      	DB *dbp;
    + 	const char *name;
      	u_int32_t ndx;
      {
      	u_int32_t i;
    ***************
    *** 226,242 ****
    --- 262,288 ----
      		for (i = logp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) {
      			logp->dbentry[i].dbp = NULL;
      			logp->dbentry[i].deleted = 0;
    + 			logp->dbentry[i].name = NULL;
      		}
      
      		logp->dbentry_cnt = i;
      	}
      
    + 	/* Make space for the name and copy it in. */
    + 	if (name != NULL) {
    + 		if ((ret = __os_malloc(strlen(name) + 1, 
    + 		    NULL, &logp->dbentry[ndx].name)) != 0)
    + 			goto err;
    + 		strcpy(logp->dbentry[ndx].name, name);
    + 	}
    + 
      	if (logp->dbentry[ndx].deleted == 0 && logp->dbentry[ndx].dbp == NULL) {
      		logp->dbentry[ndx].dbp = dbp;
      		logp->dbentry[ndx].refcount = 1;
      		logp->dbentry[ndx].deleted = dbp == NULL;
      	} else
      		logp->dbentry[ndx].refcount++;
    + 
      
      err:	UNLOCK_LOGTHREAD(logp);
      	return (ret);
    *** log/log_register.c.orig	Mon Mar 15 18:13:48 1999
    --- log/log_register.c	Wed Aug 11 15:35:08 1999
    ***************
    *** 117,123 ****
      		if ((ret = __log_register_log(dblp, NULL, &r_unused,
      		    0, LOG_OPEN, &r_name, &fid_dbt, fnp->id, type)) != 0)
      			goto err;
    ! 		if ((ret = __log_add_logid(dblp, dbp, fnp->id)) != 0)
      			goto err;
      	}
      
    --- 117,123 ----
      		if ((ret = __log_register_log(dblp, NULL, &r_unused,
      		    0, LOG_OPEN, &r_name, &fid_dbt, fnp->id, type)) != 0)
      			goto err;
    ! 		if ((ret = __log_add_logid(dblp, dbp, name, fnp->id)) != 0)
      			goto err;
      	}
    

  15. Fix a memory pool race during buffer discard in memory tight environments.
  16. Apply the following patch to the db-2.6.6 mp/mp_fput.c, mp/mp_region.c and mp/mp_sync.c files.  
    *** mp/mp_fput.c.orig	Tue Dec 15 09:57:18 1998
    --- mp/mp_fput.c	Fri Aug 27 17:48:09 1999
    ***************
    *** 119,124 ****
    --- 119,131 ----
      		return (0);
      	}
      
    + 	/* Move the buffer to the head/tail of the LRU chain. */
    + 	SH_TAILQ_REMOVE(&mp->bhq, bhp, q, __bh);
    + 	if (F_ISSET(bhp, BH_DISCARD))
    + 		SH_TAILQ_INSERT_HEAD(&mp->bhq, bhp, q, __bh);
    + 	else
    + 		SH_TAILQ_INSERT_TAIL(&mp->bhq, bhp, q);
    + 
      	/*
      	 * If this buffer is scheduled for writing because of a checkpoint, we
      	 * need to write it (if we marked it dirty), or update the checkpoint
    ***************
    *** 138,151 ****
      			--dbmfp->mfp->lsn_cnt;
      			--mp->lsn_cnt;
      		}
    - 
    - 	/* Move the buffer to the head/tail of the LRU chain. */
    - 	SH_TAILQ_REMOVE(&mp->bhq, bhp, q, __bh);
    - 	if (F_ISSET(bhp, BH_DISCARD))
    - 		SH_TAILQ_INSERT_HEAD(&mp->bhq, bhp, q, __bh);
    - 	else
    - 		SH_TAILQ_INSERT_TAIL(&mp->bhq, bhp, q);
    - 
      
      	UNLOCKREGION(dbmp);
      	return (0);
    --- 145,150 ----
    *** mp/mp_region.c.orig	Fri Dec 11 14:29:42 1998
    --- mp/mp_region.c	Fri Aug 27 17:48:09 1999
    ***************
    *** 137,145 ****
    --- 137,147 ----
      		 * the buffer list.
      		 */
      		if (F_ISSET(bhp, BH_DIRTY)) {
    + 			++bhp->ref;
      			if ((ret = __memp_bhwrite(dbmp,
      			    mfp, bhp, &restart, &wrote)) != 0)
      				return (ret);
    + 			--bhp->ref;
      
      			/*
      			 * It's possible that another process wants this buffer
    *** mp/mp_sync.c.orig	Fri Apr  9 21:50:42 1999
    --- mp/mp_sync.c	Fri Aug 27 17:48:09 1999
    ***************
    *** 446,451 ****
    --- 446,452 ----
      	BH *bhp;
      	MPOOL *mp;
      	MPOOLFILE *mfp;
    + 	db_pgno_t pgno;
      	u_long total;
      	int ret, wrote;
      
    ***************
    *** 493,498 ****
    --- 494,500 ----
      		if (F_ISSET(mfp, MP_TEMP))
      			continue;
      
    + 		pgno = bhp->pgno;
      		if ((ret = __memp_bhwrite(dbmp, mfp, bhp, NULL, &wrote)) != 0)
      			goto err;
      
    ***************
    *** 503,509 ****
      		 */
      		if (!wrote) {
      			__db_err(dbmp->dbenv, "%s: unable to flush page: %lu",
    ! 			    __memp_fns(dbmp, mfp), (u_long)bhp->pgno);
      			ret = EPERM;
      			goto err;
      		}
    --- 505,511 ----
      		 */
      		if (!wrote) {
      			__db_err(dbmp->dbenv, "%s: unable to flush page: %lu",
    ! 			    __memp_fns(dbmp, mfp), (u_long)pgno);
      			ret = EPERM;
      			goto err;
      		}
    

  17. Update the Berkeley DB release version numbers from 2.6.6 to 2.6.7.
  18. Apply the following patches to the db-2.6.6 README, build_vms/db.h, build_win16/db.h, build_win32/db.h, build_win32/libdb.rc, docs/index.html and include/db.h files.  
    *** README.orig	Fri Apr  9 21:51:04 1999
    --- README	Fri Aug 20 12:08:01 1999
    ***************
    *** 1,8 ****
      # @(#)README	10.71 (Sleepycat) 12/16/98
      
    ! This is version 2.6.6 (03/14/99) of Sleepycat Software's Berkeley DB
      product.  To view the documentation for this release, point your web
    ! browser at the distribution file db-2.6.6/docs/index.html.
      
      Sleepycat Software	db@sleepycat.com
      394 E. Riding Dr.	+1-510-526-3972
    --- 1,8 ----
      # @(#)README	10.71 (Sleepycat) 12/16/98
      
    ! This is version 2.6.7 (08/20/99) of Sleepycat Software's Berkeley DB
      product.  To view the documentation for this release, point your web
    ! browser at the distribution file db-2.6.7/docs/index.html.
      
      Sleepycat Software	db@sleepycat.com
      394 E. Riding Dr.	+1-510-526-3972
    diff -r -c db-2.6.6/build_vms/db.h db-2.6.7/build_vms/db.h
    *** build_vms/db.h.orig	Fri Apr  9 21:51:06 1999
    --- build_vms/db.h	Fri Aug 20 12:08:15 1999
    ***************
    *** 69,76 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	6
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.6: (03/14/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */
    --- 69,76 ----
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.7: (08/20/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */
    diff -r -c db-2.6.6/build_win16/db.h db-2.6.7/build_win16/db.h
    *** build_win16/db.h.orig	Fri Apr  9 21:51:09 1999
    --- build_win16/db.h	Fri Aug 20 12:08:20 1999
    ***************
    *** 75,82 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	6
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.6: (03/14/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */
    --- 75,82 ----
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.7: (08/20/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */
    diff -r -c db-2.6.6/build_win32/db.h db-2.6.7/build_win32/db.h
    *** build_win32/db.h.orig	Fri Apr  9 21:51:10 1999
    --- build_win32/db.h	Fri Aug 20 12:08:26 1999
    ***************
    *** 75,82 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	6
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.6: (03/14/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */
    --- 75,82 ----
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.7: (08/20/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */
    diff -r -c db-2.6.6/build_win32/libdb.rc db-2.6.7/build_win32/libdb.rc
    *** build_win32/libdb.rc.orig	Fri Apr  9 21:51:05 1999
    --- build_win32/libdb.rc	Fri Aug 20 12:08:08 1999
    ***************
    *** 1,6 ****
      1 VERSIONINFO
    !  FILEVERSION 2,0,6,6
    !  PRODUCTVERSION 2,0,6,6
       FILEFLAGSMASK 0x3fL
      #ifdef _DEBUG
       FILEFLAGS 0x1L
    --- 1,6 ----
      1 VERSIONINFO
    !  FILEVERSION 2,0,6,7
    !  PRODUCTVERSION 2,0,6,7
       FILEFLAGSMASK 0x3fL
      #ifdef _DEBUG
       FILEFLAGS 0x1L
    ***************
    *** 18,29 ****
              BEGIN
                  VALUE "CompanyName", "Sleepycat Software\0"
                  VALUE "FileDescription", "Berkeley DB 2.0 DLL\0"
    !             VALUE "FileVersion", "2.6.6\0"
                  VALUE "InternalName", "libdb.dll\0"
                  VALUE "LegalCopyright", "Copyright © Sleepycat Software Inc. 1997, 1998\0"
                  VALUE "OriginalFilename", "libdb.dll\0"
                  VALUE "ProductName", "Sleepycat Software libdb\0"
    !             VALUE "ProductVersion", "2.6.6\0"
              END
          END
          BLOCK "VarFileInfo"
    --- 18,29 ----
              BEGIN
                  VALUE "CompanyName", "Sleepycat Software\0"
                  VALUE "FileDescription", "Berkeley DB 2.0 DLL\0"
    !             VALUE "FileVersion", "2.6.7\0"
                  VALUE "InternalName", "libdb.dll\0"
                  VALUE "LegalCopyright", "Copyright © Sleepycat Software Inc. 1997, 1998\0"
                  VALUE "OriginalFilename", "libdb.dll\0"
                  VALUE "ProductName", "Sleepycat Software libdb\0"
    !             VALUE "ProductVersion", "2.6.7\0"
              END
          END
          BLOCK "VarFileInfo"
    diff -r -c db-2.6.6/docs/index.html db-2.6.7/docs/index.html
    *** docs/index.html.orig	Fri Apr  9 21:50:59 1999
    --- docs/index.html	Fri Aug 20 12:07:48 1999
    ***************
    *** 10,16 ****
      
      
      <p><br><p>
    ! <h1><b>Berkeley DB: version 2.6.6, 03/14/99</b></h1>
      
      <hr size=1 noshade>
      
    --- 10,16 ----
      
      
      <p><br><p>
    ! <h1><b>Berkeley DB: version 2.6.7, 08/20/99</b></h1>
      
      <hr size=1 noshade>
      
    diff -r -c db-2.6.6/include/db.h db-2.6.7/include/db.h
    *** include/db.h.orig	Fri Apr  9 21:51:02 1999
    --- include/db.h	Fri Aug 20 12:07:55 1999
    ***************
    *** 72,79 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	6
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.6: (03/14/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */
    --- 72,79 ----
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	6
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.6.7: (08/20/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */