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

« back to all changes in this revision

Viewing changes to libdb/txn/txn_rec.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
 
 * Copyright (c) 1996
9
 
 *      The President and Fellows of Harvard University.  All rights reserved.
10
 
 *
11
 
 * Redistribution and use in source and binary forms, with or without
12
 
 * modification, are permitted provided that the following conditions
13
 
 * are met:
14
 
 * 1. Redistributions of source code must retain the above copyright
15
 
 *    notice, this list of conditions and the following disclaimer.
16
 
 * 2. Redistributions in binary form must reproduce the above copyright
17
 
 *    notice, this list of conditions and the following disclaimer in the
18
 
 *    documentation and/or other materials provided with the distribution.
19
 
 * 3. Neither the name of the University nor the names of its contributors
20
 
 *    may be used to endorse or promote products derived from this software
21
 
 *    without specific prior written permission.
22
 
 *
23
 
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 
 * SUCH DAMAGE.
34
 
 */
35
 
 
36
 
#include "db_config.h"
37
 
 
38
 
#ifndef lint
39
 
static const char revid[] = "$Id$";
40
 
#endif /* not lint */
41
 
 
42
 
#ifndef NO_SYSTEM_INCLUDES
43
 
#include <sys/types.h>
44
 
 
45
 
#include <string.h>
46
 
#endif
47
 
 
48
 
#include "db_int.h"
49
 
#include "dbinc/db_page.h"
50
 
#include "dbinc/txn.h"
51
 
#include "dbinc/db_am.h"
52
 
#include "dbinc/db_dispatch.h"
53
 
 
54
 
#define IS_XA_TXN(R) (R->xid.size != 0)
55
 
 
56
 
/*
57
 
 * PUBLIC: int __txn_regop_recover
58
 
 * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
59
 
 *
60
 
 * These records are only ever written for commits.  Normally, we redo any
61
 
 * committed transaction, however if we are doing recovery to a timestamp, then
62
 
 * we may treat transactions that commited after the timestamp as aborted.
63
 
 */
64
 
int
65
 
__txn_regop_recover(dbenv, dbtp, lsnp, op, info)
66
 
        DB_ENV *dbenv;
67
 
        DBT *dbtp;
68
 
        DB_LSN *lsnp;
69
 
        db_recops op;
70
 
        void *info;
71
 
{
72
 
        DB_TXNHEAD *headp;
73
 
        __txn_regop_args *argp;
74
 
        int ret;
75
 
 
76
 
#ifdef DEBUG_RECOVER
77
 
        (void)__txn_regop_print(dbenv, dbtp, lsnp, op, info);
78
 
#endif
79
 
 
80
 
        if ((ret = __txn_regop_read(dbenv, dbtp->data, &argp)) != 0)
81
 
                return (ret);
82
 
 
83
 
        headp = info;
84
 
        /*
85
 
         * We are only ever called during FORWARD_ROLL or BACKWARD_ROLL.
86
 
         * We check for the former explicitly and the last two clauses
87
 
         * apply to the BACKWARD_ROLL case.
88
 
         */
89
 
 
90
 
        if (op == DB_TXN_FORWARD_ROLL)
91
 
                /*
92
 
                 * If this was a 2-phase-commit transaction, then it
93
 
                 * might already have been removed from the list, and
94
 
                 * that's OK.  Ignore the return code from remove.
95
 
                 */
96
 
                (void)__db_txnlist_remove(dbenv, info, argp->txnid->txnid);
97
 
        else if ((dbenv->tx_timestamp != 0 &&
98
 
            argp->timestamp > (int32_t)dbenv->tx_timestamp) ||
99
 
            (!IS_ZERO_LSN(headp->trunc_lsn) &&
100
 
            log_compare(&headp->trunc_lsn, lsnp) < 0)) {
101
 
                /*
102
 
                 * We failed either the timestamp check or the trunc_lsn check,
103
 
                 * so we treat this as an abort even if it was a commit record.
104
 
                 */
105
 
                ret = __db_txnlist_update(dbenv,
106
 
                    info, argp->txnid->txnid, TXN_ABORT, NULL);
107
 
 
108
 
                if (ret == TXN_NOTFOUND)
109
 
                        ret = __db_txnlist_add(dbenv,
110
 
                            info, argp->txnid->txnid, TXN_IGNORE, NULL);
111
 
                else if (ret != TXN_OK)
112
 
                        goto err;
113
 
                /* else ret = 0; Not necessary because TXN_OK == 0 */
114
 
        } else {
115
 
                /* This is a normal commit; mark it appropriately. */
116
 
                ret = __db_txnlist_update(dbenv,
117
 
                    info, argp->txnid->txnid, argp->opcode, lsnp);
118
 
 
119
 
                if (ret == TXN_NOTFOUND)
120
 
                        ret = __db_txnlist_add(dbenv,
121
 
                            info, argp->txnid->txnid,
122
 
                            argp->opcode == TXN_ABORT ?
123
 
                            TXN_IGNORE : argp->opcode, lsnp);
124
 
                else if (ret != TXN_OK)
125
 
                        goto err;
126
 
                /* else ret = 0; Not necessary because TXN_OK == 0 */
127
 
        }
128
 
 
129
 
        if (ret == 0)
130
 
                *lsnp = argp->prev_lsn;
131
 
 
132
 
        if (0) {
133
 
err:            __db_err(dbenv,
134
 
                    "txnid %lx commit record found, already on commit list",
135
 
                    argp->txnid->txnid);
136
 
                ret = EINVAL;
137
 
        }
138
 
        __os_free(dbenv, argp);
139
 
 
140
 
        return (ret);
141
 
}
142
 
 
143
 
