about summary refs log tree commit diff
path: root/db2/db/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'db2/db/db.c')
-rw-r--r--db2/db/db.c313
1 files changed, 108 insertions, 205 deletions
diff --git a/db2/db/db.c b/db2/db/db.c
index 70c6c5443b..2b4c270324 100644
--- a/db2/db/db.c
+++ b/db2/db/db.c
@@ -44,7 +44,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db.c	10.57 (Sleepycat) 5/7/98";
+static const char sccsid[] = "@(#)db.c	10.75 (Sleepycat) 12/3/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -67,9 +67,6 @@ static const char sccsid[] = "@(#)db.c	10.57 (Sleepycat) 5/7/98";
 #include "db_am.h"
 #include "common_ext.h"
 
-static int db_close __P((DB *, u_int32_t));
-static int db_fd __P((DB *, int *));
-
 /*
  * If the metadata page has the flag set, set the local flag.  If the page
  * does NOT have the flag set, return EINVAL if the user's dbinfo argument
@@ -87,11 +84,6 @@ static int db_fd __P((DB *, int *));
 		}							\
 }
 
-#ifdef _LIBC
-#define db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp) \
-  __nss_db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
-#endif
-
 /*
  * db_open --
  *	Main library interface to the DB access methods.
@@ -141,9 +133,10 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
 
 		/*
 		 * Specifying a cachesize to db_open(3), after creating an
-		 * environment, is a common mistake.
+		 * environment with DB_INIT_MPOOL, is a common mistake.
 		 */
-		if (dbinfo != NULL && dbinfo->db_cachesize != 0) {
+		if (dbenv->mp_info != NULL &&
+		    dbinfo != NULL && dbinfo->db_cachesize != 0) {
 			__db_err(dbenv,
 			    "cachesize will be ignored if environment exists");
 			return (EINVAL);
@@ -156,12 +149,16 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
 	real_name = NULL;
 
 	/* Allocate the DB structure, reference the DB_ENV structure. */
-	if ((dbp = (DB *)__db_calloc(1, sizeof(DB))) == NULL) {
-		__db_err(dbenv, "%s", strerror(ENOMEM));
-		return (ENOMEM);
-	}
+	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);
+	if ((ret = __db_init_wrapper(dbp)) != 0)
+		goto err;
+
 	/* Convert the db_open(3) flags. */
 	if (LF_ISSET(DB_RDONLY))
 		F_SET(dbp, DB_AM_RDONLY);
@@ -192,21 +189,16 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
 	}
 
 	/*
-	 * Always set the master and initialize the queues, so we can
-	 * use these fields without checking the thread bit.
-	 */
-	dbp->master = dbp;
-	LIST_INIT(&dbp->handleq);
-	LIST_INSERT_HEAD(&dbp->handleq, dbp, links);
-	TAILQ_INIT(&dbp->curs_queue);
-
-	/*
 	 * Set based on the dbenv fields, although no logging or transactions
 	 * are possible for temporary files.
 	 */
 	if (dbenv != NULL) {
-		if (dbenv->lk_info != NULL)
-			F_SET(dbp, DB_AM_LOCKING);
+		if (dbenv->lk_info != NULL) {
+			if (F_ISSET(dbenv, DB_ENV_CDB))
+				F_SET(dbp, DB_AM_CDB);
+			else
+				F_SET(dbp, DB_AM_LOCKING);
+		}
 		if (fname != NULL && dbenv->lg_info != NULL)
 			F_SET(dbp, DB_AM_LOGGING);
 	}
@@ -215,9 +207,29 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
 	if (dbinfo == NULL) {
 		dbp->pgsize = 0;
 		dbp->db_malloc = NULL;
+		dbp->dup_compare = NULL;
 	} else {
+		/*
+		 * We don't want anything that's not a power-of-2, as we rely
+		 * on that for alignment of various types on the pages.
+		 */
+		if ((dbp->pgsize = dbinfo->db_pagesize) != 0 &&
+		    (u_int32_t)1 << __db_log2(dbp->pgsize) != dbp->pgsize) {
+			__db_err(dbenv, "page sizes must be a power-of-2");
+			goto einval;
+		}
 		dbp->pgsize = dbinfo->db_pagesize;
 		dbp->db_malloc = dbinfo->db_malloc;
+		if (F_ISSET(dbinfo, DB_DUPSORT)) {
+			if (F_ISSET(dbinfo, DB_DUP))
+				dbp->dup_compare = dbinfo->dup_compare == NULL ?
+				    __bam_defcmp : dbinfo->dup_compare;
+			else {
+				__db_err(dbenv, "DB_DUPSORT requires DB_DUP");
+				goto einval;
+			}
+			F_CLR(dbinfo, DB_DUPSORT);
+		}
 	}
 
 	/* Fill in the default file mode. */
@@ -235,6 +247,7 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
 		default:
 			goto err;
 		}
