1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 2013 Oracle and/or its affiliates. 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 #include "dbinc/txn.h"
15
16 /*
17 * __memp_dirty --
18 * Upgrade a page from a read-only to a writable 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 */
23 int
__memp_dirty(dbmfp,addrp,ip,txn,priority,flags)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 *dbmp;
34 DB_MPOOL_HASH *hp;
35 DB_TXN *ancestor;
36 ENV *env;
37 MPOOL *c_mp;
38 #ifdef DIAG_MVCC
39 MPOOLFILE *mfp;
40 #endif
41 REGINFO *infop;
42 int mvcc, ret;
43 db_pgno_t pgno;
44 void *pgaddr;
45
46 env = dbmfp->env;
47 dbmp = env->mp_handle;
48 mvcc = atomic_read(&dbmfp->mfp->multiversion);
49
50 /* Convert the page address to a buffer header. */
51 pgaddr = *(void **)addrp;
52 bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
53 pgno = bhp->pgno;
54
55 /* If we have it exclusively then its already dirty. */
56 if (F_ISSET(bhp, BH_EXCLUSIVE)) {
57 DB_ASSERT(env, F_ISSET(bhp, BH_DIRTY));
58 return (0);
59 }
60
61 if (flags == 0)
62 flags = DB_MPOOL_DIRTY;
63 DB_ASSERT(env, flags == DB_MPOOL_DIRTY || flags == DB_MPOOL_EDIT);
64
65 if (F_ISSET(dbmfp, MP_READONLY)) {
66 __db_errx(env, DB_STR_A("3008",
67 "%s: dirty flag set for readonly file page", "%s"),
68 __memp_fn(dbmfp));
69 return (EACCES);
70 }
71
72 for (ancestor = txn;
73 ancestor != NULL && ancestor->parent != NULL;
74 ancestor = ancestor->parent)
75 ;
76
77 if (mvcc && txn != NULL && flags == DB_MPOOL_DIRTY &&
78 (!BH_OWNED_BY(env, bhp, ancestor) || SH_CHAIN_HASNEXT(bhp, vc))) {
79 atomic_inc(env, &bhp->ref);
80 *(void **)addrp = NULL;
81 if ((ret = __memp_fput(dbmfp, ip, pgaddr, priority)) != 0) {
82 __db_errx(env, DB_STR_A("3009",
83 "%s: error releasing a read-only page", "%s"),
84 __memp_fn(dbmfp));
85 atomic_dec(env, &bhp->ref);
86 return (ret);
87 }
88 if ((ret = __memp_fget(dbmfp,
89 &pgno, ip, txn, flags, addrp)) != 0) {
90 if (ret != DB_LOCK_DEADLOCK)
91 __db_errx(env, DB_STR_A("3010",
92 "%s: error getting a page for writing",
93 "%s"), __memp_fn(dbmfp));
94 atomic_dec(env, &bhp->ref);
95 return (ret);
96 }
97 atomic_dec(env, &bhp->ref);
98
99 /*
100 * If the MVCC handle count hasn't changed, we should get a
101 * different version of the page.
102 */
103 DB_ASSERT(env, *(void **)addrp != pgaddr ||
104 mvcc != atomic_read(&dbmfp->mfp->multiversion));
105
106 pgaddr = *(void **)addrp;
107 bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
108 DB_ASSERT(env, pgno == bhp->pgno);
109 return (0);
110 }
111
112 infop = &dbmp->reginfo[bhp->region];
113 c_mp = infop->primary;
114 hp = R_ADDR(infop, c_mp->htab);
115 hp = &hp[bhp->bucket];
116
117 /* Drop the shared latch and get an exclusive. We have the buf ref'ed.*/
118 MUTEX_UNLOCK(env, bhp->mtx_buf);
119 MUTEX_LOCK(env, bhp->mtx_buf);
120 DB_ASSERT(env, !F_ISSET(bhp, BH_EXCLUSIVE));
121 F_SET(bhp, BH_EXCLUSIVE);
122
123 /* Set/clear the page bits. */
124 if (!F_ISSET(bhp, BH_DIRTY)) {
125 #ifdef DIAGNOSTIC
126 MUTEX_LOCK(env, hp->mtx_hash);
127 #endif
128 atomic_inc(env, &hp->hash_page_dirty);
129 F_SET(bhp, BH_DIRTY);
130 #ifdef DIAGNOSTIC
131 MUTEX_UNLOCK(env, hp->mtx_hash);
132 #endif
133 }
134
135 #ifdef DIAG_MVCC
136 mfp = R_ADDR(env->mp_handle->reginfo, bhp->mf_offset);
137 MVCC_MPROTECT(bhp->buf, mfp->pagesize, PROT_READ | PROT_WRITE);
138 #endif
139 DB_ASSERT(env, !F_ISSET(bhp, BH_DIRTY) ||
140 atomic_read(&hp->hash_page_dirty) != 0);
141 return (0);
142 }
143
144 /*
145 * __memp_shared --
146 * Downgrade a page from exlusively held to shared.
147 *
148 * PUBLIC: int __memp_shared __P((DB_MPOOLFILE *, void *));
149 */
150 int
__memp_shared(dbmfp,pgaddr)151 __memp_shared(dbmfp, pgaddr)
152 DB_MPOOLFILE *dbmfp;
153 void *pgaddr;
154 {
155 BH *bhp;
156 ENV *env;
157
158 env = dbmfp->env;
159 /* Convert the page address to a buffer header. */
160 bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
161
162 if (F_ISSET(bhp, BH_DIRTY))
163 dbmfp->mfp->file_written = 1;
164 DB_ASSERT(env, F_ISSET(bhp, BH_EXCLUSIVE));
165 F_CLR(bhp, BH_EXCLUSIVE);
166 MUTEX_UNLOCK(env, bhp->mtx_buf);
167 MUTEX_READLOCK(env, bhp->mtx_buf);
168
169 return (0);
170 }
171