~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to db/mp/mp_region.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * See the file LICENSE for redistribution information.
 
3
 *
 
4
 * Copyright (c) 1996-2001
 
5
 *      Sleepycat Software.  All rights reserved.
 
6
 */
 
7
#include "db_config.h"
 
8
 
 
9
#ifndef lint
 
10
static const char revid[] = "$Id: mp_region.c,v 11.33 2001/06/13 01:42:58 bostic Exp $";
 
11
#endif /* not lint */
 
12
 
 
13
#ifndef NO_SYSTEM_INCLUDES
 
14
#include <sys/types.h>
 
15
 
 
16
#include <string.h>
 
17
#endif
 
18
 
 
19
#include "db_int.h"
 
20
#include "db_shash.h"
 
21
#include "mp.h"
 
22
 
 
23
static int __mpool_init __P((DB_ENV *, DB_MPOOL *, int, int));
 
24
#ifdef MUTEX_SYSTEM_RESOURCES
 
25
static size_t __mpool_region_maint __P((REGINFO *));
 
26
#endif
 
27
 
 
28
/*
 
29
 * __memp_open --
 
30
 *      Internal version of memp_open: only called from DB_ENV->open.
 
31
 *
 
32
 * PUBLIC: int __memp_open __P((DB_ENV *));
 
33
 */
 
34
int
 
35
__memp_open(dbenv)
 
36
        DB_ENV *dbenv;
 
