~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/lock/lock_region.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

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-2002
5
 
 *      Sleepycat Software.  All rights reserved.
6
 
 */
7
 
 
8
 
#include "db_config.h"
9
 
 
10
 
#ifndef lint
11
 
static const char revid[] = "$Id$";
12
 
#endif /* not lint */
13
 
 
14
 
#ifndef NO_SYSTEM_INCLUDES
15
 
#include <sys/types.h>
16
 
 
17
 
#include <string.h>
18
 
#endif
19
 
 
20
 
#include "db_int.h"
21
 
#include "dbinc/db_shash.h"
22
 
#include "dbinc/lock.h"
23
 
 
24
 
static int  __lock_init __P((DB_ENV *, DB_LOCKTAB *));
25
 
static size_t
26
 
            __lock_region_size __P((DB_ENV *));
27
 
 
28
 
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
29
 
static size_t __lock_region_maint __P((DB_ENV *));
30
 
#endif
31
 
 
32
 
/*
33
 
 * The conflict arrays are set up such that the row is the lock you are
34
 
 * holding and the column is the lock that is desired.
35
 
 */
36
 
#define DB_LOCK_RIW_N   9
37
 
static const u_int8_t db_riw_conflicts[] = {
38
 
/*         N   R   W   WT  IW  IR  RIW DR  WW */
39
 
/*   N */  0,  0,  0,  0,  0,  0,  0,  0,  0,
40
 
/*   R */  0,  0,  1,  0,  1,  0,  1,  0,  1,
41
 
/*   W */  0,  1,  1,  1,  1,  1,  1,  1,  1,
42
 
/*  WT */  0,  0,  0,  0,  0,  0,  0,  0,  0,
43
 
/*  IW */  0,  1,  1,  0,  0,  0,  0,  1,  1,
44
 
/*  IR */  0,  0,  1,  0,  0,  0,  0,  0,  1,
45
 
/* RIW */  0,  1,  1,  0,  0,  0,  0,  1,  1,
46
 
/*  DR */  0,  0,  1,  0,  1,  0,  1,  0,  0,
47
 
/*  WW */  0,  1,  1,  0,  1,  1,  1,  0,  1
48
 
};
49
 
 
50
 
/*
51
 
 * This conflict array is used for concurrent db access (CDB).  It uses
52
 
 * the same locks as the db_riw_conflicts array, but adds an IW mode to
53
 
 * be used for write cursors.
54
 
 */
55
 
#define DB_LOCK_CDB_N   5
56
 
static const u_int8_t db_cdb_conflicts[] = {
57
 
        /*              N       R       W       WT      IW */
58
 
        /*   N */       0,      0,      0,      0,      0,
59
 
        /*   R */       0,      0,      1,      0,      0,
60
 
        /*   W */       0,      1,      1,      1,      1,
61
 
        /*  WT */       0,      0,      0,      0,      0,
62
 
        /*  IW */       0,      0,      1,      0,      1
63
 
};
64
 
 
65
 
/*
66
 
 * __lock_open --
67
 
 *      Internal version of lock_open: only called from DB_ENV->open.
68
 
 *
69
 
 * PUBLIC: int __lock_open __P((DB_ENV *));
70
 
 */
71
 
int
72
 
__lock_open(dbenv)
73
 
        DB_ENV *dbenv;
74
 
{
75
 
        DB_LOCKREGION *region;
76
 
        DB_LOCKTAB *lt;
77
 
        size_t size;
78
 
        int ret;
79
 
 
80
 
        /* Create the lock table structure. */
81
 
        if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOCKTAB), &lt)) != 0)
82
 
                return (ret);
83
 
        lt->dbenv = dbenv;
84
 
 
85
 
        /* Join/create the lock region. */
86
 
        lt->reginfo.type = REGION_TYPE_LOCK;
87
 
        lt->reginfo.id = INVALID_REGION_ID;
88
 
        lt->reginfo.mode = dbenv->db_mode;
89
 
        lt->reginfo.flags = REGION_JOIN_OK;