/*
144
 
 * PUBLIC: int __txn_xa_regop_recover
145
 
 * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
146
 
 *
147
 
 * These records are only ever written for prepares.
148
 
 */
149
 
int
150
 
__txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info)
151
 
        DB_ENV *dbenv;
152
 
        DBT *dbtp;
153
 
        DB_LSN *lsnp;
154
 
        db_recops op;
155
 
        void *info;
156
 
{
157
 
        __txn_xa_regop_args *argp;
158
 
        int ret;
159
 
 
160
 
#ifdef DEBUG_RECOVER
161
 
        (void)__txn_xa_regop_print(dbenv, dbtp, lsnp, op, info);
162
 
#endif
163
 
 
164
 
        if ((ret = __txn_xa_regop_read(dbenv, dbtp->data, &argp)) != 0)
165
 
                return (ret);
166
 
 
167
 
        if (argp->opcode != TXN_PREPARE) {
168
 
                ret = EINVAL;
169
 
                goto err;
170
 
        }
171
 
 
172
 
        ret = __db_txnlist_find(dbenv, info, argp->txnid->txnid);
173
 
 
174
 
        /*
175
 
         * If we are rolling forward, then an aborted prepare
176
 
         * indicates that this may the last record we'll see for
177
 
         * this transaction ID, so we should remove it from the
178
 
         * list.
179
 
         */
180
 
 
181
 
        if (op == DB_TXN_FORWARD_ROLL) {
182
 
                if ((ret = __db_txnlist_remove(dbenv,
183
 
                    info, argp->txnid->txnid)) != TXN_OK)
184
 
                        goto txn_err;
185
 
        } else if (op == DB_TXN_BACKWARD_ROLL && ret == TXN_PREPARE) {
186
 
                /*
187
 
                 * On the backward pass, we have three possibilities:
188
 
                 * 1. The transaction is already committed, no-op.
189
 
                 * 2. The transaction is already aborted, no-op.
190
 
                 * 3. The transaction is neither committed nor aborted.
191
 
                 *       Treat this like a commit and roll forward so that
192
 
                 *       the transaction can be resurrected in the region.
193
 
                 * We handle case 3 here; cases 1 and 2 are the final clause
194
 
                 * below.
195
 
                 * This is prepared, but not yet committed transaction.  We
196
 
                 * need to add it to the transaction list, so that it gets
197
 
                 * rolled forward. We also have to add it to the region's
198
 
                 * internal state so it can be properly aborted or committed
199
 
                 * after recovery (see txn_recover).
200
 
                 */
201
 
                if ((ret = __db_txnlist_remove(dbenv,
202
 
                   info, argp->txnid->txnid)) != TXN_OK) {
203
 
txn_err:                __db_err(dbenv,
204
 
                            "Transaction not in list %x", argp->txnid->txnid);
205
 
                        ret = DB_NOTFOUND;
206
 
                } else if ((ret = __db_txnlist_add(dbenv,
207
 
                   info, argp->txnid->txnid, TXN_COMMIT, lsnp)) == 0)
208
 
                        ret = __txn_restore_txn(dbenv, lsnp, argp);
209
 
        } else
210
 
                ret = 0;
211
 
 
212
 
        if (ret == 0)
213
 
                *lsnp = argp->prev_lsn;
214
 
 
215
 
err:    __os_free(dbenv, argp);
216
 
 
217
 
        return (ret);
218
 
}
219
 
 
220
 
/*
221
 
 * PUBLIC: int __txn_ckp_recover
222
 
 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
223
 
 */
224
 
int
225
 
__txn_ckp_recover(dbenv, dbtp, lsnp, op, info)
226
 
        DB_ENV *dbenv;
