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