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