diff options
Diffstat (limited to 'db2/mp/mp_fput.c')
-rw-r--r-- | db2/mp/mp_fput.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/db2/mp/mp_fput.c b/db2/mp/mp_fput.c new file mode 100644 index 0000000000..5fac8ae76b --- /dev/null +++ b/db2/mp/mp_fput.c @@ -0,0 +1,140 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997 + * Sleepycat Software. All rights reserved. + */ +#include "config.h" + +#ifndef lint +static const char sccsid[] = "@(#)mp_fput.c 10.10 (Sleepycat) 7/20/97"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include <sys/types.h> + +#include <errno.h> +#include <stdlib.h> +#endif + +#include "db_int.h" +#include "shqueue.h" +#include "db_shash.h" +#include "mp.h" +#include "common_ext.h" + +/* + * memp_fput -- + * Mpool file put function. + */ +int +memp_fput(dbmfp, pgaddr, flags) + DB_MPOOLFILE *dbmfp; + void *pgaddr; + u_long flags; +{ + BH *bhp; + DB_MPOOL *dbmp; + MPOOLFILE *mfp; + int wrote, ret; + + dbmp = dbmfp->dbmp; + + /* Validate arguments. */ + if (flags) { + if ((ret = __db_fchk(dbmp->dbenv, "memp_fput", flags, + DB_MPOOL_CLEAN | DB_MPOOL_DIRTY | DB_MPOOL_DISCARD)) != 0) + return (ret); + if ((ret = __db_fcchk(dbmp->dbenv, "memp_fput", + flags, DB_MPOOL_CLEAN, DB_MPOOL_DIRTY)) != 0) + return (ret); + + if (LF_ISSET(DB_MPOOL_DIRTY) && F_ISSET(dbmfp, MP_READONLY)) { + __db_err(dbmp->dbenv, + "%s: dirty flag set for readonly file page", + dbmfp->path); + return (EACCES); + } + } + + /* Decrement the pinned reference count. */ + LOCKHANDLE(dbmp, &dbmfp->mutex); + if (dbmfp->pinref == 0) + __db_err(dbmp->dbenv, + "%s: put: more blocks returned than retrieved", + dbmfp->path); + else + --dbmfp->pinref; + UNLOCKHANDLE(dbmp, &dbmfp->mutex); + + /* + * If we're mapping the file, there's nothing to do. Because we can + * quit mapping at any time, we have to check on each buffer to see + * if it's in the map region. + */ + if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr && + (u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len) + return (0); + + /* Convert the page address to a buffer header. */ + bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf)); + + LOCKREGION(dbmp); + + /* Set/clear the page bits. */ + if (LF_ISSET(DB_MPOOL_CLEAN)) + F_CLR(bhp, BH_DIRTY); + if (LF_ISSET(DB_MPOOL_DIRTY)) + F_SET(bhp, BH_DIRTY); + if (LF_ISSET(DB_MPOOL_DISCARD)) + F_SET(bhp, BH_DISCARD); + + /* + * If more than one reference to the page, we're done. Ignore discard + * flags (for now) and leave it at its position in the LRU chain. The + * rest gets done at last reference close. + */ +#ifdef DEBUG + if (bhp->ref == 0) { + __db_err(dbmp->dbenv, + "Internal error: bhp->ref on page %lu went negative.", + (u_long)bhp->pgno); + abort(); + } +#endif + if (--bhp->ref > 0) { + UNLOCKREGION(dbmp); + return (0); + } + + /* Move the buffer to the head/tail of the LRU chain. */ + SH_TAILQ_REMOVE(&dbmp->mp->bhq, bhp, q, __bh); + if (F_ISSET(bhp, BH_DISCARD)) + SH_TAILQ_INSERT_HEAD(&dbmp->mp->bhq, bhp, q, __bh); + else + SH_TAILQ_INSERT_TAIL(&dbmp->mp->bhq, bhp, q); + + /* + * If this buffer is scheduled for writing because of a checkpoint, + * write it now. If we can't write it, set a flag so that the next + * time the memp_sync function is called we try writing it there, + * as the checkpoint application better be able to write all of the + * files. + */ + if (F_ISSET(bhp, BH_WRITE)) + if (F_ISSET(bhp, BH_DIRTY)) { + if (__memp_bhwrite(dbmp, + dbmfp->mfp, bhp, NULL, &wrote) != 0 || !wrote) + F_SET(dbmp->mp, MP_LSN_RETRY); + } else { + F_CLR(bhp, BH_WRITE); + + mfp = ADDR(dbmp, bhp->mf_offset); + --mfp->lsn_cnt; + + --dbmp->mp->lsn_cnt; + } + + UNLOCKREGION(dbmp); + return (0); +} |