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__alloc_8c-source.html,v 1.1 2008年06月08日 10:20:39 sebdiaz Exp $"; 00011 #endif /* not lint */ 00012 00013 #ifndef NO_SYSTEM_INCLUDES 00014 #include <sys/types.h> 00015 #endif 00016 00017 #include "db_int.h" 00018 #include "db_shash.h" 00019 #include "mp.h" 00020 00021 /* 00022 * CDB___memp_alloc -- 00023 * Allocate some space from a cache region. 00024 * 00025 * PUBLIC: int CDB___memp_alloc __P((DB_MPOOL *, 00026 * PUBLIC: REGINFO *, MPOOLFILE *, size_t, roff_t *, void *)); 00027 */ 00028 int 00029 CDB___memp_alloc(dbmp, memreg, mfp, len, offsetp, retp) 00030 DB_MPOOL *dbmp; 00031 REGINFO *memreg; 00032 MPOOLFILE *mfp; 00033 size_t len; 00034 roff_t *offsetp; 00035 void *retp; 00036 { 00037 BH *bhp, *nbhp; 00038 MPOOL *c_mp; 00039 MPOOLFILE *bh_mfp; 00040 size_t total; 00041 int nomore, restart, ret, wrote; 00042 void *p; 00043 00044 c_mp = memreg->primary; 00045 00046 /* 00047 * If we're allocating a buffer, and the one we're discarding is the 00048 * same size, we don't want to waste the time to re-integrate it into 00049 * the shared memory free list. If the DB_MPOOLFILE argument isn't 00050 * NULL, we'll compare the underlying page sizes of the two buffers 00051 * before free-ing and re-allocating buffers. 00052 */ 00053 if (mfp != NULL) 00054 len = (sizeof(BH) - sizeof(u_int8_t)) + mfp->stat.st_pagesize; 00055 00056 nomore = 0; 00057 alloc: if ((ret = CDB___db_shalloc(memreg->addr, len, MUTEX_ALIGN, &p)) == 0) { 00058 if (offsetp != NULL) 00059 *offsetp = R_OFFSET(memreg, p); 00060 *(void **)retp = p; 00061 return (0); 00062 } 00063 if (nomore) { 00064 CDB___db_err(dbmp->dbenv, 00065 "Unable to allocate %lu bytes from mpool shared region: %s\n", 00066 (u_long)len, CDB_db_strerror(ret)); 00067 return (ret); 00068 } 00069 00070 retry: /* Find a buffer we can flush; pure LRU. */ 00071 restart = total = 0; 00072 for (bhp = 00073 SH_TAILQ_FIRST(&c_mp->bhq, __bh); bhp != NULL; bhp = nbhp) { 00074 nbhp = SH_TAILQ_NEXT(bhp, q, __bh); 00075 00076 /* Ignore pinned or locked (I/O in progress) buffers. */ 00077 if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED)) 00078 continue; 00079 00080 /* Find the associated MPOOLFILE. */ 00081 bh_mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset); 00082 00083 /* Write the page if it's dirty. */ 00084 if (F_ISSET(bhp, BH_DIRTY)) { 00085 ++bhp->ref; 00086 if ((ret = CDB___memp_bhwrite(dbmp, 00087 bh_mfp, bhp, &restart, &wrote)) != 0) 00088 return (ret); 00089 --bhp->ref; 00090 00091 /* 00092 * Another process may have acquired this buffer and 00093 * incremented the ref count after we wrote it. 00094 */ 00095 if (bhp->ref != 0) 00096 goto retry; 00097 00098 /* 00099 * If we wrote the page, continue and free the buffer. 00100 * We don't have to rewalk the list to acquire the 00101 * buffer because it was never available for any other 00102 * process to modify it. 00103 * 00104 * If we didn't write the page, but we discarded and 00105 * reacquired the region lock, restart the list walk. 00106 * 00107 * If we neither wrote the buffer nor discarded the 00108 * region lock, continue down the buffer list. 00109 */ 00110 if (wrote) 00111 ++c_mp->stat.st_rw_evict; 00112 else { 00113 if (restart) 00114 goto retry; 00115 continue; 00116 } 00117 } else 00118 ++c_mp->stat.st_ro_evict; 00119 00120 /* 00121 * Check to see if the buffer is the size we're looking for. 00122 * If it is, simply reuse it. 00123 */ 00124 if (mfp != NULL && 00125 mfp->stat.st_pagesize == bh_mfp->stat.st_pagesize) { 00126 CDB___memp_bhfree(dbmp, bhp, 0); 00127 00128 if (offsetp != NULL) 00129 *offsetp = R_OFFSET(memreg, bhp); 00130 *(void **)retp = bhp; 00131 return (0); 00132 } 00133 00134 /* Note how much space we've freed, and free the buffer. */ 00135 total += CDB___db_shsizeof(bhp); 00136 CDB___memp_bhfree(dbmp, bhp, 1); 00137 00138 /* 00139 * Retry as soon as we've freed up sufficient space. If we 00140 * have to coalesce of memory to satisfy the request, don't 00141 * try until it's likely (possible?) that we'll succeed. 00142 */ 00143 if (total >= 3 * len) 00144 goto alloc; 00145 00146 /* Restart the walk if we discarded the region lock. */ 00147 if (restart) 00148 goto retry; 00149 } 00150 nomore = 1; 00151 goto alloc; 00152 }