summaryrefslogtreecommitdiff
path: root/src/dbinc/db_am.h
blob: f34578c4f2595708cafe65a6e843bf337d698f36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 1996, 2012 Oracle and/or its affiliates.  All rights reserved.
 *
 * $Id$
 */
#ifndef _DB_AM_H_
#define	_DB_AM_H_

#if defined(__cplusplus)
extern "C" {
#endif

struct __db_foreign_info; \
			typedef struct __db_foreign_info DB_FOREIGN_INFO;

/*
 * Keep track of information for foreign keys.  Used to maintain a linked list
 * of 'primary' DBs which reference this 'foreign' DB.
 */
struct __db_foreign_info {
	DB *dbp;
	u_int32_t flags;
	int (*callback) __P((DB *, const DBT *, DBT *, const DBT *, int *));

	/*
	 * List entries for foreign key.
	 *
	 * !!!
	 * Explicit representations of structures from queue.h.
	 * LIST_ENTRY(__db) s_links;
	 */
	struct {
		struct __db_foreign_info *le_next;
		struct __db_foreign_info **le_prev;
	} f_links;
};

/*
 * IS_ENV_AUTO_COMMIT --
 *	Auto-commit test for enviroment operations: DbEnv::{open,remove,rename}
 */
#define	IS_ENV_AUTO_COMMIT(env, txn, flags)				\
	(LF_ISSET(DB_AUTO_COMMIT) ||					\
	    (((txn) == NULL || F_ISSET((txn), TXN_FAMILY)) &&		\
	    F_ISSET((env)->dbenv, DB_ENV_AUTO_COMMIT) &&		\
	    !LF_ISSET(DB_NO_AUTO_COMMIT)))

/*
 * IS_DB_AUTO_COMMIT --
 *	Auto-commit test for database operations.
 */
#define	IS_DB_AUTO_COMMIT(dbp, txn)					\
	(((txn) == NULL || F_ISSET((txn), TXN_FAMILY)) &&		\
	    F_ISSET((dbp), DB_AM_TXN))

/*
 * STRIP_AUTO_COMMIT --
 *	Releases after 4.3 no longer requires DB operations to specify the
 *	AUTO_COMMIT flag, but the API continues to allow it to be specified.
 */
#define	STRIP_AUTO_COMMIT(f)	FLD_CLR((f), DB_AUTO_COMMIT)

/* DB recovery operation codes. */
#define	DB_ADD_DUP	1
#define	DB_REM_DUP	2
#define	DB_ADD_BIG	3
#define	DB_REM_BIG	4
#define	DB_ADD_PAGE_COMPAT	5	/* Compatibility for 4.2 db_relink */
#define	DB_REM_PAGE_COMPAT	6	/* Compatibility for 4.2 db_relink */
#define	DB_APPEND_BIG	7
#define	DB_ADD_HEAP	8
#define	DB_REM_HEAP	9

#define OP_MODE_SHIFT   8
#define OP_PAGE_MASK    0xff

#define OP_SET(mode, page)	(((mode) << OP_MODE_SHIFT) | (TYPE(page)))
#define OP_MODE_GET(mode)	((mode) >> OP_MODE_SHIFT)
#define OP_PAGE_GET(mode)	((mode) & OP_PAGE_MASK)


/*
 * Standard initialization and shutdown macros for all recovery functions.
 */
#define	REC_INTRO(func, ip, do_cursor) do {				\
	argp = NULL;							\
	dbc = NULL;							\
	file_dbp = NULL;						\
	COMPQUIET(mpf, NULL);	/* Not all recovery routines use mpf. */\
	if ((ret = func(env, &file_dbp,					\
	    (info != NULL) ? ((DB_TXNHEAD *)info)->td : NULL,		\
	    dbtp->data, &argp)) != 0) {					\
		if (ret	== DB_DELETED) {				\
			ret = 0;					\
			goto done;					\
		}							\
		goto out;						\
	}								\
	if (do_cursor) {						\
		if ((ret = __db_cursor(file_dbp,			\
		    ip, NULL, &dbc, DB_RECOVER)) != 0)			\
			goto out;					\
	}								\
	mpf = file_dbp->mpf;						\
} while (0)

#define	REC_CLOSE {							\
	int __t_ret;							\
	if (argp != NULL)						\
		__os_free(env, argp);					\
	if (dbc != NULL &&						\
	    (__t_ret = __dbc_close(dbc)) != 0 && ret == 0)		\
		ret = __t_ret;						\
	}								\
	return (ret)