227
 
        DBT *dbtp;
228
 
        DB_LSN *lsnp;
229
 
        db_recops op;
230
 
        void *info;
231
 
{
232
 
        __txn_ckp_args *argp;
233
 
        int ret;
234
 
 
235
 
#ifdef DEBUG_RECOVER
236
 
        __txn_ckp_print(dbenv, dbtp, lsnp, op, info);
237
 
#endif
238
 
        COMPQUIET(dbenv, NULL);
239
 
 
240
 
        if ((ret = __txn_ckp_read(dbenv, dbtp->data, &argp)) != 0)
241
 
                return (ret);
242
 
 
243
 
        if (op == DB_TXN_BACKWARD_ROLL)
244
 
                __db_txnlist_ckp(dbenv, info, lsnp);
245
 
 
246
 
        *lsnp = argp->last_ckp;
247
 
        __os_free(dbenv, argp);
248
 
        return (DB_TXN_CKP);
249
 
}
250
 
 
251
 
/*
252
 
 * __txn_child_recover
253
 
 *      Recover a commit record for a child transaction.
254
 
 *
255
 
 * PUBLIC: int __txn_child_recover
256
 
 * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
257
 
 */
258
 
int
259
 
__txn_child_recover(dbenv, dbtp, lsnp, op, info)
260
 
        DB_ENV *dbenv;
261
 
        DBT *dbtp;
262
 
        DB_LSN *lsnp;
263
 
        db_recops op;
264
 
        void *info;
265
 
{
266
 
        __txn_child_args *argp;
267
 
        int c_stat, p_stat, ret;
268
 
 
269
 
#ifdef DEBUG_RECOVER
270
 
        (void)__txn_child_print(dbenv, dbtp, lsnp, op, info);
271
 
#endif
272
 
        if ((ret = __txn_child_read(dbenv, dbtp->data, &argp)) != 0)
273
 
                return (ret);
274
 
 
275
 
        /*
276
 
         * This is a record in a PARENT's log trail indicating that a
277
 
         * child commited.  If we are aborting, we need to update the
278
 
         * parent's LSN array.  If we are in recovery, then if the
279
 
         * parent is commiting, we set ourselves up to commit, else
280
 
         * we do nothing.
281
 
         */
282
 
        if (op == DB_TXN_ABORT) {
283
 
                /* Note that __db_txnlist_lsnadd rewrites its LSN
284
 
                 * parameter, so you cannot reuse the argp->c_lsn field.
285
 
                 */
286
 
                ret = __db_txnlist_lsnadd(dbenv,
287
 
                    info, &argp->c_lsn, TXNLIST_NEW);
288
 
        } else if (op == DB_TXN_BACKWARD_ROLL) {
289
 
                /* Child might exist -- look for it. */
290
 
                c_stat = __db_txnlist_find(dbenv, info, argp->child);
291
 
                p_stat = __db_txnlist_find(dbenv, info, argp->txnid->txnid);
292
 
 
293
 
                if (c_stat == TXN_EXPECTED) {
294
 
                        /*
295
 
                         * The open after this create succeeded.  If the
296
 
                         * parent succeeded, we don't want to redo; if the
297
 
                         * parent aborted, we do want to undo.
298
 
                         */
299
 
                        ret = __db_txnlist_update(dbenv,
300
 
                            info, argp->child,
301
 
                            p_stat == TXN_COMMIT ? TXN_IGNORE : TXN_ABORT,
302
 
                            NULL);
303
 
                        if (ret > 0)
304
 
                                ret = 0;
305
 
                } else if (c_stat == TXN_UNEXPECTED) {
306
 
                        /*
307
 
                         * The open after this create failed.  If the parent
308
 
                         * is rolling forward, we need to roll forward.  If
309
 
                         * the parent failed, then we do not want to abort
310
 
                         * (because the file may not be the one in which we
311
 
                         * are interested).
312
 
                         */
313
 
                        ret = __db_txnlist_update(dbenv, info, argp->child,
314
 
                            p_stat == TXN_COMMIT ? TXN_COMMIT : TXN_IGNORE,
315
 
                            NULL);
316
 
                        if (ret > 0)
317
 
                                ret = 0;
318
 
                } else if (c_stat != TXN_IGNORE) {
319
 
                        ret = __db_txnlist_add(dbenv, info, argp->child,
320
 
                            p_stat == TXN_COMMIT ? TXN_COMMIT : TXN_ABORT,
321
 
                            NULL);
322
 
                }
323
 
        } else {
324
 
                /* Forward Roll */
325
 
                if ((ret =
326
 
                    __db_txnlist_remove(dbenv, info, argp->child)) != TXN_OK) {
327
 
                        __db_err(dbenv,
328
 
                            "Transaction not in list %x", argp->txnid->txnid);
329
 
                        ret = DB_NOTFOUND;
330
 
                }
331
 
        }
332
 
 
333
 
        if (ret == 0)
334
 
                *lsnp = argp->prev_lsn;
335
 
 
336
 
        __os_free(dbenv, argp);
337
 
 
338
 
        return (ret);
339
 
}
340
 
 
341
 