90
 
        if (F_ISSET(dbenv, DB_ENV_CREATE))
91
 
                F_SET(&lt->reginfo, REGION_CREATE_OK);
92
 
        size = __lock_region_size(dbenv);
93
 
        if ((ret = __db_r_attach(dbenv, &lt->reginfo, size)) != 0)
94
 
                goto err;
95
 
 
96
 
        /* If we created the region, initialize it. */
97
 
        if (F_ISSET(&lt->reginfo, REGION_CREATE))
98
 
                if ((ret = __lock_init(dbenv, lt)) != 0)
99
 
                        goto err;
100
 
 
101
 
        /* Set the local addresses. */
102
 
        region = lt->reginfo.primary =
103
 
            R_ADDR(&lt->reginfo, lt->reginfo.rp->primary);
104
 
 
105
 
        /* Check for incompatible automatic deadlock detection requests. */
106
 
        if (dbenv->lk_detect != DB_LOCK_NORUN) {
107
 
                if (region->detect != DB_LOCK_NORUN &&
108
 
                    dbenv->lk_detect != DB_LOCK_DEFAULT &&
109
 
                    region->detect != dbenv->lk_detect) {
110
 
                        __db_err(dbenv,
111
 
                    "lock_open: incompatible deadlock detector mode");
112
 
                        ret = EINVAL;
113
 
                        goto err;
114
 
                }
115
 
 
116
 
                /*
117
 
                 * Upgrade if our caller wants automatic detection, and it
118
 
                 * was not currently being done, whether or not we created
119
 
                 * the region.
120
 
                 */
121
 
                if (region->detect == DB_LOCK_NORUN)
122
 
                        region->detect = dbenv->lk_detect;
123
 
        }
124
 
 
125
 
        /*
126
 
         * A process joining the region may have reset the lock and transaction
127
 
         * timeouts.
128
 
         */
129
 
         if (dbenv->lk_timeout != 0)
130
 
                region->lk_timeout = dbenv->lk_timeout;
131
 
         if (dbenv->tx_timeout != 0)
132
 
                region->tx_timeout = dbenv->tx_timeout;
133
 
 
134
 
        /* Set remaining pointers into region. */
135
 
        lt->conflicts = (u_int8_t *)R_ADDR(&lt->reginfo, region->conf_off);
136
 
        lt->obj_tab = (DB_HASHTAB *)R_ADDR(&lt->reginfo, region->obj_off);
137
 
        lt->locker_tab = (DB_HASHTAB *)R_ADDR(&lt->reginfo, region->locker_off);
138
 
 
139
 
        R_UNLOCK(dbenv, &lt->reginfo);
140
 
 
141
 
        dbenv->lk_handle = lt;
142
 
        return (0);
143
 
 
144
 
err:    if (lt->reginfo.addr != NULL) {
145
 
                if (F_ISSET(&lt->reginfo, REGION_CREATE))
146
 
                        ret = __db_panic(dbenv, ret);
147
 
                R_UNLOCK(dbenv, &lt->reginfo);
148
 
                (void)__db_r_detach(dbenv, &lt->reginfo, 0);
149
 
        }
150
 
        __os_free(dbenv, lt);
151
 
        return (ret);
152
 
}
153
 
 
154
 
/*
155
 
 * __lock_init --
156
 
 *      Initialize the lock region.
157
 
 */
158
 
static int
159
 
__lock_init(dbenv, lt)
160
 
        DB_ENV *dbenv;
161
 
        DB_LOCKTAB *lt;
162
 
