1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/log.h"
13#include "dbinc/mp.h"
14
15static int __memp_get_clear_len __P((DB_MPOOLFILE *, u_int32_t *));
16static int __memp_get_lsn_offset __P((DB_MPOOLFILE *, int32_t *));
17static int __memp_get_maxsize __P((DB_MPOOLFILE *, u_int32_t *, u_int32_t *));
18static int __memp_set_maxsize __P((DB_MPOOLFILE *, u_int32_t, u_int32_t));
19static int __memp_get_priority __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY *));
20static int __memp_set_priority __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY));
21
22/*
23 * __memp_fcreate_pp --
24 *	ENV->memp_fcreate pre/post processing.
25 *
26 * PUBLIC: int __memp_fcreate_pp __P((DB_ENV *, DB_MPOOLFILE **, u_int32_t));
27 */
28int
29__memp_fcreate_pp(dbenv, retp, flags)
30	DB_ENV *dbenv;
31	DB_MPOOLFILE **retp;
32	u_int32_t flags;
33{
34	DB_THREAD_INFO *ip;
35	ENV *env;
36	int ret;
37
38	env = dbenv->env;
39
40	/* Validate arguments. */
41	if ((ret = __db_fchk(env, "DB_ENV->memp_fcreate", flags, 0)) != 0)
42		return (ret);
43
44	if (REP_ON(env)) {
45		__db_errx(env,
46  "DB_ENV->memp_fcreate: method not permitted when replication is configured");
47		return (EINVAL);
48	}
49
50	ENV_ENTER(env, ip);
51	ret = __memp_fcreate(env, retp);
52	ENV_LEAVE(env, ip);
53	return (ret);
54}
55
56/*
57 * __memp_fcreate --
58 *	ENV->memp_fcreate.
59 *
60 * PUBLIC: int __memp_fcreate __P((ENV *, DB_MPOOLFILE **));
61 */
62int
63__memp_fcreate(env, retp)
64	ENV *env;
65	DB_MPOOLFILE **retp;
66{
67	DB_MPOOLFILE *dbmfp;
68	int ret;
69
70	/* Allocate and initialize the per-process structure. */
71	if ((ret = __os_calloc(env, 1, sizeof(DB_MPOOLFILE), &dbmfp)) != 0)
72		return (ret);
73
74	dbmfp->ref = 1;
75	dbmfp->lsn_offset = DB_LSN_OFF_NOTSET;
76	dbmfp->env = env;
77	dbmfp->mfp = INVALID_ROFF;
78
79	dbmfp->close = __memp_fclose_pp;
80	dbmfp->get = __memp_fget_pp;
81	dbmfp->get_clear_len = __memp_get_clear_len;
82	dbmfp->get_fileid = __memp_get_fileid;
83	dbmfp->get_flags = __memp_get_flags;
84	dbmfp->get_ftype = __memp_get_ftype;
85	dbmfp->get_last_pgno = __memp_get_last_pgno;
86	dbmfp->get_lsn_offset = __memp_get_lsn_offset;
87	dbmfp->get_maxsize = __memp_get_maxsize;
88	dbmfp->get_pgcookie = __memp_get_pgcookie;
89	dbmfp->get_priority = __memp_get_priority;
90	dbmfp->open = __memp_fopen_pp;
91	dbmfp->put = __memp_fput_pp;
92	dbmfp->set_clear_len = __memp_set_clear_len;
93	dbmfp->set_fileid = __memp_set_fileid;
94	dbmfp->set_flags = __memp_set_flags;
95	dbmfp->set_ftype = __memp_set_ftype;
96	dbmfp->set_lsn_offset = __memp_set_lsn_offset;
97	dbmfp->set_maxsize = __memp_set_maxsize;
98	dbmfp->set_pgcookie = __memp_set_pgcookie;
99	dbmfp->set_priority = __memp_set_priority;
100	dbmfp->sync = __memp_fsync_pp;
101
102	*retp = dbmfp;
103	return (0);
104}
105
106/*
107 * __memp_get_clear_len --
108 *	Get the clear length.
109 */
110static int
111__memp_get_clear_len(dbmfp, clear_lenp)
112	DB_MPOOLFILE *dbmfp;
113	u_int32_t *clear_lenp;
114{
115	*clear_lenp = dbmfp->clear_len;
116	return (0);
117}
118
119/*
120 * __memp_set_clear_len --
121 *	DB_MPOOLFILE->set_clear_len.
122 *
123 * PUBLIC: int __memp_set_clear_len __P((DB_MPOOLFILE *, u_int32_t));
124 */
125int
126__memp_set_clear_len(dbmfp, clear_len)
127	DB_MPOOLFILE *dbmfp;
128	u_int32_t clear_len;
129{
130	MPF_ILLEGAL_AFTER_OPEN(dbmfp, "DB_MPOOLFILE->set_clear_len");
131
132	dbmfp->clear_len = clear_len;
133	return (0);
134}
135
136/*
137 * __memp_get_fileid --
138 *	DB_MPOOLFILE->get_fileid.
139 *
140 * PUBLIC: int __memp_get_fileid __P((DB_MPOOLFILE *, u_int8_t *));
141 */
142int
143__memp_get_fileid(dbmfp, fileid)
144	DB_MPOOLFILE *dbmfp;
145	u_int8_t *fileid;
146{
147	if (!F_ISSET(dbmfp, MP_FILEID_SET)) {
148		__db_errx(dbmfp->env, "get_fileid: file ID not set");
149		return (EINVAL);
150	}
151
152	memcpy(fileid, dbmfp->fileid, DB_FILE_ID_LEN);
153	return (0);
154}
155
156/*
157 * __memp_set_fileid --
158 *	DB_MPOOLFILE->set_fileid.
159 *
160 * PUBLIC: int __memp_set_fileid __P((DB_MPOOLFILE *, u_int8_t *));
161 */
162int
163__memp_set_fileid(dbmfp, fileid)
164	DB_MPOOLFILE *dbmfp;
165	u_int8_t *fileid;
166{
167	MPF_ILLEGAL_AFTER_OPEN(dbmfp, "DB_MPOOLFILE->set_fileid");
168
169	memcpy(dbmfp->fileid, fileid, DB_FILE_ID_LEN);
170	F_SET(dbmfp, MP_FILEID_SET);
171
172	return (0);
173}
174
175/*
176 * __memp_get_flags --
177 *	Get the DB_MPOOLFILE flags;
178 *
179 * PUBLIC: int __memp_get_flags __P((DB_MPOOLFILE *, u_int32_t *));
180 */
181int
182__memp_get_flags(dbmfp, flagsp)
183	DB_MPOOLFILE *dbmfp;
184	u_int32_t *flagsp;
185{
186	MPOOLFILE *mfp;
187
188	mfp = dbmfp->mfp;
189
190	*flagsp = 0;
191
192	if (mfp == NULL)
193		*flagsp = FLD_ISSET(dbmfp->config_flags,
194		     DB_MPOOL_NOFILE | DB_MPOOL_UNLINK);
195	else {
196		if (mfp->no_backing_file)
197			FLD_SET(*flagsp, DB_MPOOL_NOFILE);
198		if (mfp->unlink_on_close)
199			FLD_SET(*flagsp, DB_MPOOL_UNLINK);
200	}
201	return (0);
202}
203
204/*
205 * __memp_set_flags --
206 *	Set the DB_MPOOLFILE flags;
207 *
208 * PUBLIC: int __memp_set_flags __P((DB_MPOOLFILE *, u_int32_t, int));
209 */
210int
211__memp_set_flags(dbmfp, flags, onoff)
212	DB_MPOOLFILE *dbmfp;
213	u_int32_t flags;
214	int onoff;
215{
216	ENV *env;
217	MPOOLFILE *mfp;
218	int ret;
219
220	env = dbmfp->env;
221	mfp = dbmfp->mfp;
222
223	switch (flags) {
224	case DB_MPOOL_NOFILE:
225		if (mfp == NULL)
226			if (onoff)
227				FLD_SET(dbmfp->config_flags, DB_MPOOL_NOFILE);
228			else
229				FLD_CLR(dbmfp->config_flags, DB_MPOOL_NOFILE);
230		else
231			mfp->no_backing_file = onoff;
232		break;
233	case DB_MPOOL_UNLINK:
234		if (mfp == NULL)
235			if (onoff)
236				FLD_SET(dbmfp->config_flags, DB_MPOOL_UNLINK);
237			else
238				FLD_CLR(dbmfp->config_flags, DB_MPOOL_UNLINK);
239		else
240			mfp->unlink_on_close = onoff;
241		break;
242	default:
243		if ((ret = __db_fchk(env, "DB_MPOOLFILE->set_flags",
244		    flags, DB_MPOOL_NOFILE | DB_MPOOL_UNLINK)) != 0)
245			return (ret);
246		break;
247	}
248	return (0);
249}
250
251/*
252 * __memp_get_ftype --
253 *	Get the file type (as registered).
254 *
255 * PUBLIC: int __memp_get_ftype __P((DB_MPOOLFILE *, int *));
256 */
257int
258__memp_get_ftype(dbmfp, ftypep)
259	DB_MPOOLFILE *dbmfp;
260	int *ftypep;
261{
262	*ftypep = dbmfp->ftype;
263	return (0);
264}
265
266/*
267 * __memp_set_ftype --
268 *	DB_MPOOLFILE->set_ftype.
269 *
270 * PUBLIC: int __memp_set_ftype __P((DB_MPOOLFILE *, int));
271 */
272int
273__memp_set_ftype(dbmfp, ftype)
274	DB_MPOOLFILE *dbmfp;
275	int ftype;
276{
277	MPF_ILLEGAL_AFTER_OPEN(dbmfp, "DB_MPOOLFILE->set_ftype");
278
279	dbmfp->ftype = ftype;
280	return (0);
281}
282
283/*
284 * __memp_get_lsn_offset --
285 *	Get the page's LSN offset.
286 */
287static int
288__memp_get_lsn_offset(dbmfp, lsn_offsetp)
289	DB_MPOOLFILE *dbmfp;
290	int32_t *lsn_offsetp;
291{
292	*lsn_offsetp = dbmfp->lsn_offset;
293	return (0);
294}
295
296/*
297 * __memp_set_lsn_offset --
298 *	Set the page's LSN offset.
299 *
300 * PUBLIC: int __memp_set_lsn_offset __P((DB_MPOOLFILE *, int32_t));
301 */
302int
303__memp_set_lsn_offset(dbmfp, lsn_offset)
304	DB_MPOOLFILE *dbmfp;
305	int32_t lsn_offset;
306{
307	MPF_ILLEGAL_AFTER_OPEN(dbmfp, "DB_MPOOLFILE->set_lsn_offset");
308
309	dbmfp->lsn_offset = lsn_offset;
310	return (0);
311}
312
313/*
314 * __memp_get_maxsize --
315 *	Get the file's maximum size.
316 */
317static int
318__memp_get_maxsize(dbmfp, gbytesp, bytesp)
319	DB_MPOOLFILE *dbmfp;
320	u_int32_t *gbytesp, *bytesp;
321{
322	ENV *env;
323	MPOOLFILE *mfp;
324
325	if ((mfp = dbmfp->mfp) == NULL) {
326		*gbytesp = dbmfp->gbytes;
327		*bytesp = dbmfp->bytes;
328	} else {
329		env = dbmfp->env;
330
331		MUTEX_LOCK(env, mfp->mutex);
332		*gbytesp = (u_int32_t)
333		    (mfp->maxpgno / (GIGABYTE / mfp->stat.st_pagesize));
334		*bytesp = (u_int32_t)
335		    ((mfp->maxpgno % (GIGABYTE / mfp->stat.st_pagesize)) *
336		    mfp->stat.st_pagesize);
337		MUTEX_UNLOCK(env, mfp->mutex);
338	}
339
340	return (0);
341}
342
343/*
344 * __memp_set_maxsize --
345 *	Set the file's maximum size.
346 */
347static int
348__memp_set_maxsize(dbmfp, gbytes, bytes)
349	DB_MPOOLFILE *dbmfp;
350	u_int32_t gbytes, bytes;
351{
352	ENV *env;
353	MPOOLFILE *mfp;
354
355	if ((mfp = dbmfp->mfp) == NULL) {
356		dbmfp->gbytes = gbytes;
357		dbmfp->bytes = bytes;
358	} else {
359		env = dbmfp->env;
360
361		MUTEX_LOCK(env, mfp->mutex);
362		mfp->maxpgno = (db_pgno_t)
363		    (gbytes * (GIGABYTE / mfp->stat.st_pagesize));
364		mfp->maxpgno += (db_pgno_t)
365		    ((bytes + mfp->stat.st_pagesize - 1) /
366		    mfp->stat.st_pagesize);
367		MUTEX_UNLOCK(env, mfp->mutex);
368	}
369
370	return (0);
371}
372
373/*
374 * __memp_get_pgcookie --
375 *	Get the pgin/pgout cookie.
376 *
377 * PUBLIC: int __memp_get_pgcookie __P((DB_MPOOLFILE *, DBT *));
378 */
379int
380__memp_get_pgcookie(dbmfp, pgcookie)
381	DB_MPOOLFILE *dbmfp;
382	DBT *pgcookie;
383{
384	if (dbmfp->pgcookie == NULL) {
385		pgcookie->size = 0;
386		pgcookie->data = "";
387	} else
388		memcpy(pgcookie, dbmfp->pgcookie, sizeof(DBT));
389	return (0);
390}
391
392/*
393 * __memp_set_pgcookie --
394 *	Set the pgin/pgout cookie.
395 *
396 * PUBLIC: int __memp_set_pgcookie __P((DB_MPOOLFILE *, DBT *));
397 */
398int
399__memp_set_pgcookie(dbmfp, pgcookie)
400	DB_MPOOLFILE *dbmfp;
401	DBT *pgcookie;
402{
403	DBT *cookie;
404	ENV *env;
405	int ret;
406
407	MPF_ILLEGAL_AFTER_OPEN(dbmfp, "DB_MPOOLFILE->set_pgcookie");
408	env = dbmfp->env;
409
410	if ((ret = __os_calloc(env, 1, sizeof(*cookie), &cookie)) != 0)
411		return (ret);
412	if ((ret = __os_malloc(env, pgcookie->size, &cookie->data)) != 0) {
413		__os_free(env, cookie);
414		return (ret);
415	}
416
417	memcpy(cookie->data, pgcookie->data, pgcookie->size);
418	cookie->size = pgcookie->size;
419
420	dbmfp->pgcookie = cookie;
421	return (0);
422}
423
424/*
425 * __memp_get_priority --
426 *	Set the cache priority for pages from this file.
427 */
428static int
429__memp_get_priority(dbmfp, priorityp)
430	DB_MPOOLFILE *dbmfp;
431	DB_CACHE_PRIORITY *priorityp;
432{
433	switch (dbmfp->priority) {
434	case MPOOL_PRI_VERY_LOW:
435		*priorityp = DB_PRIORITY_VERY_LOW;
436		break;
437	case MPOOL_PRI_LOW:
438		*priorityp = DB_PRIORITY_LOW;
439		break;
440	case MPOOL_PRI_DEFAULT:
441		*priorityp = DB_PRIORITY_DEFAULT;
442		break;
443	case MPOOL_PRI_HIGH:
444		*priorityp = DB_PRIORITY_HIGH;
445		break;
446	case MPOOL_PRI_VERY_HIGH:
447		*priorityp = DB_PRIORITY_VERY_HIGH;
448		break;
449	default:
450		__db_errx(dbmfp->env,
451		    "DB_MPOOLFILE->get_priority: unknown priority value: %d",
452		    dbmfp->priority);
453		return (EINVAL);
454	}
455
456	return (0);
457}
458
459/*
460 * __memp_set_priority --
461 *	Set the cache priority for pages from this file.
462 */
463static int
464__memp_set_priority(dbmfp, priority)
465	DB_MPOOLFILE *dbmfp;
466	DB_CACHE_PRIORITY priority;
467{
468	switch (priority) {
469	case DB_PRIORITY_VERY_LOW:
470		dbmfp->priority = MPOOL_PRI_VERY_LOW;
471		break;
472	case DB_PRIORITY_LOW:
473		dbmfp->priority = MPOOL_PRI_LOW;
474		break;
475	case DB_PRIORITY_DEFAULT:
476		dbmfp->priority = MPOOL_PRI_DEFAULT;
477		break;
478	case DB_PRIORITY_HIGH:
479		dbmfp->priority = MPOOL_PRI_HIGH;
480		break;
481	case DB_PRIORITY_VERY_HIGH:
482		dbmfp->priority = MPOOL_PRI_VERY_HIGH;
483		break;
484	default:
485		__db_errx(dbmfp->env,
486		    "DB_MPOOLFILE->set_priority: unknown priority value: %d",
487		    priority);
488		return (EINVAL);
489	}
490
491	/* Update the underlying file if we've already opened it. */
492	if (dbmfp->mfp != NULL)
493		dbmfp->mfp->priority = dbmfp->priority;
494
495	return (0);
496}
497
498/*
499 * __memp_get_last_pgno --
500 *	Return the page number of the last page in the file.
501 *
502 * !!!
503 * The method is undocumented, but the handle is exported, users occasionally
504 * ask for it.
505 *
506 * PUBLIC: int __memp_get_last_pgno __P((DB_MPOOLFILE *, db_pgno_t *));
507 */
508int
509__memp_get_last_pgno(dbmfp, pgnoaddr)
510	DB_MPOOLFILE *dbmfp;
511	db_pgno_t *pgnoaddr;
512{
513	ENV *env;
514	MPOOLFILE *mfp;
515
516	env = dbmfp->env;
517	mfp = dbmfp->mfp;
518
519	MUTEX_LOCK(env, mfp->mutex);
520	*pgnoaddr = mfp->last_pgno;
521	MUTEX_UNLOCK(env, mfp->mutex);
522
523	return (0);
524}
525
526/*
527 * __memp_fn --
528 *	On errors we print whatever is available as the file name.
529 *
530 * PUBLIC: char * __memp_fn __P((DB_MPOOLFILE *));
531 */
532char *
533__memp_fn(dbmfp)
534	DB_MPOOLFILE *dbmfp;
535{
536	return (__memp_fns(dbmfp->env->mp_handle, dbmfp->mfp));
537}
538
539/*
540 * __memp_fns --
541 *	On errors we print whatever is available as the file name.
542 *
543 * PUBLIC: char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *));
544 *
545 */
546char *
547__memp_fns(dbmp, mfp)
548	DB_MPOOL *dbmp;
549	MPOOLFILE *mfp;
550{
551	if (mfp == NULL || mfp->path_off == 0)
552		return ((char *)"unknown");
553
554	return ((char *)R_ADDR(dbmp->reginfo, mfp->path_off));
555}
556