/*
342
 
 * __txn_restore_txn --
343
 
 *      Using only during XA recovery.  If we find any transactions that are
344
 
 * prepared, but not yet committed, then we need to restore the transaction's
345
 
 * state into the shared region, because the TM is going to issue an abort
346
 
 * or commit and we need to respond correctly.
347
 
 *
348
 
 * lsnp is the LSN of the returned LSN
349
 
 * argp is the perpare record (in an appropriate structure)
350
 
 *
351
 
 * PUBLIC: int __txn_restore_txn __P((DB_ENV *,
352
 
 * PUBLIC:     DB_LSN *, __txn_xa_regop_args *));
353
 
 */
354
 
int
355
 
__txn_restore_txn(dbenv, lsnp, argp)
356
 
        DB_ENV *dbenv;
357
 
        DB_LSN *lsnp;
358
 
        __txn_xa_regop_args *argp;
359
 
{
360
 
        DB_TXNMGR *mgr;
361
 
        TXN_DETAIL *td;
362
 
        DB_TXNREGION *region;
363
 
        int ret;
364
 
 
365
 
        if (argp->xid.size == 0)
366
 
        return (0);
367
 
 
368
 
        mgr = dbenv->tx_handle;
369
 
        region = mgr->reginfo.primary;
370
 
        R_LOCK(dbenv, &mgr->reginfo);
371
 
 
372
 
        /* Allocate a new transaction detail structure. */
373
 
        if ((ret =
374
 
            __db_shalloc(mgr->reginfo.addr, sizeof(TXN_DETAIL), 0, &td)) != 0) {
375
 
                R_UNLOCK(dbenv, &mgr->reginfo);
376
 
                return (ret);
377
 
        }
378
 
 
379
 
        /* Place transaction on active transaction list. */
380
 
        SH_TAILQ_INSERT_HEAD(&region->active_txn, td, links, __txn_detail);
381
 
 
382
 
        td->txnid = argp->txnid->txnid;
383
 
        td->begin_lsn = argp->begin_lsn;
384
 
        td->last_lsn = *lsnp;
385
 
        td->parent = 0;
386
 
        td->status = TXN_PREPARED;
387
 
        td->xa_status = TXN_XA_PREPARED;
388
 
        memcpy(td->xid, argp->xid.data, argp->xid.size);
389
 
        td->bqual = argp->bqual;
390
 
        td->gtrid = argp->gtrid;
391
 
        td->format = argp->formatID;
392
 
        td->flags = 0;
393
 
        F_SET(td, TXN_RESTORED);
394
 
 
395
 
        region->stat.st_nrestores++;
396
 
        region->stat.st_nactive++;
397
 
        if (region->stat.st_nactive > region->stat.st_maxnactive)
398
 
                region->stat.st_maxnactive = region->stat.st_nactive;
399
 
        R_UNLOCK(dbenv, &mgr->reginfo);
400
 
        return (0);
401
 
}
402
 
 
403
 
/*
404
 
 * __txn_recycle_recover --
405
 
 *      Recovery function for recycle.
406
 
 *
407
 
 * PUBLIC: int __txn_recycle_recover
408
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
409
 
 */
410
 
int
411
 
__txn_recycle_recover(dbenv, dbtp, lsnp, op, info)
412
 
        DB_ENV *dbenv;
413
 
        DBT *dbtp;
414
 
        DB_LSN *lsnp;
415
 
        db_recops op;
416
 
        void *info;
417
 
{
418
 
        __txn_recycle_args *argp;
419
 
        int ret;
420
 
 
421
 
#ifdef DEBUG_RECOVER
422
 
        (void)__txn_child_print(dbenv, dbtp, lsnp, op, info);
423
 
#endif
424
 
        if ((ret = __txn_recycle_read(dbenv, dbtp->data, &argp)) != 0)
425
 
                return (ret);
426
 
 
427
 
        COMPQUIET(lsnp, NULL);
428
 
 
429
 
        if ((ret = __db_txnlist_gen(dbenv, info,
430
 
            DB_UNDO(op) ? -1 : 1, argp->min, argp->max)) != 0)
431
 
                return (ret);
432
 
 
433
 
        __os_free(dbenv, argp);
434
 
 
435
 
        return (0);
436
 
}