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

« back to all changes in this revision

Viewing changes to libdb/txn/txn_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
 
#if TIME_WITH_SYS_TIME
18
 
#include <sys/time.h>
19
 
#include <time.h>
20
 
#else
21
 
#if HAVE_SYS_TIME_H
22
 
#include <sys/time.h>
23
 
#else
24
 
#include <time.h>
25
 
#endif
26
 
#endif
27
 
 
28
 
#include <string.h>
29
 
#endif
30
 
 
31
 
#include "db_int.h"
32
 
#include "dbinc/log.h"
33
 
#include "dbinc/txn.h"
34
 
 
35
 
static int __txn_findlastckp __P((DB_ENV *, DB_LSN *));
36
 
static int __txn_init __P((DB_ENV *, DB_TXNMGR *));
37
 
static size_t __txn_region_size __P((DB_ENV *));
38
 
 
39
 
/*
40
 
 * __txn_open --
41
 
 *      Open a transaction region.
42
 
 *
43
 
 * PUBLIC: int __txn_open __P((DB_ENV *));
44
 
 */
45
 
int
46
 
__txn_open(dbenv)
47
 
        DB_ENV *dbenv;
48
 
{
49
 
        DB_TXNMGR *tmgrp;
50
 
        int ret;
51
 
 
52
 
        /* Create/initialize the transaction manager structure. */
53
 
        if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXNMGR), &tmgrp)) != 0)
54
 
                return (ret);
55
 
        TAILQ_INIT(&tmgrp->txn_chain);
56
 
        tmgrp->dbenv = dbenv;
57
 
 
58
 
        /* Join/create the txn region. */
59
 
        tmgrp->reginfo.type = REGION_TYPE_TXN;
60
 
        tmgrp->reginfo.id = INVALID_REGION_ID;
61
 
        tmgrp->reginfo.mode = dbenv->db_mode;
62
 
        tmgrp->reginfo.flags = REGION_JOIN_OK;
63
 
        if (F_ISSET(dbenv, DB_ENV_CREATE))
64
 
                F_SET(&tmgrp->reginfo, REGION_CREATE_OK);
65
 
        if ((ret = __db_r_attach(dbenv,
66
 
            &tmgrp->reginfo, __txn_region_size(dbenv))) != 0)
67
 
                goto err;
68
 
 
69
 
        /* If we created the region, initialize it. */
70
 
        if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
71
 
                if ((ret = __txn_init(dbenv, tmgrp)) != 0)
72
 
                        goto err;
73
 
 
74
 
        /* Set the local addresses. */
75
 
        tmgrp->reginfo.primary =
76
 
            R_ADDR(&tmgrp->reginfo, tmgrp->reginfo.rp->primary);
77
 
 
78
 
        /* Acquire a mutex to protect the active TXN list. */
79
 
        if (F_ISSET(dbenv, DB_ENV_THREAD) &&
80
 
            (ret = __db_mutex_setup(dbenv, &tmgrp->reginfo, &tmgrp->mutexp,
81
 
            MUTEX_ALLOC | MUTEX_NO_RLOCK | MUTEX_THREAD)) != 0)
82
 
                goto err;
83
 
 
84
 
        R_UNLOCK(dbenv, &tmgrp->reginfo);
85
 
 
86
 
        dbenv->tx_handle = tmgrp;
87
 
        return (0);
88
 
 
89
 
err:    if (tmgrp->reginfo.addr != NULL) {
90
 
                if (F_ISSET(&tmgrp->reginfo, REGION_CREATE))
91
 
                        ret = __db_panic(dbenv, ret);
92
 
                R_UNLOCK(dbenv, &tmgrp->reginfo);
93
 
 
94
 
                (void)__db_r_detach(dbenv, &tmgrp->reginfo, 0);
95
 
        }
96
 
        if (tmgrp->mutexp != NULL)
97
 
                __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp);
98
 
        __os_free(dbenv, tmgrp);
99
 
        return (ret);