+	dbp->byteswapped = F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0;
 
 	/*
 	 * If we have a file name, try and read the first page, figure out
@@ -289,7 +302,7 @@ open_retry:	if (LF_ISSET(DB_CREATE)) {
 		 * sizes, we limit the default pagesize to 16K.
 		 */
 		if (dbp->pgsize == 0) {
-			if ((ret = __db_ioinfo(real_name,
+			if ((ret = __os_ioinfo(real_name,
 			    fd, NULL, NULL, &iopsize)) != 0) {
 				__db_err(dbenv,
 				    "%s: %s", real_name, strerror(ret));
@@ -299,6 +312,14 @@ open_retry:	if (LF_ISSET(DB_CREATE)) {
 				iopsize = 512;
 			if (iopsize > 16 * 1024)
 				iopsize = 16 * 1024;
+
+			/*
+			 * Sheer paranoia, but we don't want anything that's
+			 * not a power-of-2, as we rely on that for alignment
+			 * of various types on the pages.
+			 */
+			DB_ROUNDOFF(iopsize, 512);
+
 			dbp->pgsize = iopsize;
 			F_SET(dbp, DB_AM_PGDEF);
 		}
@@ -308,11 +329,11 @@ open_retry:	if (LF_ISSET(DB_CREATE)) {
 		 * that the meta-data for all access methods fits in 512
 		 * bytes, and that no database will be smaller than that.
 		 */
-		if ((ret = __db_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)
+		if ((ret = __os_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)
 			goto err;
 
 		/* The fd is no longer needed. */
-		(void)__db_close(fd);
+		(void)__os_close(fd);
 		fd = -1;
 
 		if (nr != sizeof(mbuf)) {
@@ -337,7 +358,7 @@ open_retry:	if (LF_ISSET(DB_CREATE)) {
 			 */
 			if (retry_cnt++ < 3 &&
 			    !LF_ISSET(DB_CREATE | DB_TRUNCATE)) {
-				__db_sleep(1, 0);
+				__os_sleep(1, 0);
 				goto open_retry;
 			}
 			if (type == DB_UNKNOWN) {
@@ -396,7 +417,7 @@ retry:		switch (((BTMETA *)mbuf)->magic) {
 
 			/* Copy the file's unique id. */
 			need_fileid = 0;
-			memcpy(dbp->lock.fileid, btm->uid, DB_FILE_ID_LEN);
+			memcpy(dbp->fileid, btm->uid, DB_FILE_ID_LEN);
 			break;
 		case DB_HASHMAGIC:
 			if (type != DB_HASH && type != DB_UNKNOWN)
@@ -425,7 +446,7 @@ retry:		switch (((BTMETA *)mbuf)->magic) {
 
 			/* Copy the file's unique id. */
 			need_fileid = 0;
-			memcpy(dbp->lock.fileid, hashm->uid, DB_FILE_ID_LEN);
+			memcpy(dbp->fileid, hashm->uid, DB_FILE_ID_LEN);
 			break;
 		default:
 			if (swapped) {
@@ -489,11 +510,9 @@ empty:	/*
 		F_SET(dbp, DB_AM_MLOCAL);
 
 		if (dbenv == NULL) {
-			if ((dbp->mp_dbenv =
-			    (DB_ENV *)__db_calloc(sizeof(DB_ENV), 1)) == NULL) {
-				ret = ENOMEM;
+			if ((ret = __os_calloc(1,
+			    sizeof(DB_ENV), &dbp->mp_dbenv)) != 0)
 				goto err;
-			}
 
 			envp = dbp->mp_dbenv;
 			restore = 0;
@@ -554,20 +573,20 @@ empty:	/*
 	 */
 	if (need_fileid) {
 		if (fname == NULL) {
-			memset(dbp->lock.fileid, 0, DB_FILE_ID_LEN);
+			memset(dbp->fileid, 0, DB_FILE_ID_LEN);
 			if (F_ISSET(dbp, DB_AM_LOCKING) &&
 			    (ret = lock_id(dbenv->lk_info,
-			    (u_int32_t *)dbp->lock.fileid)) != 0)
+			    (u_int32_t *)dbp->fileid)) != 0)
 				goto err;
 		} else
-			if ((ret = __db_fileid(dbenv,
-			    real_name, 1, dbp->lock.fileid)) != 0)
+			if ((ret = __os_fileid(dbenv,
+			    real_name, 1, dbp->fileid)) != 0)
 				goto err;
 	}
 
 	/* No further use for the real name. */
 	if (real_name != NULL)
-		FREES(real_name);
+		__os_freestr(real_name);
 	real_name = NULL;
 
 	/*
@@ -595,7 +614,7 @@ empty:	/*
 	memset(&finfo, 0, sizeof(finfo));
 	finfo.ftype = ftype;
 	finfo.pgcookie = &pgcookie;
-	finfo.fileid = dbp->lock.fileid;
+	finfo.fileid = dbp->fileid;
 	finfo.lsn_offset = 0;
 	finfo.clear_len = DB_PAGE_CLEAR_LEN;
 	if ((ret = memp_fopen(dbp->mp, fname,
@@ -605,12 +624,21 @@ empty:	/*
 
 	/*
 	 * XXX
-	 * Truly spectacular layering violation.  We need a per-thread mutex
-	 * that lives in shared memory (thanks, HP-UX!) and so we acquire a
-	 * pointer to the mpool one.
+	 * We need a per-thread mutex that lives in shared memory -- HP-UX
+	 * can't allocate mutexes in malloc'd memory.  Allocate it from the
+	 * shared memory region, since it's the only one that is guaranteed
+	 * to exist.
 	 */
-	if (F_ISSET(dbp, DB_AM_THREAD))
-		dbp->mutexp = dbp->mpf->mutexp;
+	if (F_ISSET(dbp, DB_AM_THREAD)) {
+		if ((ret = __memp_reg_alloc(dbp->mp,
+		    sizeof(db_mutex_t), NULL, &dbp->mutexp)) != 0)
+			goto err;
+		/*
+		 * Since we only get here if DB_THREAD was specified, we know
+		 * we have spinlocks and no file offset argument is needed.
+		 */
+		(void)__db_mutex_init(dbp->mutexp, 0);
+	}
 
 	/* Get a log file id. */
 	if (F_ISSET(dbp, DB_AM_LOGGING) &&
@@ -618,18 +646,6 @@ empty:	/*
 	    dbp, fname, type, &dbp->log_fileid)) != 0)
 		goto err;
 
-	/*
-	 * Get a locker id for this DB, and build the lock cookie: the first
-	 * db_pgno_t bytes are the page number, the next N bytes are the file
-	 * id.
-	 */
-	if (F_ISSET(dbp, DB_AM_LOCKING)) {
-		if ((ret = lock_id(dbenv->lk_info, &dbp->locker)) != 0)
-			goto err;
-		dbp->lock_dbt.size = sizeof(dbp->lock);
-		dbp->lock_dbt.data = &dbp->lock;
-	}
-
 	/* Call the real open function. */
 	switch (type) {
 	case DB_BTREE:
@@ -639,7 +655,7 @@ empty:	/*
 		if (dbinfo != NULL && (ret = __db_fcchk(dbenv,
 		    "db_open", dbinfo->flags, DB_DUP, DB_RECNUM)) != 0)
 			goto err;
-		if ((ret = __bam_open(dbp, type, dbinfo)) != 0)
+		if ((ret = __bam_open(dbp, dbinfo)) != 0)
 			goto err;
 		break;
 	case DB_HASH:
@@ -655,24 +671,20 @@ empty:	/*
 		if (dbinfo != NULL && (ret = __db_fchk(dbenv,
 		    "db_open", dbinfo->flags, DB_INFO_FLAGS)) != 0)
 			goto err;
-		if ((ret = __ram_open(dbp, type, dbinfo)) != 0)
+		if ((ret = __ram_open(dbp, dbinfo)) != 0)
 			goto err;
 		break;
 	default:
 		abort();
 	}
 
-	/* Call a local close routine. */
-	dbp->close = db_close;
-	dbp->fd = db_fd;
-
 	*dbpp = dbp;
 	return (0);
 
 einval:	ret = EINVAL;
 err:	/* Close the file descriptor. */
 	if (fd != -1)
-		(void)__db_close(fd);
+		(void)__os_close(fd);
 
 	/* Discard the log file id. */
 	if (dbp->log_fileid != 0)
@@ -688,90 +700,60 @@ err:	/* Close the file descriptor. */
 
 	/* If we allocated a DB_ENV, discard it. */
 	if (dbp->mp_dbenv != NULL)
-		FREE(dbp->mp_dbenv, sizeof(DB_ENV));
+		__os_free(dbp->mp_dbenv, sizeof(DB_ENV));
 
 	if (real_name != NULL)
-		FREES(real_name);
+		__os_freestr(real_name);
 	if (dbp != NULL)
-		FREE(dbp, sizeof(DB));
+		__os_free(dbp, sizeof(DB));
 
 	return (ret);
 }
 
-#ifdef _LIBC
-# undef db_open
-weak_alias (__nss_db_open, db_open)
-#endif
-
 /*
- * db_close --
+ * __db_close --
  *	Close a DB tree.
+ *
+ * PUBLIC: int __db_close __P((DB *, u_int32_t));
  */
-static int
-db_close(dbp, flags)
+int
+__db_close(dbp, flags)
 	DB *dbp;
 	u_int32_t flags;
 {
 	DBC *dbc;
-	DB *tdbp;
 	int ret, t_ret;
 
+	DB_PANIC_CHECK(dbp);
+
 	/* Validate arguments. */
-	if ((ret = __db_fchk(dbp->dbenv, "db_close", flags, DB_NOSYNC)) != 0)
+	if ((ret = __db_closechk(dbp, flags)) != 0)
 		return (ret);
 
 	/* Sync the underlying file. */
-	if (!LF_ISSET(DB_NOSYNC) &&
+	if (flags != DB_NOSYNC &&
 	    (t_ret = dbp->sync(dbp, 0)) != 0 && ret == 0)
 		ret = t_ret;
 
 	/*
-	 * Call the underlying access method close routine for all the
-	 * cursors and handles.
+	 * Go through the active cursors and call the cursor recycle routine,
+	 * which resolves pending operations and moves the cursors onto the
+	 * free list.  Then, walk the free list and call the cursor destroy
+	 * routine.
 	 */
-	for (tdbp = LIST_FIRST(&dbp->handleq);
-	    tdbp != NULL; tdbp = LIST_NEXT(tdbp, links)) {
-		while ((dbc = TAILQ_FIRST(&tdbp->curs_queue)) != NULL)
-			switch (tdbp->type) {
-			case DB_BTREE:
-				if ((t_ret =
-				    __bam_c_iclose(tdbp, dbc)) != 0 && ret == 0)
-					ret = t_ret;
-				break;
-			case DB_HASH:
-				if ((t_ret =
-				    __ham_c_iclose(tdbp, dbc)) != 0 && ret == 0)
-					ret = t_ret;
-				break;
-			case DB_RECNO:
-				if ((t_ret =
-				    __ram_c_iclose(tdbp, dbc)) != 0 && ret == 0)
-					ret = t_ret;
-				break;
-			default:
-				abort();
-			}
-
-		switch (tdbp->type) {
-		case DB_BTREE:
-			if ((t_ret = __bam_close(tdbp)) != 0 && ret == 0)
-				ret = t_ret;
-			break;
-		case DB_HASH:
-			if ((t_ret = __ham_close(tdbp)) != 0 && ret == 0)
-				ret = t_ret;
-			break;
-		case DB_RECNO:
-			if ((t_ret = __ram_close(tdbp)) != 0 && ret == 0)
-				ret = t_ret;
-			break;
-		default:
-			abort();
-		}
-	}
+	while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
+		if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
+			ret = t_ret;
+	while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
+		if ((t_ret = __db_c_destroy(dbc)) != 0 && ret == 0)
+			ret = t_ret;
+
+	/* Call the access specific close function. */
+	if ((t_ret = dbp->am_close(dbp)) != 0 && ret == 0)
+		ret = t_ret;
 
 	/* Sync the memory pool. */
-	if (!LF_ISSET(DB_NOSYNC) && (t_ret = memp_fsync(dbp->mpf)) != 0 &&
+	if (flags != DB_NOSYNC && (t_ret = memp_fsync(dbp->mpf)) != 0 &&
 	    t_ret != DB_INCOMPLETE && ret == 0)
 		ret = t_ret;
 
@@ -788,91 +770,12 @@ db_close(dbp, flags)
 	if (F_ISSET(dbp, DB_AM_LOGGING))
 		(void)log_unregister(dbp->dbenv->lg_info, dbp->log_fileid);
 
-	/* Discard the lock cookie for all handles. */
-	for (tdbp = LIST_FIRST(&dbp->handleq);
-	    tdbp != NULL; tdbp = LIST_NEXT(tdbp, links))
-		if (F_ISSET(tdbp, DB_AM_LOCKING)) {
-#ifdef DEBUG
-			DB_LOCKREQ request;
-
-			/*
-			 * If we're running tests, display any locks currently
-			 * held.  It's possible that some applications may hold
-			 * locks for long periods, e.g., conference room locks,
-			 * but the DB tests should never close holding locks.
-			 */
-			request.op = DB_LOCK_DUMP;
-			if ((t_ret = lock_vec(tdbp->dbenv->lk_info,
-			    tdbp->locker, 0, &request, 1, NULL)) != 0 &&
-			    ret == 0)
-				ret = EAGAIN;
-#endif
-		}
-
 	/* If we allocated a DB_ENV, discard it. */
 	if (dbp->mp_dbenv != NULL)
-		FREE(dbp->mp_dbenv, sizeof(DB_ENV));
+		__os_free(dbp->mp_dbenv, sizeof(DB_ENV));
 
-	/* Free all of the DB's. */
-	LIST_REMOVE(dbp, links);
-	while ((tdbp = LIST_FIRST(&dbp->handleq)) != NULL) {
-		LIST_REMOVE(tdbp, links);
-		FREE(tdbp, sizeof(*tdbp));
-	}
-	FREE(dbp, sizeof(*dbp));
+	/* Free the DB. */
+	__os_free(dbp, sizeof(*dbp));
 
 	return (ret);
 }
-
-/*
- * db_fd --
- *	Return a file descriptor for flock'ing.
- */
-static int
-db_fd(dbp, fdp)
-        DB *dbp;
-	int *fdp;
-{
-	/*
-	 * XXX
-	 * Truly spectacular layering violation.
-	 */
-	return (__mp_xxx_fd(dbp->mpf, fdp));
-}
-
-/*
- * __db_pgerr --
- *	Error when unable to retrieve a specified page.
- *
- * PUBLIC: int __db_pgerr __P((DB *, db_pgno_t));
- */
-int
-__db_pgerr(dbp, pgno)
-	DB *dbp;
-	db_pgno_t pgno;
-{
-	/*
-	 * Three things are certain:
-	 * Death, taxes, and lost data.
-	 * Guess which has occurred.
-	 */
-	__db_err(dbp->dbenv,
-	    "unable to create/retrieve page %lu", (u_long)pgno);
-	return (__db_panic(dbp));
-}
-
-/*
- * __db_pgfmt --
- *	Error when a page has the wrong format.
- *
- * PUBLIC: int __db_pgfmt __P((DB *, db_pgno_t));
- */
-int
-__db_pgfmt(dbp, pgno)
-	DB *dbp;
-	db_pgno_t pgno;
-{
-	__db_err(dbp->dbenv,
-	    "page %lu: illegal page type or format", (u_long)pgno);
-	return (__db_panic(dbp));
-}