mp_alloc.c

Go to the documentation of this file.
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 }

Generated on Sun Jun 8 10:56:38 2008 for GNUmifluz by  doxygen 1.5.5