100
 
}
101
 
 
102
 
/*
103
 
 * __txn_init --
104
 
 *      Initialize a transaction region in shared memory.
105
 
 */
106
 
static int
107
 
__txn_init(dbenv, tmgrp)
108
 
        DB_ENV *dbenv;
109
 
        DB_TXNMGR *tmgrp;
110
 
{
111
 
        DB_LSN last_ckp;
112
 
        DB_TXNREGION *region;
113
 
        int ret;
114
 
#ifdef  HAVE_MUTEX_SYSTEM_RESOURCES
115
 
        u_int8_t *addr;
116
 
#endif
117
 
 
118
 
        /*
119
 
         * Find the last checkpoint in the log.
120
 
         */
121
 
        ZERO_LSN(last_ckp);
122
 
        if (LOGGING_ON(dbenv)) {
123
 
                /*
124
 
                 * The log system has already walked through the last
125
 
                 * file.  Get the LSN of a checkpoint it may have found.
126
 
                 */
127
 
                __log_get_cached_ckp_lsn(dbenv, &last_ckp);
128
 
 
129
 
                /*
130
 
                 * If that didn't work, look backwards from the beginning of
131
 
                 * the last log file until we find the last checkpoint.
132
 
                 */
133
 
                if (IS_ZERO_LSN(last_ckp) &&
134
 
                    (ret = __txn_findlastckp(dbenv, &last_ckp)) != 0)
135
 
                        return (ret);
136
 
        }
137
 
 
138
 
        if ((ret = __db_shalloc(tmgrp->reginfo.addr,
139
 
            sizeof(DB_TXNREGION), 0, &tmgrp->reginfo.primary)) != 0) {
140
 
                __db_err(dbenv,
141
 
                    "Unable to allocate memory for the transaction region");
142
 
                return (ret);
143
 
        }
144
 
        tmgrp->reginfo.rp->primary =
145
 
            R_OFFSET(&tmgrp->reginfo, tmgrp->reginfo.primary);
146
 
        region = tmgrp->reginfo.primary;
147
 
        memset(region, 0, sizeof(*region));
148
 
 
149
 
        region->maxtxns = dbenv->tx_max;
150
 
        region->last_txnid = TXN_MINIMUM;
151
 
        region->cur_maxid = TXN_MAXIMUM;
152
 
        region->last_ckp = last_ckp;
153
 
        region->time_ckp = time(NULL);
154
 
 
155
 
        /*
156
 
         * XXX
157
 
         * If we ever do more types of locking and logging, this changes.
158
 
         */
159
 
        region->logtype = 0;
160
 
        region->locktype = 0;
161
 
 
162
 
        memset(&region->stat, 0, sizeof(region->stat));
163
 
        region->stat.st_maxtxns = region->maxtxns;
164
 
 
165
 
        SH_TAILQ_INIT(&region->active_txn);
166
 
#ifdef  HAVE_MUTEX_SYSTEM_RESOURCES
167
 
        /* Allocate room for the txn maintenance info and initialize it. */
168
 
        if ((ret = __db_shalloc(tmgrp->reginfo.addr,
169
 
            sizeof(REGMAINT) + TXN_MAINT_SIZE, 0, &addr)) != 0) {
170
 
                __db_err(dbenv,
171
 
                    "Unable to allocate memory for mutex maintenance");
172
 
                return (ret);
173
 
        }
174
 
        __db_maintinit(&tmgrp->reginfo, addr, TXN_MAINT_SIZE);
175
 
        region->maint_off = R_OFFSET(&tmgrp->reginfo, addr);
176
 
#endif
177
 
        return (0);
178
 
}
179
 
 
180
 
/*
181
 
 * __txn_findlastckp --
182
 
 *      Find the last checkpoint in the log, walking backwards from the
183
 
 *      beginning of the last log file.  (The log system looked through
184
 
 *      the last log file when it started up.)
185
 
 */
186
 
static int
187
 
