1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999,2008 Oracle.  All rights reserved.
5 *
6 * $Id: log_method.c,v 12.19 2008/05/02 16:35:31 mbrey Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/log.h"
13
14/*
15 * __log_env_create --
16 *	Log specific initialization of the DB_ENV structure.
17 *
18 * PUBLIC: int __log_env_create __P((DB_ENV *));
19 */
20int
21__log_env_create(dbenv)
22	DB_ENV *dbenv;
23{
24	/*
25	 * !!!
26	 * Our caller has not yet had the opportunity to reset the panic
27	 * state or turn off mutex locking, and so we can neither check
28	 * the panic state or acquire a mutex in the DB_ENV create path.
29	 */
30	dbenv->lg_bsize = 0;
31	dbenv->lg_regionmax = LG_BASE_REGION_SIZE;
32
33	return (0);
34}
35
36/*
37 * __log_env_destroy --
38 *	Log specific destruction of the DB_ENV structure.
39 *
40 * PUBLIC: void __log_env_destroy __P((DB_ENV *));
41 */
42void
43__log_env_destroy(dbenv)
44	DB_ENV *dbenv;
45{
46	COMPQUIET(dbenv, NULL);
47}
48
49/*
50 * PUBLIC: int __log_get_lg_bsize __P((DB_ENV *, u_int32_t *));
51 */
52int
53__log_get_lg_bsize(dbenv, lg_bsizep)
54	DB_ENV *dbenv;
55	u_int32_t *lg_bsizep;
56{
57	ENV *env;
58
59	env = dbenv->env;
60
61	ENV_NOT_CONFIGURED(env,
62	    env->lg_handle, "DB_ENV->get_lg_bsize", DB_INIT_LOG);
63
64	if (LOGGING_ON(env)) {
65		/* Cannot be set after open, no lock required to read. */
66		*lg_bsizep =
67		    ((LOG *)env->lg_handle->reginfo.primary)->buffer_size;
68	} else
69		*lg_bsizep = dbenv->lg_bsize;
70	return (0);
71}
72
73/*
74 * __log_set_lg_bsize --
75 *	DB_ENV->set_lg_bsize.
76 *
77 * PUBLIC: int __log_set_lg_bsize __P((DB_ENV *, u_int32_t));
78 */
79int
80__log_set_lg_bsize(dbenv, lg_bsize)
81	DB_ENV *dbenv;
82	u_int32_t lg_bsize;
83{
84	ENV *env;
85
86	env = dbenv->env;
87
88	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_lg_bsize");
89
90	dbenv->lg_bsize = lg_bsize;
91	return (0);
92}
93
94/*
95 * PUBLIC: int __log_get_lg_filemode __P((DB_ENV *, int *));
96 */
97int
98__log_get_lg_filemode(dbenv, lg_modep)
99	DB_ENV *dbenv;
100	int *lg_modep;
101{
102	DB_LOG *dblp;
103	DB_THREAD_INFO *ip;
104	ENV *env;
105
106	env = dbenv->env;
107
108	ENV_NOT_CONFIGURED(env,
109	    env->lg_handle, "DB_ENV->get_lg_filemode", DB_INIT_LOG);
110
111	if (LOGGING_ON(env)) {
112		dblp = env->lg_handle;
113		ENV_ENTER(env, ip);
114		LOG_SYSTEM_LOCK(env);
115		*lg_modep = ((LOG *)dblp->reginfo.primary)->filemode;
116		LOG_SYSTEM_UNLOCK(env);
117		ENV_LEAVE(env, ip);
118	} else
119		*lg_modep = dbenv->lg_filemode;
120
121	return (0);
122}
123
124/*
125 * __log_set_lg_filemode --
126 *	DB_ENV->set_lg_filemode.
127 *
128 * PUBLIC: int __log_set_lg_filemode __P((DB_ENV *, int));
129 */
130int
131__log_set_lg_filemode(dbenv, lg_mode)
132	DB_ENV *dbenv;
133	int lg_mode;
134{
135	DB_LOG *dblp;
136	DB_THREAD_INFO *ip;
137	ENV *env;
138	LOG *lp;
139
140	env = dbenv->env;
141
142	ENV_NOT_CONFIGURED(env,
143	    env->lg_handle, "DB_ENV->set_lg_filemode", DB_INIT_LOG);
144
145	if (LOGGING_ON(env)) {
146		dblp = env->lg_handle;
147		lp = dblp->reginfo.primary;
148		ENV_ENTER(env, ip);
149		LOG_SYSTEM_LOCK(env);
150		lp->filemode = lg_mode;
151		LOG_SYSTEM_UNLOCK(env);
152		ENV_LEAVE(env, ip);
153	} else
154		dbenv->lg_filemode = lg_mode;
155
156	return (0);
157}
158
159/*
160 * PUBLIC: int __log_get_lg_max __P((DB_ENV *, u_int32_t *));
161 */
162int
163__log_get_lg_max(dbenv, lg_maxp)
164	DB_ENV *dbenv;
165	u_int32_t *lg_maxp;
166{
167	DB_LOG *dblp;
168	DB_THREAD_INFO *ip;
169	ENV *env;
170
171	env = dbenv->env;
172
173	ENV_NOT_CONFIGURED(env,
174	    env->lg_handle, "DB_ENV->get_lg_max", DB_INIT_LOG);
175
176	if (LOGGING_ON(env)) {
177		dblp = env->lg_handle;
178		ENV_ENTER(env, ip);
179		LOG_SYSTEM_LOCK(env);
180		*lg_maxp = ((LOG *)dblp->reginfo.primary)->log_nsize;
181		LOG_SYSTEM_UNLOCK(env);
182		ENV_LEAVE(env, ip);
183	} else
184		*lg_maxp = dbenv->lg_size;
185
186	return (0);
187}
188
189/*
190 * __log_set_lg_max --
191 *	DB_ENV->set_lg_max.
192 *
193 * PUBLIC: int __log_set_lg_max __P((DB_ENV *, u_int32_t));
194 */
195int
196__log_set_lg_max(dbenv, lg_max)
197	DB_ENV *dbenv;
198	u_int32_t lg_max;
199{
200	DB_LOG *dblp;
201	DB_THREAD_INFO *ip;
202	ENV *env;
203	LOG *lp;
204	int ret;
205
206	env = dbenv->env;
207	ret = 0;
208
209	ENV_NOT_CONFIGURED(env,
210	    env->lg_handle, "DB_ENV->set_lg_max", DB_INIT_LOG);
211
212	if (LOGGING_ON(env)) {
213		dblp = env->lg_handle;
214		lp = dblp->reginfo.primary;
215		ENV_ENTER(env, ip);
216		if ((ret = __log_check_sizes(env, lg_max, 0)) == 0) {
217			LOG_SYSTEM_LOCK(env);
218			lp->log_nsize = lg_max;
219			LOG_SYSTEM_UNLOCK(env);
220		}
221		ENV_LEAVE(env, ip);
222	} else
223		dbenv->lg_size = lg_max;
224
225	return (ret);
226}
227
228/*
229 * PUBLIC: int __log_get_lg_regionmax __P((DB_ENV *, u_int32_t *));
230 */
231int
232__log_get_lg_regionmax(dbenv, lg_regionmaxp)
233	DB_ENV *dbenv;
234	u_int32_t *lg_regionmaxp;
235{
236	ENV *env;
237
238	env = dbenv->env;
239
240	ENV_NOT_CONFIGURED(env,
241	    env->lg_handle, "DB_ENV->get_lg_regionmax", DB_INIT_LOG);
242
243	if (LOGGING_ON(env)) {
244		/* Cannot be set after open, no lock required to read. */
245		*lg_regionmaxp =
246		    ((LOG *)env->lg_handle->reginfo.primary)->regionmax;
247	} else
248		*lg_regionmaxp = dbenv->lg_regionmax;
249	return (0);
250}
251
252/*
253 * __log_set_lg_regionmax --
254 *	DB_ENV->set_lg_regionmax.
255 *
256 * PUBLIC: int __log_set_lg_regionmax __P((DB_ENV *, u_int32_t));
257 */
258int
259__log_set_lg_regionmax(dbenv, lg_regionmax)
260	DB_ENV *dbenv;
261	u_int32_t lg_regionmax;
262{
263	ENV *env;
264
265	env = dbenv->env;
266
267	ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_lg_regionmax");
268
269					/* Let's not be silly. */
270	if (lg_regionmax != 0 && lg_regionmax < LG_BASE_REGION_SIZE) {
271		__db_errx(env,
272		    "log region size must be >= %d", LG_BASE_REGION_SIZE);
273		return (EINVAL);
274	}
275
276	dbenv->lg_regionmax = lg_regionmax;
277	return (0);
278}
279
280/*
281 * PUBLIC: int __log_get_lg_dir __P((DB_ENV *, const char **));
282 */
283int
284__log_get_lg_dir(dbenv, dirp)
285	DB_ENV *dbenv;
286	const char **dirp;
287{
288	*dirp = dbenv->db_log_dir;
289	return (0);
290}
291
292/*
293 * __log_set_lg_dir --
294 *	DB_ENV->set_lg_dir.
295 *
296 * PUBLIC: int __log_set_lg_dir __P((DB_ENV *, const char *));
297 */
298int
299__log_set_lg_dir(dbenv, dir)
300	DB_ENV *dbenv;
301	const char *dir;
302{
303	ENV *env;
304
305	env = dbenv->env;
306
307	if (dbenv->db_log_dir != NULL)
308		__os_free(env, dbenv->db_log_dir);
309	return (__os_strdup(env, dir, &dbenv->db_log_dir));
310}
311
312/*
313 * __log_get_flags --
314 *	DB_ENV->get_flags.
315 *
316 * PUBLIC: void __log_get_flags __P((DB_ENV *, u_int32_t *));
317 */
318void
319__log_get_flags(dbenv, flagsp)
320	DB_ENV *dbenv;
321	u_int32_t *flagsp;
322{
323	DB_LOG *dblp;
324	ENV *env;
325	LOG *lp;
326	u_int32_t flags;
327
328	env = dbenv->env;
329
330	if ((dblp = env->lg_handle) == NULL)
331		return;
332
333	lp = dblp->reginfo.primary;
334
335	flags = *flagsp;
336	if (lp->db_log_autoremove)
337		LF_SET(DB_LOG_AUTO_REMOVE);
338	else
339		LF_CLR(DB_LOG_AUTO_REMOVE);
340	if (lp->db_log_inmemory)
341		LF_SET(DB_LOG_IN_MEMORY);
342	else
343		LF_CLR(DB_LOG_IN_MEMORY);
344	*flagsp = flags;
345}
346
347/*
348 * __log_set_flags --
349 *	DB_ENV->set_flags.
350 *
351 * PUBLIC: void __log_set_flags __P((ENV *, u_int32_t, int));
352 */
353void
354__log_set_flags(env, flags, on)
355	ENV *env;
356	u_int32_t flags;
357	int on;
358{
359	DB_LOG *dblp;
360	LOG *lp;
361
362	if ((dblp = env->lg_handle) == NULL)
363		return;
364
365	lp = dblp->reginfo.primary;
366
367	if (LF_ISSET(DB_LOG_AUTO_REMOVE))
368		lp->db_log_autoremove = on ? 1 : 0;
369	if (LF_ISSET(DB_LOG_IN_MEMORY))
370		lp->db_log_inmemory = on ? 1 : 0;
371}
372
373/*
374 * List of flags we can handle here.  DB_LOG_INMEMORY must be
375 * processed before creating the region, leave it out for now.
376 */
377#undef	OK_FLAGS
378#define	OK_FLAGS							\
379    (DB_LOG_AUTO_REMOVE | DB_LOG_DIRECT |				\
380    DB_LOG_DSYNC | DB_LOG_IN_MEMORY | DB_LOG_ZERO)
381#ifndef BREW
382static
383#endif
384const FLAG_MAP LogMap[] = {
385	{ DB_LOG_AUTO_REMOVE,	DBLOG_AUTOREMOVE},
386	{ DB_LOG_DIRECT,	DBLOG_DIRECT},
387	{ DB_LOG_DSYNC,		DBLOG_DSYNC},
388	{ DB_LOG_IN_MEMORY,	DBLOG_INMEMORY},
389	{ DB_LOG_ZERO,		DBLOG_ZERO}
390};
391/*
392 * __log_get_config --
393 *	Configure the logging subsystem.
394 *
395 * PUBLIC: int __log_get_config __P((DB_ENV *, u_int32_t, int *));
396 */
397int
398__log_get_config(dbenv, which, onp)
399	DB_ENV *dbenv;
400	u_int32_t which;
401	int *onp;
402{
403	ENV *env;
404	DB_LOG *dblp;
405	u_int32_t flags;
406
407	env = dbenv->env;
408	if (FLD_ISSET(which, ~OK_FLAGS))
409		return (__db_ferr(env, "DB_ENV->log_get_config", 0));
410	dblp = env->lg_handle;
411	ENV_REQUIRES_CONFIG(env, dblp, "DB_ENV->log_get_config", DB_INIT_LOG);
412
413	__env_fetch_flags(LogMap, sizeof(LogMap), &dblp->flags, &flags);
414	__log_get_flags(dbenv, &flags);
415	if (LF_ISSET(which))
416		*onp = 1;
417	else
418		*onp = 0;
419
420	return (0);
421}
422
423/*
424 * __log_set_config --
425 *	Configure the logging subsystem.
426 *
427 * PUBLIC: int __log_set_config __P((DB_ENV *, u_int32_t, int));
428 */
429int
430__log_set_config(dbenv, flags, on)
431	DB_ENV *dbenv;
432	u_int32_t flags;
433	int on;
434{
435	return (__log_set_config_int(dbenv, flags, on, 0));
436}
437/*
438 * __log_set_config_int --
439 *	Configure the logging subsystem.
440 *
441 * PUBLIC: int __log_set_config_int __P((DB_ENV *, u_int32_t, int, int));
442 */
443int
444__log_set_config_int(dbenv, flags, on, in_open)
445	DB_ENV *dbenv;
446	u_int32_t flags;
447	int on;
448	int in_open;
449{
450	ENV *env;
451	DB_LOG *dblp;
452	u_int32_t mapped_flags;
453
454	env = dbenv->env;
455	dblp = env->lg_handle;
456	if (FLD_ISSET(flags, ~OK_FLAGS))
457		return (__db_ferr(env, "DB_ENV->log_set_config", 0));
458	ENV_NOT_CONFIGURED(env, dblp, "DB_ENV->log_set_config", DB_INIT_LOG);
459	if (LF_ISSET(DB_LOG_DIRECT) && __os_support_direct_io() == 0) {
460		__db_errx(env,
461"DB_ENV->log_set_config: direct I/O either not configured or not supported");
462		return (EINVAL);
463	}
464
465	if (LOGGING_ON(env)) {
466		if (!in_open && LF_ISSET(DB_LOG_IN_MEMORY))
467			ENV_ILLEGAL_AFTER_OPEN(env,
468			     "DB_ENV->log_set_config: DB_LOG_IN_MEMORY");
469		__log_set_flags(env, flags, on);
470		mapped_flags = 0;
471		__env_map_flags(LogMap, sizeof(LogMap), &flags, &mapped_flags);
472		if (on)
473			F_SET(dblp, mapped_flags);
474		else
475			F_CLR(dblp, mapped_flags);
476	} else {
477		/*
478		 * DB_LOG_IN_MEMORY, DB_TXN_NOSYNC and DB_TXN_WRITE_NOSYNC
479		 * are mutually incompatible.  If we're setting one of them,
480		 * clear all current settings.
481		 */
482		if (on && LF_ISSET(DB_LOG_IN_MEMORY))
483			F_CLR(dbenv,
484			     DB_ENV_TXN_NOSYNC | DB_ENV_TXN_WRITE_NOSYNC);
485
486		if (on)
487			FLD_SET(dbenv->lg_flags, flags);
488		else
489			FLD_CLR(dbenv->lg_flags, flags);
490	}
491
492	return (0);
493}
494
495/*
496 * __log_check_sizes --
497 *	Makes sure that the log file size and log buffer size are compatible.
498 *
499 * PUBLIC: int __log_check_sizes __P((ENV *, u_int32_t, u_int32_t));
500 */
501int
502__log_check_sizes(env, lg_max, lg_bsize)
503	ENV *env;
504	u_int32_t lg_max;
505	u_int32_t lg_bsize;
506{
507	DB_ENV *dbenv;
508	LOG *lp;
509	int inmem;
510
511	dbenv = env->dbenv;
512
513	if (LOGGING_ON(env)) {
514		lp = env->lg_handle->reginfo.primary;
515		inmem = lp->db_log_inmemory;
516		lg_bsize = lp->buffer_size;
517	} else
518		inmem = (FLD_ISSET(dbenv->lg_flags, DB_LOG_IN_MEMORY) != 0);
519
520	if (inmem) {
521		if (lg_bsize == 0)
522			lg_bsize = LG_BSIZE_INMEM;
523		if (lg_max == 0)
524			lg_max = LG_MAX_INMEM;
525
526		if (lg_bsize <= lg_max) {
527			__db_errx(env,
528		  "in-memory log buffer must be larger than the log file size");
529			return (EINVAL);
530		}
531	}
532
533	return (0);
534}
535