/*
 * No-op versions of the same macros.
 */
#define	REC_NOOP_INTRO(func) do {					\
	argp = NULL;							\
	if ((ret = func(env, dbtp->data, &argp)) != 0)		\
		return (ret);						\
} while (0)
#define	REC_NOOP_CLOSE							\
	if (argp != NULL)						\
		__os_free(env, argp);					\
	return (ret)

/*
 * Macro for reading pages during recovery.  In most cases we
 * want to avoid an error if the page is not found during rollback.
 */
#define	REC_FGET(mpf, ip, pgno, pagep, cont)				\
	if ((ret = __memp_fget(mpf,					\
	     &(pgno), ip, NULL, 0, pagep)) != 0) {			\
		if (ret != DB_PAGE_NOTFOUND) {				\
			ret = __db_pgerr(file_dbp, pgno, ret);		\
			goto out;					\
		} else							\
			goto cont;					\
	}
#define	REC_DIRTY(mpf, ip, priority, pagep)				\
	if ((ret = __memp_dirty(mpf,					\
	    pagep, ip, NULL, priority, DB_MPOOL_EDIT)) != 0) {		\
		ret = __db_pgerr(file_dbp, PGNO(*(pagep)), ret);	\
		goto out;						\
	}

/*
 * Standard debugging macro for all recovery functions.
 */
#ifdef DEBUG_RECOVER
#define	REC_PRINT(func)							\
	(void)func(env, dbtp, lsnp, op, info);
#else
#define	REC_PRINT(func)
#endif

/*
 * Actions to __db_lget
 */
#define	LCK_ALWAYS		1	/* Lock even for off page dup cursors */
#define	LCK_COUPLE		2	/* Lock Couple */
#define	LCK_COUPLE_ALWAYS	3	/* Lock Couple even in txn. */
#define	LCK_DOWNGRADE		4	/* Downgrade the lock. (internal) */
#define	LCK_ROLLBACK		5	/* Lock even if in rollback */

/*
 * If doing transactions we have to hold the locks associated with a data item
 * from a page for the entire transaction.  However, we don't have to hold the
 * locks associated with walking the tree.  Distinguish between the two so that
 * we don't tie up the internal pages of the tree longer than necessary.
 */
#define	__LPUT(dbc, lock)						\
	__ENV_LPUT((dbc)->env, lock)

#define	__ENV_LPUT(env, lock)						\
	(LOCK_ISSET(lock) ? __lock_put(env, &(lock)) : 0)

/*
 * __TLPUT -- transactional lock put
 *	If the lock is valid then
 *	   If we are not in a transaction put the lock.
 *	   Else if the cursor is doing dirty reads and this was a read then
 *		put the lock.
 *	   Else if the db is supporting dirty reads and this is a write then
 *		downgrade it.
 *	Else do nothing.
 */
#define	__TLPUT(dbc, lock)						\
	(LOCK_ISSET(lock) ? __db_lput(dbc, &(lock)) : 0)

/*
 * Check whether a database is a primary (that is, has associated secondaries).
 */
#define	DB_IS_PRIMARY(dbp) (LIST_FIRST(&dbp->s_secondaries) != NULL)
/*
 * A database should be required to be readonly if it's been explicitly
 * specified as such or if we're a client in a replicated environment
 * and the user did not specify DB_TXN_NOT_DURABLE.
 */
#define	DB_IS_READONLY(dbp)						\
    (F_ISSET(dbp, DB_AM_RDONLY) ||					\
    (IS_REP_CLIENT((dbp)->env) && !F_ISSET((dbp), DB_AM_NOT_DURABLE)))

#ifdef HAVE_COMPRESSION
/*
 * Check whether a database is compressed (btree only)
 */
#define	DB_IS_COMPRESSED(dbp)						\
    (((BTREE *)(dbp)->bt_internal)->bt_compress != NULL)
#endif

/*
 * We copy the key out if there's any chance the key in the database is not
 * the same as the user-specified key.  If there is a custom comparator we
 * return a key, as the user-specified key might be a partial key, containing
 * only the unique identifier.  [#13572] [#15770]
 *
 * The test for (flags != 0) is necessary for Db.{get,pget}, but it's not
 * legal to pass a non-zero flags value to Dbc.{get,pget}.
 *
 * We need to split out the hash component, since it is possible to build
 * without hash support enabled. Which would result in a null pointer access.
 */