__txn_findlastckp(dbenv, lsnp)
188
 
        DB_ENV *dbenv;
189
 
        DB_LSN *lsnp;
190
 
{
191
 
        DB_LOGC *logc;
192
 
        DB_LSN lsn;
193
 
        DBT dbt;
194
 
        int ret, t_ret;
195
 
        u_int32_t rectype;
196
 
 
197
 
        if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
198
 
                return (ret);
199
 
 
200
 
        /* Get the last LSN. */
201
 
        memset(&dbt, 0, sizeof(dbt));
202
 
        if ((ret = logc->get(logc, &lsn, &dbt, DB_LAST)) != 0)
203
 
                goto err;
204
 
 
205
 
        /*
206
 
         * Twiddle the last LSN so it points to the beginning of the last
207
 
         * file;  we know there's no checkpoint after that, since the log
208
 
         * system already looked there.
209
 
         */
210
 
        lsn.offset = 0;
211
 
 
212
 
        /* Read backwards, looking for checkpoints. */
213
 
        while ((ret = logc->get(logc, &lsn, &dbt, DB_PREV)) == 0) {
214
 
                if (dbt.size < sizeof(u_int32_t))
215
 
                        continue;
216
 
                memcpy(&rectype, dbt.data, sizeof(u_int32_t));
217
 
                if (rectype == DB___txn_ckp) {
218
 
                        *lsnp = lsn;
219
 
                        break;
220
 
                }
221
 
        }
222
 
 
223
 
err:    if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
224
 
                ret = t_ret;
225
 
        /*
226
 
         * Not finding a checkpoint is not an error;  there may not exist
227
 
         * one in the log.
228
 
         */
229
 
        return ((ret == 0 || ret == DB_NOTFOUND) ? 0 : ret);
230
 
}
231
 
 
232
 
/*
233
 
 * __txn_dbenv_refresh --
234
 
 *      Clean up after the transaction system on a close or failed open.
235
 
 * Called only from __dbenv_refresh.  (Formerly called __txn_close.)
236
 
 *
237
 
 * PUBLIC: int __txn_dbenv_refresh __P((DB_ENV *));
238
 
 */
239
 
int
240
 
__txn_dbenv_refresh(dbenv)
241
 
        DB_ENV *dbenv;
242
 
{
243
 
        DB_TXN *txnp;
244
 
        DB_TXNMGR *tmgrp;
245
 
        u_int32_t txnid;
246
 
        int ret, t_ret;
247
 
 
248
 
        ret = 0;
249
 
        tmgrp = dbenv->tx_handle;
250
 
 
251
 
        /*
252
 
         * This function can only be called once per process (i.e., not
253
 
         * once per thread), so no synchronization is required.
254
 
         *
255
 
         * The caller is doing something wrong if close is called with
256
 
         * active transactions.  Try and abort any active transactions,
257
 
         * but it's quite likely the aborts will fail because recovery
258
 
         * won't find open files.  If we can't abort any transaction,
259
 
         * panic, we have to run recovery to get back to a known state.
260
 
         */
261
 
        if (TAILQ_FIRST(&tmgrp->txn_chain) != NULL) {
262
 
                __db_err(dbenv,
263
 
        "Error: closing the transaction region with active transactions");
264
 
                ret = EINVAL;
265
 
                while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL) {
266
 
                        txnid = txnp->txnid;
267
 
                        if ((t_ret = txnp->abort(txnp)) != 0) {
268
 
                                __db_err(dbenv,
269
 
                                    "Unable to abort transaction 0x%x: %s",
270
 
                                    txnid, db_strerror(t_ret));
271
 
                                ret = __db_panic(dbenv, t_ret);
272
 
                                break;
273
 
                        }
274
 
                }
275
 
        }
276
 
 
277
 
        /* Flush the log. */
278
 
        if (LOGGING_ON(dbenv) &&
279
 
            (t_ret = dbenv->log_flush(dbenv, NULL)) != 0 && ret == 0)
