1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1998,2008 Oracle.  All rights reserved.
5 *
6 * $Id: debug.h,v 12.19 2008/01/29 01:41:10 bostic Exp $
7 */
8
9#ifndef _DB_DEBUG_H_
10#define	_DB_DEBUG_H_
11
12#if defined(__cplusplus)
13extern "C" {
14#endif
15
16/*
17 * Turn on additional error checking in gcc 3.X.
18 */
19#if !defined(__GNUC__) || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
20#define	__attribute__(s)
21#endif
22
23/*
24 * When running with #DIAGNOSTIC defined, we smash memory and do memory
25 * guarding with a special byte value.
26 */
27#define	CLEAR_BYTE	0xdb
28#define	GUARD_BYTE	0xdc
29
30/*
31 * DB assertions.
32 *
33 * Use __STDC__ rather than STDC_HEADERS, the #e construct is ANSI C specific.
34 */
35#if defined(DIAGNOSTIC) && defined(__STDC__)
36#define	DB_ASSERT(env, e)						\
37	((e) ? (void)0 : __db_assert(env, #e, __FILE__, __LINE__))
38#else
39#define	DB_ASSERT(env, e)
40#endif
41
42/*
43 * "Shut that bloody compiler up!"
44 *
45 * Unused, or not-used-yet variable.  We need to write and then read the
46 * variable, some compilers are too bloody clever by half.
47 */
48#define	COMPQUIET(n, v)	do {					        \
49	(n) = (v);						        \
50	(n) = (n);						        \
51} while (0)
52
53/*
54 * Purify and other run-time tools complain about uninitialized reads/writes
55 * of structure fields whose only purpose is padding, as well as when heap
56 * memory that was never initialized is written to disk.
57 */
58#ifdef	UMRW
59#define	UMRW_SET(v)	(v) = 0
60#else
61#define	UMRW_SET(v)
62#endif
63
64/*
65 * Errors are in one of two areas: a Berkeley DB error, or a system-level
66 * error.  We use db_strerror to translate the former and __os_strerror to
67 * translate the latter.
68 */
69typedef enum {
70	DB_ERROR_NOT_SET=0,
71	DB_ERROR_SET=1,
72	DB_ERROR_SYSTEM=2
73} db_error_set_t;
74
75/*
76 * Message handling.  Use a macro instead of a function because va_list
77 * references to variadic arguments cannot be reset to the beginning of the
78 * variadic argument list (and then rescanned), by functions other than the
79 * original routine that took the variadic list of arguments.
80 */
81#if defined(STDC_HEADERS) || defined(__cplusplus)
82#define	DB_REAL_ERR(dbenv, error, error_set, app_call, fmt) {		\
83	va_list __ap;							\
84									\
85	/* Call the application's callback function, if specified. */	\
86	va_start(__ap, fmt);						\
87	if ((dbenv) != NULL && (dbenv)->db_errcall != NULL)		\
88		__db_errcall(dbenv, error, error_set, fmt, __ap);	\
89	va_end(__ap);							\
90									\
91	/*								\
92	 * If the application specified a file descriptor, write to it.	\
93	 * If we wrote to neither the application's callback routine or	\
94	 * its file descriptor, and it's an application error message	\
95	 * using {DbEnv,Db}.{err,errx} or the application has never	\
96	 * configured an output channel, default by writing to stderr.	\
97	 */								\
98	va_start(__ap, fmt);						\
99	if ((dbenv) == NULL ||						\
100	    (dbenv)->db_errfile != NULL ||				\
101	    ((dbenv)->db_errcall == NULL &&				\
102	    ((app_call) || F_ISSET((dbenv)->env, ENV_NO_OUTPUT_SET))))	\
103		__db_errfile(dbenv, error, error_set, fmt, __ap);	\
104	va_end(__ap);							\
105}
106#else
107#define	DB_REAL_ERR(dbenv, error, error_set, app_call, fmt) {		\
108	va_list __ap;							\
109									\
110	/* Call the application's callback function, if specified. */	\
111	va_start(__ap);							\
112	if ((dbenv) != NULL && (dbenv)->db_errcall != NULL)		\
113		__db_errcall(dbenv, error, error_set, fmt, __ap);	\
114	va_end(__ap);							\
115									\
116	/*								\
117	 * If the application specified a file descriptor, write to it.	\
118	 * If we wrote to neither the application's callback routine or	\
119	 * its file descriptor, and it's an application error message	\
120	 * using {DbEnv,Db}.{err,errx} or the application has never	\
121	 * configured an output channel, default by writing to stderr.	\
122	 */								\
123	va_start(__ap);							\
124	if ((dbenv) == NULL ||						\
125	    (dbenv)->db_errfile != NULL ||				\
126	    ((dbenv)->db_errcall == NULL &&				\
127	    ((app_call) || F_ISSET((dbenv)->env, ENV_NO_OUTPUT_SET))))	\
128		 __db_errfile(env, error, error_set, fmt, __ap); 	\
129	va_end(__ap);							\
130}
131#endif
132#if defined(STDC_HEADERS) || defined(__cplusplus)
133#define	DB_REAL_MSG(dbenv, fmt) {					\
134	va_list __ap;							\
135									\
136	/* Call the application's callback function, if specified. */	\
137	va_start(__ap, fmt);						\
138	if ((dbenv) != NULL && (dbenv)->db_msgcall != NULL)		\
139		__db_msgcall(dbenv, fmt, __ap);				\
140	va_end(__ap);							\
141									\
142	/*								\
143	 * If the application specified a file descriptor, write to it.	\
144	 * If we wrote to neither the application's callback routine or	\
145	 * its file descriptor, write to stdout.			\
146	 */								\
147	va_start(__ap, fmt);						\
148	if ((dbenv) == NULL ||						\
149	    (dbenv)->db_msgfile != NULL ||				\
150	    (dbenv)->db_msgcall == NULL) {				\
151		__db_msgfile(dbenv, fmt, __ap);				\
152	}								\
153	va_end(__ap);							\
154}
155#else
156#define	DB_REAL_MSG(dbenv, fmt) {					\
157	va_list __ap;							\
158									\
159	/* Call the application's callback function, if specified. */	\
160	va_start(__ap);							\
161	if ((dbenv) != NULL && (dbenv)->db_msgcall != NULL)		\
162		__db_msgcall(dbenv, fmt, __ap);				\
163	va_end(__ap);							\
164									\
165	/*								\
166	 * If the application specified a file descriptor, write to it.	\
167	 * If we wrote to neither the application's callback routine or	\
168	 * its file descriptor, write to stdout.			\
169	 */								\
170	va_start(__ap);							\
171	if ((dbenv) == NULL ||						\
172	    (dbenv)->db_msgfile != NULL ||				\
173	    (dbenv)->db_msgcall == NULL) {				\
174		__db_msgfile(dbenv, fmt, __ap);				\
175	}								\
176	va_end(__ap);							\
177}
178#endif
179
180/*
181 * Debugging macro to log operations.
182 *	If DEBUG_WOP is defined, log operations that modify the database.
183 *	If DEBUG_ROP is defined, log operations that read the database.
184 *
185 * D dbp
186 * T txn
187 * O operation (string)
188 * K key
189 * A data
190 * F flags
191 */
192#define	LOG_OP(C, T, O, K, A, F) {					\
193	DB_LSN __lsn;							\
194	DBT __op;							\
195	if (DBC_LOGGING((C))) {						\
196		memset(&__op, 0, sizeof(__op));				\
197		__op.data = O;						\
198		__op.size = strlen(O) + 1;				\
199		(void)__db_debug_log((C)->env, T, &__lsn, 0,		\
200		    &__op, (C)->dbp->log_filename->id, K, A, F);	\
201	}								\
202}
203#ifdef	DEBUG_ROP
204#define	DEBUG_LREAD(C, T, O, K, A, F)	LOG_OP(C, T, O, K, A, F)
205#else
206#define	DEBUG_LREAD(C, T, O, K, A, F)
207#endif
208#ifdef	DEBUG_WOP
209#define	DEBUG_LWRITE(C, T, O, K, A, F)	LOG_OP(C, T, O, K, A, F)
210#else
211#define	DEBUG_LWRITE(C, T, O, K, A, F)
212#endif
213
214/*
215 * Hook for testing recovery at various places in the create/delete paths.
216 * Hook for testing subdb locks.
217 */
218#if CONFIG_TEST
219#define	DB_TEST_SUBLOCKS(env, flags) do {				\
220	if ((env)->test_abort == DB_TEST_SUBDB_LOCKS)			\
221		(flags) |= DB_LOCK_NOWAIT;				\
222} while (0)
223
224#define	DB_ENV_TEST_RECOVERY(env, val, ret, name) do {			\
225	int __ret;							\
226	PANIC_CHECK((env));						\
227	if ((env)->test_copy == (val)) {				\
228		/* COPY the FILE */					\
229		if ((__ret = __db_testcopy((env), NULL, (name))) != 0)	\
230			(ret) = __env_panic((env), __ret);		\
231	}								\
232	if ((env)->test_abort == (val)) {				\
233		/* ABORT the TXN */					\
234		(env)->test_abort = 0;					\
235		(ret) = EINVAL;						\
236		goto db_tr_err;						\
237	}								\
238} while (0)
239
240#define	DB_TEST_RECOVERY(dbp, val, ret, name) do {			\
241	ENV *__env = (dbp)->env;					\
242	int __ret;							\
243	PANIC_CHECK(__env);						\
244	if (__env->test_copy == (val)) {				\
245		/* Copy the file. */					\
246		if (F_ISSET((dbp),					\
247		    DB_AM_OPEN_CALLED) && (dbp)->mpf != NULL)		\
248			(void)__db_sync(dbp);				\
249		if ((__ret =						\
250		    __db_testcopy(__env, (dbp), (name))) != 0)		\
251			(ret) = __env_panic(__env, __ret);		\
252	}								\
253	if (__env->test_abort == (val)) {				\
254		/* Abort the transaction. */				\
255		__env->test_abort = 0;					\
256		(ret) = EINVAL;						\
257		goto db_tr_err;						\
258	}								\
259} while (0)
260
261#define	DB_TEST_RECOVERY_LABEL	db_tr_err:
262
263#define	DB_TEST_WAIT(env, val)						\
264	if ((val) != 0)							\
265		__os_yield((env), (u_long)(val), 0)
266#else
267#define	DB_TEST_SUBLOCKS(env, flags)
268#define	DB_ENV_TEST_RECOVERY(env, val, ret, name)
269#define	DB_TEST_RECOVERY(dbp, val, ret, name)
270#define	DB_TEST_RECOVERY_LABEL
271#define	DB_TEST_WAIT(env, val)
272#endif
273
274#if defined(__cplusplus)
275}
276#endif
277#endif /* !_DB_DEBUG_H_ */
278