~vlad-lesin/percona-server/mysql-5.0.33-original

« back to all changes in this revision

Viewing changes to bdb/txn/txn_util.c

  • Committer: Vlad Lesin
  • Date: 2012-07-31 09:21:34 UTC
  • Revision ID: vladislav.lesin@percona.com-20120731092134-zfodx022b7992wsi
VirginĀ 5.0.33

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) 2001-2002
 
5
 *      Sleepycat Software.  All rights reserved.
 
6
 */
 
7
 
 
8
#include "db_config.h"
 
9
 
 
10
#ifndef lint
 
11
static const char revid[] = "$Id: txn_util.c,v 11.18 2002/08/06 06:25:12 bostic Exp $";
 
12
#endif /* not lint */
 
13
 
 
14
#ifndef NO_SYSTEM_INCLUDES
 
15
#include <sys/types.h>
 
16
#include <string.h>
 
17
#endif
 
18
 
 
19
#include "db_int.h"
 
20
#include "dbinc/db_shash.h"
 
21
#include "dbinc/lock.h"
 
22
#include "dbinc/txn.h"
 
23
 
 
24
typedef struct __txn_event TXN_EVENT;
 
25
struct __txn_event {
 
26
        TXN_EVENT_T op;
 
27
        TAILQ_ENTRY(__txn_event) links;
 
28
        union {
 
29
                struct {
 
30
                        /* Delayed remove. */
 
31
                        char *name;
 
32
                        u_int8_t *fileid;
 
33
                } r;
 
34
                struct {
 
35
                        /* Lock event. */
 
36
                        DB_LOCK lock;
 
37
                        u_int32_t locker;
 
38
                        DB *dbp;
 
39
                } t;
 
40
        } u;
 
41
};
 
42
 
 
43
/*
 
44
 * __txn_remevent --
 
45
 *
 
46
 * Creates a remove event that can be added to the commit list.
 
47
 *
 
48
 * PUBLIC: int __txn_remevent __P((DB_ENV *,
 
49
 * PUBLIC:       DB_TXN *, const char *, u_int8_t*));
 
50
 */
 
51
int
 
52
__txn_remevent(dbenv, txn, name, fileid)
 
53
        DB_ENV *dbenv;
 
54
        DB_TXN *txn;
 
55
        const char *name;
 
56
        u_int8_t *fileid;
 
57
{
 
58
        int ret;
 
59
        TXN_EVENT *e;
 
60
 
 
61
        e = NULL;
 
62
        if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
 
63
                return (ret);
 
64
 
 
65
        if ((ret = __os_strdup(dbenv, name, &e->u.r.name)) != 0)
 
66
                goto err;
 
67
 
 
68
        if (fileid != NULL) {
 
69
                if ((ret = __os_calloc(dbenv,
 
70
                    1, DB_FILE_ID_LEN, &e->u.r.fileid)) != 0)
 
71
                        return (ret);
 
72
                memcpy(e->u.r.fileid, fileid, DB_FILE_ID_LEN);
 
73
        }
 
74
 
 
75
        e->op = TXN_REMOVE;
 
76
        TAILQ_INSERT_TAIL(&txn->events, e, links);
 
77
 
 
78
        return (0);
 
79
 
 
80
err:    if (e != NULL)
 
81
                __os_free(dbenv, e);
 
82
 
 
83
        return (ret);
 
84
}
 
85
 
 
86
/*
 
87
 * __txn_lockevent --
 
88
 *
 
89
 * Add a lockevent to the commit-queue.  The lock event indicates a locker
 
90
 * trade.
 
91
 *
 
92
 * PUBLIC: int __txn_lockevent __P((DB_ENV *,
 
93
 * PUBLIC:     DB_TXN *, DB *, DB_LOCK *, u_int32_t));
 
94
 */
 
95
int
 
96
__txn_lockevent(dbenv, txn, dbp, lock, locker)
 
97
        DB_ENV *dbenv;
 
98
        DB_TXN *txn;
 
99
        DB *dbp;
 
100
        DB_LOCK *lock;
 
101
        u_int32_t locker;
 
102
{
 
103
        int ret;
 
104
        TXN_EVENT *e;
 
105
 
 
106
        if (!LOCKING_ON(dbenv))
 
107
                return (0);
 
108
 
 
109
        e = NULL;
 
110
        if ((ret = __os_calloc(dbenv, 1, sizeof(TXN_EVENT), &e)) != 0)
 
111
                return (ret);
 
112
 
 
113
        e->u.t.locker = locker;
 
114
        e->u.t.lock = *lock;
 
115
        e->u.t.dbp = dbp;
 
116
        e->op = TXN_TRADE;
 
117
        TAILQ_INSERT_TAIL(&txn->events, e, links);
 
118
 
 
119
        return (0);
 
120
}
 
121
 
 
122
/*
 
123
 * __txn_remlock --
 
124
 *      Remove a lock event because the locker is going away.  We can remove
 
125
 * by lock (using offset) or by locker_id (or by both).
 
126
 *
 
127
 * PUBLIC: void __txn_remlock __P((DB_ENV *, DB_TXN *, DB_LOCK *, u_int32_t));
 
128
 */
 
