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