1
/* Copyright (C) 2000-2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24
Abort logging when we get an error in reading or writing log files
27
#include <drizzled/server_includes.h>
28
#include <drizzled/replicator.h>
29
#include <mysys/hash.h>
31
#include <mysys/my_dir.h>
34
#include <drizzled/plugin.h>
35
#include <drizzled/error.h>
36
#include <drizzled/errmsg_print.h>
37
#include <drizzled/gettext.h>
38
#include <drizzled/data_home.h>
39
#include <drizzled/session.h>
40
#include <drizzled/handler.h>
46
static const string engine_name("binlog");
48
StorageEngine *binlog_engine= NULL;
51
Save position of binary log transaction cache.
54
binlog_trans_log_savepos()
56
session The thread to take the binlog data from
57
pos Pointer to variable where the position will be stored
61
Save the current position in the binary log transaction cache into
62
the variable pointed to by 'pos'
66
binlog_trans_log_savepos(Session *, my_off_t *pos)
74
class BinlogEngine : public StorageEngine
77
BinlogEngine(const string &name_arg)
78
: StorageEngine(name_arg,
79
HTON_NOT_USER_SELECTABLE | HTON_HIDDEN,
82
virtual int close_connection(Session *)
88
virtual int prepare(Session *session, bool)
92
just pretend we can do 2pc, so that MySQL won't
94
real work will be done in DRIZZLE_BIN_LOG::log_xid()
97
(void)replicator_prepare(session);
103
This function is called once after each statement.
105
It has the responsibility to flush the transaction cache to the
106
binlog file on commits.
108
@param engine The binlog StorageEngine.
109
@param session The client thread that executes the transaction.
110
@param all This is @c true if this is a real transaction commit, and
113
@see StorageEngine::commit
115
virtual int commit(Session *session, bool all)
118
Decision table for committing a transaction. The top part, the
119
*conditions* represent different cases that can occur, and hte
120
bottom part, the *actions*, represent what should be done in that
123
Real transaction 'all' was true
125
Statement in cache There were at least one statement in the
128
In transaction We are inside a transaction
130
Stmt modified non-trans The statement being committed modified a
131
non-transactional table
133
All modified non-trans Some statement before this one in the
134
transaction modified a non-transactional
138
============================= = = = = = = = = = = = = = = = =
139
Real transaction N N N N N N N N N N N N N N N N
140
Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y
141
In transaction N N N N Y Y Y Y N N N N Y Y Y Y
142
Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y
143
All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y
145
Action: (C)ommit/(A)ccumulate C C - C A C - C - - - - A A - A
146
============================= = = = = = = = = = = = = = = = =
149
============================= = = = = = = = = = = = = = = = =
150
Real transaction Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
151
Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y
152
In transaction N N N N Y Y Y Y N N N N Y Y Y Y
153
Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y
154
All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y
156
(C)ommit/(A)ccumulate/(-) - - - - C C - C - - - - C C - C
157
============================= = = = = = = = = = = = = = = = =
159
In other words, we commit the transaction if and only if both of
160
the following are true:
161
- We are not in a transaction and committing a statement
163
- We are in a transaction and one (or more) of the following are
166
- A full transaction is committed
170
- A non-transactional statement is committed and there is
173
Otherwise, we accumulate the statement
176
if (all || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
178
return replicator_end_transaction(session, all, true);
185
This function is called when a transaction involving a transactional
186
table is rolled back.
188
It has the responsibility to flush the transaction cache to the
189
binlog file. However, if the transaction does not involve
190
non-transactional tables, nothing needs to be logged.
192
@param engine The binlog StorageEngine.
193
@param session The client thread that executes the transaction.
194
@param all This is @c true if this is a real transaction rollback, and
197
@see StorageEngine::rollback
199
virtual int rollback(Session *session, bool all)
203
/* TODO: Fix return type */
204
(void)replicator_end_transaction(session, all, false);
211
How do we handle this (unlikely but legal) case:
213
[transaction] + [update to non-trans table] + [rollback to savepoint] ?
215
The problem occurs when a savepoint is before the update to the
216
non-transactional table. Then when there's a rollback to the savepoint, if we
217
simply truncate the binlog cache, we lose the part of the binlog cache where
218
the update is. If we want to not lose it, we need to write the SAVEPOINT
219
command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
220
is easy: it's just write at the end of the binlog cache, but the former
221
should be *inserted* to the place where the user called SAVEPOINT. The
222
solution is that when the user calls SAVEPOINT, we write it to the binlog
223
cache (so no need to later insert it). As transactions are never intermixed
224
in the binary log (i.e. they are serialized), we won't have conflicts with
225
savepoint names when using mysqlbinlog or in the slave SQL thread.
226
Then when ROLLBACK TO SAVEPOINT is called, if we updated some
227
non-transactional table, we don't truncate the binlog cache but instead write
228
ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
229
will chop the SAVEPOINT command from the binlog cache, which is good as in
230
that case there is no need to have it in the binlog).
233
virtual int savepoint_set_hook(Session *session, void *sv)
236
binlog_trans_log_savepos(session, (my_off_t*) sv);
237
/* Write it to the binary log */
239
error= replicator_statement(session, session->query, session->query_length);
244
virtual int savepoint_rollback_hook(Session *session, void *)
248
error= replicator_statement(session, session->query, session->query_length);
253
virtual handler* create(TABLE_SHARE*, MEM_ROOT*)
262
this function is mostly a placeholder.
263
conceptually, binlog initialization (now mostly done in DRIZZLE_BIN_LOG::open)
264
should be moved here.
267
int binlog_init(void *p)
269
StorageEngine** engine= static_cast<StorageEngine **>(p);
271
if (binlog_engine == NULL)
273
binlog_engine= new BinlogEngine(engine_name);
276
*engine= binlog_engine;
281
drizzle_declare_plugin(binlog)
283
DRIZZLE_STORAGE_ENGINE_PLUGIN,
287
"This is a pseudo storage engine to represent the binlog in a transaction",
289
binlog_init, /* Plugin Init */
290
NULL, /* Plugin Deinit */
291
NULL, /* status variables */
292
NULL, /* system variables */
293
NULL /* config options */
295
drizzle_declare_plugin_end;