107
107
void operator=(Mutex_sentry const&);
111
Helper class to store binary log transaction data.
113
class binlog_trx_data {
116
: at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF)
118
trans_log.end_of_file= max_binlog_cache_size;
123
assert(pending() == NULL);
124
close_cached_file(&trans_log);
127
my_off_t position() const {
128
return my_b_tell(&trans_log);
133
return pending() == NULL && my_b_tell(&trans_log) == 0;
137
Truncate the transaction cache to a certain position. This
138
includes deleting the pending event.
140
void truncate(my_off_t pos)
144
reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
145
if (pos < before_stmt_pos)
146
before_stmt_pos= MY_OFF_T_UNDEF;
149
The only valid positions that can be truncated to are at the
150
beginning of a statement. We are relying on this fact to be able
151
to set the at_least_one_stmt flag correctly. In other word, if
152
we are truncating to the beginning of the transaction cache,
153
there will be no statements in the cache, otherwhise, we will
154
have at least one statement in the transaction cache.
156
at_least_one_stmt= (pos > 0);
160
Reset the entire contents of the transaction cache, emptying it
166
before_stmt_pos= MY_OFF_T_UNDEF;
167
trans_log.end_of_file= max_binlog_cache_size;
170
Rows_log_event *pending() const
175
void set_pending(Rows_log_event *const pending)
180
IO_CACHE trans_log; // The transaction cache
183
Boolean that is true if there is at least one statement in the
186
bool at_least_one_stmt;
190
Pending binrows event. This event is the event where the rows are
193
Rows_log_event *m_pending;
197
Binlog position before the start of the current statement.
199
my_off_t before_stmt_pos;
202
110
handlerton *binlog_hton;
256
static int binlog_close_connection(handlerton *, Session *session)
159
static int binlog_close_connection(handlerton *, Session *)
258
binlog_trx_data *const trx_data=
259
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
260
assert(trx_data->empty());
261
session_set_ha_data(session, binlog_hton, NULL);
262
trx_data->~binlog_trx_data();
263
free((unsigned char*)trx_data);
273
session The thread whose transaction should be ended
274
trx_data Pointer to the transaction data to use
275
end_ev The end event to use, or NULL
276
all True if the entire transaction should be ended, false if
277
only the statement transaction should be ended.
281
End the currently open transaction. The transaction can be either
282
a real transaction (if 'all' is true) or a statement transaction
285
If 'end_ev' is NULL, the transaction is a rollback of only
286
transactional tables, so the transaction cache will be truncated
287
to either just before the last opened statement transaction (if
288
'all' is false), or reset completely (if 'all' is true).
291
binlog_end_trans(Session *session, binlog_trx_data *trx_data,
292
Log_event *end_ev, bool all)
295
IO_CACHE *trans_log= &trx_data->trans_log;
298
NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of
299
only transactional tables. If the transaction contain changes to
300
any non-transactiona tables, we need write the transaction and log
306
Doing a commit or a rollback including non-transactional tables,
307
i.e., ending a transaction where we might write the transaction
308
cache to the binary log.
310
We can always end the statement when ending a transaction since
311
transactions are not allowed inside stored functions. If they
312
were, we would have to ensure that we're not ending a statement
313
inside a stored function.
315
session->binlog_flush_pending_rows_event(true);
317
error= drizzle_bin_log.write(session, &trx_data->trans_log, end_ev);
321
We need to step the table map version after writing the
322
transaction cache to disk.
324
drizzle_bin_log.update_table_map_version();
325
statistic_increment(binlog_cache_use, &LOCK_status);
326
if (trans_log->disk_writes != 0)
328
statistic_increment(binlog_cache_disk_use, &LOCK_status);
329
trans_log->disk_writes= 0;
335
If rolling back an entire transaction or a single statement not
336
inside a transaction, we reset the transaction cache.
338
If rolling back a statement in a transaction, we truncate the
339
transaction cache to remove the statement.
341
if (all || !(session->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
345
assert(!session->binlog_get_pending_rows_event());
346
session->clear_binlog_table_maps();
349
trx_data->truncate(trx_data->before_stmt_pos);
352
We need to step the table map version on a rollback to ensure
353
that a new table map event is generated instead of the one that
354
was written to the thrown-away transaction cache.
356
drizzle_bin_log.update_table_map_version();
362
165
static int binlog_prepare(handlerton *, Session *session, bool)
457
250
Otherwise, we accumulate the statement
460
uint64_t const in_transaction=
461
session->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN);
464
if ((in_transaction && (all || (!trx_data->at_least_one_stmt && session->transaction.stmt.modified_non_trans_table))) || (!in_transaction && !all))
253
if (all || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
466
Query_log_event qev(session, STRING_WITH_LEN("COMMIT"), true, false);
467
qev.error_code= 0; // see comment in DRIZZLE_LOG::write(Session, IO_CACHE)
468
/* TODO: Fix return type */
469
int error= binlog_end_trans(session, trx_data, &qev, all);
470
(void)replicator_end_transaction(session, all, true);
255
return replicator_end_transaction(session, all, true);
491
276
static int binlog_rollback(handlerton *, Session *session, bool all)
494
binlog_trx_data *const trx_data=
495
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
497
280
/* TODO: Fix return type */
498
281
(void)replicator_end_transaction(session, all, false);
500
if (trx_data->empty())
507
if ((all && session->transaction.all.modified_non_trans_table) ||
508
(!all && session->transaction.stmt.modified_non_trans_table) ||
509
(session->options & OPTION_KEEP_LOG))
512
We write the transaction cache with a rollback last if we have
513
modified any non-transactional table. We do this even if we are
514
committing a single statement that has modified a
515
non-transactional table since it can have modified a
516
transactional table in that statement as well, which needs to be
517
rolled back on the slave.
519
Query_log_event qev(session, STRING_WITH_LEN("ROLLBACK"), true, false);
520
qev.error_code= 0; // see comment in DRIZZLE_LOG::write(Session, IO_CACHE)
521
error= binlog_end_trans(session, trx_data, &qev, all);
523
else if ((all && !session->transaction.all.modified_non_trans_table) ||
524
(!all && !session->transaction.stmt.modified_non_trans_table))
527
If we have modified only transactional tables, we can truncate
528
the transaction cache without writing anything to the binary
531
error= binlog_end_trans(session, trx_data, 0, all);
2083
1832
query_id_param >= session->binlog_evt_union.first_query_id);
2088
These functions are placed in this file since they need access to
2089
binlog_hton, which has internal linkage.
2092
int Session::binlog_setup_trx_data()
2094
binlog_trx_data *trx_data=
2095
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2098
return(0); // Already set up
2100
trx_data= (binlog_trx_data*) malloc(sizeof(binlog_trx_data));
2101
memset(trx_data, 0, sizeof(binlog_trx_data));
2103
open_cached_file(&trx_data->trans_log, drizzle_tmpdir,
2104
LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
2106
free((unsigned char*)trx_data);
2107
return(1); // Didn't manage to set it up
2109
session_set_ha_data(this, binlog_hton, trx_data);
2111
trx_data= new (session_get_ha_data(this, binlog_hton)) binlog_trx_data;
2116
void Session::binlog_set_stmt_begin() {
2117
binlog_trx_data *trx_data=
2118
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2121
The call to binlog_trans_log_savepos() might create the trx_data
2122
structure, if it didn't exist before, so we save the position
2123
into an auto variable and then write it into the transaction
2124
data for the binary log (i.e., trx_data).
2127
binlog_trans_log_savepos(this, &pos);
2128
trx_data= (binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2129
trx_data->before_stmt_pos= pos;
2134
Session::binlog_get_pending_rows_event() const
2136
binlog_trx_data *const trx_data=
2137
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2139
This is less than ideal, but here's the story: If there is no
2140
trx_data, prepare_pending_rows_event() has never been called
2141
(since the trx_data is set up there). In that case, we just return
2144
return trx_data ? trx_data->pending() : NULL;
2148
Session::binlog_set_pending_rows_event(Rows_log_event* ev)
2150
if (session_get_ha_data(this, binlog_hton) == NULL)
2151
binlog_setup_trx_data();
2153
binlog_trx_data *const trx_data=
2154
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2157
trx_data->set_pending(ev);
2162
1836
Moves the last bunch of rows from the pending Rows event to the binlog
2163
1837
(either cached binlog if transaction, or disk binlog). Sets a new pending
2167
DRIZZLE_BIN_LOG::flush_and_set_pending_rows_event(Session *session,
2168
Rows_log_event* event)
1841
DRIZZLE_BIN_LOG::flush_and_set_pending_rows_event(Session *, Rows_log_event*)
2170
1843
assert(drizzle_bin_log.is_open());
2174
binlog_trx_data *const trx_data=
2175
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
2179
if (Rows_log_event* pending= trx_data->pending())
2181
IO_CACHE *file= &log_file;
2184
Decide if we should write to the log file directly or to the
2187
if (pending->get_cache_stmt() || my_b_tell(&trx_data->trans_log))
2188
file= &trx_data->trans_log;
2191
If we are writing to the log file directly, we could avoid
2192
locking the log. This does not work since we need to step the
2193
m_table_map_version below, and that change has to be protected
2194
by the LOCK_log mutex.
2196
pthread_mutex_lock(&LOCK_log);
2199
Write pending event to log file or transaction cache
2201
if (pending->write(file))
2203
pthread_mutex_unlock(&LOCK_log);
2208
We step the table map version if we are writing an event
2209
representing the end of a statement. We do this regardless of
2210
wheather we write to the transaction cache or to directly to the
2213
In an ideal world, we could avoid stepping the table map version
2214
if we were writing to a transaction cache, since we could then
2215
reuse the table map that was written earlier in the transaction
2216
cache. This does not work since STMT_END_F implies closing all
2217
table mappings on the slave side.
2219
TODO: Find a solution so that table maps does not have to be
2220
written several times within a transaction.
2222
if (pending->get_flags(Rows_log_event::STMT_END_F))
2223
++m_table_map_version;
2227
if (file == &log_file)
2229
error= flush_and_sync();
2233
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
2237
pthread_mutex_unlock(&LOCK_log);
2240
session->binlog_set_pending_rows_event(event);
2300
Should we write to the binlog cache or to the binlog on disk?
2301
Write to the binlog cache if:
2302
- it is already not empty (meaning we're in a transaction; note that the
2303
present event could be about a non-transactional table, but still we need
2304
to write to the binlog cache in that case to handle updates to mixed
2305
trans/non-trans table types the best possible in binlogging)
2306
- or if the event asks for it (cache_stmt == TRUE).
2308
if (opt_using_transactions && session)
2310
if (session->binlog_setup_trx_data())
2313
binlog_trx_data *const trx_data=
2314
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
2315
IO_CACHE *trans_log= &trx_data->trans_log;
2316
my_off_t trans_log_pos= my_b_tell(trans_log);
2317
if (event_info->get_cache_stmt() || trans_log_pos != 0)
2322
TODO as Mats suggested, for all the cases above where we write to
2323
trans_log, it sounds unnecessary to lock LOCK_log. We should rather
2324
test first if we want to write to trans_log, and if not, lock
2330
1901
Write the SQL command
3508
3079
int TC_LOG_BINLOG::log_xid(Session *session, my_xid xid)
3510
3081
Xid_log_event xle(session, xid);
3511
binlog_trx_data *trx_data=
3512
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
3513
3082
/* TODO: Fix return type */
3514
(void)replicator_end_transaction(session, true, true);
3516
3084
We always commit the entire transaction when writing an XID. Also
3517
3085
note that the return value is inverted.
3087
TODO: fix backasswards logic on this method
3519
return(!binlog_end_trans(session, trx_data, &xle, true));
3090
return replicator_end_transaction(session, true, true) ? false : true;
3522
3093
void TC_LOG_BINLOG::unlog(ulong, my_xid)