1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: db_am.h,v 12.44 2008/05/07 12:27:33 bschmeck Exp $
7 */
8#ifndef _DB_AM_H_
9#define	_DB_AM_H_
10
11#if defined(__cplusplus)
12extern "C" {
13#endif
14
15struct __db_foreign_info; \
16                        typedef struct __db_foreign_info DB_FOREIGN_INFO;
17
18/*
19 * Keep track of information for foreign keys.  Used to maintain a linked list
20 * of 'primary' DBs which reference this 'foreign' DB.
21 */
22struct __db_foreign_info {
23	DB *dbp;
24	u_int32_t flags;
25	int (*callback) __P((DB *, const DBT *, DBT *, const DBT *, int *));
26
27	/*
28	 * List entries for foreign key.
29	 *
30	 * !!!
31	 * Explicit representations of structures from queue.h.
32	 * LIST_ENTRY(__db) s_links;
33	 */
34	struct {
35		struct __db_foreign_info *le_next;
36		struct __db_foreign_info **le_prev;
37	} f_links;
38};
39
40/*
41 * IS_ENV_AUTO_COMMIT --
42 *	Auto-commit test for enviroment operations: DbEnv::{open,remove,rename}
43 */
44#define	IS_ENV_AUTO_COMMIT(env, txn, flags)				\
45	(LF_ISSET(DB_AUTO_COMMIT) || ((txn) == NULL &&			\
46	    F_ISSET((env)->dbenv, DB_ENV_AUTO_COMMIT) &&		\
47	    !LF_ISSET(DB_NO_AUTO_COMMIT)))
48
49/*
50 * IS_DB_AUTO_COMMIT --
51 *	Auto-commit test for database operations.
52 */
53#define	IS_DB_AUTO_COMMIT(dbp, txn)					\
54	    ((txn) == NULL && F_ISSET((dbp), DB_AM_TXN))
55
56/*
57 * STRIP_AUTO_COMMIT --
58 *	Releases after 4.3 no longer requires DB operations to specify the
59 *	AUTO_COMMIT flag, but the API continues to allow it to be specified.
60 */
61#define	STRIP_AUTO_COMMIT(f)	FLD_CLR((f), DB_AUTO_COMMIT)
62
63/* DB recovery operation codes. */
64#define	DB_ADD_DUP	1
65#define	DB_REM_DUP	2
66#define	DB_ADD_BIG	3
67#define	DB_REM_BIG	4
68#define	DB_ADD_PAGE_COMPAT	5	/* Compatibility for 4.2 db_relink */
69#define	DB_REM_PAGE_COMPAT	6	/* Compatibility for 4.2 db_relink */
70
71/*
72 * Standard initialization and shutdown macros for all recovery functions.
73 */
74#define	REC_INTRO(func, ip, do_cursor) do {				\
75	argp = NULL;							\
76	dbc = NULL;							\
77	file_dbp = NULL;						\
78	COMPQUIET(mpf, NULL);	/* Not all recovery routines use mpf. */\
79	if ((ret = func(env, &file_dbp,					\
80	    (info != NULL) ? ((DB_TXNHEAD *)info)->td : NULL,		\
81	    dbtp->data, &argp)) != 0) {					\
82		if (ret	== DB_DELETED) {				\
83			ret = 0;					\
84			goto done;					\
85		}							\
86		goto out;						\
87	}								\
88	if (do_cursor) {						\
89		if ((ret =						\
90		    __db_cursor(file_dbp, ip, NULL, &dbc, 0)) != 0)	\
91			goto out;					\
92		F_SET(dbc, DBC_RECOVER);				\
93	}								\
94	mpf = file_dbp->mpf;						\
95} while (0)
96
97#define	REC_CLOSE {							\
98	int __t_ret;							\
99	if (argp != NULL)						\
100		__os_free(env, argp);					\
101	if (dbc != NULL &&						\
102	    (__t_ret = __dbc_close(dbc)) != 0 && ret == 0)		\
103		ret = __t_ret;						\
104	}								\
105	return (ret)
106
107/*
108 * No-op versions of the same macros.
109 */
110#define	REC_NOOP_INTRO(func) do {					\
111	argp = NULL;							\
112	if ((ret = func(env, dbtp->data, &argp)) != 0)		\
113		return (ret);						\
114} while (0)
115#define	REC_NOOP_CLOSE							\
116	if (argp != NULL)						\
117		__os_free(env, argp);					\
118	return (ret)
119
120/*
121 * Macro for reading pages during recovery.  In most cases we
122 * want to avoid an error if the page is not found during rollback.
123 */
124#define	REC_FGET(mpf, ip, pgno, pagep, cont)				\
125	if ((ret = __memp_fget(mpf,					\
126	     &(pgno), ip, NULL, 0, pagep)) != 0) { 			\
127		if (ret != DB_PAGE_NOTFOUND) {				\
128			ret = __db_pgerr(file_dbp, pgno, ret);		\
129			goto out;					\
130		} else							\
131			goto cont;					\
132	}
133#define	REC_DIRTY(mpf, ip, priority, pagep)				\
134	if ((ret = __memp_dirty(mpf,					\
135	    pagep, ip, NULL, priority, DB_MPOOL_EDIT)) != 0) {		\
136		ret = __db_pgerr(file_dbp, PGNO(*(pagep)), ret);	\
137		goto out;						\
138	}
139
140/*
141 * Standard debugging macro for all recovery functions.
142 */
143#ifdef DEBUG_RECOVER
144#define	REC_PRINT(func)							\
145	(void)func(env, dbtp, lsnp, op, info);
146#else
147#define	REC_PRINT(func)
148#endif
149
150/*
151 * Actions to __db_lget
152 */
153#define	LCK_ALWAYS		1	/* Lock even for off page dup cursors */
154#define	LCK_COUPLE		2	/* Lock Couple */
155#define	LCK_COUPLE_ALWAYS	3	/* Lock Couple even in txn. */
156#define	LCK_DOWNGRADE		4	/* Downgrade the lock. (internal) */
157#define	LCK_ROLLBACK		5	/* Lock even if in rollback */
158
159/*
160 * If doing transactions we have to hold the locks associated with a data item
161 * from a page for the entire transaction.  However, we don't have to hold the
162 * locks associated with walking the tree.  Distinguish between the two so that
163 * we don't tie up the internal pages of the tree longer than necessary.
164 */
165#define	__LPUT(dbc, lock)						\
166	__ENV_LPUT((dbc)->env, lock)
167
168#define	__ENV_LPUT(env, lock)						\
169	(LOCK_ISSET(lock) ? __lock_put(env, &(lock)) : 0)
170
171/*
172 * __TLPUT -- transactional lock put
173 *	If the lock is valid then
174 *	   If we are not in a transaction put the lock.
175 *	   Else if the cursor is doing dirty reads and this was a read then
176 *		put the lock.
177 *	   Else if the db is supporting dirty reads and this is a write then
178 *		downgrade it.
179 *	Else do nothing.
180 */
181#define	__TLPUT(dbc, lock)						\
182	(LOCK_ISSET(lock) ? __db_lput(dbc, &(lock)) : 0)
183
184/*
185 * A database should be required to be readonly if it's been explicitly
186 * specified as such or if we're a client in a replicated environment
187 * and the user did not specify DB_TXN_NOT_DURABLE.
188 */
189#define	DB_IS_READONLY(dbp)						\
190    (F_ISSET(dbp, DB_AM_RDONLY) ||					\
191    (IS_REP_CLIENT((dbp)->env) && !F_ISSET((dbp), DB_AM_NOT_DURABLE)))
192
193/*
194 * We copy the key out if there's any chance the key in the database is not
195 * the same as the user-specified key.  If there is a custom comparator we
196 * return a key, as the user-specified key might be a partial key, containing
197 * only the unique identifier.  [#13572] [#15770]
198 *
199 * The test for (flags != 0) is necessary for Db.{get,pget}, but it's not
200 * legal to pass a non-zero flags value to Dbc.{get,pget}.
201 *
202 * We need to split out the hash component, since it is possible to build
203 * without hash support enabled. Which would result in a null pointer access.
204 */
205#ifdef HAVE_HASH
206#define DB_RETURNS_A_KEY_HASH(dbp)					\
207	((HASH *)(dbp)->h_internal)->h_compare != NULL
208#else
209#define DB_RETURNS_A_KEY_HASH(dbp)	0
210#endif
211#define	DB_RETURNS_A_KEY(dbp, flags)					\
212	(((flags) != 0 && (flags) != DB_GET_BOTH &&			\
213	    (flags) != DB_GET_BOTH_RANGE && (flags) != DB_SET) ||	\
214	    ((BTREE *)(dbp)->bt_internal)->bt_compare != __bam_defcmp ||\
215	    DB_RETURNS_A_KEY_HASH(dbp))
216
217/*
218 * For portability, primary keys that are record numbers are stored in
219 * secondaries in the same byte order as the secondary database.  As a
220 * consequence, we need to swap the byte order of these keys before attempting
221 * to use them for lookups in the primary.  We also need to swap user-supplied
222 * primary keys that are used in secondary lookups (for example, with the
223 * DB_GET_BOTH flag on a secondary get).
224 */
225#include "dbinc/db_swap.h"
226
227#define	SWAP_IF_NEEDED(sdbp, pkey)					\
228	do {								\
229		if (((sdbp)->s_primary->type == DB_QUEUE ||		\
230		    (sdbp)->s_primary->type == DB_RECNO) &&		\
231		    F_ISSET((sdbp), DB_AM_SWAP))			\
232			P_32_SWAP((pkey)->data);			\
233	} while (0)
234
235/*
236 * Cursor adjustment:
237 *	Return the first DB handle in the sorted ENV list of DB
238 *	handles that has a matching file ID.
239 */
240#define	FIND_FIRST_DB_MATCH(env, dbp, tdbp) do {			\
241	for ((tdbp) = (dbp);						\
242	    TAILQ_PREV((tdbp), __dblist, dblistlinks) != NULL &&	\
243	    TAILQ_PREV((tdbp),						\
244		__dblist, dblistlinks)->adj_fileid == (dbp)->adj_fileid;\
245	    (tdbp) = TAILQ_PREV((tdbp), __dblist, dblistlinks))		\
246		;							\
247} while (0)
248
249/*
250 * Macros used to implement a binary search algorithm. Shared between the
251 * btree and hash implementations.
252 */
253#define	DB_BINARY_SEARCH_FOR(base, limit, page, adjust)			\
254	for (base = 0, limit = NUM_ENT(page) / (db_indx_t)(adjust);	\
255	    (limit) != 0; (limit) >>= 1)
256
257#define	DB_BINARY_SEARCH_INCR(index, base, limit, adjust)		\
258	index = (base) + (((limit) >> 1) * (adjust))
259
260#define	DB_BINARY_SEARCH_SHIFT_BASE(index, base, limit, adjust)	do {	\
261	base = (index) + (adjust);					\
262	--(limit);							\
263} while (0)
264
265/*
266 * Sequence macros, shared between sequence.c and seq_stat.c
267 */
268#define	SEQ_IS_OPEN(seq)	((seq)->seq_key.data != NULL)
269
270#define	SEQ_ILLEGAL_AFTER_OPEN(seq, name)				\
271	if (SEQ_IS_OPEN(seq))						\
272		return (__db_mi_open((seq)->seq_dbp->env, name, 1));
273
274#define	SEQ_ILLEGAL_BEFORE_OPEN(seq, name)				\
275	if (!SEQ_IS_OPEN(seq))						\
276		return (__db_mi_open((seq)->seq_dbp->env, name, 0));
277
278/*
279 * Flags to __db_chk_meta.
280 */
281#define	DB_CHK_META	0x01	/* Checksum the meta page. */
282#define	DB_CHK_NOLSN	0x02	/* Don't check the LSN. */
283
284#if defined(__cplusplus)
285}
286#endif
287
288#include "dbinc/db_dispatch.h"
289#include "dbinc_auto/db_auto.h"
290#include "dbinc_auto/crdel_auto.h"
291#include "dbinc_auto/db_ext.h"
292#endif /* !_DB_AM_H_ */
293