129
void
 
130
__txn_remlock(dbenv, txn, lock, locker)
 
131
        DB_ENV *dbenv;
 
132
        DB_TXN *txn;
 
133
        DB_LOCK *lock;
 
134
        u_int32_t locker;
 
135
{
 
136
        TXN_EVENT *e, *next_e;
 
137
 
 
138
        for (e = TAILQ_FIRST(&txn->events); e != NULL; e = next_e) {
 
139
                next_e = TAILQ_NEXT(e, links);
 
140
                if ((e->op != TXN_TRADE && e->op != TXN_TRADED) ||
 
141
                    (e->u.t.lock.off != lock->off && e->u.t.locker != locker))
 
142
                        continue;
 
143
                TAILQ_REMOVE(&txn->events, e, links);
 
144
                __os_free(dbenv, e);
 
145
        }
 
146
 
 
147
        return;
 
148
}
 
149
 
 
150
/*
 
151
 * __txn_doevents --
 
152
 * Process the list of events associated with a transaction.  On commit,
 
153
 * apply the events; on abort, just toss the entries.
 
154
 *
 
155
 * PUBLIC: int __txn_doevents __P((DB_ENV *, DB_TXN *, int, int));
 
156
 */
 
157
#define DO_TRADE do {                                                   \
 
158
        memset(&req, 0, sizeof(req));                                   \
 
159
        req.lock = e->u.t.lock;                                         \
 
160
        req.op = DB_LOCK_TRADE;                                         \
 
161
        t_ret = __lock_vec(dbenv, e->u.t.locker, 0, &req, 1, NULL);     \
 
162
        if (t_ret == 0)                                                 \
 
163
                e->u.t.dbp->cur_lid = e->u.t.locker;                    \
 
164
        else if (t_ret == DB_NOTFOUND)                                  \
 
165
                t_ret = 0;                                              \
 
166
        if (t_ret != 0 && ret == 0)                                     \
 
167
                ret = t_ret;                                            \
 
168
        e->op = TXN_TRADED;                                             \
 
169
} while (0)
 
170
 
 
171
int
 
172
__txn_doevents(dbenv, txn, is_commit, preprocess)
 
173
        DB_ENV *dbenv;
 
174
        DB_TXN *txn;
 
175
        int is_commit, preprocess;
 
176
{
 
177
        DB_LOCKREQ req;
 
178
        TXN_EVENT *e;
 
179
        int ret, t_ret;
 
180
 
 
181
        ret = 0;
 
182
 
 
183
        /*
 
184
         * This phase only gets called if we have a phase where we
 
185
         * release read locks.  Since not all paths will call this
 
186
         * phase, we have to check for it below as well.  So, when
 
187
         * we do the trade, we update the opcode of the entry so that
 
188
         * we don't try the trade again.
 
189
         */
 
190
        if (preprocess) {
 
191
                for (e = TAILQ_FIRST(&txn->events);
 
192
                    e != NULL; e = TAILQ_NEXT(e, links)) {
 
193
                        if (e->op != TXN_TRADE)
 
194
                                continue;
 
195
                        DO_TRADE;
 
196
                }
 
197
                return (ret);
 
198
        }
 
199
 
 
200
        while ((e = TAILQ_FIRST(&txn->events)) != NULL) {
 
201
                TAILQ_REMOVE(&txn->events, e, links);
 
202
                if (!is_commit)
 
203
                        goto dofree;
 
204
                switch (e->op) {
 
205
                case TXN_REMOVE:
 
206
                        if (e->u.r.fileid != NULL) {
 
207
                                if ((t_ret = dbenv->memp_nameop(dbenv,
 
208
                                    e->u.r.fileid,
 
209
                                    NULL, e->u.r.name, NULL)) != 0 && ret == 0)
 
210
                                        ret = t_ret;
 
211
                                __os_free(dbenv, e->u.r.fileid);
 
212
                        } else if ((t_ret =
 
213
                            __os_unlink(dbenv, e->u.r.name)) != 0 && ret == 0)
 
214
                                ret = t_ret;
 
215
                        __os_free(dbenv, e->u.r.name);
 
216
                        break;
 
217
                case TXN_TRADE:
 
218
                        DO_TRADE;
 
219
                        /* Fall through */
 
220
                case TXN_TRADED:
 
221
                        /* Downgrade the lock. */
 
222
                        if ((t_ret = __lock_downgrade(dbenv,
 
223
                            &e->u.t.lock, DB_LOCK_READ, 0)) != 0 && ret == 0)
 
224
                                ret = t_ret;
 
225
                        break;
 
226
                default:
 
227
                        /* This had better never happen. */
 
228
                        DB_ASSERT(0);
 
229
                }
 
230
dofree:         __os_free(dbenv, e);
 
231
        }
 
232
 
 
233
        return (ret);
 
234
}