1
# name : innodb_fake_changes.patch
3
# maintainer : Yasufumi
6
# Any small change to this file in the main branch
7
# should be done or reviewed by the maintainer!
8
diff -ruN a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
9
--- a/storage/innobase/btr/btr0cur.c 2011-06-01 21:04:26.346416429 +0900
10
+++ b/storage/innobase/btr/btr0cur.c 2011-06-01 21:04:53.718415294 +0900
11
@@ -1167,6 +1167,11 @@
15
+ if (thr && thr_get_trx(thr)->fake_changes) {
16
+ /* skip LOCK, UNDO */
20
/* Check if we have to wait for a lock: enqueue an explicit lock
25
#endif /* UNIV_DEBUG */
27
- ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
28
+ ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
29
max_size = page_get_max_insert_size_after_reorganize(page, 1);
30
leaf = page_is_leaf(page);
32
@@ -1393,6 +1398,12 @@
36
+ if (thr && thr_get_trx(thr)->fake_changes) {
37
+ /* skip CHANGE, LOG */
38
+ *big_rec = big_rec_vec;
39
+ return(err); /* == DB_SUCCESS */
42
page_cursor = btr_cur_get_page_cur(cursor);
44
/* Now, try the insert */
45
@@ -1535,10 +1546,10 @@
49
- ut_ad(mtr_memo_contains(mtr,
50
+ ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr,
51
dict_index_get_lock(btr_cur_get_index(cursor)),
53
- ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
54
+ ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, btr_cur_get_block(cursor),
55
MTR_MEMO_PAGE_X_FIX));
57
/* Try first an optimistic insert; reset the cursor flag: we do not
58
@@ -1604,6 +1615,16 @@
62
+ if (thr && thr_get_trx(thr)->fake_changes) {
63
+ /* skip CHANGE, LOG */
64
+ if (n_extents > 0) {
65
+ fil_space_release_free_extents(index->space,
68
+ *big_rec = big_rec_vec;
72
if (dict_index_get_page(index)
73
== buf_block_get_page_no(btr_cur_get_block(cursor))) {
75
@@ -1660,6 +1681,11 @@
77
ut_ad(cursor && update && thr && roll_ptr);
79
+ if (thr && thr_get_trx(thr)->fake_changes) {
80
+ /* skip LOCK, UNDO */
84
rec = btr_cur_get_rec(cursor);
85
index = cursor->index;
87
@@ -1958,6 +1984,14 @@
91
+ if (trx->fake_changes) {
92
+ /* skip CHANGE, LOG */
93
+ if (UNIV_LIKELY_NULL(heap)) {
94
+ mem_heap_free(heap);
96
+ return(err); /* == DB_SUCCESS */
99
if (block->is_hashed) {
100
/* The function row_upd_changes_ord_field_binary works only
101
if the update vector was built for a clustered index, we must
102
@@ -2061,7 +2095,7 @@
103
rec = btr_cur_get_rec(cursor);
104
index = cursor->index;
105
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
106
- ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
107
+ ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
108
/* The insert buffer tree should never be updated in place. */
109
ut_ad(!dict_index_is_ibuf(index));
111
@@ -2171,6 +2205,11 @@
115
+ if (thr && thr_get_trx(thr)->fake_changes) {
116
+ /* skip CHANGE, LOG */
117
+ goto err_exit; /* == DB_SUCCESS */
120
/* Ok, we may do the replacement. Store on the page infimum the
121
explicit locks on rec, before deleting rec (see the comment in
122
btr_cur_pessimistic_update). */
123
@@ -2321,9 +2360,9 @@
124
rec = btr_cur_get_rec(cursor);
125
index = cursor->index;
127
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
128
+ ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, dict_index_get_lock(index),
130
- ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
131
+ ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
132
#ifdef UNIV_ZIP_DEBUG
133
ut_a(!page_zip || page_zip_validate(page_zip, page));
134
#endif /* UNIV_ZIP_DEBUG */
135
@@ -2411,6 +2450,9 @@
137
ut_ad(big_rec_vec == NULL);
139
+ /* fake_changes should not cause undo. so never reaches here */
140
+ ut_ad(!(trx->fake_changes));
142
btr_rec_free_updated_extern_fields(
143
index, rec, page_zip, offsets, update,
144
trx_is_recv(trx) ? RB_RECOVERY : RB_NORMAL, mtr);
145
@@ -2445,6 +2487,12 @@
149
+ if (trx->fake_changes) {
150
+ /* skip CHANGE, LOG */
152
+ goto return_after_reservations;
155
/* Store state of explicit locks on rec on the page infimum record,
156
before deleting rec. The page infimum acts as a dummy carrier of the
157
locks, taking care also of lock releases, before we can move the locks
158
@@ -2746,6 +2794,11 @@
159
ut_ad(dict_index_is_clust(index));
160
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
162
+ if (thr && thr_get_trx(thr)->fake_changes) {
163
+ /* skip LOCK, UNDO, CHANGE, LOG */
164
+ return(DB_SUCCESS);
167
err = lock_clust_rec_modify_check_and_lock(flags, block,
168
rec, index, offsets, thr);
170
@@ -2883,6 +2936,11 @@
174
+ if (thr && thr_get_trx(thr)->fake_changes) {
175
+ /* skip LOCK, CHANGE, LOG */
176
+ return(DB_SUCCESS);
179
block = btr_cur_get_block(cursor);
180
rec = btr_cur_get_rec(cursor);
182
diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
183
--- a/storage/innobase/handler/ha_innodb.cc 2011-06-01 21:04:26.511385596 +0900
184
+++ b/storage/innobase/handler/ha_innodb.cc 2011-06-01 21:04:53.723390828 +0900
186
" or 2 (write at commit, flush once per second).",
187
NULL, NULL, 1, 0, 2, 0);
189
+static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG,
190
+ "In the transaction after enabled, UPDATE, INSERT and DELETE only move the cursor to the records "
191
+ "and do nothing other operations (no changes, no ibuf, no undo, no transaction log) in the transaction. "
192
+ "ATTENTION: the transaction started after enabled is affected.",
193
+ NULL, NULL, FALSE);
196
static handler *innobase_create_handler(handlerton *hton,
198
@@ -1675,6 +1681,8 @@
199
trx->check_unique_secondary = !thd_test_options(
200
thd, OPTION_RELAXED_UNIQUE_CHECKS);
202
+ trx->fake_changes = THDVAR(thd, fake_changes);
204
#ifdef EXTENDED_SLOWLOG
205
if (thd_log_slow_verbosity(thd) & SLOG_V_INNODB) {
206
trx->take_stats = TRUE;
207
@@ -7486,12 +7494,20 @@
209
parent_trx = check_trx_exists(thd);
212
+ if (parent_trx->fake_changes
213
+ && thd_sql_command(thd) != SQLCOM_CREATE_TABLE) {
214
+ sql_print_error("innodb_fake_changes cannot treat new table during other than CREATE TABLE. (%s)\n", name);
215
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
218
/* In case MySQL calls this in the middle of a SELECT query, release
219
possible adaptive hash latch to avoid deadlocks of threads */
221
trx_search_latch_release_if_reserved(parent_trx);
223
trx = innobase_trx_allocate(thd);
224
+ trx->fake_changes = FALSE;
226
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
227
or lock waits can happen in it during a table create operation.
228
@@ -7701,6 +7717,7 @@
229
/*==============================*/
232
+ ibool fake_changes_reserved = FALSE;
234
DBUG_ENTER("ha_innobase::truncate");
236
@@ -7713,10 +7730,21 @@
237
DBUG_RETURN(HA_ERR_CRASHED);
240
+ if (prebuilt->trx->fake_changes) {
241
+ /* disable temporally */
242
+ prebuilt->trx->fake_changes = FALSE;
243
+ fake_changes_reserved = TRUE;
246
/* Truncate the table in InnoDB */
248
error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
250
+ if (fake_changes_reserved) {
251
+ prebuilt->trx->fake_changes = TRUE;
252
+ fake_changes_reserved = FALSE;
255
if (share->ib_table->is_corrupt) {
256
DBUG_RETURN(HA_ERR_CRASHED);
258
@@ -7768,6 +7796,7 @@
259
trx_search_latch_release_if_reserved(parent_trx);
261
trx = innobase_trx_allocate(thd);
262
+ trx->fake_changes = FALSE;
264
name_len = strlen(name);
266
@@ -7855,6 +7884,7 @@
267
trx->mysql_thd = NULL;
269
trx = innobase_trx_allocate(thd);
270
+ trx->fake_changes = FALSE;
272
row_drop_database_for_mysql(namebuf, trx);
274
@@ -7960,6 +7990,7 @@
275
trx_search_latch_release_if_reserved(parent_trx);
277
trx = innobase_trx_allocate(thd);
278
+ trx->fake_changes = FALSE;
280
error = innobase_rename_table(trx, from, to, TRUE);
282
@@ -12228,6 +12259,7 @@
283
MYSQL_SYSVAR(rollback_segments),
284
MYSQL_SYSVAR(corrupt_table_action),
285
MYSQL_SYSVAR(lazy_drop_table),
286
+ MYSQL_SYSVAR(fake_changes),
290
diff -ruN a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
291
--- a/storage/innobase/handler/handler0alter.cc 2011-04-11 19:44:03.000000000 +0900
292
+++ b/storage/innobase/handler/handler0alter.cc 2011-06-01 21:04:53.728495636 +0900
294
ibool dict_locked = FALSE;
297
+ ulint should_fake_changes = FALSE;
299
DBUG_ENTER("ha_innobase::add_index");
301
@@ -677,11 +678,17 @@
304
heap = mem_heap_create(1024);
306
+ if (prebuilt->trx->fake_changes) {
307
+ prebuilt->trx->fake_changes = FALSE;
308
+ should_fake_changes = TRUE;
310
trx_start_if_not_started(prebuilt->trx);
312
/* Create a background transaction for the operations on
313
the data dictionary tables. */
314
trx = innobase_trx_allocate(user_thd);
315
+ trx->fake_changes = FALSE;
316
trx_start_if_not_started(trx);
318
/* Create table containing all indexes to be built in this
320
row_mysql_unlock_data_dictionary(trx);
321
trx_free_for_mysql(trx);
322
trx_commit_for_mysql(prebuilt->trx);
323
+ if (should_fake_changes) {
324
+ prebuilt->trx->fake_changes = TRUE;
330
trx_commit_for_mysql(trx);
332
trx_commit_for_mysql(prebuilt->trx);
333
+ if (should_fake_changes) {
334
+ prebuilt->trx->fake_changes = TRUE;
339
@@ -1172,6 +1185,7 @@
340
/* Create a background transaction for the operations on
341
the data dictionary tables. */
342
trx = innobase_trx_allocate(user_thd);
343
+ trx->fake_changes = FALSE;
344
trx_start_if_not_started(trx);
346
/* Flag this transaction as a dictionary operation, so that
347
diff -ruN a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c
348
--- a/storage/innobase/ibuf/ibuf0ibuf.c 2011-06-01 21:04:26.529383815 +0900
349
+++ b/storage/innobase/ibuf/ibuf0ibuf.c 2011-06-01 21:04:53.732416483 +0900
350
@@ -3496,6 +3496,8 @@
352
ut_a(trx_sys_multiple_tablespace_format);
354
+ ut_ad(!(thr_get_trx(thr)->fake_changes));
358
/* Perform dirty reads of ibuf->size and ibuf->max_size, to
359
diff -ruN a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
360
--- a/storage/innobase/include/trx0trx.h 2011-06-01 21:04:25.762416618 +0900
361
+++ b/storage/innobase/include/trx0trx.h 2011-06-01 21:04:53.736387944 +0900
363
FALSE, one can save CPU time and about
364
150 bytes in the undo log size as then
366
+ ulint fake_changes;
367
ulint flush_log_later;/* In 2PC, we hold the
368
prepare_commit mutex across
369
both phases. In that case, we
370
diff -ruN a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c
371
--- a/storage/innobase/lock/lock0lock.c 2011-06-01 21:04:26.543396960 +0900
372
+++ b/storage/innobase/lock/lock0lock.c 2011-06-01 21:04:53.739416526 +0900
373
@@ -3909,6 +3909,10 @@
375
trx = thr_get_trx(thr);
377
+ if (trx->fake_changes && mode == LOCK_IX) {
381
lock_mutex_enter_kernel();
383
/* Look for stronger locks the same trx already has on the table */
384
@@ -5107,6 +5111,11 @@
387
trx = thr_get_trx(thr);
389
+ if (trx->fake_changes) {
390
+ return(DB_SUCCESS);
393
next_rec = page_rec_get_next_const(rec);
394
next_rec_heap_no = page_rec_get_heap_no(next_rec);
396
@@ -5275,6 +5284,10 @@
400
+ if (thr && thr_get_trx(thr)->fake_changes) {
401
+ return(DB_SUCCESS);
404
heap_no = rec_offs_comp(offsets)
405
? rec_get_heap_no_new(rec)
406
: rec_get_heap_no_old(rec);
407
@@ -5333,6 +5346,10 @@
411
+ if (thr && thr_get_trx(thr)->fake_changes) {
412
+ return(DB_SUCCESS);
415
heap_no = page_rec_get_heap_no(rec);
417
/* Another transaction cannot have an implicit lock on the record,
418
@@ -5420,6 +5437,10 @@
422
+ if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) {
426
heap_no = page_rec_get_heap_no(rec);
428
lock_mutex_enter_kernel();
429
@@ -5496,6 +5517,10 @@
433
+ if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) {
437
heap_no = page_rec_get_heap_no(rec);
439
lock_mutex_enter_kernel();
440
diff -ruN a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c
441
--- a/storage/innobase/que/que0que.c 2011-06-01 21:04:25.553416889 +0900
442
+++ b/storage/innobase/que/que0que.c 2011-06-01 21:04:53.743419001 +0900
443
@@ -1417,6 +1417,12 @@
445
ut_a(trx->error_state == DB_SUCCESS);
447
+ if (trx->fake_changes) {
448
+ /* fake_changes should not access to system tables */
449
+ fprintf(stderr, "InnoDB: ERROR: innodb_fake_changes tried to access to system tables.\n");
453
if (reserve_dict_mutex) {
454
mutex_enter(&dict_sys->mutex);
456
diff -ruN a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
457
--- a/storage/innobase/row/row0ins.c 2011-06-01 21:04:26.099449453 +0900
458
+++ b/storage/innobase/row/row0ins.c 2011-06-01 21:04:53.746383371 +0900
459
@@ -1499,6 +1499,11 @@
460
if (UNIV_LIKELY_NULL(heap)) {
464
+ if (trx->fake_changes) {
471
@@ -2004,7 +2009,7 @@
474
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
476
+ thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : search_mode,
477
&cursor, 0, __FILE__, __LINE__, &mtr);
479
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
480
@@ -2065,7 +2070,7 @@
482
btr_cur_search_to_nth_level(index, 0, entry,
485
+ thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT),
487
__FILE__, __LINE__, &mtr);
489
@@ -2119,6 +2124,22 @@
490
if (UNIV_LIKELY_NULL(big_rec)) {
494
+ if (thr_get_trx(thr)->fake_changes) {
495
+ /* skip store extern */
497
+ dtuple_big_rec_free(big_rec);
499
+ dtuple_convert_back_big_rec(index, entry, big_rec);
502
+ if (UNIV_LIKELY_NULL(heap)) {
503
+ mem_heap_free(heap);
511
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
512
diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
513
--- a/storage/innobase/row/row0mysql.c 2011-06-01 21:04:26.287385626 +0900
514
+++ b/storage/innobase/row/row0mysql.c 2011-06-01 21:04:53.749372325 +0900
515
@@ -1245,6 +1245,7 @@
516
prebuilt->table->stat_n_rows--;
519
+ if (!(trx->fake_changes))
520
row_update_statistics_if_needed(prebuilt->table);
523
@@ -1504,6 +1505,7 @@
524
that changes indexed columns, UPDATEs that change only non-indexed
525
columns would not affect statistics. */
526
if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
527
+ if (!(trx->fake_changes))
528
row_update_statistics_if_needed(prebuilt->table);
531
@@ -1721,6 +1723,7 @@
532
srv_n_rows_updated++;
535
+ if (!(trx->fake_changes))
536
row_update_statistics_if_needed(table);
539
diff -ruN a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c
540
--- a/storage/innobase/row/row0upd.c 2011-06-01 21:04:25.588384975 +0900
541
+++ b/storage/innobase/row/row0upd.c 2011-06-01 21:04:53.753385366 +0900
542
@@ -1603,7 +1603,8 @@
543
mode |= BTR_DELETE_MARK;
546
- search_result = row_search_index_entry(index, entry, mode,
547
+ search_result = row_search_index_entry(index, entry,
548
+ trx->fake_changes ? BTR_SEARCH_LEAF : mode,
551
btr_cur = btr_pcur_get_btr_cur(&pcur);
552
@@ -1850,9 +1851,11 @@
553
the previous invocation of this function. Mark the
554
off-page columns in the entry inherited. */
556
+ if (!(trx->fake_changes)) {
557
change_ownership = row_upd_clust_rec_by_insert_inherit(
558
NULL, NULL, entry, node->update);
559
ut_a(change_ownership);
562
case UPD_NODE_INSERT_CLUSTERED:
563
/* A lock wait occurred in row_ins_index_entry() in
564
@@ -1882,7 +1885,7 @@
565
delete-marked old record, mark them disowned by the
566
old record and owned by the new entry. */
568
- if (rec_offs_any_extern(offsets)) {
569
+ if (rec_offs_any_extern(offsets) && !(trx->fake_changes)) {
570
change_ownership = row_upd_clust_rec_by_insert_inherit(
571
rec, offsets, entry, node->update);
573
@@ -2012,7 +2015,8 @@
574
the same transaction do not modify the record in the meantime.
575
Therefore we can assert that the restoration of the cursor succeeds. */
577
- ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
578
+ ut_a(btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_TREE,
581
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
582
dict_table_is_comp(index->table)));
583
@@ -2022,7 +2026,8 @@
584
node->cmpl_info, thr, mtr);
587
- if (err == DB_SUCCESS && big_rec) {
588
+ /* skip store extern for fake_changes */
589
+ if (err == DB_SUCCESS && big_rec && !(thr_get_trx(thr)->fake_changes)) {
590
ulint offsets_[REC_OFFS_NORMAL_SIZE];
592
rec_offs_init(offsets_);
593
@@ -2146,7 +2151,8 @@
595
ut_a(pcur->rel_pos == BTR_PCUR_ON);
597
- success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
598
+ success = btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF,
602
err = DB_RECORD_NOT_FOUND;
603
diff -ruN a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c
604
--- a/storage/innobase/trx/trx0trx.c 2011-06-01 21:04:26.411537237 +0900
605
+++ b/storage/innobase/trx/trx0trx.c 2011-06-01 21:04:53.756415956 +0900
608
trx->support_xa = TRUE;
610
+ trx->fake_changes = FALSE;
612
trx->check_foreigns = TRUE;
613
trx->check_unique_secondary = TRUE;