{
163
 
        const u_int8_t *lk_conflicts;
164
 
        struct __db_lock *lp;
165
 
        DB_LOCKER *lidp;
166
 
        DB_LOCKOBJ *op;
167
 
        DB_LOCKREGION *region;
168
 
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
169
 
        size_t maint_size;
170
 
#endif
171
 
        u_int32_t i, lk_modes;
172
 
        u_int8_t *addr;
173
 
        int ret;
174
 
 
175
 
        if ((ret = __db_shalloc(lt->reginfo.addr,
176
 
            sizeof(DB_LOCKREGION), 0, &lt->reginfo.primary)) != 0)
177
 
                goto mem_err;
178
 
        lt->reginfo.rp->primary = R_OFFSET(&lt->reginfo, lt->reginfo.primary);
179
 
        region = lt->reginfo.primary;
180
 
        memset(region, 0, sizeof(*region));
181
 
 
182
 
        /* Select a conflict matrix if none specified. */
183
 
        if (dbenv->lk_modes == 0)
184
 
                if (CDB_LOCKING(dbenv)) {
185
 
                        lk_modes = DB_LOCK_CDB_N;
186
 
                        lk_conflicts = db_cdb_conflicts;
187
 
                } else {
188
 
                        lk_modes = DB_LOCK_RIW_N;
189
 
                        lk_conflicts = db_riw_conflicts;
190
 
                }
191
 
        else {
192
 
                lk_modes = dbenv->lk_modes;
193
 
                lk_conflicts = dbenv->lk_conflicts;
194
 
        }
195
 
 
196
 
        region->need_dd = 0;
197
 
        region->detect = DB_LOCK_NORUN;
198
 
        region->lk_timeout = dbenv->lk_timeout;
199
 
        region->tx_timeout = dbenv->tx_timeout;
200
 
        region->locker_t_size = __db_tablesize(dbenv->lk_max_lockers);
201
 
        region->object_t_size = __db_tablesize(dbenv->lk_max_objects);
202
 
        memset(&region->stat, 0, sizeof(region->stat));
203
 
        region->stat.st_id = 0;
204
 
        region->stat.st_cur_maxid = DB_LOCK_MAXID;
205
 
        region->stat.st_maxlocks = dbenv->lk_max;
206
 
        region->stat.st_maxlockers = dbenv->lk_max_lockers;
207
 
        region->stat.st_maxobjects = dbenv->lk_max_objects;
208
 
        region->stat.st_nmodes = lk_modes;
209
 
 
210
 
        /* Allocate room for the conflict matrix and initialize it. */
211
 
        if ((ret =
212
 
            __db_shalloc(lt->reginfo.addr, lk_modes * lk_modes, 0, &addr)) != 0)
213
 
                goto mem_err;
214
 
        memcpy(addr, lk_conflicts, lk_modes * lk_modes);
215
 
        region->conf_off = R_OFFSET(&lt->reginfo, addr);
216
 
 
217
 
        /* Allocate room for the object hash table and initialize it. */
218
 
        if ((ret = __db_shalloc(lt->reginfo.addr,
219
 
            region->object_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
220
 
                goto mem_err;
221
 
        __db_hashinit(addr, region->object_t_size);
222
 
        region->obj_off = R_OFFSET(&lt->reginfo, addr);
223
 
 
224
 
        /* Allocate room for the locker hash table and initialize it. */
225
 
        if ((ret = __db_shalloc(lt->reginfo.addr,
226
 
            region->locker_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0)
227
 
                goto mem_err;
228
 
        __db_hashinit(addr, region->locker_t_size);
229
 
        region->locker_off = R_OFFSET(&lt->reginfo, addr);
230
 
 
231
 
#ifdef  HAVE_MUTEX_SYSTEM_RESOURCES
232
 
        maint_size = __lock_region_maint(dbenv);
233
 
        /* Allocate room for the locker maintenance info and initialize it. */
234
 
        if ((ret = __db_shalloc(lt->reginfo.addr,
235
 
            sizeof(REGMAINT) + maint_size, 0, &addr)) != 0)
236
 
                goto mem_err;
237
 
        __db_maintinit(&lt->reginfo, addr, maint_size);
238
 
        region->maint_off = R_OFFSET(&lt->reginfo, addr);
239
 
#endif
240
 
 
241
 
        /*
242
 
         * Initialize locks onto a free list. Initialize and lock the mutex
243
 
         * so that when we need to block, all we need do is try to acquire
244
 
         * the mutex.
245
 
         */
246
 
        SH_TAILQ_INIT(&region->free_locks);
247
 
        for (i = 0; i < region->stat.st_maxlocks; ++i) {
248
 
                if ((ret = __db_shalloc(lt->reginfo.addr,
249
 
                    sizeof(struct __db_lock), MUTEX_ALIGN, &lp)) != 0)
250
 
                        goto mem_err;
251
 
                lp->status = DB_LSTAT_FREE;
252
 
                lp->gen = 0;
253
 
                if ((ret = __db_mutex_setup(dbenv, &lt->reginfo, &lp->mutex,
254
 
                    MUTEX_NO_RLOCK | MUTEX_SELF_BLOCK)) != 0)
255
 
                        return (ret);
256
 
                MUTEX_LOCK(dbenv, &lp->mutex);
257
 
                SH_TAILQ_INSERT_HEAD(&region->free_locks, lp, links, __db_lock);
258
 
        }
259
 
 
260
 
        /* Initialize objects onto a free list.  */
261
 
        SH_TAILQ_INIT(&region->dd_objs);
262
 
        SH_TAILQ_INIT(&region->free_objs);
263
 
        for (i = 0; i < region->stat.st_maxobjects; ++i) {
264
 
                if ((ret = __db_shalloc(lt->reginfo.addr,
265
 
                    sizeof(DB_LOCKOBJ), 0, &op)) != 0)
266
 
                        goto mem_err;
267
 
                SH_TAILQ_INSERT_HEAD(
268
 
                    &region->free_objs, op, links, __db_lockobj);
269
 
        }
270
 
 
271
 
        /* Initialize lockers onto a free list.  */
272
 
        SH_TAILQ_INIT(&region->lockers);
273
 
        SH_TAILQ_INIT(&region->free_lockers);
274
 
        for (i = 0; i < region->stat.st_maxlockers; ++i) {
275
 
                if ((ret = __db_shalloc(lt->reginfo.addr,
276
 
                    sizeof(DB_LOCKER), 0, &lidp)) != 0) {
277
 
mem_err:                __db_err(dbenv,
278
 
                            "Unable to allocate memory for the lock table");
279
 
                        return (ret);
280
 
                }
281
 
                SH_TAILQ_INSERT_HEAD(
282
 
                    &region->free_lockers, lidp, links, __db_locker);
283
 
        }
284
 
 
285
 
        return (0);
286
 
}
287
 
 
288
 
/*
289
 
 * __lock_dbenv_refresh --
290
 
 *      Clean up after the lock system on a close or failed open.  Called
291
 
 * only from __dbenv_refresh.  (Formerly called __lock_close.)
292
 
 *
293
 
 * PUBLIC: int __lock_dbenv_refresh __P((DB_ENV *));
294
 
 */
295
 
int
296
 
__lock_dbenv_refresh(dbenv)
297
 
        DB_ENV *dbenv;
298
 
{
299
 
        DB_LOCKTAB *lt;
300
 
        int ret;
301
 
 
302
 
        lt = dbenv->lk_handle;
303
 
 
304
 
        /* Detach from the region. */
305
 
        ret = __db_r_detach(dbenv, &lt->reginfo, 0);
306
 
 
307
 
        __os_free(dbenv, lt);
308
 
 
309
 
        dbenv->lk_handle = NULL;
310
 
        return (ret);
311
 
}
312
 
 
313
 
/*
314
 
 * __lock_region_size --
315
 
 *      Return the region size.
316
 
 */
317
 
static size_t
318
 
__lock_region_size(dbenv)
319
 
        DB_ENV *dbenv;
320
 
{
321
 
        size_t retval;
322
 
 
323
 
        /*
324
 
         * Figure out how much space we're going to need.  This list should
325
 
         * map one-to-one with the __db_shalloc calls in __lock_init.
326
 
         */
327
 
        retval = 0;
328
 
        retval += __db_shalloc_size(sizeof(DB_LOCKREGION), sizeof(db_align_t));
329
 
        retval += __db_shalloc_size(dbenv->lk_modes * dbenv->lk_modes, sizeof(db_align_t));
330
 
        retval += __db_shalloc_size(
331
 
            __db_tablesize(dbenv->lk_max_lockers) * (sizeof(DB_HASHTAB)), sizeof(db_align_t));
332
 
        retval += __db_shalloc_size(
333
 
            __db_tablesize(dbenv->lk_max_objects) * (sizeof(DB_HASHTAB)), sizeof(db_align_t));
334
 
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
335
 
        retval +=
336
 
            __db_shalloc_size(sizeof(REGMAINT) + __lock_region_maint(dbenv), sizeof(db_align_t));
337
 
#endif
338
 
        retval += __db_shalloc_size(
339
 
            sizeof(struct __db_lock), MUTEX_ALIGN) * dbenv->lk_max;
340
 
        retval += __db_shalloc_size(
341
 
            sizeof(DB_LOCKOBJ), sizeof(db_align_t)) * dbenv->lk_max_objects;
342
 
        retval += __db_shalloc_size(
343
 
            sizeof(DB_LOCKER), sizeof(db_align_t)) * dbenv->lk_max_lockers;
344
 
 
345
 
        /*
346
 
         * Include 16 bytes of string space per lock.  DB doesn't use it
347
 
         * because we pre-allocate lock space for DBTs in the structure.
348
 
         */
349
 
        retval += __db_shalloc_size(dbenv->lk_max * 16, sizeof(size_t));
350
 
 
351
 
        /* And we keep getting this wrong, let's be generous. */
352
 
        retval += retval / 4;
353
 
 
354
 
        return (retval);
355
 
}
356
 
 
357
 
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
358
 
/*
359
 
 * __lock_region_maint --
360
 
 *      Return the amount of space needed for region maintenance info.
361
 
 */
362
 
static size_t
363
 
__lock_region_maint(dbenv)
364
 
        DB_ENV *dbenv;
365
 
{
366
 
        size_t s;
367
 
 
368
 
        s = sizeof(DB_MUTEX *) * dbenv->lk_max;
369
 
        return (s);
370
 
}
371
 
#endif
372
 
 
373
 
/*
374
 
 * __lock_region_destroy
375
 
 *      Destroy any region maintenance info.
376
 
 *
377
 
 * PUBLIC: void __lock_region_destroy __P((DB_ENV *, REGINFO *));
378
 
 */
379
 
void
380
 
__lock_region_destroy(dbenv, infop)
381
 
        DB_ENV *dbenv;
382
 
        REGINFO *infop;
383
 
{
384
 
        __db_shlocks_destroy(infop, (REGMAINT *)R_ADDR(infop,
385
 
            ((DB_LOCKREGION *)R_ADDR(infop, infop->rp->primary))->maint_off));
386
 
 
387
 
        COMPQUIET(dbenv, NULL);
388
 
        COMPQUIET(infop, NULL);
389
 
}
390
 
 
391
 
#ifdef CONFIG_TEST
392
 
/*
393
 
 * __lock_id_set --
394
 
 *      Set the current locker ID and current maximum unused ID (for
395
 
 *      testing purposes only).
396
 
 *
397
 
 * PUBLIC: int __lock_id_set __P((DB_ENV *, u_int32_t, u_int32_t));
398
 
 */
399
 
int
400
 
__lock_id_set(dbenv, cur_id, max_id)
401
 
        DB_ENV *dbenv;
402
 
        u_int32_t cur_id, max_id;
403
 
{
404
 
        DB_LOCKTAB *lt;
405
 
        DB_LOCKREGION *region;
406
 
 
407
 
        ENV_REQUIRES_CONFIG(dbenv,
408
 
            dbenv->lk_handle, "lock_id_set", DB_INIT_LOCK);
409
 
 
410
 
        lt = dbenv->lk_handle;
411
 
        region = lt->reginfo.primary;
412
 
        region->stat.st_id = cur_id;
413
 
        region->stat.st_cur_maxid = max_id;
414
 
 
415
 
        return (0);
416
 
}
417
 
#endif