37
{
 
38
        DB_MPOOL *dbmp;
 
39
        MPOOL *mp;
 
40
        REGINFO reginfo;
 
41
        roff_t reg_size, *regids;
 
42
        u_int32_t i;
 
43
        int htab_buckets, ret;
 
44
 
 
45
        /* Figure out how big each cache region is. */
 
46
        reg_size = (dbenv->mp_gbytes / dbenv->mp_ncache) * GIGABYTE;
 
47
        reg_size += ((dbenv->mp_gbytes %
 
48
            dbenv->mp_ncache) * GIGABYTE) / dbenv->mp_ncache;
 
49
        reg_size += dbenv->mp_bytes / dbenv->mp_ncache;
 
50
 
 
51
        /*
 
52
         * Figure out how many hash buckets each region will have.  Assume we
 
53
         * want to keep the hash chains with under 10 pages on each chain.  We
 
54
         * don't know the pagesize in advance, and it may differ for different
 
55
         * files.  Use a pagesize of 1K for the calculation -- we walk these
 
56
         * chains a lot, they must be kept short.
 
57
         */
 
58
        htab_buckets = __db_tablesize((reg_size / (1 * 1024)) / 10);
 
59
 
 
60
        /* Create and initialize the DB_MPOOL structure. */
 
61
        if ((ret = __os_calloc(dbenv, 1, sizeof(*dbmp), &dbmp)) != 0)
 
62
                return (ret);
 
63
        LIST_INIT(&dbmp->dbregq);
 
64
        TAILQ_INIT(&dbmp->dbmfq);
 
65
        dbmp->dbenv = dbenv;
 
66
 
 
67
        /* Join/create the first mpool region. */
 
68
        memset(&reginfo, 0, sizeof(REGINFO));
 
69
        reginfo.type = REGION_TYPE_MPOOL;
 
70
        reginfo.id = INVALID_REGION_ID;
 
71
        reginfo.mode = dbenv->db_mode;
 
72
        reginfo.flags = REGION_JOIN_OK;
 
73
        if (F_ISSET(dbenv, DB_ENV_CREATE))
 
74
                F_SET(&reginfo, REGION_CREATE_OK);
 
75
        if ((ret = __db_r_attach(dbenv, &reginfo, reg_size)) != 0)
 
76
                goto err;
 
77
 
 
78
        /*
 
79
         * If we created the region, initialize it.  Create or join any
 
80
         * additional regions.
 
81
         */
 
82
        if (F_ISSET(&reginfo, REGION_CREATE)) {
 
83
                /*
 
84
                 * We define how many regions there are going to be, allocate
 
85
                 * the REGINFO structures and create them.  Make sure we don't
 
86
                 * clear the wrong entries on error.
 
87
                 */
 
88
                dbmp->nreg = dbenv->mp_ncache;
 
89
                if ((ret = __os_calloc(dbenv,
 
90
                    dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0)
 
91
                        goto err;
 
92
                /* Make sure we don't clear the wrong entries on error. */
 
93
                for (i = 0; i < dbmp->nreg; ++i)
 
94
                        dbmp->reginfo[i].id = INVALID_REGION_ID;
 
95
                dbmp->reginfo[0] = reginfo;
 
96
 
 
97
                /* Initialize the first region. */
 
98
                if ((ret = __mpool_init(dbenv, dbmp, 0, htab_buckets)) != 0)
 
99
                        goto err;
 
100
 
 
101
                /*
 
102
                 * Create/initialize remaining regions and copy their IDs into
 
103
                 * the first region.
 
104
                 */
 
105
                mp = R_ADDR(dbmp->reginfo, dbmp->reginfo[0].rp->primary);
 
106
                regids = R_ADDR(dbmp->reginfo, mp->regids);
 
107
                for (i = 1; i < dbmp->nreg; ++i) {
 
108
                        dbmp->reginfo[i].type = REGION_TYPE_MPOOL;
 
109
                        dbmp->reginfo[i].id = INVALID_REGION_ID;
 
110
                        dbmp->reginfo[i].mode = dbenv->db_mode;
 
111
                        dbmp->reginfo[i].flags = REGION_CREATE_OK;
 
112
                        if ((ret = __db_r_attach(
 
113
                            dbenv, &dbmp->reginfo[i], reg_size)) != 0)
 
114
                                goto err;
 
115
                        if ((ret =
 
116
                            __mpool_init(dbenv, dbmp, i, htab_buckets)) != 0)
 
117
                                goto err;
 
118
                        R_UNLOCK(dbenv, &dbmp->reginfo[i]);
 
119
 
 
120
                        regids[i] = dbmp->reginfo[i].id;
 
121
                }
 
122
        } else {
 
123
                /*
 
124
                 * Determine how many regions there are going to be, allocate
 
125
                 * the REGINFO structures and fill in local copies of that
 
126
                 * information.
 
127
                 */
 
128
                mp = R_ADDR(&reginfo, reginfo.rp->primary);
 
129
                dbmp->nreg = mp->nreg;
 
130
                if ((ret = __os_calloc(dbenv,
 
131
                    dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0)
 
132
                        goto err;
 
133
                /* Make sure we don't clear the wrong entries on error. */
 
134
                for (i = 0; i < dbmp->nreg; ++i)
 
135
                        dbmp->reginfo[i].id = INVALID_REGION_ID;
 
136
                dbmp->reginfo[0] = reginfo;
 
137
 
 
138
                /* Join remaining regions. */
 
139
                regids = R_ADDR(dbmp->reginfo, mp->regids);
 
140
                for (i = 1; i < dbmp->nreg; ++i) {
 
141
                        dbmp->reginfo[i].type = REGION_TYPE_MPOOL;
 
142
                        dbmp->reginfo[i].id = regids[i];
 
143
                        dbmp->reginfo[i].mode = 0;
 
144
                        dbmp->reginfo[i].flags = REGION_JOIN_OK;
 
145
                        if ((ret = __db_r_attach(
 
146
                            dbenv, &dbmp->reginfo[i], 0)) != 0)
 
147
                                goto err;
 
148
                        R_UNLOCK(dbenv, &dbmp->reginfo[i]);
 
149
                }
 
150
        }
 
151
 
 
152
        /* Set the local addresses for the regions. */
 
153
        for (i = 0; i < dbmp->nreg; ++i)
 
154
                dbmp->reginfo[i].primary =
 
155
                    R_ADDR(&dbmp->reginfo[i], dbmp->reginfo[i].rp->primary);
 
156
 
 
157
        /* If the region is threaded, allocate a mutex to lock the handles. */
 
158
        if (F_ISSET(dbenv, DB_ENV_THREAD)) {
 
159
                if ((ret = __db_mutex_alloc(
 
160
                    dbenv, dbmp->reginfo, 1, &dbmp->mutexp)) != 0) {
 
161
                        goto err;
 
162
                }
 
163
                if ((ret = __db_shmutex_init(dbenv, dbmp->mutexp, 0,
 
164
                    MUTEX_THREAD, dbmp->reginfo,
 
165
                    (REGMAINT *)R_ADDR(dbmp->reginfo, mp->maint_off))) != 0)
 
166
                        goto err;
 
167
        }
 
168
 
 
169
        R_UNLOCK(dbenv, dbmp->reginfo);
 
170
 
 
171
        dbenv->mp_handle = dbmp;
 
172
        return (0);
 
173
 
 
174
err:    if (dbmp->reginfo != NULL && dbmp->reginfo[0].addr != NULL) {
 
175
                if (F_ISSET(dbmp->reginfo, REGION_CREATE))
 
176
                        ret = __db_panic(dbenv, ret);
 
177
 
 
178
                R_UNLOCK(dbenv, dbmp->reginfo);
 
179
 
 
180
                for (i = 0; i < dbmp->nreg; ++i)
 
181
                        if (dbmp->reginfo[i].id != INVALID_REGION_ID)
 
182
                                (void)__db_r_detach(
 
183
                                    dbenv, &dbmp->reginfo[i], 0);
 
184
                __os_free(dbenv, dbmp->reginfo,
 
185
                    dbmp->nreg * sizeof(*dbmp->reginfo));
 
186
        }
 
187
        if (dbmp->mutexp != NULL)
 
188
                __db_mutex_free(dbenv, dbmp->reginfo, dbmp->mutexp);
 
189
        __os_free(dbenv, dbmp, sizeof(*dbmp));
 
190
        return (ret);
 
191
}
 
192
 
 
193
/*
 
194
 * __mpool_init --
 
195
 *      Initialize a MPOOL structure in shared memory.
 
196
 */
 
197
static int
 
198
__mpool_init(dbenv, dbmp, reginfo_off, htab_buckets)
 
199
        DB_ENV *dbenv;
 
200
        DB_MPOOL *dbmp;
 
201
        int reginfo_off, htab_buckets;
 
202
{
 
203
        DB_HASHTAB *htab;
 
204
        MPOOL *mp;
 
205
        REGINFO *reginfo;
 
206
#ifdef MUTEX_SYSTEM_RESOURCES
 
207
        size_t maint_size;
 
208
#endif
 
209
        int ret;
 
210
        void *p;
 
211
 
 
212
        mp = NULL;
 
213
 
 
214
        reginfo = &dbmp->reginfo[reginfo_off];
 
215
        if ((ret = __db_shalloc(reginfo->addr,
 
216
            sizeof(MPOOL), MUTEX_ALIGN, &reginfo->primary)) != 0)
 
217
                goto mem_err;
 
218
        reginfo->rp->primary = R_OFFSET(reginfo, reginfo->primary);
 
219
        mp = reginfo->primary;
 
220
        memset(mp, 0, sizeof(*mp));
 
221
 
 
222
#ifdef  MUTEX_SYSTEM_RESOURCES
 
223
        maint_size = __mpool_region_maint(reginfo);
 
224
        /* Allocate room for the maintenance info and initialize it. */
 
225
        if ((ret = __db_shalloc(reginfo->addr,
 
226
            sizeof(REGMAINT) + maint_size, 0, &p)) != 0)
 
227
                goto mem_err;
 
228
        __db_maintinit(reginfo, p, maint_size);
 
229
        mp->maint_off = R_OFFSET(reginfo, p);
 
230
#endif
 
231
 
 
232
        if (reginfo_off == 0) {
 
233
                SH_TAILQ_INIT(&mp->mpfq);
 
234
 
 
235
                if ((ret = __db_shmutex_init(dbenv, &mp->sync_mutex,
 
236
                    R_OFFSET(dbmp->reginfo, &mp->sync_mutex) +
 
237
                    DB_FCNTL_OFF_MPOOL, 0, dbmp->reginfo,
 
238
                    (REGMAINT *)R_ADDR(dbmp->reginfo, mp->maint_off))) != 0)
 
239
                        goto err;
 
240
 
 
241
                ZERO_LSN(mp->lsn);
 
242
                mp->lsn_cnt = 0;
 
243
 
 
244
                mp->nreg = dbmp->nreg;
 
245
                if ((ret = __db_shalloc(dbmp->reginfo[0].addr,
 
246
                    dbmp->nreg * sizeof(int), 0, &p)) != 0)
 
247
                        goto mem_err;
 
248
                mp->regids = R_OFFSET(dbmp->reginfo, p);
 
249
        }
 
250
 
 
251
        SH_TAILQ_INIT(&mp->bhq);
 
252
 
 
253
        /* Allocate hash table space and initialize it. */
 
254
        if ((ret = __db_shalloc(reginfo->addr,
 
255
            htab_buckets * sizeof(DB_HASHTAB), 0, &htab)) != 0)
 
256
                goto mem_err;
 
257
        __db_hashinit(htab, htab_buckets);
 
258
        mp->htab = R_OFFSET(reginfo, htab);
 
259
        mp->htab_buckets = htab_buckets;
 
260
 
 
261
        /*
 
262
         * Only the environment creator knows the total cache size, fill in
 
263
         * those statistics now.
 
264
         */
 
265
        mp->stat.st_gbytes = dbenv->mp_gbytes;
 
266
        mp->stat.st_bytes = dbenv->mp_bytes;
 
267
 
 
268
        return (0);
 
269
 
 
270
mem_err:__db_err(dbenv, "Unable to allocate memory for mpool region");
 
271
err:    if (reginfo->primary != NULL)
 
272
                __db_shalloc_free(reginfo->addr, reginfo->primary);
 
273
        return (ret);
 
274
}
 
275
 
 
276
/*
 
277
 * __memp_close --
 
278
 *      Internal version of memp_close: only called from DB_ENV->close.
 
279
 *
 
280
 * PUBLIC: int __memp_close __P((DB_ENV *));
 
281
 */
 
282
int
 
283
__memp_close(dbenv)
 
284
        DB_ENV *dbenv;
 
285
{
 
286
        DB_MPOOL *dbmp;
 
287
        DB_MPOOLFILE *dbmfp;
 
288
        DB_MPREG *mpreg;
 
289
        u_int32_t i;
 
290
        int ret, t_ret;
 
291
 
 
292
        ret = 0;
 
293
        dbmp = dbenv->mp_handle;
 
294
 
 
295
        /* Discard DB_MPREGs. */
 
296
        while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) {
 
297
                LIST_REMOVE(mpreg, q);
 
298
                __os_free(dbenv, mpreg, sizeof(DB_MPREG));
 
299
        }
 
300
 
 
301
        /* Discard DB_MPOOLFILEs. */
 
302
        while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL)
 
303
                if ((t_ret = __memp_fclose(dbmfp, 1)) != 0 && ret == 0)
 
304
                        ret = t_ret;
 
305
 
 
306
        /* Discard the thread mutex. */
 
307
        if (dbmp->mutexp != NULL)
 
308
                __db_mutex_free(dbenv, dbmp->reginfo, dbmp->mutexp);
 
309
 
 
310
        /* Detach from the region(s). */
 
311
        for (i = 0; i < dbmp->nreg; ++i)
 
312
                if ((t_ret = __db_r_detach(
 
313
                    dbenv, &dbmp->reginfo[i], 0)) != 0 && ret == 0)
 
314
                        ret = t_ret;
 
315
 
 
316
        __os_free(dbenv, dbmp->reginfo, dbmp->nreg * sizeof(*dbmp->reginfo));
 
317
        __os_free(dbenv, dbmp, sizeof(*dbmp));
 
318
 
 
319
        dbenv->mp_handle = NULL;
 
320
        return (ret);
 
321
}
 
322
 
 
323
#ifdef MUTEX_SYSTEM_RESOURCES
 
324
/*
 
325
 * __mpool_region_maint --
 
326
 *      Return the amount of space needed for region maintenance info.
 
327
 *
 
328
 */
 
329
static size_t
 
330
__mpool_region_maint(infop)
 
331
        REGINFO *infop;
 
332
{
 
333
        size_t s;
 
334
        int numlocks;
 
335
 
 
336
        /*
 
337
         * For mutex maintenance we need one mutex per possible page.
 
338
         * Compute the maximum number of pages this cache can have.
 
339
         * Also add in an mpool mutex and mutexes for all dbenv and db
 
340
         * handles.
 
341
         */
 
342
        numlocks = ((infop->rp->size / DB_MIN_PGSIZE) + 1);
 
343
        numlocks += DB_MAX_HANDLES;
 
344
        s = sizeof(roff_t) * numlocks;
 
345
        return (s);
 
346
}
 
347
#endif
 
348
 
 
349
/*
 
350
 * __mpool_region_destroy
 
351
 *      Destroy any region maintenance info.
 
352
 *
 
353
 * PUBLIC: void __mpool_region_destroy __P((DB_ENV *, REGINFO *));
 
354
 */
 
355
void
 
356
__mpool_region_destroy(dbenv, infop)
 
357
        DB_ENV *dbenv;
 
358
        REGINFO *infop;
 
359
{
 
360
        __db_shlocks_destroy(infop, (REGMAINT *)R_ADDR(infop,
 
361
            ((MPOOL *)R_ADDR(infop, infop->rp->primary))->maint_off));
 
362
 
 
363
        COMPQUIET(dbenv, NULL);
 
364
        COMPQUIET(infop, NULL);
 
365
}