280
 
                ret = t_ret;
281
 
 
282
 
        /* Discard the per-thread lock. */
283
 
        if (tmgrp->mutexp != NULL)
284
 
                __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp);
285
 
 
286
 
        /* Detach from the region. */
287
 
        if ((t_ret = __db_r_detach(dbenv, &tmgrp->reginfo, 0)) != 0 && ret == 0)
288
 
                ret = t_ret;
289
 
 
290
 
        __os_free(dbenv, tmgrp);
291
 
 
292
 
        dbenv->tx_handle = NULL;
293
 
        return (ret);
294
 
}
295
 
 
296
 
/*
297
 
 * __txn_region_size --
298
 
 *       Return the amount of space needed for the txn region.  Make the
299
 
 *       region large enough to hold txn_max transaction detail structures
300
 
 *       plus some space to hold thread handles and the beginning of the
301
 
 *       shalloc region and anything we need for mutex system resource
302
 
 *       recording.
303
 
 */
304
 
static size_t
305
 
__txn_region_size(dbenv)
306
 
        DB_ENV *dbenv;
307
 
{
308
 
        size_t s;
309
 
 
310
 
        s = sizeof(DB_TXNREGION) +
311
 
            dbenv->tx_max * sizeof(TXN_DETAIL) + 10 * 1024;
312
 
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
313
 
        if (F_ISSET(dbenv, DB_ENV_THREAD))
314
 
                s += sizeof(REGMAINT) + TXN_MAINT_SIZE;
315
 
#endif
316
 
        return (s);
317
 
}
318
 
 
319
 
/*
320
 
 * __txn_region_destroy
321
 
 *      Destroy any region maintenance info.
322
 
 *
323
 
 * PUBLIC: void __txn_region_destroy __P((DB_ENV *, REGINFO *));
324
 
 */
325
 
void
326
 
__txn_region_destroy(dbenv, infop)
327
 
        DB_ENV *dbenv;
328
 
        REGINFO *infop;
329
 
{
330
 
        __db_shlocks_destroy(infop, (REGMAINT *)R_ADDR(infop,
331
 
            ((DB_TXNREGION *)R_ADDR(infop, infop->rp->primary))->maint_off));
332
 
 
333
 
        COMPQUIET(dbenv, NULL);
334
 
        COMPQUIET(infop, NULL);
335
 
}
336
 
 
337
 
#ifdef CONFIG_TEST
338
 
/*
339
 
 * __txn_id_set --
340
 
 *      Set the current transaction ID and current maximum unused ID (for
341
 
 *      testing purposes only).
342
 
 *
343
 
 * PUBLIC: int __txn_id_set __P((DB_ENV *, u_int32_t, u_int32_t));
344
 
 */
345
 
int
346
 
__txn_id_set(dbenv, cur_txnid, max_txnid)
347
 
        DB_ENV *dbenv;
348
 
        u_int32_t cur_txnid, max_txnid;
349
 
{
350
 
        DB_TXNMGR *mgr;
351
 
        DB_TXNREGION *region;
352
 
        int ret;
353
 
 
354
 
        ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "txn_id_set", DB_INIT_TXN);
355
 
 
356
 
        mgr = dbenv->tx_handle;
357
 
        region = mgr->reginfo.primary;
358
 
        region->last_txnid = cur_txnid;
359
 
        region->cur_maxid = max_txnid;
360
 
 
361
 
        ret = 0;
362
 
        if (cur_txnid < TXN_MINIMUM) {
363
 
                __db_err(dbenv, "Current ID value %lu below minimum",
364
 
                    cur_txnid);
365
 
                ret = EINVAL;
366
 
        }
367
 
        if (max_txnid < TXN_MINIMUM) {
368
 
                __db_err(dbenv, "Maximum ID value %lu below minimum",
369
 
                    max_txnid);
370
 
                ret = EINVAL;
371
 
        }
372
 
        return (ret);
373
 
}
374
 
#endif