Update from db-2.3.12.
[kopensolaris-gnu/glibc.git] / db2 / mp / mp_fput.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997
5  *      Sleepycat Software.  All rights reserved.
6  */
7 #include "config.h"
8
9 #ifndef lint
10 static const char sccsid[] = "@(#)mp_fput.c     10.14 (Sleepycat) 10/5/97";
11 #endif /* not lint */
12
13 #ifndef NO_SYSTEM_INCLUDES
14 #include <sys/types.h>
15
16 #include <errno.h>
17 #include <stdlib.h>
18 #endif
19
20 #include "db_int.h"
21 #include "shqueue.h"
22 #include "db_shash.h"
23 #include "mp.h"
24 #include "common_ext.h"
25
26 /*
27  * memp_fput --
28  *      Mpool file put function.
29  */
30 int
31 memp_fput(dbmfp, pgaddr, flags)
32         DB_MPOOLFILE *dbmfp;
33         void *pgaddr;
34         int flags;
35 {
36         BH *bhp;
37         DB_MPOOL *dbmp;
38         MPOOL *mp;
39         MPOOLFILE *mfp;
40         int wrote, ret;
41
42         dbmp = dbmfp->dbmp;
43         mp = dbmp->mp;
44
45         /* Validate arguments. */
46         if (flags) {
47                 if ((ret = __db_fchk(dbmp->dbenv, "memp_fput", flags,
48                     DB_MPOOL_CLEAN | DB_MPOOL_DIRTY | DB_MPOOL_DISCARD)) != 0)
49                         return (ret);
50                 if ((ret = __db_fcchk(dbmp->dbenv, "memp_fput",
51                     flags, DB_MPOOL_CLEAN, DB_MPOOL_DIRTY)) != 0)
52                         return (ret);
53
54                 if (LF_ISSET(DB_MPOOL_DIRTY) && F_ISSET(dbmfp, MP_READONLY)) {
55                         __db_err(dbmp->dbenv,
56                             "%s: dirty flag set for readonly file page",
57                             dbmfp->path);
58                         return (EACCES);
59                 }
60         }
61
62         /* Decrement the pinned reference count. */
63         LOCKHANDLE(dbmp, dbmfp->mutexp);
64         if (dbmfp->pinref == 0)
65                 __db_err(dbmp->dbenv,
66                     "%s: put: more blocks returned than retrieved",
67                     dbmfp->path);
68         else
69                 --dbmfp->pinref;
70         UNLOCKHANDLE(dbmp, dbmfp->mutexp);
71
72         /*
73          * If we're mapping the file, there's nothing to do.  Because we can
74          * quit mapping at any time, we have to check on each buffer to see
75          * if it's in the map region.
76          */
77         if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr &&
78             (u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len)
79                 return (0);
80
81         /* Convert the page address to a buffer header. */
82         bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
83
84         LOCKREGION(dbmp);
85
86         /* Set/clear the page bits. */
87         if (LF_ISSET(DB_MPOOL_CLEAN) && F_ISSET(bhp, BH_DIRTY)) {
88                 ++mp->stat.st_page_clean;
89                 --mp->stat.st_page_dirty;
90                 F_CLR(bhp, BH_DIRTY);
91         }
92         if (LF_ISSET(DB_MPOOL_DIRTY) && !F_ISSET(bhp, BH_DIRTY)) {
93                 --mp->stat.st_page_clean;
94                 ++mp->stat.st_page_dirty;
95                 F_SET(bhp, BH_DIRTY);
96         }
97         if (LF_ISSET(DB_MPOOL_DISCARD))
98                 F_SET(bhp, BH_DISCARD);
99
100         /*
101          * If more than one reference to the page, we're done.  Ignore discard
102          * flags (for now) and leave it at its position in the LRU chain.  The
103          * rest gets done at last reference close.
104          */
105 #ifdef DEBUG
106         if (bhp->ref == 0) {
107                 __db_err(dbmp->dbenv,
108                     "Internal error: bhp->ref on page %lu went negative.",
109                     (u_long)bhp->pgno);
110                 abort();
111         }
112 #endif
113         if (--bhp->ref > 0) {
114                 UNLOCKREGION(dbmp);
115                 return (0);
116         }
117
118         /* Move the buffer to the head/tail of the LRU chain. */
119         SH_TAILQ_REMOVE(&mp->bhq, bhp, q, __bh);
120         if (F_ISSET(bhp, BH_DISCARD))
121                 SH_TAILQ_INSERT_HEAD(&mp->bhq, bhp, q, __bh);
122         else
123                 SH_TAILQ_INSERT_TAIL(&mp->bhq, bhp, q);
124
125         /*
126          * If this buffer is scheduled for writing because of a checkpoint,
127          * write it now.  If we can't write it, set a flag so that the next
128          * time the memp_sync function is called we try writing it there,
129          * as the checkpoint application better be able to write all of the
130          * files.
131          */
132         if (F_ISSET(bhp, BH_WRITE))
133                 if (F_ISSET(bhp, BH_DIRTY)) {
134                         if (__memp_bhwrite(dbmp,
135                             dbmfp->mfp, bhp, NULL, &wrote) != 0 || !wrote)
136                                 F_SET(mp, MP_LSN_RETRY);
137                 } else {
138                         F_CLR(bhp, BH_WRITE);
139
140                         mfp = R_ADDR(dbmp, bhp->mf_offset);
141                         --mfp->lsn_cnt;
142
143                         --mp->lsn_cnt;
144                 }
145
146         UNLOCKREGION(dbmp);
147         return (0);
148 }