xref: /illumos-gate/usr/src/cmd/sendmail/db/db/db_am.c (revision 2a8bcb4e)
17c478bd9Sstevel@tonic-gate /*-
27c478bd9Sstevel@tonic-gate  * See the file LICENSE for redistribution information.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1998
57c478bd9Sstevel@tonic-gate  *	Sleepycat Software.  All rights reserved.
67c478bd9Sstevel@tonic-gate  */
77c478bd9Sstevel@tonic-gate 
87c478bd9Sstevel@tonic-gate #include "config.h"
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate #ifndef lint
117c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)db_am.c	10.15 (Sleepycat) 12/30/98";
127c478bd9Sstevel@tonic-gate #endif /* not lint */
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES
157c478bd9Sstevel@tonic-gate #include <sys/types.h>
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include <errno.h>
187c478bd9Sstevel@tonic-gate #include <stdlib.h>
197c478bd9Sstevel@tonic-gate #include <string.h>
207c478bd9Sstevel@tonic-gate #endif
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate #include "db_int.h"
237c478bd9Sstevel@tonic-gate #include "shqueue.h"
247c478bd9Sstevel@tonic-gate #include "db_page.h"
257c478bd9Sstevel@tonic-gate #include "db_shash.h"
267c478bd9Sstevel@tonic-gate #include "mp.h"
277c478bd9Sstevel@tonic-gate #include "btree.h"
287c478bd9Sstevel@tonic-gate #include "hash.h"
297c478bd9Sstevel@tonic-gate #include "db_am.h"
307c478bd9Sstevel@tonic-gate #include "db_ext.h"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate static int __db_c_close __P((DBC *));
337c478bd9Sstevel@tonic-gate static int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t));
347c478bd9Sstevel@tonic-gate static int __db_fd __P((DB *, int *));
357c478bd9Sstevel@tonic-gate static int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
367c478bd9Sstevel@tonic-gate static int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * __db_init_wrapper --
407c478bd9Sstevel@tonic-gate  *	Wrapper layer to implement generic DB functions.
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * PUBLIC: int __db_init_wrapper __P((DB *));
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate int
__db_init_wrapper(dbp)457c478bd9Sstevel@tonic-gate __db_init_wrapper(dbp)
467c478bd9Sstevel@tonic-gate 	DB *dbp;
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 	dbp->close = __db_close;
497c478bd9Sstevel@tonic-gate 	dbp->cursor = __db_cursor;
507c478bd9Sstevel@tonic-gate 	dbp->del = NULL;		/* !!! Must be set by access method. */
517c478bd9Sstevel@tonic-gate 	dbp->fd = __db_fd;
527c478bd9Sstevel@tonic-gate 	dbp->get = __db_get;
537c478bd9Sstevel@tonic-gate 	dbp->join = __db_join;
547c478bd9Sstevel@tonic-gate 	dbp->put = __db_put;
557c478bd9Sstevel@tonic-gate 	dbp->stat = NULL;		/* !!! Must be set by access method. */
567c478bd9Sstevel@tonic-gate 	dbp->sync = __db_sync;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	return (0);
597c478bd9Sstevel@tonic-gate }
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * __db_cursor --
637c478bd9Sstevel@tonic-gate  *	Allocate and return a cursor.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate static int
__db_cursor(dbp,txn,dbcp,flags)667c478bd9Sstevel@tonic-gate __db_cursor(dbp, txn, dbcp, flags)
677c478bd9Sstevel@tonic-gate 	DB *dbp;
687c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
697c478bd9Sstevel@tonic-gate 	DBC **dbcp;
707c478bd9Sstevel@tonic-gate 	u_int32_t flags;
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate 	DBC *dbc, *adbc;
737c478bd9Sstevel@tonic-gate 	int ret;
747c478bd9Sstevel@tonic-gate 	db_lockmode_t mode;
757c478bd9Sstevel@tonic-gate 	u_int32_t op;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	DB_PANIC_CHECK(dbp);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	/* Take one from the free list if it's available. */
807c478bd9Sstevel@tonic-gate 	DB_THREAD_LOCK(dbp);
817c478bd9Sstevel@tonic-gate 	if ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
827c478bd9Sstevel@tonic-gate 		TAILQ_REMOVE(&dbp->free_queue, dbc, links);
837c478bd9Sstevel@tonic-gate 	else {
847c478bd9Sstevel@tonic-gate 		DB_THREAD_UNLOCK(dbp);
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 		if ((ret = __os_calloc(1, sizeof(DBC), &dbc)) != 0)
877c478bd9Sstevel@tonic-gate 			return (ret);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 		dbc->dbp = dbp;
907c478bd9Sstevel@tonic-gate 		dbc->c_close = __db_c_close;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 		/* Set up locking information. */
937c478bd9Sstevel@tonic-gate 		if (F_ISSET(dbp, DB_AM_LOCKING | DB_AM_CDB)) {
947c478bd9Sstevel@tonic-gate  			/*
957c478bd9Sstevel@tonic-gate  			 * If we are not threaded, then there is no need to
967c478bd9Sstevel@tonic-gate  			 * create new locker ids.  We know that no one else
977c478bd9Sstevel@tonic-gate  			 * is running concurrently using this DB, so we can
987c478bd9Sstevel@tonic-gate  			 * take a peek at any cursors on the active queue.
997c478bd9Sstevel@tonic-gate  			 */
1007c478bd9Sstevel@tonic-gate  			if (!F_ISSET(dbp, DB_AM_THREAD) &&
1017c478bd9Sstevel@tonic-gate  			    (adbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
1027c478bd9Sstevel@tonic-gate  				dbc->lid = adbc->lid;
1037c478bd9Sstevel@tonic-gate  			else
1047c478bd9Sstevel@tonic-gate  				if ((ret = lock_id(dbp->dbenv->lk_info,
1057c478bd9Sstevel@tonic-gate  				    &dbc->lid)) != 0)
1067c478bd9Sstevel@tonic-gate  					goto err;
107*2a8bcb4eSToomas Soome 
1087c478bd9Sstevel@tonic-gate 			memcpy(dbc->lock.fileid, dbp->fileid, DB_FILE_ID_LEN);
1097c478bd9Sstevel@tonic-gate 			if (F_ISSET(dbp, DB_AM_CDB)) {
1107c478bd9Sstevel@tonic-gate 				dbc->lock_dbt.size = DB_FILE_ID_LEN;
1117c478bd9Sstevel@tonic-gate 				dbc->lock_dbt.data = dbc->lock.fileid;
1127c478bd9Sstevel@tonic-gate 			} else {
1137c478bd9Sstevel@tonic-gate 				dbc->lock_dbt.size = sizeof(dbc->lock);
1147c478bd9Sstevel@tonic-gate 				dbc->lock_dbt.data = &dbc->lock;
1157c478bd9Sstevel@tonic-gate 			}
1167c478bd9Sstevel@tonic-gate 		}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 		switch (dbp->type) {
1197c478bd9Sstevel@tonic-gate 		case DB_BTREE:
1207c478bd9Sstevel@tonic-gate 		case DB_RECNO:
1217c478bd9Sstevel@tonic-gate 			if ((ret = __bam_c_init(dbc)) != 0)
1227c478bd9Sstevel@tonic-gate 				goto err;
1237c478bd9Sstevel@tonic-gate 			break;
1247c478bd9Sstevel@tonic-gate 		case DB_HASH:
1257c478bd9Sstevel@tonic-gate 			if ((ret = __ham_c_init(dbc)) != 0)
1267c478bd9Sstevel@tonic-gate 				goto err;
1277c478bd9Sstevel@tonic-gate 			break;
1287c478bd9Sstevel@tonic-gate 		default:
1297c478bd9Sstevel@tonic-gate 			ret = EINVAL;
1307c478bd9Sstevel@tonic-gate 			goto err;
1317c478bd9Sstevel@tonic-gate 		}
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		DB_THREAD_LOCK(dbp);
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if ((dbc->txn = txn) == NULL)
1377c478bd9Sstevel@tonic-gate 		dbc->locker = dbc->lid;
1387c478bd9Sstevel@tonic-gate 	else
1397c478bd9Sstevel@tonic-gate 		dbc->locker = txn->txnid;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links);
1427c478bd9Sstevel@tonic-gate 	DB_THREAD_UNLOCK(dbp);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	/*
1457c478bd9Sstevel@tonic-gate 	 * If this is the concurrent DB product, then we do all locking
1467c478bd9Sstevel@tonic-gate 	 * in the interface, which is right here.
1477c478bd9Sstevel@tonic-gate 	 */
1487c478bd9Sstevel@tonic-gate 	if (F_ISSET(dbp, DB_AM_CDB)) {
1497c478bd9Sstevel@tonic-gate 		op = LF_ISSET(DB_OPFLAGS_MASK);
1507c478bd9Sstevel@tonic-gate 		mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE :
1517c478bd9Sstevel@tonic-gate 		    (LF_ISSET(DB_RMW) ? DB_LOCK_IWRITE : DB_LOCK_READ);
1527c478bd9Sstevel@tonic-gate 		if ((ret = lock_get(dbp->dbenv->lk_info, dbc->locker, 0,
1537c478bd9Sstevel@tonic-gate 		    &dbc->lock_dbt, mode, &dbc->mylock)) != 0) {
1547c478bd9Sstevel@tonic-gate 			(void)__db_c_close(dbc);
1557c478bd9Sstevel@tonic-gate 			return (EAGAIN);
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 		if (LF_ISSET(DB_RMW))
1587c478bd9Sstevel@tonic-gate 			F_SET(dbc, DBC_RMW);
1597c478bd9Sstevel@tonic-gate 		if (op == DB_WRITELOCK)
1607c478bd9Sstevel@tonic-gate 			F_SET(dbc, DBC_WRITER);
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	*dbcp = dbc;
1647c478bd9Sstevel@tonic-gate 	return (0);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate err:	__os_free(dbc, sizeof(*dbc));
1677c478bd9Sstevel@tonic-gate 	return (ret);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * __db_c_close --
1727c478bd9Sstevel@tonic-gate  *	Close the cursor (recycle for later use).
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate static int
__db_c_close(dbc)1757c478bd9Sstevel@tonic-gate __db_c_close(dbc)
1767c478bd9Sstevel@tonic-gate 	DBC *dbc;
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	DB *dbp;
1797c478bd9Sstevel@tonic-gate 	int ret, t_ret;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	dbp = dbc->dbp;
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	DB_PANIC_CHECK(dbp);
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	ret = 0;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/*
1887c478bd9Sstevel@tonic-gate 	 * We cannot release the lock until after we've called the
1897c478bd9Sstevel@tonic-gate 	 * access method specific routine, since btrees may have pending
1907c478bd9Sstevel@tonic-gate 	 * deletes.
1917c478bd9Sstevel@tonic-gate 	 */
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/* Remove the cursor from the active queue. */
1947c478bd9Sstevel@tonic-gate 	DB_THREAD_LOCK(dbp);
1957c478bd9Sstevel@tonic-gate 	TAILQ_REMOVE(&dbp->active_queue, dbc, links);
1967c478bd9Sstevel@tonic-gate 	DB_THREAD_UNLOCK(dbp);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	/* Call the access specific cursor close routine. */
1997c478bd9Sstevel@tonic-gate 	if ((t_ret = dbc->c_am_close(dbc)) != 0 && ret == 0)
2007c478bd9Sstevel@tonic-gate 		t_ret = ret;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/* Release the lock. */
2037c478bd9Sstevel@tonic-gate 	if (F_ISSET(dbc->dbp, DB_AM_CDB) && dbc->mylock != LOCK_INVALID) {
2047c478bd9Sstevel@tonic-gate 		ret = lock_put(dbc->dbp->dbenv->lk_info, dbc->mylock);
2057c478bd9Sstevel@tonic-gate 		dbc->mylock = LOCK_INVALID;
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/* Clean up the cursor. */
2097c478bd9Sstevel@tonic-gate 	dbc->flags = 0;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate #ifdef DEBUG
2127c478bd9Sstevel@tonic-gate 	/*
2137c478bd9Sstevel@tonic-gate 	 * Check for leftover locks, unless we're running with transactions.
2147c478bd9Sstevel@tonic-gate 	 *
2157c478bd9Sstevel@tonic-gate 	 * If we're running tests, display any locks currently held.  It's
2167c478bd9Sstevel@tonic-gate 	 * possible that some applications may hold locks for long periods,
2177c478bd9Sstevel@tonic-gate 	 * e.g., conference room locks, but the DB tests should never close
2187c478bd9Sstevel@tonic-gate 	 * holding locks.
2197c478bd9Sstevel@tonic-gate 	 */
2207c478bd9Sstevel@tonic-gate 	if (F_ISSET(dbp, DB_AM_LOCKING) && dbc->lid == dbc->locker) {
2217c478bd9Sstevel@tonic-gate 		DB_LOCKREQ request;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 		request.op = DB_LOCK_DUMP;
2247c478bd9Sstevel@tonic-gate 		if ((t_ret = lock_vec(dbp->dbenv->lk_info,
2257c478bd9Sstevel@tonic-gate 		    dbc->locker, 0, &request, 1, NULL)) != 0 && ret == 0)
2267c478bd9Sstevel@tonic-gate 			ret = EAGAIN;
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate #endif
2297c478bd9Sstevel@tonic-gate 	/* Move the cursor to the free queue. */
2307c478bd9Sstevel@tonic-gate 	DB_THREAD_LOCK(dbp);
2317c478bd9Sstevel@tonic-gate 	TAILQ_INSERT_TAIL(&dbp->free_queue, dbc, links);
2327c478bd9Sstevel@tonic-gate 	DB_THREAD_UNLOCK(dbp);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	return (ret);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate #ifdef DEBUG
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * __db_cprint --
2407c478bd9Sstevel@tonic-gate  *	Display the current cursor list.
2417c478bd9Sstevel@tonic-gate  *
2427c478bd9Sstevel@tonic-gate  * PUBLIC: int __db_cprint __P((DB *));
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate int
__db_cprint(dbp)2457c478bd9Sstevel@tonic-gate __db_cprint(dbp)
2467c478bd9Sstevel@tonic-gate 	DB *dbp;
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	static const FN fn[] = {
2497c478bd9Sstevel@tonic-gate 		{ DBC_RECOVER, 	"recover" },
2507c478bd9Sstevel@tonic-gate 		{ DBC_RMW, 	"read-modify-write" },
2517c478bd9Sstevel@tonic-gate 		{ 0 },
2527c478bd9Sstevel@tonic-gate 	};
2537c478bd9Sstevel@tonic-gate 	DBC *dbc;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	DB_THREAD_LOCK(dbp);
2567c478bd9Sstevel@tonic-gate 	for (dbc = TAILQ_FIRST(&dbp->active_queue);
2577c478bd9Sstevel@tonic-gate 	    dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
2587c478bd9Sstevel@tonic-gate 		fprintf(stderr,
2597c478bd9Sstevel@tonic-gate 		    "%#0x: dbp: %#0x txn: %#0x lid: %lu locker: %lu",
2607c478bd9Sstevel@tonic-gate 		    (u_int)dbc, (u_int)dbc->dbp, (u_int)dbc->txn,
2617c478bd9Sstevel@tonic-gate 		    (u_long)dbc->lid, (u_long)dbc->locker);
2627c478bd9Sstevel@tonic-gate 		__db_prflags(dbc->flags, fn, stderr);
2637c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\n");
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 	DB_THREAD_UNLOCK(dbp);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	return (0);
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * __db_c_destroy --
2737c478bd9Sstevel@tonic-gate  *	Destroy the cursor.
2747c478bd9Sstevel@tonic-gate  *
2757c478bd9Sstevel@tonic-gate  * PUBLIC: int __db_c_destroy __P((DBC *));
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate int
__db_c_destroy(dbc)2787c478bd9Sstevel@tonic-gate __db_c_destroy(dbc)
2797c478bd9Sstevel@tonic-gate 	DBC *dbc;
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	DB *dbp;
2827c478bd9Sstevel@tonic-gate 	int ret;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	dbp = dbc->dbp;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/* Remove the cursor from the free queue. */
2877c478bd9Sstevel@tonic-gate 	DB_THREAD_LOCK(dbp);
2887c478bd9Sstevel@tonic-gate 	TAILQ_REMOVE(&dbp->free_queue, dbc, links);
2897c478bd9Sstevel@tonic-gate 	DB_THREAD_UNLOCK(dbp);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/* Call the access specific cursor destroy routine. */
2927c478bd9Sstevel@tonic-gate 	ret = dbc->c_am_destroy == NULL ? 0 : dbc->c_am_destroy(dbc);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* Free up allocated memory. */
2957c478bd9Sstevel@tonic-gate 	if (dbc->rkey.data != NULL)
2967c478bd9Sstevel@tonic-gate 		__os_free(dbc->rkey.data, dbc->rkey.ulen);
2977c478bd9Sstevel@tonic-gate 	if (dbc->rdata.data != NULL)
2987c478bd9Sstevel@tonic-gate 		__os_free(dbc->rdata.data, dbc->rdata.ulen);
2997c478bd9Sstevel@tonic-gate 	__os_free(dbc, sizeof(*dbc));
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	return (0);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * db_fd --
3067c478bd9Sstevel@tonic-gate  *	Return a file descriptor for flock'ing.
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate static int
__db_fd(dbp,fdp)3097c478bd9Sstevel@tonic-gate __db_fd(dbp, fdp)
3107c478bd9Sstevel@tonic-gate         DB *dbp;
3117c478bd9Sstevel@tonic-gate 	int *fdp;
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate 	DB_PANIC_CHECK(dbp);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * XXX
3177c478bd9Sstevel@tonic-gate 	 * Truly spectacular layering violation.
3187c478bd9Sstevel@tonic-gate 	 */
3197c478bd9Sstevel@tonic-gate 	return (__mp_xxx_fd(dbp->mpf, fdp));
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * __db_get --
3247c478bd9Sstevel@tonic-gate  *	Return a key/data pair.
3257c478bd9Sstevel@tonic-gate  */
3267c478bd9Sstevel@tonic-gate static int
__db_get(dbp,txn,key,data,flags)3277c478bd9Sstevel@tonic-gate __db_get(dbp, txn, key, data, flags)
3287c478bd9Sstevel@tonic-gate 	DB *dbp;
3297c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
3307c478bd9Sstevel@tonic-gate 	DBT *key, *data;
3317c478bd9Sstevel@tonic-gate 	u_int32_t flags;
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	DBC *dbc;
3347c478bd9Sstevel@tonic-gate 	int ret, t_ret;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	DB_PANIC_CHECK(dbp);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	if ((ret = __db_getchk(dbp, key, data, flags)) != 0)
3397c478bd9Sstevel@tonic-gate 		return (ret);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
3427c478bd9Sstevel@tonic-gate 		return (ret);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	DEBUG_LREAD(dbc, txn, "__db_get", key, NULL, flags);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	ret = dbc->c_get(dbc, key, data,
3477c478bd9Sstevel@tonic-gate 	    flags == 0 || flags == DB_RMW ? flags | DB_SET : flags);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
3507c478bd9Sstevel@tonic-gate 		ret = t_ret;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	return (ret);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate /*
3567c478bd9Sstevel@tonic-gate  * __db_put --
3577c478bd9Sstevel@tonic-gate  *	Store a key/data pair.
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate static int
__db_put(dbp,txn,key,data,flags)3607c478bd9Sstevel@tonic-gate __db_put(dbp, txn, key, data, flags)
3617c478bd9Sstevel@tonic-gate 	DB *dbp;
3627c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
3637c478bd9Sstevel@tonic-gate 	DBT *key, *data;
3647c478bd9Sstevel@tonic-gate 	u_int32_t flags;
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate 	DBC *dbc;
3677c478bd9Sstevel@tonic-gate 	DBT tdata;
3687c478bd9Sstevel@tonic-gate 	int ret, t_ret;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	DB_PANIC_CHECK(dbp);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if ((ret = __db_putchk(dbp, key, data,
3737c478bd9Sstevel@tonic-gate 	    flags, F_ISSET(dbp, DB_AM_RDONLY), F_ISSET(dbp, DB_AM_DUP))) != 0)
3747c478bd9Sstevel@tonic-gate 		return (ret);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
3777c478bd9Sstevel@tonic-gate 		return (ret);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	DEBUG_LWRITE(dbc, txn, "__db_put", key, data, flags);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (flags == DB_NOOVERWRITE) {
3827c478bd9Sstevel@tonic-gate 		/*
3837c478bd9Sstevel@tonic-gate 		 * Set DB_DBT_USERMEM, this might be a threaded application and
3847c478bd9Sstevel@tonic-gate 		 * the flags checking will catch us.  We don't want the actual
3857c478bd9Sstevel@tonic-gate 		 * data, so request a partial of length 0.
3867c478bd9Sstevel@tonic-gate 		 */
3877c478bd9Sstevel@tonic-gate 		memset(&tdata, 0, sizeof(tdata));
3887c478bd9Sstevel@tonic-gate 		F_SET(&tdata, DB_DBT_USERMEM | DB_DBT_PARTIAL);
3897c478bd9Sstevel@tonic-gate 		if ((ret = dbc->c_get(dbc, key, &tdata, DB_SET | DB_RMW)) == 0)
3907c478bd9Sstevel@tonic-gate 			ret = DB_KEYEXIST;
3917c478bd9Sstevel@tonic-gate 		else if (ret == DB_NOTFOUND)
3927c478bd9Sstevel@tonic-gate 			ret = 0;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	if (ret == 0)
3957c478bd9Sstevel@tonic-gate 		ret = dbc->c_put(dbc, key, data, DB_KEYLAST);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
3987c478bd9Sstevel@tonic-gate 		ret = t_ret;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return (ret);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate  * __db_sync --
4057c478bd9Sstevel@tonic-gate  *	Flush the database cache.
4067c478bd9Sstevel@tonic-gate  *
4077c478bd9Sstevel@tonic-gate  * PUBLIC: int __db_sync __P((DB *, u_int32_t));
4087c478bd9Sstevel@tonic-gate  */
4097c478bd9Sstevel@tonic-gate int
__db_sync(dbp,flags)4107c478bd9Sstevel@tonic-gate __db_sync(dbp, flags)
4117c478bd9Sstevel@tonic-gate 	DB *dbp;
4127c478bd9Sstevel@tonic-gate 	u_int32_t flags;
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	int ret;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	DB_PANIC_CHECK(dbp);
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if ((ret = __db_syncchk(dbp, flags)) != 0)
4197c478bd9Sstevel@tonic-gate 		return (ret);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/* If it wasn't possible to modify the file, we're done. */
4227c478bd9Sstevel@tonic-gate 	if (F_ISSET(dbp, DB_AM_INMEM | DB_AM_RDONLY))
4237c478bd9Sstevel@tonic-gate 		return (0);
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/* Flush any dirty pages from the cache to the backing file. */
4267c478bd9Sstevel@tonic-gate 	if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE)
4277c478bd9Sstevel@tonic-gate 		ret = 0;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	return (ret);
4307c478bd9Sstevel@tonic-gate }
431