1/* Copyright 2008-2015 Codership Oy <http://www.codership.com>
2
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.
6
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.
11
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16#include "mariadb.h"
17#include <mysqld.h>
18#include "sql_base.h"
19#include "rpl_filter.h"
20#include <sql_class.h>
21#include "wsrep_mysqld.h"
22#include "wsrep_binlog.h"
23#include "wsrep_xid.h"
24#include <cstdio>
25#include <cstdlib>
26#include "debug_sync.h"
27
28extern ulonglong thd_to_trx_id(THD *thd);
29
30extern "C" int thd_binlog_format(const MYSQL_THD thd);
31// todo: share interface with ha_innodb.c
32
33/*
34 Cleanup after local transaction commit/rollback, replay or TOI.
35*/
36void wsrep_cleanup_transaction(THD *thd)
37{
38 if (!WSREP(thd)) return;
39
40 if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd);
41 thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID;
42 thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
43 thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
44 thd->wsrep_exec_mode= LOCAL_STATE;
45 thd->wsrep_affected_rows= 0;
46 thd->wsrep_skip_wsrep_GTID= false;
47 return;
48}
49
50/*
51 wsrep hton
52*/
53handlerton *wsrep_hton;
54
55
56/*
57 Registers wsrep hton at commit time if transaction has registered htons
58 for supported engine types.
59
60 Hton should not be registered for TOTAL_ORDER operations.
61
62 Registration is needed for both LOCAL_MODE and REPL_RECV transactions to run
63 commit in 2pc so that wsrep position gets properly recorded in storage
64 engines.
65
66 Note that all hton calls should immediately return for threads that are
67 in REPL_RECV mode as their states are controlled by wsrep appliers or
68 replaying code. Only threads in LOCAL_MODE should run wsrep callbacks
69 from hton methods.
70*/
71void wsrep_register_hton(THD* thd, bool all)
72{
73 if (WSREP(thd) && thd->wsrep_exec_mode != TOTAL_ORDER &&
74 !thd->wsrep_apply_toi)
75 {
76 if (thd->wsrep_exec_mode == LOCAL_STATE &&
77 (thd_sql_command(thd) == SQLCOM_OPTIMIZE ||
78 thd_sql_command(thd) == SQLCOM_ANALYZE ||
79 thd_sql_command(thd) == SQLCOM_REPAIR) &&
80 thd->lex->no_write_to_binlog == 1)
81 {
82 WSREP_DEBUG("Skipping wsrep_register_hton for LOCAL sql admin command : %s",
83 thd->query());
84 return;
85 }
86
87 THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
88 for (Ha_trx_info *i= trans->ha_list; i; i = i->next())
89 {
90 if ((i->ht()->db_type == DB_TYPE_INNODB) ||
91 (i->ht()->db_type == DB_TYPE_TOKUDB))
92 {
93 trans_register_ha(thd, all, wsrep_hton);
94
95 /* follow innodb read/write settting
96 * but, as an exception: CTAS with empty result set will not be
97 * replicated unless we declare wsrep hton as read/write here
98 */
99 if (i->is_trx_read_write() ||
100 ((thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
101 thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) &&
102 thd->wsrep_exec_mode == LOCAL_STATE))
103 {
104 thd->ha_data[wsrep_hton->slot].ha_info[all].set_trx_read_write();
105 }
106 break;
107 }
108 }
109 }
110}
111
112/*
113 Calls wsrep->post_commit() for locally executed transactions that have
114 got seqno from provider (must commit) and don't require replaying.
115 */
116void wsrep_post_commit(THD* thd, bool all)
117{
118 if (!WSREP(thd)) return;
119
120 switch (thd->wsrep_exec_mode)
121 {
122 case LOCAL_COMMIT:
123 {
124 DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
125 if (wsrep && wsrep->post_commit(wsrep, &thd->wsrep_ws_handle))
126 {
127 DBUG_PRINT("wsrep", ("set committed fail"));
128 WSREP_WARN("set committed fail: %llu %d",
129 (long long)thd->real_id, thd->get_stmt_da()->status());
130 }
131 wsrep_cleanup_transaction(thd);
132 break;
133 }
134 case LOCAL_STATE:
135 {
136 /*
137 Non-InnoDB statements may have populated events in stmt cache => cleanup
138 */
139 WSREP_DEBUG("cleanup transaction for LOCAL_STATE: %s", thd->query());
140 wsrep_cleanup_transaction(thd);
141 break;
142 }
143 default: break;
144 }
145
146}
147
148/*
149 wsrep exploits binlog's caches even if binlogging itself is not
150 activated. In such case connection close needs calling
151 actual binlog's method.
152 Todo: split binlog hton from its caches to use ones by wsrep
153 without referring to binlog's stuff.
154*/
155static int
156wsrep_close_connection(handlerton* hton, THD* thd)
157{
158 DBUG_ENTER("wsrep_close_connection");
159
160 if (thd->wsrep_exec_mode == REPL_RECV)
161 {
162 DBUG_RETURN(0);
163 }
164 DBUG_RETURN(wsrep_binlog_close_connection (thd));
165}
166
167/*
168 prepare/wsrep_run_wsrep_commit can fail in two ways
169 - certification test or an equivalent. As a result,
170 the current transaction just rolls back
171 Error codes:
172 WSREP_TRX_CERT_FAIL, WSREP_TRX_SIZE_EXCEEDED, WSREP_TRX_ERROR
173 - a post-certification failure makes this server unable to
174 commit its own WS and therefore the server must abort
175*/
176static int wsrep_prepare(handlerton *hton, THD *thd, bool all)
177{
178 DBUG_ENTER("wsrep_prepare");
179
180 if (thd->wsrep_exec_mode == REPL_RECV)
181 {
182 DBUG_RETURN(0);
183 }
184
185 DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
186 DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
187 DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
188
189 if ((all ||
190 !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
191 (thd->variables.wsrep_on && !wsrep_trans_cache_is_empty(thd)))
192 {
193 int res= wsrep_run_wsrep_commit(thd, all);
194 if (res != 0)
195 {
196 if (res == WSREP_TRX_SIZE_EXCEEDED)
197 res= EMSGSIZE;
198 else
199 res= EDEADLK; // for a better error message
200 }
201 DBUG_RETURN (res);
202 }
203 DBUG_RETURN(0);
204}
205
206static int wsrep_savepoint_set(handlerton *hton, THD *thd, void *sv)
207{
208 DBUG_ENTER("wsrep_savepoint_set");
209
210 if (thd->wsrep_exec_mode == REPL_RECV)
211 {
212 DBUG_RETURN(0);
213 }
214
215 if (!wsrep_emulate_bin_log) DBUG_RETURN(0);
216 int rcode = wsrep_binlog_savepoint_set(thd, sv);
217 DBUG_RETURN(rcode);
218}
219
220static int wsrep_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
221{
222 DBUG_ENTER("wsrep_savepoint_rollback");
223
224 if (thd->wsrep_exec_mode == REPL_RECV)
225 {
226 DBUG_RETURN(0);
227 }
228
229 if (!wsrep_emulate_bin_log) DBUG_RETURN(0);
230 int rcode = wsrep_binlog_savepoint_rollback(thd, sv);
231 DBUG_RETURN(rcode);
232}
233
234static int wsrep_rollback(handlerton *hton, THD *thd, bool all)
235{
236 DBUG_ENTER("wsrep_rollback");
237
238 if (thd->wsrep_exec_mode == REPL_RECV)
239 {
240 DBUG_RETURN(0);
241 }
242
243 mysql_mutex_lock(&thd->LOCK_thd_data);
244 switch (thd->wsrep_exec_mode)
245 {
246 case TOTAL_ORDER:
247 case REPL_RECV:
248 mysql_mutex_unlock(&thd->LOCK_thd_data);
249 WSREP_DEBUG("Avoiding wsrep rollback for failed DDL: %s", thd->query());
250 DBUG_RETURN(0);
251 default: break;
252 }
253
254 if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
255 (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
256 {
257 if (wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
258 {
259 DBUG_PRINT("wsrep", ("setting rollback fail"));
260 WSREP_ERROR("settting rollback fail: thd: %llu, schema: %s, SQL: %s",
261 (long long)thd->real_id, thd->get_db(), thd->query());
262 }
263 wsrep_cleanup_transaction(thd);
264 }
265 mysql_mutex_unlock(&thd->LOCK_thd_data);
266 DBUG_RETURN(0);
267}
268
269int wsrep_commit(handlerton *hton, THD *thd, bool all)
270{
271 DBUG_ENTER("wsrep_commit");
272
273 if (thd->wsrep_exec_mode == REPL_RECV)
274 {
275 DBUG_RETURN(0);
276 }
277
278 mysql_mutex_lock(&thd->LOCK_thd_data);
279 if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
280 (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
281 {
282 if (thd->wsrep_exec_mode == LOCAL_COMMIT)
283 {
284 DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
285 /*
286 Call to wsrep->post_commit() (moved to wsrep_post_commit()) must
287 be done only after commit has done for all involved htons.
288 */
289 DBUG_PRINT("wsrep", ("commit"));
290 }
291 else
292 {
293 /*
294 Transaction didn't go through wsrep->pre_commit() so just roll back
295 possible changes to clean state.
296 */
297 if (WSREP_PROVIDER_EXISTS) {
298 if (wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
299 {
300 DBUG_PRINT("wsrep", ("setting rollback fail"));
301 WSREP_ERROR("settting rollback fail: thd: %llu, schema: %s, SQL: %s",
302 (long long)thd->real_id, thd->get_db(),
303 thd->query());
304 }
305 }
306 wsrep_cleanup_transaction(thd);
307 }
308 }
309 mysql_mutex_unlock(&thd->LOCK_thd_data);
310 DBUG_RETURN(0);
311}
312
313
314extern Rpl_filter* binlog_filter;
315extern my_bool opt_log_slave_updates;
316
317enum wsrep_trx_status
318wsrep_run_wsrep_commit(THD *thd, bool all)
319{
320 int rcode= -1;
321 size_t data_len= 0;
322 IO_CACHE *cache;
323 int replay_round= 0;
324 DBUG_ENTER("wsrep_run_wsrep_commit");
325
326 if (thd->get_stmt_da()->is_error()) {
327 WSREP_DEBUG("commit issue, error: %d %s",
328 thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
329 }
330
331 DEBUG_SYNC(thd, "wsrep_before_replication");
332
333 if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK);
334
335 if (thd->wsrep_exec_mode == REPL_RECV) {
336
337 mysql_mutex_lock(&thd->LOCK_thd_data);
338 if (thd->wsrep_conflict_state == MUST_ABORT) {
339 if (wsrep_debug)
340 WSREP_INFO("WSREP: must abort for BF");
341 DBUG_PRINT("wsrep", ("BF apply commit fail"));
342 thd->wsrep_conflict_state = NO_CONFLICT;
343 mysql_mutex_unlock(&thd->LOCK_thd_data);
344 //
345 // TODO: test all calls of the rollback.
346 // rollback must happen automagically innobase_rollback(hton, thd, 1);
347 //
348 DBUG_RETURN(WSREP_TRX_ERROR);
349 }
350 mysql_mutex_unlock(&thd->LOCK_thd_data);
351 }
352
353 if (thd->wsrep_exec_mode != LOCAL_STATE) DBUG_RETURN(WSREP_TRX_OK);
354
355 if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING) {
356 WSREP_DEBUG("commit for consistency check: %s", thd->query());
357 DBUG_RETURN(WSREP_TRX_OK);
358 }
359
360 DBUG_PRINT("wsrep", ("replicating commit"));
361
362 mysql_mutex_lock(&thd->LOCK_thd_data);
363 if (thd->wsrep_conflict_state == MUST_ABORT) {
364 DBUG_PRINT("wsrep", ("replicate commit fail"));
365 thd->wsrep_conflict_state = ABORTED;
366 mysql_mutex_unlock(&thd->LOCK_thd_data);
367 if (wsrep_debug) {
368 WSREP_INFO("innobase_commit, abort %s",
369 (thd->query()) ? thd->query() : "void");
370 }
371 DBUG_RETURN(WSREP_TRX_CERT_FAIL);
372 }
373
374 mysql_mutex_lock(&LOCK_wsrep_replaying);
375
376 DBUG_PRINT("info", ("wsrep_replaying: %d wsrep_conflict_state: %d killed: %d shutdown_in_progress: %d",
377 (int) wsrep_replaying, (int) thd->wsrep_conflict_state,
378 (int) thd->killed,
379 (int) shutdown_in_progress));
380
381 while (wsrep_replaying > 0 &&
382 thd->wsrep_conflict_state == NO_CONFLICT &&
383 thd->killed == NOT_KILLED &&
384 !shutdown_in_progress)
385 {
386
387 mysql_mutex_unlock(&LOCK_wsrep_replaying);
388 mysql_mutex_unlock(&thd->LOCK_thd_data);
389
390 mysql_mutex_lock(&thd->mysys_var->mutex);
391 thd_proc_info(thd, "WSREP waiting on replaying");
392 thd->mysys_var->current_mutex= &LOCK_wsrep_replaying;
393 thd->mysys_var->current_cond= &COND_wsrep_replaying;
394 mysql_mutex_unlock(&thd->mysys_var->mutex);
395
396 mysql_mutex_lock(&LOCK_wsrep_replaying);
397 // Using timedwait is a hack to avoid deadlock in case if BF victim
398 // misses the signal.
399 struct timespec wtime = {0, 1000000};
400 mysql_cond_timedwait(&COND_wsrep_replaying, &LOCK_wsrep_replaying,
401 &wtime);
402
403 if (replay_round++ % 100000 == 0)
404 WSREP_DEBUG("commit waiting for replaying: replayers %d, thd: %lld "
405 "conflict: %d (round: %d)",
406 wsrep_replaying, (longlong) thd->thread_id,
407 thd->wsrep_conflict_state, replay_round);
408
409 mysql_mutex_unlock(&LOCK_wsrep_replaying);
410
411 mysql_mutex_lock(&thd->mysys_var->mutex);
412 thd->mysys_var->current_mutex= 0;
413 thd->mysys_var->current_cond= 0;
414 mysql_mutex_unlock(&thd->mysys_var->mutex);
415
416 mysql_mutex_lock(&thd->LOCK_thd_data);
417 mysql_mutex_lock(&LOCK_wsrep_replaying);
418 }
419 mysql_mutex_unlock(&LOCK_wsrep_replaying);
420
421 if (thd->wsrep_conflict_state == MUST_ABORT) {
422 DBUG_PRINT("wsrep", ("replicate commit fail"));
423 thd->wsrep_conflict_state = ABORTED;
424 mysql_mutex_unlock(&thd->LOCK_thd_data);
425 WSREP_DEBUG("innobase_commit abort after replaying wait %s",
426 (thd->query()) ? thd->query() : "void");
427 DBUG_RETURN(WSREP_TRX_CERT_FAIL);
428 }
429
430 thd->wsrep_query_state = QUERY_COMMITTING;
431 mysql_mutex_unlock(&thd->LOCK_thd_data);
432
433 cache = get_trans_log(thd);
434 rcode = 0;
435 if (cache) {
436 thd->binlog_flush_pending_rows_event(true);
437 rcode = wsrep_write_cache(wsrep, thd, cache, &data_len);
438 if (WSREP_OK != rcode) {
439 WSREP_ERROR("rbr write fail, data_len: %zu, %d", data_len, rcode);
440 DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED);
441 }
442 }
443
444 DBUG_PRINT("info", ("rcode: %d wsrep_conflict_state: %d",
445 rcode, thd->wsrep_conflict_state));
446
447 if (data_len == 0)
448 {
449 if (thd->get_stmt_da()->is_ok() &&
450 thd->get_stmt_da()->affected_rows() > 0 &&
451 !binlog_filter->is_on())
452 {
453 WSREP_DEBUG("empty rbr buffer, query: %s, "
454 "affected rows: %llu, "
455 "changed tables: %d, "
456 "sql_log_bin: %d, "
457 "wsrep status (%d %d %d)",
458 thd->query(), thd->get_stmt_da()->affected_rows(),
459 stmt_has_updated_trans_table(thd), thd->variables.sql_log_bin,
460 thd->wsrep_exec_mode, thd->wsrep_query_state,
461 thd->wsrep_conflict_state);
462 }
463 else
464 {
465 WSREP_DEBUG("empty rbr buffer, query: %s", thd->query());
466 }
467 thd->wsrep_query_state= QUERY_EXEC;
468 DBUG_RETURN(WSREP_TRX_OK);
469 }
470
471 if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id)
472 {
473 WSREP_WARN("SQL statement was ineffective thd: %lld buf: %zu\n"
474 "schema: %s \n"
475 "QUERY: %s\n"
476 " => Skipping replication",
477 (longlong) thd->thread_id, data_len,
478 thd->get_db(), thd->query());
479 rcode = WSREP_TRX_FAIL;
480 }
481 else if (!rcode)
482 {
483 if (WSREP_OK == rcode && wsrep)
484 rcode = wsrep->pre_commit(wsrep,
485 (wsrep_conn_id_t)thd->thread_id,
486 &thd->wsrep_ws_handle,
487 WSREP_FLAG_COMMIT |
488 ((thd->wsrep_PA_safe) ?
489 0ULL : WSREP_FLAG_PA_UNSAFE),
490 &thd->wsrep_trx_meta);
491
492 DBUG_PRINT("info", ("rcode after pre_commit: %d", rcode));
493
494 if (rcode == WSREP_TRX_MISSING) {
495 WSREP_WARN("Transaction missing in provider, thd: %lld schema: %s SQL: %s",
496 (longlong) thd->thread_id,
497 thd->get_db(), thd->query());
498 rcode = WSREP_TRX_FAIL;
499 } else if (rcode == WSREP_BF_ABORT) {
500 WSREP_DEBUG("thd: %lld seqno: %lld BF aborted by provider, will replay",
501 (longlong) thd->thread_id,
502 (longlong) thd->wsrep_trx_meta.gtid.seqno);
503 mysql_mutex_lock(&thd->LOCK_thd_data);
504 thd->wsrep_conflict_state = MUST_REPLAY;
505 DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
506 mysql_mutex_unlock(&thd->LOCK_thd_data);
507 mysql_mutex_lock(&LOCK_wsrep_replaying);
508 wsrep_replaying++;
509 WSREP_DEBUG("replaying increased: %d, thd: %lld",
510 wsrep_replaying, (longlong) thd->thread_id);
511 mysql_mutex_unlock(&LOCK_wsrep_replaying);
512 }
513 } else {
514 WSREP_ERROR("I/O error reading from thd's binlog iocache: "
515 "errno=%d, io cache code=%d", my_errno, cache->error);
516 DBUG_ASSERT(0); // failure like this can not normally happen
517 DBUG_RETURN(WSREP_TRX_ERROR);
518 }
519
520 mysql_mutex_lock(&thd->LOCK_thd_data);
521
522 DEBUG_SYNC(thd, "wsrep_after_replication");
523
524 DBUG_PRINT("info", ("rcode: %d wsrep_conflict_state: %d",
525 rcode, thd->wsrep_conflict_state));
526
527 switch(rcode) {
528 case 0:
529 /*
530 About MUST_ABORT: We assume that even if thd conflict state was set
531 to MUST_ABORT, underlying transaction was not rolled back or marked
532 as deadlock victim in QUERY_COMMITTING state. Conflict state is
533 set to NO_CONFLICT and commit proceeds as usual.
534 */
535 if (thd->wsrep_conflict_state == MUST_ABORT)
536 thd->wsrep_conflict_state= NO_CONFLICT;
537
538 if (thd->wsrep_conflict_state != NO_CONFLICT)
539 {
540 WSREP_WARN("thd: %llu seqno: %lld conflict state %d after post commit",
541 (longlong) thd->thread_id,
542 (longlong) thd->wsrep_trx_meta.gtid.seqno,
543 thd->wsrep_conflict_state);
544 }
545 thd->wsrep_exec_mode= LOCAL_COMMIT;
546 DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
547 /* Override XID iff it was generated by mysql */
548 if (thd->transaction.xid_state.xid.get_my_xid())
549 {
550 wsrep_xid_init(&thd->transaction.xid_state.xid,
551 thd->wsrep_trx_meta.gtid.uuid,
552 thd->wsrep_trx_meta.gtid.seqno);
553 }
554 DBUG_PRINT("wsrep", ("replicating commit success"));
555 break;
556 case WSREP_BF_ABORT:
557 DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
558 /* fall through */
559 case WSREP_TRX_FAIL:
560 WSREP_DEBUG("commit failed for reason: %d", rcode);
561 DBUG_PRINT("wsrep", ("replicating commit fail"));
562
563 thd->wsrep_query_state= QUERY_EXEC;
564
565 if (thd->wsrep_conflict_state == MUST_ABORT) {
566 thd->wsrep_conflict_state= ABORTED;
567 }
568 else
569 {
570 WSREP_DEBUG("conflict state: %d", thd->wsrep_conflict_state);
571 if (thd->wsrep_conflict_state == NO_CONFLICT)
572 {
573 thd->wsrep_conflict_state = CERT_FAILURE;
574 WSREP_LOG_CONFLICT(NULL, thd, FALSE);
575 }
576 }
577 mysql_mutex_unlock(&thd->LOCK_thd_data);
578
579 DBUG_RETURN(WSREP_TRX_CERT_FAIL);
580
581 case WSREP_SIZE_EXCEEDED:
582 WSREP_ERROR("transaction size exceeded");
583 mysql_mutex_unlock(&thd->LOCK_thd_data);
584 DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED);
585 case WSREP_CONN_FAIL:
586 WSREP_ERROR("connection failure");
587 mysql_mutex_unlock(&thd->LOCK_thd_data);
588 DBUG_RETURN(WSREP_TRX_ERROR);
589 default:
590 WSREP_ERROR("unknown connection failure");
591 mysql_mutex_unlock(&thd->LOCK_thd_data);
592 DBUG_RETURN(WSREP_TRX_ERROR);
593 }
594
595 thd->wsrep_query_state= QUERY_EXEC;
596 mysql_mutex_unlock(&thd->LOCK_thd_data);
597
598 DBUG_RETURN(WSREP_TRX_OK);
599}
600
601
602static int wsrep_hton_init(void *p)
603{
604 wsrep_hton= (handlerton *)p;
605 //wsrep_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
606 wsrep_hton->state= SHOW_OPTION_YES;
607 wsrep_hton->db_type=(legacy_db_type)0;
608 wsrep_hton->savepoint_offset= sizeof(my_off_t);
609 wsrep_hton->close_connection= wsrep_close_connection;
610 wsrep_hton->savepoint_set= wsrep_savepoint_set;
611 wsrep_hton->savepoint_rollback= wsrep_savepoint_rollback;
612 wsrep_hton->commit= wsrep_commit;
613 wsrep_hton->rollback= wsrep_rollback;
614 wsrep_hton->prepare= wsrep_prepare;
615 wsrep_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN; // todo: fix flags
616 return 0;
617}
618
619
620struct st_mysql_storage_engine wsrep_storage_engine=
621{ MYSQL_HANDLERTON_INTERFACE_VERSION };
622
623
624maria_declare_plugin(wsrep)
625{
626 MYSQL_STORAGE_ENGINE_PLUGIN,
627 &wsrep_storage_engine,
628 "wsrep",
629 "Codership Oy",
630 "A pseudo storage engine to represent transactions in multi-master "
631 "synchornous replication",
632 PLUGIN_LICENSE_GPL,
633 wsrep_hton_init, /* Plugin Init */
634 NULL, /* Plugin Deinit */
635 0x0100 /* 1.0 */,
636 NULL, /* status variables */
637 NULL, /* system variables */
638 "1.0", /* string version */
639 MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
640}
641maria_declare_plugin_end;
642