#ifdef HAVE_HASH
#define	DB_RETURNS_A_KEY_HASH(dbp)					\
	((HASH *)(dbp)->h_internal)->h_compare != NULL
#else
#define	DB_RETURNS_A_KEY_HASH(dbp)	0
#endif
#define	DB_RETURNS_A_KEY(dbp, flags)					\
	(((flags) != 0 && (flags) != DB_GET_BOTH &&			\
	    (flags) != DB_GET_BOTH_RANGE && (flags) != DB_SET) ||	\
	    ((BTREE *)(dbp)->bt_internal)->bt_compare != __bam_defcmp ||\
	    DB_RETURNS_A_KEY_HASH(dbp))

/*
 * For portability, primary keys that are record numbers are stored in
 * secondaries in the same byte order as the secondary database.  As a
 * consequence, we need to swap the byte order of these keys before attempting
 * to use them for lookups in the primary.  We also need to swap user-supplied
 * primary keys that are used in secondary lookups (for example, with the
 * DB_GET_BOTH flag on a secondary get).
 */
#include "dbinc/db_swap.h"

#define	SWAP_IF_NEEDED(sdbp, pkey)					\
	do {								\
		if (((sdbp)->s_primary->type == DB_QUEUE ||		\
		    (sdbp)->s_primary->type == DB_RECNO) &&		\
		    F_ISSET((sdbp), DB_AM_SWAP))			\
			P_32_SWAP((pkey)->data);			\
	} while (0)

/*
 * Cursor adjustment:
 *	Return the first DB handle in the sorted ENV list of DB
 *	handles that has a matching file ID.
 */
#define	FIND_FIRST_DB_MATCH(env, dbp, tdbp) do {			\
	for ((tdbp) = (dbp);						\
	    TAILQ_PREV((tdbp), __dblist, dblistlinks) != NULL &&	\
	    TAILQ_PREV((tdbp),						\
		__dblist, dblistlinks)->adj_fileid == (dbp)->adj_fileid;\
	    (tdbp) = TAILQ_PREV((tdbp), __dblist, dblistlinks))		\
		;							\
} while (0)

/*
 * Macros used to implement a binary search algorithm. Shared between the
 * btree and hash implementations.
 */
#define	DB_BINARY_SEARCH_FOR(base, limit, nument, adjust)		\
	for (base = 0, limit = (nument) / (db_indx_t)(adjust);		\
	    (limit) != 0; (limit) >>= 1)

#define	DB_BINARY_SEARCH_INCR(index, base, limit, adjust)		\
	index = (base) + (((limit) >> 1) * (adjust))

#define	DB_BINARY_SEARCH_SHIFT_BASE(index, base, limit, adjust)	do {	\
	base = (index) + (adjust);					\
	--(limit);							\
} while (0)

/*
 * Sequence macros, shared between sequence.c and seq_stat.c
 */
#define	SEQ_IS_OPEN(seq)	((seq)->seq_key.data != NULL)

#define	SEQ_ILLEGAL_AFTER_OPEN(seq, name)				\
	if (SEQ_IS_OPEN(seq))						\
		return (__db_mi_open((seq)->seq_dbp->env, name, 1));

#define	SEQ_ILLEGAL_BEFORE_OPEN(seq, name)				\
	if (!SEQ_IS_OPEN(seq))						\
		return (__db_mi_open((seq)->seq_dbp->env, name, 0));

/*
 * Flags to __db_chk_meta.
 */
#define	DB_CHK_META	0x01	/* Checksum the meta page. */
#define	DB_CHK_NOLSN	0x02	/* Don't check the LSN. */
#define	DB_CHK_ONLY	0x04	/* Only do the checksum. */
#define	DB_SKIP_CHK	0x08	/* Don't checksum or decrypt the meta page. */

/*
 * Flags to __db_truncate_page.
 */
#define DB_EXCH_FREE		0x01	/* Free the old page. */
#define DB_EXCH_PARENT		0x02	/* There is a parent to update. */

/* We usually want to do these operations. */
#define DB_EXCH_DEFAULT		(DB_EXCH_FREE | DB_EXCH_PARENT)

#if defined(__cplusplus)
}
#endif

#include "dbinc/db_dispatch.h"
#include "dbinc_auto/db_auto.h"
#include "dbinc_auto/crdel_auto.h"
#include "dbinc_auto/db_ext.h"
#endif /* !_DB_AM_H_ */