Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

mp_method.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: mp_method.c,v 12.15 2005/10/12 12:45:10 margo Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_shash.h"
00020 #include "dbinc/mp.h"
00021 
00022 /*
00023  * __memp_dbenv_create --
00024  *      Mpool specific creation of the DB_ENV structure.
00025  *
00026  * PUBLIC: void __memp_dbenv_create __P((DB_ENV *));
00027  */
00028 void
00029 __memp_dbenv_create(dbenv)
00030         DB_ENV *dbenv;
00031 {
00032         /*
00033          * !!!
00034          * Our caller has not yet had the opportunity to reset the panic
00035          * state or turn off mutex locking, and so we can neither check
00036          * the panic state or acquire a mutex in the DB_ENV create path.
00037          *
00038          * We default to 32 8K pages.  We don't default to a flat 256K, because
00039          * some systems require significantly more memory to hold 32 pages than
00040          * others.  For example, HP-UX with POSIX pthreads needs 88 bytes for
00041          * a POSIX pthread mutex and almost 200 bytes per buffer header, while
00042          * Solaris needs 24 and 52 bytes for the same structures.  The minimum
00043          * number of hash buckets is 37.  These contain a mutex also.
00044          */
00045         dbenv->mp_bytes =
00046             32 * ((8 * 1024) + sizeof(BH)) + 37 * sizeof(DB_MPOOL_HASH);
00047         dbenv->mp_ncache = 1;
00048 }
00049 
00050 /*
00051  * __memp_get_cachesize --
00052  *      {DB_ENV,DB}->get_cachesize.
00053  *
00054  * PUBLIC: int __memp_get_cachesize
00055  * PUBLIC:         __P((DB_ENV *, u_int32_t *, u_int32_t *, int *));
00056  */
00057 int
00058 __memp_get_cachesize(dbenv, gbytesp, bytesp, ncachep)
00059         DB_ENV *dbenv;
00060         u_int32_t *gbytesp, *bytesp;
00061         int *ncachep;
00062 {
00063         MPOOL *mp;
00064 
00065         ENV_NOT_CONFIGURED(dbenv,
00066             dbenv->mp_handle, "DB_ENV->get_cachesize", DB_INIT_MPOOL);
00067 
00068         if (MPOOL_ON(dbenv)) {
00069                 /* Cannot be set after open, no lock required to read. */
00070                 mp = ((DB_MPOOL *)dbenv->mp_handle)->reginfo[0].primary;
00071                 if (gbytesp != NULL)
00072                         *gbytesp = mp->stat.st_gbytes;
00073                 if (bytesp != NULL)
00074                         *bytesp = mp->stat.st_bytes;
00075                 if (ncachep != NULL)
00076                         *ncachep = (int)mp->nreg;
00077         } else {
00078                 if (gbytesp != NULL)
00079                         *gbytesp = dbenv->mp_gbytes;
00080                 if (bytesp != NULL)
00081                         *bytesp = dbenv->mp_bytes;
00082                 if (ncachep != NULL)
00083                         *ncachep = (int)dbenv->mp_ncache;
00084         }
00085         return (0);
00086 }
00087 
00088 /*
00089  * __memp_set_cachesize --
00090  *      {DB_ENV,DB}->set_cachesize.
00091  *
00092  * PUBLIC: int __memp_set_cachesize __P((DB_ENV *, u_int32_t, u_int32_t, int));
00093  */
00094 int
00095 __memp_set_cachesize(dbenv, gbytes, bytes, arg_ncache)
00096         DB_ENV *dbenv;
00097         u_int32_t gbytes, bytes;
00098         int arg_ncache;
00099 {
00100         u_int ncache;
00101 
00102         ENV_ILLEGAL_AFTER_OPEN(dbenv, "DB_ENV->set_cachesize");
00103 
00104         /* Normalize the cache count. */
00105         ncache = arg_ncache <= 0 ? 1 : (u_int)arg_ncache;
00106 
00107         /*
00108          * You can only store 4GB-1 in an unsigned 32-bit value, so correct for
00109          * applications that specify 4GB cache sizes -- we know what they meant.
00110          */
00111         if (sizeof(roff_t) == 4 && gbytes / ncache == 4 && bytes == 0) {
00112                 --gbytes;
00113                 bytes = GIGABYTE - 1;
00114         } else {
00115                 gbytes += bytes / GIGABYTE;
00116                 bytes %= GIGABYTE;
00117         }
00118 
00119         /*
00120          * !!!
00121          * With 32-bit region offsets, individual cache regions must be smaller
00122          * than 4GB.  Also, cache sizes larger than 10TB would cause 32-bit
00123          * wrapping in the calculation of the number of hash buckets.  See
00124          * __memp_open for details.
00125          */
00126         if (sizeof(roff_t) <= 4) {
00127                 if (gbytes / ncache >= 4) {
00128                         __db_err(dbenv,
00129                             "individual cache size too large: maximum is 4GB");
00130                         return (EINVAL);
00131                 }
00132         } else
00133                 if (gbytes / ncache > 10000) {
00134                         __db_err(dbenv,
00135                             "individual cache size too large: maximum is 10TB");
00136                         return (EINVAL);
00137                 }
00138 
00139         /*
00140          * If the application requested less than 500Mb, increase the cachesize
00141          * by 25% and factor in the size of the hash buckets to account for our
00142          * overhead.  (I'm guessing caches over 500Mb are specifically sized,
00143          * that is, it's a large server and the application actually knows how
00144          * much memory is available.  We only document the 25% overhead number,
00145          * not the hash buckets, but I don't see a reason to confuse the issue,
00146          * it shouldn't matter to an application.)
00147          *
00148          * There is a minimum cache size, regardless.
00149          */
00150         if (gbytes == 0) {
00151                 if (bytes < 500 * MEGABYTE)
00152                         bytes += (bytes / 4) + 37 * sizeof(DB_MPOOL_HASH);
00153                 if (bytes / ncache < DB_CACHESIZE_MIN)
00154                         bytes = ncache * DB_CACHESIZE_MIN;
00155         }
00156 
00157         dbenv->mp_gbytes = gbytes;
00158         dbenv->mp_bytes = bytes;
00159         dbenv->mp_ncache = ncache;
00160 
00161         return (0);
00162 }
00163 
00164 /*
00165  * PUBLIC: int __memp_get_mp_max_openfd __P((DB_ENV *, int *));
00166  */
00167 int
00168 __memp_get_mp_max_openfd(dbenv, maxopenfdp)
00169         DB_ENV *dbenv;
00170         int *maxopenfdp;
00171 {
00172         DB_MPOOL *dbmp;
00173         MPOOL *mp;
00174 
00175         ENV_NOT_CONFIGURED(dbenv,
00176             dbenv->mp_handle, "DB_ENV->get_mp_max_openfd", DB_INIT_MPOOL);
00177 
00178         if (MPOOL_ON(dbenv)) {
00179                 dbmp = dbenv->mp_handle;
00180                 mp = dbmp->reginfo[0].primary;
00181                 MPOOL_SYSTEM_LOCK(dbenv);
00182                 *maxopenfdp = mp->mp_maxopenfd;
00183                 MPOOL_SYSTEM_UNLOCK(dbenv);
00184         } else
00185                 *maxopenfdp = dbenv->mp_maxopenfd;
00186         return (0);
00187 }
00188 
00189 /*
00190  * __memp_set_mp_max_openfd --
00191  *      Set the maximum number of open fd's when flushing the cache.
00192  * PUBLIC: int __memp_set_mp_max_openfd __P((DB_ENV *, int));
00193  */
00194 int
00195 __memp_set_mp_max_openfd(dbenv, maxopenfd)
00196         DB_ENV *dbenv;
00197         int maxopenfd;
00198 {
00199         DB_MPOOL *dbmp;
00200         MPOOL *mp;
00201 
00202         ENV_NOT_CONFIGURED(dbenv,
00203             dbenv->mp_handle, "DB_ENV->set_mp_max_openfd", DB_INIT_MPOOL);
00204 
00205         if (MPOOL_ON(dbenv)) {
00206                 dbmp = dbenv->mp_handle;
00207                 mp = dbmp->reginfo[0].primary;
00208                 MPOOL_SYSTEM_LOCK(dbenv);
00209                 mp->mp_maxopenfd = maxopenfd;
00210                 MPOOL_SYSTEM_UNLOCK(dbenv);
00211         } else
00212                 dbenv->mp_maxopenfd = maxopenfd;
00213         return (0);
00214 }
00215 
00216 /*
00217  * PUBLIC: int __memp_get_mp_max_write __P((DB_ENV *, int *, int *));
00218  */
00219 int
00220 __memp_get_mp_max_write(dbenv, maxwritep, maxwrite_sleepp)
00221         DB_ENV *dbenv;
00222         int *maxwritep, *maxwrite_sleepp;
00223 {
00224         DB_MPOOL *dbmp;
00225         MPOOL *mp;
00226 
00227         ENV_NOT_CONFIGURED(dbenv,
00228             dbenv->mp_handle, "DB_ENV->get_mp_max_write", DB_INIT_MPOOL);
00229 
00230         if (MPOOL_ON(dbenv)) {
00231                 dbmp = dbenv->mp_handle;
00232                 mp = dbmp->reginfo[0].primary;
00233                 MPOOL_SYSTEM_LOCK(dbenv);
00234                 *maxwritep = mp->mp_maxwrite;
00235                 *maxwrite_sleepp = mp->mp_maxwrite_sleep;
00236                 MPOOL_SYSTEM_UNLOCK(dbenv);
00237         } else {
00238                 *maxwritep = dbenv->mp_maxwrite;
00239                 *maxwrite_sleepp = dbenv->mp_maxwrite_sleep;
00240         }
00241         return (0);
00242 }
00243 
00244 /*
00245  * __memp_set_mp_max_write --
00246  *      Set the maximum continuous I/O count.
00247  *
00248  * PUBLIC: int __memp_set_mp_max_write __P((DB_ENV *, int, int));
00249  */
00250 int
00251 __memp_set_mp_max_write(dbenv, maxwrite, maxwrite_sleep)
00252         DB_ENV *dbenv;
00253         int maxwrite, maxwrite_sleep;
00254 {
00255         DB_MPOOL *dbmp;
00256         MPOOL *mp;
00257 
00258         ENV_NOT_CONFIGURED(dbenv,
00259             dbenv->mp_handle, "DB_ENV->get_mp_max_write", DB_INIT_MPOOL);
00260 
00261         if (MPOOL_ON(dbenv)) {
00262                 dbmp = dbenv->mp_handle;
00263                 mp = dbmp->reginfo[0].primary;
00264                 MPOOL_SYSTEM_LOCK(dbenv);
00265                 mp->mp_maxwrite = maxwrite;
00266                 mp->mp_maxwrite_sleep = maxwrite_sleep;
00267                 MPOOL_SYSTEM_UNLOCK(dbenv);
00268         } else {
00269                 dbenv->mp_maxwrite = maxwrite;
00270                 dbenv->mp_maxwrite_sleep = maxwrite_sleep;
00271         }
00272         return (0);
00273 }
00274 
00275 /*
00276  * PUBLIC: int __memp_get_mp_mmapsize __P((DB_ENV *, size_t *));
00277  */
00278 int
00279 __memp_get_mp_mmapsize(dbenv, mp_mmapsizep)
00280         DB_ENV *dbenv;
00281         size_t *mp_mmapsizep;
00282 {
00283         DB_MPOOL *dbmp;
00284         MPOOL *mp;
00285 
00286         ENV_NOT_CONFIGURED(dbenv,
00287             dbenv->mp_handle, "DB_ENV->get_mp_max_mmapsize", DB_INIT_MPOOL);
00288 
00289         if (MPOOL_ON(dbenv)) {
00290                 dbmp = dbenv->mp_handle;
00291                 mp = dbmp->reginfo[0].primary;
00292                 MPOOL_SYSTEM_LOCK(dbenv);
00293                 *mp_mmapsizep = mp->mp_mmapsize;
00294                 MPOOL_SYSTEM_UNLOCK(dbenv);
00295         } else
00296                 *mp_mmapsizep = dbenv->mp_mmapsize;
00297         return (0);
00298 }
00299 
00300 /*
00301  * __memp_set_mp_mmapsize --
00302  *      DB_ENV->set_mp_mmapsize.
00303  *
00304  * PUBLIC: int __memp_set_mp_mmapsize __P((DB_ENV *, size_t));
00305  */
00306 int
00307 __memp_set_mp_mmapsize(dbenv, mp_mmapsize)
00308         DB_ENV *dbenv;
00309         size_t mp_mmapsize;
00310 {
00311         DB_MPOOL *dbmp;
00312         MPOOL *mp;
00313 
00314         ENV_NOT_CONFIGURED(dbenv,
00315             dbenv->mp_handle, "DB_ENV->get_mp_max_mmapsize", DB_INIT_MPOOL);
00316 
00317         if (MPOOL_ON(dbenv)) {
00318                 dbmp = dbenv->mp_handle;
00319                 mp = dbmp->reginfo[0].primary;
00320                 MPOOL_SYSTEM_LOCK(dbenv);
00321                 mp->mp_mmapsize = mp_mmapsize;
00322                 MPOOL_SYSTEM_UNLOCK(dbenv);
00323         } else
00324                 dbenv->mp_mmapsize = mp_mmapsize;
00325         return (0);
00326 }
00327 
00328 /*
00329  * __memp_nameop
00330  *      Remove or rename a file in the pool.
00331  *
00332  * PUBLIC: int __memp_nameop __P((DB_ENV *,
00333  * PUBLIC:     u_int8_t *, const char *, const char *, const char *, int));
00334  *
00335  * XXX
00336  * Undocumented interface: DB private.
00337  */
00338 int
00339 __memp_nameop(dbenv, fileid, newname, fullold, fullnew, inmem)
00340         DB_ENV *dbenv;
00341         u_int8_t *fileid;
00342         const char *newname, *fullold, *fullnew;
00343         int inmem;
00344 {
00345         DB_MPOOL *dbmp;
00346         MPOOL *mp;
00347         MPOOLFILE *save_mfp, *mfp;
00348         roff_t newname_off;
00349         int is_remove, locked, ret;
00350         void *p;
00351 
00352         ret = locked = 0;
00353         dbmp = NULL;
00354         save_mfp = mfp = NULL;
00355         is_remove = newname == NULL;
00356         if (!MPOOL_ON(dbenv))
00357                 goto fsop;
00358 
00359         dbmp = dbenv->mp_handle;
00360         mp = dbmp->reginfo[0].primary;
00361 
00362         /*
00363          * Remove or rename a file that the mpool might know about.  We assume
00364          * that the fop layer has the file locked for exclusive access, so we
00365          * don't worry about locking except for the mpool mutexes.  Checkpoint
00366          * can happen at any time, independent of file locking, so we have to
00367          * do the actual unlink or rename system call to avoid any race.
00368          *
00369          * If this is a rename, allocate first, because we can't recursively
00370          * grab the region lock.
00371          */
00372         if (is_remove) {
00373                 p = NULL;
00374                 COMPQUIET(newname_off, INVALID_ROFF);
00375         } else {
00376                 if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
00377                     NULL, strlen(newname) + 1, &newname_off, &p)) != 0)
00378                         return (ret);
00379                 memcpy(p, newname, strlen(newname) + 1);
00380         }
00381 
00382         locked = 1;
00383         MPOOL_SYSTEM_LOCK(dbenv);
00384 
00385         /*
00386          * Find the file -- if mpool doesn't know about this file, that may
00387          * not be an error -- if the file is not a memory-only file and it
00388          * is not open, it won't show up here.  If this is a memory file
00389          * then on a rename, we need to make sure that the new name does
00390          * not exist.
00391          */
00392         for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
00393             mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
00394                 /* Ignore non-active files. */
00395                 if (mfp->deadfile || F_ISSET(mfp, MP_TEMP))
00396                         continue;
00397 
00398                 if (!is_remove && inmem && mfp->no_backing_file &&
00399                     strcmp(newname, R_ADDR(dbmp->reginfo, mfp->path_off))
00400                     == 0) {
00401                         ret = EEXIST;
00402                         goto err;
00403                 }
00404 
00405                 /* Try to match on fileid. */
00406                 if (memcmp(fileid, R_ADDR(
00407                     dbmp->reginfo, mfp->fileid_off), DB_FILE_ID_LEN) != 0)
00408                         continue;
00409 
00410                 if (is_remove) {
00411                         MUTEX_LOCK(dbenv, mfp->mutex);
00412                         /*
00413                          * In-memory dbs have an artificially incremented
00414                          * ref count so that they do not ever get reclaimed
00415                          * as long as they exist.  Since we are now deleting
00416                          * the database, we need to dec that count.
00417                          */
00418                         if (mfp->no_backing_file)
00419                                 mfp->mpf_cnt--;
00420                         mfp->deadfile = 1;
00421                         MUTEX_UNLOCK(dbenv, mfp->mutex);
00422                 } else {
00423                         /*
00424                          * Else, it's a rename.  We've allocated memory
00425                          * for the new name.  Swap it with the old one.
00426                          */
00427                         p = R_ADDR(dbmp->reginfo, mfp->path_off);
00428                         mfp->path_off = newname_off;
00429                 }
00430                 save_mfp = mfp;
00431                 if (!inmem || is_remove)
00432                         break;
00433         }
00434 
00435         /* Delete the memory we no longer need. */
00436         if (p != NULL)
00437                 __db_shalloc_free(&dbmp->reginfo[0], p);
00438 
00439 fsop:   if (save_mfp == NULL && inmem) {
00440                 ret = ENOENT;
00441                 goto err;
00442         }
00443 
00444         /*
00445          * If this is a real file, then save_mfp could be NULL, because
00446          * mpool isn't turned on, and we still need to do the file ops.
00447          */
00448         if (save_mfp == NULL || !save_mfp->no_backing_file) {
00449                 if (is_remove) {
00450                         /*
00451                          * !!!
00452                          * Replication may ask us to unlink a file that's been
00453                          * renamed.  Don't complain if it doesn't exist.
00454                          */
00455                         if ((ret = __os_unlink(dbenv, fullold)) == ENOENT)
00456                                 ret = 0;
00457                 } else {
00458                         /*
00459                          * Defensive only, fullname should never be
00460                          * NULL.
00461                          */
00462                         DB_ASSERT(fullnew != NULL);
00463                         if (fullnew == NULL)
00464                                 return (EINVAL);
00465                         ret = __os_rename(dbenv, fullold, fullnew, 1);
00466                 }
00467         }
00468 
00469 err:    if (locked)
00470                 MPOOL_SYSTEM_UNLOCK(dbenv);
00471 
00472         return (ret);
00473 }
00474 
00475 /*
00476  * __memp_get_refcnt
00477  *      Return a reference count, given a fileid.
00478  *
00479  * PUBLIC: int __memp_get_refcnt __P((DB_ENV *, u_int8_t *, u_int32_t *));
00480  */
00481 int
00482 __memp_get_refcnt(dbenv, fileid, refp)
00483         DB_ENV *dbenv;
00484         u_int8_t *fileid;
00485         u_int32_t *refp;
00486 {
00487         DB_MPOOL *dbmp;
00488         MPOOL *mp;
00489         MPOOLFILE *mfp;
00490 
00491         *refp = 0;
00492 
00493         if (!MPOOL_ON(dbenv))
00494                 return (0);
00495 
00496         dbmp = dbenv->mp_handle;
00497         mp = dbmp->reginfo[0].primary;
00498 
00499         MPOOL_SYSTEM_LOCK(dbenv);
00500         /*
00501          * Find the file -- if mpool doesn't know about this file, the
00502          * reference count is 0.
00503          */
00504         for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
00505             mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
00506 
00507                 /* Ignore non-active files. */
00508                 if (mfp->deadfile || F_ISSET(mfp, MP_TEMP))
00509                         continue;
00510 
00511                 /* Ignore non-matching files. */
00512                 if (memcmp(fileid, R_ADDR(
00513                     dbmp->reginfo, mfp->fileid_off), DB_FILE_ID_LEN) != 0)
00514                         continue;
00515 
00516                 MUTEX_LOCK(dbenv, mfp->mutex);
00517                 *refp = mfp->mpf_cnt;
00518                 MUTEX_UNLOCK(dbenv, mfp->mutex);
00519                 break;
00520         }
00521         MPOOL_SYSTEM_UNLOCK(dbenv);
00522 
00523         return (0);
00524 }
00525 
00526 #ifdef HAVE_FTRUNCATE
00527 /*
00528  * __memp_ftruncate __
00529  *      Truncate the file.
00530  *
00531  * PUBLIC: int __memp_ftruncate __P((DB_MPOOLFILE *, db_pgno_t, u_int32_t));
00532  */
00533 int
00534 __memp_ftruncate(dbmfp, pgno, flags)
00535         DB_MPOOLFILE *dbmfp;
00536         db_pgno_t pgno;
00537         u_int32_t flags;
00538 {
00539         DB_ENV *dbenv;
00540         void *pagep;
00541         db_pgno_t last_pgno, pg;
00542         u_int32_t mbytes, bytes, pgsize;
00543         int ret;
00544 
00545         dbenv = dbmfp->dbenv;
00546 
00547         MPOOL_SYSTEM_LOCK(dbenv);
00548         last_pgno = dbmfp->mfp->last_pgno;
00549         MPOOL_SYSTEM_UNLOCK(dbenv);
00550 
00551         if (pgno > last_pgno) {
00552                 if (LF_ISSET(MP_TRUNC_RECOVER))
00553                         return (0);
00554                 __db_err(dbenv, "Truncate beyond the end of file");
00555                 return (EINVAL);
00556         }
00557 
00558         pg = pgno;
00559         do {
00560                 if ((ret =
00561                     __memp_fget(dbmfp, &pg, DB_MPOOL_FREE, &pagep)) != 0)
00562                         return (ret);
00563         } while (pg++ < last_pgno);
00564 
00565         /*
00566          * If we are aborting an extend of a file, the call to __os_truncate
00567          * could extend the file if the new page(s) had not yet been written
00568          * to disk.  If we are out of disk space, avoid generating an error on
00569          * the truncate if we are actually extending the file. [#12743]
00570          */
00571         if (!F_ISSET(dbmfp->mfp, MP_TEMP) && !dbmfp->mfp->no_backing_file &&
00572             (ret = __os_truncate(dbenv,
00573             dbmfp->fhp, pgno, dbmfp->mfp->stat.st_pagesize)) != 0) {
00574                 if ((__os_ioinfo(dbenv,
00575                     NULL, dbmfp->fhp, &mbytes, &bytes, NULL)) != 0)
00576                         return (ret);
00577                 pgsize = dbmfp->mfp->stat.st_pagesize;
00578                 if (pgno < (mbytes * (MEGABYTE / pgsize)) + (bytes / pgsize))
00579                         return (ret);
00580                 ret = 0;
00581         }
00582 
00583         /*
00584          * This set could race with another thread of control that extending
00585          * the file.  It's not a problem because we should have the page
00586          * locked at a higher level of the system.
00587          */
00588         MPOOL_SYSTEM_LOCK(dbenv);
00589         dbmfp->mfp->last_pgno = pgno - 1;
00590         MPOOL_SYSTEM_UNLOCK(dbenv);
00591 
00592         return (ret);
00593 }
00594 
00595 /*
00596  * Support routines for maintaining a sorted freelist
00597  * while we try to rearrange and truncate the file.
00598  */
00599 
00600 /*
00601  * __memp_alloc_freelist -- allocate mpool space for the freelist.
00602  *
00603  * PUBLIC: int __memp_alloc_freelist __P((DB_MPOOLFILE *,
00604  * PUBLIC:       u_int32_t, db_pgno_t **));
00605  */
00606 int
00607 __memp_alloc_freelist(dbmfp, nelems, listp)
00608         DB_MPOOLFILE *dbmfp;
00609         u_int32_t nelems;
00610         db_pgno_t **listp;
00611 {
00612         DB_ENV *dbenv;
00613         DB_MPOOL *dbmp;
00614         MPOOLFILE *mfp;
00615         void *retp;
00616         int ret;
00617 
00618         dbenv = dbmfp->dbenv;
00619         dbmp = dbenv->mp_handle;
00620         mfp = dbmfp->mfp;
00621 
00622         *listp = NULL;
00623 
00624         /*
00625          * These fields are protected because the database layer
00626          * has the metapage locked while manipulating them.
00627          */
00628         mfp->free_ref++;
00629         if (mfp->free_size != 0)
00630                 return (EBUSY);
00631 
00632         /* Allocate at least a few slots. */
00633         mfp->free_cnt = nelems;
00634         if (nelems == 0)
00635                 nelems = 50;
00636 
00637         if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
00638             NULL, nelems * sizeof(db_pgno_t), &mfp->free_list, &retp)) != 0)
00639                 return (ret);
00640 
00641         mfp->free_size = nelems * sizeof(db_pgno_t);
00642 
00643         *listp = retp;
00644 
00645         return (0);
00646 }
00647 
00648 /*
00649  * __memp_free_freelist -- free the list.
00650  *
00651  * PUBLIC: void __memp_free_freelist __P((DB_MPOOLFILE *));
00652  */
00653 void
00654 __memp_free_freelist(dbmfp)
00655         DB_MPOOLFILE *dbmfp;
00656 {
00657         DB_ENV *dbenv;
00658         DB_MPOOL *dbmp;
00659         MPOOLFILE *mfp;
00660 
00661         dbenv = dbmfp->dbenv;
00662         dbmp = dbenv->mp_handle;
00663         mfp = dbmfp->mfp;
00664 
00665         DB_ASSERT(mfp->free_ref > 0);
00666         if (--mfp->free_ref > 0)
00667                 return;
00668 
00669         DB_ASSERT(mfp->free_size != 0);
00670 
00671         __db_shalloc_free(dbmp->reginfo, R_ADDR(dbmp->reginfo, mfp->free_list));
00672 
00673         mfp->free_cnt = 0;
00674         mfp->free_list = 0;
00675         mfp->free_size = 0;
00676 }
00677 
00678 /*
00679  * __memp_get_freelst -- return current list.
00680  *
00681  * PUBLIC: int __memp_get_freelist __P((
00682  * PUBLIC:      DB_MPOOLFILE *, u_int32_t *, db_pgno_t **));
00683  */
00684 int
00685 __memp_get_freelist(dbmfp, nelemp, listp)
00686         DB_MPOOLFILE *dbmfp;
00687         u_int32_t *nelemp;
00688         db_pgno_t **listp;
00689 {
00690         MPOOLFILE *mfp;
00691         DB_ENV *dbenv;
00692         DB_MPOOL *dbmp;
00693 
00694         dbenv = dbmfp->dbenv;
00695         dbmp = dbenv->mp_handle;
00696         mfp = dbmfp->mfp;
00697 
00698         if (mfp->free_size == 0) {
00699                 *nelemp = 0;
00700                 *listp = NULL;
00701                 return (0);
00702         }
00703 
00704         *nelemp = mfp->free_cnt;
00705         *listp = R_ADDR(dbmp->reginfo, mfp->free_list);
00706 
00707         return (0);
00708 }
00709 
00710 /*
00711  * __memp_extend_freelist -- extend the list.
00712  *
00713  * PUBLIC: int __memp_extend_freelist __P((
00714  * PUBLIC:      DB_MPOOLFILE *, u_int32_t , db_pgno_t **));
00715  */
00716 int
00717 __memp_extend_freelist(dbmfp, count, listp)
00718         DB_MPOOLFILE *dbmfp;
00719         u_int32_t count;
00720         db_pgno_t **listp;
00721 {
00722         DB_ENV *dbenv;
00723         DB_MPOOL *dbmp;
00724         MPOOLFILE *mfp;
00725         int ret;
00726         void *retp;
00727 
00728         dbenv = dbmfp->dbenv;
00729         dbmp = dbenv->mp_handle;
00730         mfp = dbmfp->mfp;
00731 
00732         if (mfp->free_size == 0)
00733                 return (EINVAL);
00734 
00735         if (count * sizeof(db_pgno_t) > mfp->free_size) {
00736                 mfp->free_size =
00737                      (size_t)DB_ALIGN(count * sizeof(db_pgno_t), 512);
00738                 *listp = R_ADDR(dbmp->reginfo, mfp->free_list);
00739                 if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
00740                     NULL, mfp->free_size, &mfp->free_list, &retp)) != 0)
00741                         return (ret);
00742 
00743                 memcpy(retp, *listp, mfp->free_cnt * sizeof(db_pgno_t));
00744 
00745                 __db_shalloc_free(dbmp->reginfo, *listp);
00746         }
00747 
00748         mfp->free_cnt = count;
00749         *listp = R_ADDR(dbmp->reginfo, mfp->free_list);
00750 
00751         return (0);
00752 }
00753 #endif

Generated on Sun Dec 25 12:14:41 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2