mp_fput.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__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 }

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