Patches for Berkeley DB version 2.7.5

  1. Fix potential races in updating checkpoint buffer counts that can cause checkpoint calls to never finish.
  2. Apply the following patch to the db-2.7.5 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);
    

  3. Fix for XA support, allows two-phase commit processing to work.
  4. Apply the following patch to the db-2.7.5 xa/xa.c file.  
    *** xa/xa.c.orig	Sun Apr 18 21:19:43 1999
    --- xa/xa.c	Tue Apr 20 22:44:24 1999
    ***************
    *** 195,201 ****
      	 */
      	if (is_known) {
      		td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off);
    ! 		if (td->xa_status == TXN_XA_SUSPENDED && !LF_SET(TMRESUME))
      			return (XAER_PROTO);
      		if (td->xa_status == TXN_XA_DEADLOCKED)
      			return (XA_RBDEADLOCK);
    --- 195,201 ----
      	 */
      	if (is_known) {
      		td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off);
    ! 		if (td->xa_status == TXN_XA_SUSPENDED && !LF_ISSET(TMRESUME))
      			return (XAER_PROTO);
      		if (td->xa_status == TXN_XA_DEADLOCKED)
      			return (XA_RBDEADLOCK);
    ***************
    *** 361,371 ****
      	if (td->xa_status == TXN_XA_ABORTED)
      		return (XA_RBOTHER);
      
    ! 	if (LF_SET(TMONEPHASE) &&
      	    td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
      		return (XAER_PROTO);
      
    ! 	if (!LF_SET(TMONEPHASE) && td->xa_status != TXN_XA_PREPARED)
      		return (XAER_PROTO);
      
      	/* Now, fill in the global transaction structure. */
    --- 361,371 ----
      	if (td->xa_status == TXN_XA_ABORTED)
      		return (XA_RBOTHER);
      
    ! 	if (LF_ISSET(TMONEPHASE) &&
      	    td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
      		return (XAER_PROTO);
      
    ! 	if (!LF_ISSET(TMONEPHASE) && td->xa_status != TXN_XA_PREPARED)
      		return (XAER_PROTO);
      
      	/* Now, fill in the global transaction structure. */
    ***************
    *** 572,582 ****
      	if (td->xa_status == TXN_XA_ABORTED)
      		return (XA_RBOTHER);
      
    ! 	if (LF_SET(TMONEPHASE) &&
      	    td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
    - 		return (XAER_PROTO);
    - 
    - 	if (!LF_SET(TMONEPHASE) && td->xa_status != TXN_XA_PREPARED)
      		return (XAER_PROTO);
      
      	/* Now, fill in the global transaction structure. */
    --- 572,579 ----
      	if (td->xa_status == TXN_XA_ABORTED)
      		return (XA_RBOTHER);
      
    ! 	if (LF_ISSET(TMONEPHASE) &&
      	    td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED)
      		return (XAER_PROTO);
      
      	/* Now, fill in the global transaction structure. */
    

  5. Fix a recovery bug when database files are opened/closed multiple times in the same session.
  6. Apply the following patch to the db-2.7.5 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:06:58 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:06:27 1999
    --- include/log_ext.h	Wed Aug 11 16:06:38 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 Apr 12 12:07:38 1999
    --- log/log.c	Wed Aug 11 15:36:34 1999
    ***************
    *** 432,437 ****
    --- 432,438 ----
      log_close(dblp)
      	DB_LOG *dblp;
      {
    + 	u_int32_t i;
      	int ret, t_ret;
      
      	LOG_PANIC_CHECK(dblp);
    ***************
    *** 457,465 ****
      	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);
      
    --- 458,471 ----
      	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 Apr 12 12:07:38 1999
    --- log/log_rec.c	Fri Aug 13 16:30:27 1999
    ***************
    *** 73,78 ****
    --- 73,79 ----
      	int redo;
      	void *info;
      {
    + 	DB_ENTRY *dbe;
      	__log_register_args *argp;
      	int ret;
      
    ***************
    *** 104,113 ****
      				    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
    --- 105,120 ----
      				    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
    ***************
    *** 116,129 ****
      		 * 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))) {
    --- 123,141 ----
      		 * 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))) {
    ***************
    *** 160,176 ****
      	DB_LOG *lp;
      	__log_register_args *argp;
      {
      	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);
      	return (__log_do_open(lp,
      	    argp->uid.data, argp->name.data, argp->ftype, argp->id));
      }
    --- 172,213 ----
      	DB_LOG *lp;
      	__log_register_args *argp;
      {
    + 	DB_ENTRY *dbe;
    +   
    + 	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);
    ! 
    ! 	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);
    !         }
    ! 
    ! 
      	return (__log_do_open(lp,
      	    argp->uid.data, argp->name.data, argp->ftype, argp->id));
      }
    ***************
    *** 206,212 ****
      	}
      
      	if (ret == 0 || ret == ENOENT)
    ! 		(void)__log_add_logid(lp, dbp, ndx);
      
      	return (ret);
      }
    --- 243,249 ----
      	}
      
      	if (ret == 0 || ret == ENOENT)
    ! 		(void)__log_add_logid(lp, dbp, name, ndx);
      
      	return (ret);
      }
    ***************
    *** 215,226 ****
       * __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;
    --- 252,264 ----
       * __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;
    ***************
    *** 244,260 ****
    --- 282,308 ----
      		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 Apr 12 12:07:24 1999
    --- log/log_register.c	Wed Aug 11 15:48:14 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;
      	}
    

  7. Change file descriptor usage to permit Sendmail's fcntl(2) locking scheme.
  8. Apply the following patch to the db-2.7.5 db/db.c and include/db.h files.  
    *** include/db.h.orig	Mon Aug  2 13:13:13 1999
    --- include/db.h	Mon Aug  2 13:15:57 1999
    ***************
    *** 199,204 ****
    --- 199,205 ----
      #define	DB_SEQUENTIAL	      0x008000	/* Sequential access (internal). */
      #define	DB_TEMPORARY	      0x010000	/* Remove on last close (internal). */
      #define	DB_TRUNCATE	      0x020000	/* O_TRUNCATE: replace existing DB. */
    + #define	DB_FCNTL_LOCKING      0x040000	/* Undocumented: fcntl(2) locking. */
      
      /*
       * Deadlock detector modes; used in the DBENV structure to configure the
    ***************
    *** 405,410 ****
    --- 406,412 ----
      					/* Documented, returned information. */
      	DBTYPE	 type;			/* DB access method. */
      	int	 byteswapped;		/* Database byte order is swapped. */
    + 	int	 saved_open_fd;		/* For fcntl lock preservation. */
      
      	DB_ENV	*dbenv;			/* DB_ENV structure. */
      	DB_ENV	*mp_dbenv;		/* DB_ENV for local mpool creation. */
    *** build_win32/db.h.orig	Tue Aug 31 13:40:16 1999
    --- build_win32/db.h	Tue Aug 31 13:40:26 1999
    ***************
    *** 202,207 ****
    --- 202,208 ----
      #define	DB_SEQUENTIAL	      0x008000	/* Sequential access (internal). */
      #define	DB_TEMPORARY	      0x010000	/* Remove on last close (internal). */
      #define	DB_TRUNCATE	      0x020000	/* O_TRUNCATE: replace existing DB. */
    + #define	DB_FCNTL_LOCKING      0x040000	/* Undocumented: fcntl(2) locking. */
      
      /*
       * Deadlock detector modes; used in the DBENV structure to configure the
    ***************
    *** 408,413 ****
    --- 409,415 ----
      					/* Documented, returned information. */
      	DBTYPE	 type;			/* DB access method. */
      	int	 byteswapped;		/* Database byte order is swapped. */
    + 	int	 saved_open_fd;		/* For fcntl lock preservation. */
      
      	DB_ENV	*dbenv;			/* DB_ENV structure. */
      	DB_ENV	*mp_dbenv;		/* DB_ENV for local mpool creation. */
    *** build_vms/db.h.orig	Tue Aug 31 13:41:09 1999
    --- build_vms/db.h	Tue Aug 31 13:41:18 1999
    ***************
    *** 196,201 ****
    --- 196,202 ----
      #define	DB_SEQUENTIAL	      0x008000	/* Sequential access (internal). */
      #define	DB_TEMPORARY	      0x010000	/* Remove on last close (internal). */
      #define	DB_TRUNCATE	      0x020000	/* O_TRUNCATE: replace existing DB. */
    + #define	DB_FCNTL_LOCKING      0x040000	/* Undocumented: fcntl(2) locking. */
      
      /*
       * Deadlock detector modes; used in the DBENV structure to configure the
    ***************
    *** 402,407 ****
    --- 403,409 ----
      					/* Documented, returned information. */
      	DBTYPE	 type;			/* DB access method. */
      	int	 byteswapped;		/* Database byte order is swapped. */
    + 	int	 saved_open_fd;		/* For fcntl lock preservation. */
      
      	DB_ENV	*dbenv;			/* DB_ENV structure. */
      	DB_ENV	*mp_dbenv;		/* DB_ENV for local mpool creation. */
    *** build_win16/db.h.orig	Tue Aug 31 13:41:58 1999
    --- build_win16/db.h	Tue Aug 31 13:42:03 1999
    ***************
    *** 202,207 ****
    --- 202,208 ----
      #define	DB_SEQUENTIAL	      0x008000	/* Sequential access (internal). */
      #define	DB_TEMPORARY	      0x010000	/* Remove on last close (internal). */
      #define	DB_TRUNCATE	      0x020000	/* O_TRUNCATE: replace existing DB. */
    + #define	DB_FCNTL_LOCKING      0x040000	/* Undocumented: fcntl(2) locking. */
      
      /*
       * Deadlock detector modes; used in the DBENV structure to configure the
    ***************
    *** 408,413 ****
    --- 409,415 ----
      					/* Documented, returned information. */
      	DBTYPE	 type;			/* DB access method. */
      	int	 byteswapped;		/* Database byte order is swapped. */
    + 	int	 saved_open_fd;		/* For fcntl lock preservation. */
      
      	DB_ENV	*dbenv;			/* DB_ENV structure. */
      	DB_ENV	*mp_dbenv;		/* DB_ENV for local mpool creation. */
    *** db/db.c.orig	Wed Aug 18 13:05:35 1999
    --- db/db.c	Wed Aug 18 13:18:01 1999
    ***************
    *** 113,121 ****
      
      	/* Validate arguments. */
      #ifdef HAVE_SPINLOCKS
    ! #define	OKFLAGS	(DB_CREATE | DB_NOMMAP | DB_RDONLY | DB_THREAD | DB_TRUNCATE)
      #else
    ! #define	OKFLAGS	(DB_CREATE | DB_NOMMAP | DB_RDONLY | DB_TRUNCATE)
      #endif
      	if ((ret = __db_fchk(dbenv, "db_open", flags, OKFLAGS)) != 0)
      		return (ret);
    --- 113,121 ----
      
      	/* Validate arguments. */
      #ifdef HAVE_SPINLOCKS
    ! #define	OKFLAGS	(DB_CREATE | DB_FCNTL_LOCKING | DB_NOMMAP | DB_RDONLY | DB_THREAD | DB_TRUNCATE)
      #else
    ! #define	OKFLAGS	(DB_CREATE | DB_FCNTL_LOCKING | DB_NOMMAP | DB_RDONLY | DB_TRUNCATE)
      #endif
      	if ((ret = __db_fchk(dbenv, "db_open", flags, OKFLAGS)) != 0)
      		return (ret);
    ***************
    *** 143,158 ****
      		}
      	}
      
    - 	/* Initialize for error return. */
    - 	fd = -1;
    - 	need_fileid = 1;
    - 	real_name = NULL;
    - 
      	/* Allocate the DB structure, reference the DB_ENV structure. */
      	if ((ret = __os_calloc(1, sizeof(DB), &dbp)) != 0)
      		return (ret);
      	dbp->dbenv = dbenv;
      
      	/* Random initialization. */
      	TAILQ_INIT(&dbp->free_queue);
      	TAILQ_INIT(&dbp->active_queue);
    --- 143,158 ----
      		}
      	}
      
      	/* Allocate the DB structure, reference the DB_ENV structure. */
      	if ((ret = __os_calloc(1, sizeof(DB), &dbp)) != 0)
      		return (ret);
      	dbp->dbenv = dbenv;
      
    + 	/* Initialize for error return. */
    + 	dbp->saved_open_fd = fd = -1;
    + 	need_fileid = 1;
    + 	real_name = NULL;
    + 
      	/* Random initialization. */
      	TAILQ_INIT(&dbp->free_queue);
      	TAILQ_INIT(&dbp->active_queue);
    ***************
    *** 330,337 ****
      		if ((ret = __os_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)
      			goto err;
      
    ! 		/* The fd is no longer needed. */
    ! 		(void)__os_close(fd);
      		fd = -1;
      
      		if (nr != sizeof(mbuf)) {
    --- 330,339 ----
      		if ((ret = __os_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)
      			goto err;
      
    ! 		if (LF_ISSET(DB_FCNTL_LOCKING))
    ! 			dbp->saved_open_fd = fd;
    ! 		else
    ! 			(void)__os_close(fd);
      		fd = -1;
      
      		if (nr != sizeof(mbuf)) {
    ***************
    *** 762,767 ****
    --- 764,774 ----
      	if (F_ISSET(dbp, DB_AM_MLOCAL) &&
      	    (t_ret = memp_close(dbp->mp)) != 0 && ret == 0)
      		ret = t_ret;
    + 
    + 	if (dbp->saved_open_fd != -1) {
    + 		(void)__os_close(dbp->saved_open_fd);
    + 		dbp->saved_open_fd = -1;
    + 	}
      
      	/* Discard the log file id. */
      	if (F_ISSET(dbp, DB_AM_LOGGING))
    

  9. Fix ANSI C++ usage to avoid GNU gcc-2.95 warning messages.
  10. Apply the following patch to the db-2.7.5 include/db_cxx.h file.  
    *** include/db_cxx.h.orig	Thu Aug  5 10:30:10 1999
    --- include/db_cxx.h	Thu Aug  5 10:30:14 1999
    ***************
    *** 300,306 ****
      
          // no copying
          DbLog(const DbLog &);
    !     operator = (const DbLog &);
      
          DEFINE_DB_CLASS(DbLog);
      };
    --- 300,306 ----
      
          // no copying
          DbLog(const DbLog &);
    !     DbLog &operator = (const DbLog &);
      
          DEFINE_DB_CLASS(DbLog);
      };
    ***************
    *** 345,351 ****
      private:
          // no copying
          DbMpoolFile(const DbMpoolFile &);
    !     operator = (const DbMpoolFile &);
      
          DEFINE_DB_CLASS(DbMpoolFile);
      };
    --- 345,351 ----
      private:
          // no copying
          DbMpoolFile(const DbMpoolFile &);
    !     DbMpoolFile &operator = (const DbMpoolFile &);
      
          DEFINE_DB_CLASS(DbMpoolFile);
      };
    ***************
    *** 432,438 ****
      
          // no copying
          DbTxnMgr(const DbTxnMgr &);
    !     operator = (const DbTxnMgr &);
      
          DEFINE_DB_CLASS(DbTxnMgr);
      };
    --- 432,438 ----
      
          // no copying
          DbTxnMgr(const DbTxnMgr &);
    !     DbTxnMgr &operator = (const DbTxnMgr &);
      
          DEFINE_DB_CLASS(DbTxnMgr);
      };
    ***************
    *** 461,467 ****
      
          // no copying
          DbTxn(const DbTxn &);
    !     operator = (const DbTxn &);
      
          DEFINE_DB_CLASS(DbTxn);
      };
    --- 461,467 ----
      
          // no copying
          DbTxn(const DbTxn &);
    !     DbTxn &operator = (const DbTxn &);
      
          DEFINE_DB_CLASS(DbTxn);
      };
    ***************
    *** 730,736 ****
      
          // no copying
          DbEnv(const DbEnv &);
    !     operator = (const DbEnv &);
      
          ErrorModel error_model_;
          static void stream_error_function(const char *, char *);
    --- 730,736 ----
      
          // no copying
          DbEnv(const DbEnv &);
    !     DbEnv &operator = (const DbEnv &);
      
          ErrorModel error_model_;
          static void stream_error_function(const char *, char *);
    

  11. 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.
  12. Apply the following patch to the db-2.7.5 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]);
    

  13. Fix a case where it was possible for EAGAIN to not be returned from the database get-by-key interface.
  14. Apply the following patch to the db-2.7.5 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)
    

  15. Ignore log records not involved in transactions so that actions taken outside of transactions are not undone during recovery.
  16. Apply the following patch to the db-2.7.5 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;
    

  17. Fix a memory pool race during buffer discard in memory tight environments.
  18. Apply the following patch to the db-2.7.5 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:37:03 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:37:03 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	Mon Apr 12 12:07:38 1999
    --- mp/mp_sync.c	Fri Aug 27 17:37:03 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;
      		}
    

  19. Update the Berkeley DB release version numbers from 2.7.5 to 2.7.7.
  20. Apply the following patches to the db-2.7.5 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.  
    diff -r -c db-2.7.5/README db-2.7.7/README
    *** README	Sun Apr 18 21:21:03 1999
    --- README	Fri Aug 20 12:12:23 1999
    ***************
    *** 1,8 ****
      # @(#)README	10.72 (Sleepycat) 1/3/99
      
    ! This is version 2.7.5 (04/18/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.7.5/docs/index.html.
      
      Sleepycat Software	db@sleepycat.com
      394 E. Riding Dr.	+1-510-526-3972
    --- 1,8 ----
      # @(#)README	10.72 (Sleepycat) 1/3/99
      
    ! This is version 2.7.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.7.7/docs/index.html.
      
      Sleepycat Software	db@sleepycat.com
      394 E. Riding Dr.	+1-510-526-3972
    diff -r -c db-2.7.5/build_vms/db.h db-2.7.7/build_vms/db.h
    *** build_vms/db.h	Sun Apr 18 21:21:42 1999
    --- build_vms/db.h	Fri Aug 20 12:12:37 1999
    ***************
    *** 69,76 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	7
    ! #define	DB_VERSION_PATCH	5
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.5: (04/18/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	7
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.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.7.5/build_win16/db.h db-2.7.7/build_win16/db.h
    *** build_win16/db.h	Sun Apr 18 21:21:42 1999
    --- build_win16/db.h	Fri Aug 20 12:12:44 1999
    ***************
    *** 75,82 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	7
    ! #define	DB_VERSION_PATCH	5
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.5: (04/18/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	7
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.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.7.5/build_win32/db.h db-2.7.7/build_win32/db.h
    *** build_win32/db.h	Sun Apr 18 21:21:42 1999
    --- build_win32/db.h	Fri Aug 20 12:12:50 1999
    ***************
    *** 75,82 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	7
    ! #define	DB_VERSION_PATCH	5
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.5: (04/18/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	7
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.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.7.5/build_win32/libdb.rc db-2.7.7/build_win32/libdb.rc
    *** build_win32/libdb.rc	Sun Apr 18 21:21:42 1999
    --- build_win32/libdb.rc	Fri Aug 20 12:12:30 1999
    ***************
    *** 1,6 ****
      1 VERSIONINFO
    !  FILEVERSION 2,0,7,5
    !  PRODUCTVERSION 2,0,7,5
       FILEFLAGSMASK 0x3fL
      #ifdef _DEBUG
       FILEFLAGS 0x1L
    --- 1,6 ----
      1 VERSIONINFO
    !  FILEVERSION 2,0,7,7
    !  PRODUCTVERSION 2,0,7,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.7.5\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.7.5\0"
              END
          END
          BLOCK "VarFileInfo"
    --- 18,29 ----
              BEGIN
                  VALUE "CompanyName", "Sleepycat Software\0"
                  VALUE "FileDescription", "Berkeley DB 2.0 DLL\0"
    !             VALUE "FileVersion", "2.7.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.7.7\0"
              END
          END
          BLOCK "VarFileInfo"
    diff -r -c db-2.7.5/docs/index.html db-2.7.7/docs/index.html
    *** docs/index.html	Sun Apr 18 21:20:14 1999
    --- docs/index.html	Fri Aug 20 12:12:05 1999
    ***************
    *** 10,16 ****
      
      
      <p><br><p>
    ! <h1><b>Berkeley DB: version 2.7.5, 04/18/99</b></h1>
      
      <hr size=1 noshade>
      
    --- 10,16 ----
      
      
      <p><br><p>
    ! <h1><b>Berkeley DB: version 2.7.7, 08/20/99</b></h1>
      
      <hr size=1 noshade>
      
    diff -r -c db-2.7.5/include/db.h db-2.7.7/include/db.h
    *** include/db.h	Sun Apr 18 21:20:41 1999
    --- include/db.h	Fri Aug 20 12:12:11 1999
    ***************
    *** 72,79 ****
      
      #define	DB_VERSION_MAJOR	2
      #define	DB_VERSION_MINOR	7
    ! #define	DB_VERSION_PATCH	5
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.5: (04/18/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	7
    ! #define	DB_VERSION_PATCH	7
    ! #define	DB_VERSION_STRING	"Sleepycat Software: Berkeley DB 2.7.7: (08/20/99)"
      
      typedef	u_int32_t	db_pgno_t;	/* Page number type. */
      typedef	u_int16_t	db_indx_t;	/* Page offset type. */