1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: mp_fset.c,v 12.29 2008/03/13 15:21:21 mbrey 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#include "dbinc/txn.h"
15
16/*
17 * __memp_dirty --
18 *	Upgrade a page from a read-only to a writeable pointer.
19 *
20 * PUBLIC: int __memp_dirty __P((DB_MPOOLFILE *, void *,
21 * PUBLIC:     DB_THREAD_INFO *, DB_TXN *, DB_CACHE_PRIORITY, u_int32_t));
22 */
23int
24__memp_dirty(dbmfp, addrp, ip, txn, priority, flags)
25	DB_MPOOLFILE *dbmfp;
26	void *addrp;
27	DB_THREAD_INFO *ip;
28	DB_TXN *txn;
29	DB_CACHE_PRIORITY priority;
30	u_int32_t flags;
31{
32	BH *bhp;
33	DB_MPOOL_HASH *hp;
34	DB_TXN *ancestor;
35	ENV *env;
36#ifdef DIAG_MVCC
37	MPOOLFILE *mfp;
38#endif
39	REGINFO *infop;
40	int mvcc, ret;
41	db_pgno_t pgno;
42	void *pgaddr;
43
44	env = dbmfp->env;
45	pgaddr = *(void **)addrp;
46	mvcc = dbmfp->mfp->multiversion;
47
48	/* Convert the page address to a buffer header. */
49	bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
50	pgno = bhp->pgno;
51
52	if (flags == 0)
53		flags = DB_MPOOL_DIRTY;
54	DB_ASSERT(env, flags == DB_MPOOL_DIRTY || flags == DB_MPOOL_EDIT);
55
56	if (F_ISSET(dbmfp, MP_READONLY)) {
57		__db_errx(env, "%s: dirty flag set for readonly file page",
58		    __memp_fn(dbmfp));
59		return (EACCES);
60	}
61
62	for (ancestor = txn;
63	    ancestor != NULL && ancestor->parent != NULL;
64	    ancestor = ancestor->parent)
65		;
66
67	if (mvcc && txn != NULL &&
68	    (!BH_OWNED_BY(env, bhp, ancestor) || SH_CHAIN_HASNEXT(bhp, vc))) {
69slow:		if ((ret = __memp_fget(dbmfp,
70		    &pgno, ip, txn, flags, addrp)) != 0) {
71			if (ret != DB_LOCK_DEADLOCK)
72				__db_errx(env,
73				    "%s: error getting a page for writing",
74				    __memp_fn(dbmfp));
75			*(void **)addrp = pgaddr;
76			return (ret);
77		}
78
79		DB_ASSERT(env,
80		    (flags == DB_MPOOL_EDIT && *(void **)addrp == pgaddr) ||
81		    (flags != DB_MPOOL_EDIT && *(void **)addrp != pgaddr));
82
83		if ((ret = __memp_fput(dbmfp, ip, pgaddr, priority)) != 0) {
84			__db_errx(env,
85			    "%s: error releasing a read-only page",
86			    __memp_fn(dbmfp));
87			(void)__memp_fput(dbmfp, ip, *(void **)addrp, priority);
88			*(void **)addrp = NULL;
89			return (ret);
90		}
91		pgaddr = *(void **)addrp;
92		bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
93		DB_ASSERT(env, pgno == bhp->pgno);
94		return (0);
95	}
96
97	MP_GET_BUCKET(env, dbmfp->mfp, pgno, &infop, hp, ret);
98	if (ret != 0)
99		return (ret);
100
101	/* Need to recheck in case we raced with a freeze operation. */
102	if (mvcc && txn != NULL && SH_CHAIN_HASNEXT(bhp, vc)) {
103		MUTEX_UNLOCK(env, hp->mtx_hash);
104		goto slow;
105	}
106
107	/* Set/clear the page bits. */
108	if (!F_ISSET(bhp, BH_DIRTY)) {
109		++hp->hash_page_dirty;
110		F_SET(bhp, BH_DIRTY);
111	}
112	MUTEX_UNLOCK(env, hp->mtx_hash);
113
114#ifdef DIAG_MVCC
115	mfp = R_ADDR(env->mp_handle->reginfo, bhp->mf_offset);
116	MVCC_MPROTECT(bhp->buf, mfp->stat.st_pagesize, PROT_READ | PROT_WRITE);
117#endif
118	return (0);
119}
120