00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 #include "config.h" 00008 00009 #ifndef lint 00010 static const char revid[] = "$Id: mp__fput_8c-source.html,v 1.1 2008年06月08日 10:20:47 sebdiaz Exp $"; 00011 #endif /* not lint */ 00012 00013 #ifndef NO_SYSTEM_INCLUDES 00014 #include <sys/types.h> 00015 00016 #include <errno.h> 00017 #endif 00018 00019 #ifdef HAVE_RPC 00020 #include "db_server.h" 00021 #endif 00022 00023 #include "db_int.h" 00024 #include "db_shash.h" 00025 #include "mp.h" 00026 00027 #ifdef HAVE_RPC 00028 #include "gen_client_ext.h" 00029 #include "rpc_client_ext.h" 00030 #endif 00031 00032 /* 00033 * CDB_memp_fput -- 00034 * Mpool file put function. 00035 */ 00036 int 00037 CDB_memp_fput(dbmfp, pgaddr, flags) 00038 DB_MPOOLFILE *dbmfp; 00039 void *pgaddr; 00040 u_int32_t flags; 00041 { 00042 BH *bhp; 00043 DB_ENV *dbenv; 00044 DB_MPOOL *dbmp; 00045 MPOOL *c_mp, *mp; 00046 int ret, wrote; 00047 00048 dbmp = dbmfp->dbmp; 00049 dbenv = dbmp->dbenv; 00050 mp = dbmp->reginfo[0].primary; 00051 00052 #ifdef HAVE_RPC 00053 if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) 00054 return (__dbcl_memp_fput(dbmfp, pgaddr, flags)); 00055 #endif 00056 00057 PANIC_CHECK(dbenv); 00058 00059 /* Validate arguments. */ 00060 if (flags) { 00061 if ((ret = CDB___db_fchk(dbenv, "CDB_memp_fput", flags, 00062 DB_MPOOL_CLEAN | DB_MPOOL_DIRTY | DB_MPOOL_DISCARD)) != 0) 00063 return (ret); 00064 if ((ret = CDB___db_fcchk(dbenv, "CDB_memp_fput", 00065 flags, DB_MPOOL_CLEAN, DB_MPOOL_DIRTY)) != 0) 00066 return (ret); 00067 00068 if (LF_ISSET(DB_MPOOL_DIRTY) && F_ISSET(dbmfp, MP_READONLY)) { 00069 CDB___db_err(dbenv, 00070 "%s: dirty flag set for readonly file page", 00071 CDB___memp_fn(dbmfp)); 00072 return (EACCES); 00073 } 00074 } 00075 00076 R_LOCK(dbenv, dbmp->reginfo); 00077 00078 /* Decrement the pinned reference count. */ 00079 if (dbmfp->pinref == 0) { 00080 CDB___db_err(dbenv, 00081 "%s: more pages returned than retrieved", CDB___memp_fn(dbmfp)); 00082 R_UNLOCK(dbenv, dbmp->reginfo); 00083 return (EINVAL); 00084 } else 00085 --dbmfp->pinref; 00086 00087 /* 00088 * If we're mapping the file, there's nothing to do. Because we can 00089 * stop mapping the file at any time, we have to check on each buffer 00090 * to see if the address we gave the application was part of the map 00091 * region. 00092 */ 00093 if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr && 00094 (u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len) { 00095 R_UNLOCK(dbenv, dbmp->reginfo); 00096 return (0); 00097 } 00098 00099 /* Convert the page address to a buffer header. */ 00100 bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf)); 00101 00102 /* Convert the buffer header to a cache. */ 00103 c_mp = BH_TO_CACHE(dbmp, bhp); 00104 00105 /* UNLOCK THE REGION, LOCK THE CACHE. */ 00106 00107 /* Set/clear the page bits. */ 00108 if (LF_ISSET(DB_MPOOL_CLEAN) && F_ISSET(bhp, BH_DIRTY)) { 00109 ++c_mp->stat.st_page_clean; 00110 --c_mp->stat.st_page_dirty; 00111 F_CLR(bhp, BH_DIRTY); 00112 } 00113 if (LF_ISSET(DB_MPOOL_DIRTY) && !F_ISSET(bhp, BH_DIRTY)) { 00114 --c_mp->stat.st_page_clean; 00115 ++c_mp->stat.st_page_dirty; 00116 F_SET(bhp, BH_DIRTY); 00117 } 00118 if (LF_ISSET(DB_MPOOL_DISCARD)) 00119 F_SET(bhp, BH_DISCARD); 00120 00121 /* 00122 * Check for a reference count going to zero. This can happen if the 00123 * application returns a page twice. 00124 */ 00125 if (bhp->ref == 0) { 00126 CDB___db_err(dbenv, "%s: page %lu: unpinned page returned", 00127 CDB___memp_fn(dbmfp), (u_long)bhp->pgno); 00128 R_UNLOCK(dbenv, dbmp->reginfo); 00129 return (EINVAL); 00130 } 00131 00132 /* 00133 * If more than one reference to the page, we're done. Ignore the 00134 * discard flags (for now) and leave it at its position in the LRU 00135 * chain. The rest gets done at last reference close. 00136 */ 00137 if (--bhp->ref > 0) { 00138 R_UNLOCK(dbenv, dbmp->reginfo); 00139 return (0); 00140 } 00141 00142 /* 00143 * Move the buffer to the head/tail of the LRU chain. We do this 00144 * before writing the buffer for checkpoint purposes, as the write 00145 * can discard the region lock and allow another process to acquire 00146 * buffer. We could keep that from happening, but there seems no 00147 * reason to do so. 00148 */ 00149 SH_TAILQ_REMOVE(&c_mp->bhq, bhp, q, __bh); 00150 if (F_ISSET(bhp, BH_DISCARD)) 00151 SH_TAILQ_INSERT_HEAD(&c_mp->bhq, bhp, q, __bh); 00152 else 00153 SH_TAILQ_INSERT_TAIL(&c_mp->bhq, bhp, q); 00154 00155 /* 00156 * If this buffer is scheduled for writing because of a checkpoint, we 00157 * need to write it (if it's dirty), or update the checkpoint counters 00158 * (if it's not dirty). If we try to write it and can't, that's not 00159 * necessarily an error as it's not completely unreasonable that the 00160 * application have permission to write the underlying file, but set a 00161 * flag so that the next time the CDB_memp_sync function is called we try 00162 * writing it there, as the checkpoint thread of control better be able 00163 * to write all of the files. 00164 */ 00165 if (F_ISSET(bhp, BH_WRITE)) { 00166 if (F_ISSET(bhp, BH_DIRTY)) { 00167 if (CDB___memp_bhwrite(dbmp, 00168 dbmfp->mfp, bhp, NULL, &wrote) != 0 || !wrote) 00169 F_SET(mp, MP_LSN_RETRY); 00170 } else { 00171 F_CLR(bhp, BH_WRITE); 00172 00173 --mp->lsn_cnt; 00174 --dbmfp->mfp->lsn_cnt; 00175 } 00176 } 00177 00178 R_UNLOCK(dbenv, dbmp->reginfo); 00179 return (0); 00180 }