]>
Commit | Line | Data |
---|---|---|
3700c2a6 AM |
1 | # name : innodb_fake_changes.patch |
2 | # introduced : 5.1.58 | |
3 | # maintainer : Yasufumi | |
4 | # | |
5 | #!!! notice !!! | |
6 | # Any small change to this file in the main branch | |
7 | # should be done or reviewed by the maintainer! | |
8 | --- a/storage/innodb_plugin/btr/btr0cur.c | |
9 | +++ b/storage/innodb_plugin/btr/btr0cur.c | |
10 | @@ -1046,6 +1046,11 @@ | |
11 | rec_t* rec; | |
12 | roll_ptr_t roll_ptr; | |
13 | ||
14 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
15 | + /* skip LOCK, UNDO */ | |
16 | + return(DB_SUCCESS); | |
17 | + } | |
18 | + | |
19 | /* Check if we have to wait for a lock: enqueue an explicit lock | |
20 | request if yes */ | |
21 | ||
22 | @@ -1177,7 +1182,7 @@ | |
23 | } | |
24 | #endif /* UNIV_DEBUG */ | |
25 | ||
26 | - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); | |
27 | + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); | |
28 | max_size = page_get_max_insert_size_after_reorganize(page, 1); | |
29 | leaf = page_is_leaf(page); | |
30 | ||
31 | @@ -1272,6 +1277,12 @@ | |
32 | goto fail_err; | |
33 | } | |
34 | ||
35 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
36 | + /* skip CHANGE, LOG */ | |
37 | + *big_rec = big_rec_vec; | |
38 | + return(err); /* == DB_SUCCESS */ | |
39 | + } | |
40 | + | |
41 | page_cursor = btr_cur_get_page_cur(cursor); | |
42 | ||
43 | /* Now, try the insert */ | |
44 | @@ -1414,10 +1425,10 @@ | |
45 | ||
46 | *big_rec = NULL; | |
47 | ||
48 | - ut_ad(mtr_memo_contains(mtr, | |
49 | + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, | |
50 | dict_index_get_lock(btr_cur_get_index(cursor)), | |
51 | MTR_MEMO_X_LOCK)); | |
52 | - ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), | |
53 | + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, btr_cur_get_block(cursor), | |
54 | MTR_MEMO_PAGE_X_FIX)); | |
55 | ||
56 | /* Try first an optimistic insert; reset the cursor flag: we do not | |
57 | @@ -1483,6 +1494,16 @@ | |
58 | } | |
59 | } | |
60 | ||
61 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
62 | + /* skip CHANGE, LOG */ | |
63 | + if (n_extents > 0) { | |
64 | + fil_space_release_free_extents(index->space, | |
65 | + n_reserved); | |
66 | + } | |
67 | + *big_rec = big_rec_vec; | |
68 | + return(DB_SUCCESS); | |
69 | + } | |
70 | + | |
71 | if (dict_index_get_page(index) | |
72 | == buf_block_get_page_no(btr_cur_get_block(cursor))) { | |
73 | ||
74 | @@ -1539,6 +1560,11 @@ | |
75 | ||
76 | ut_ad(cursor && update && thr && roll_ptr); | |
77 | ||
78 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
79 | + /* skip LOCK, UNDO */ | |
80 | + return(DB_SUCCESS); | |
81 | + } | |
82 | + | |
83 | rec = btr_cur_get_rec(cursor); | |
84 | index = cursor->index; | |
85 | ||
86 | @@ -1837,6 +1863,14 @@ | |
87 | return(err); | |
88 | } | |
89 | ||
90 | + if (trx->fake_changes) { | |
91 | + /* skip CHANGE, LOG */ | |
92 | + if (UNIV_LIKELY_NULL(heap)) { | |
93 | + mem_heap_free(heap); | |
94 | + } | |
95 | + return(err); /* == DB_SUCCESS */ | |
96 | + } | |
97 | + | |
98 | if (block->is_hashed) { | |
99 | /* The function row_upd_changes_ord_field_binary works only | |
100 | if the update vector was built for a clustered index, we must | |
101 | @@ -1939,7 +1973,7 @@ | |
102 | rec = btr_cur_get_rec(cursor); | |
103 | index = cursor->index; | |
104 | ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table)); | |
105 | - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); | |
106 | + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); | |
107 | /* The insert buffer tree should never be updated in place. */ | |
108 | ut_ad(!dict_index_is_ibuf(index)); | |
109 | ||
110 | @@ -2053,6 +2087,11 @@ | |
111 | goto err_exit; | |
112 | } | |
113 | ||
114 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
115 | + /* skip CHANGE, LOG */ | |
116 | + goto err_exit; /* == DB_SUCCESS */ | |
117 | + } | |
118 | + | |
119 | /* Ok, we may do the replacement. Store on the page infimum the | |
120 | explicit locks on rec, before deleting rec (see the comment in | |
121 | btr_cur_pessimistic_update). */ | |
122 | @@ -2203,9 +2242,9 @@ | |
123 | rec = btr_cur_get_rec(cursor); | |
124 | index = cursor->index; | |
125 | ||
126 | - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), | |
127 | + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, dict_index_get_lock(index), | |
128 | MTR_MEMO_X_LOCK)); | |
129 | - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); | |
130 | + ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); | |
131 | #ifdef UNIV_ZIP_DEBUG | |
132 | ut_a(!page_zip || page_zip_validate(page_zip, page)); | |
133 | #endif /* UNIV_ZIP_DEBUG */ | |
134 | @@ -2293,6 +2332,9 @@ | |
135 | ||
136 | ut_ad(big_rec_vec == NULL); | |
137 | ||
138 | + /* fake_changes should not cause undo. so never reaches here */ | |
139 | + ut_ad(!(trx->fake_changes)); | |
140 | + | |
141 | btr_rec_free_updated_extern_fields( | |
142 | index, rec, page_zip, offsets, update, | |
143 | trx_is_recv(trx) ? RB_RECOVERY : RB_NORMAL, mtr); | |
144 | @@ -2331,6 +2373,12 @@ | |
145 | ut_ad(flags & BTR_KEEP_POS_FLAG); | |
146 | } | |
147 | ||
148 | + if (trx->fake_changes) { | |
149 | + /* skip CHANGE, LOG */ | |
150 | + err = DB_SUCCESS; | |
151 | + goto return_after_reservations; | |
152 | + } | |
153 | + | |
154 | /* Store state of explicit locks on rec on the page infimum record, | |
155 | before deleting rec. The page infimum acts as a dummy carrier of the | |
156 | locks, taking care also of lock releases, before we can move the locks | |
157 | @@ -2686,6 +2734,11 @@ | |
158 | ut_ad(dict_index_is_clust(index)); | |
159 | ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets))); | |
160 | ||
161 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
162 | + /* skip LOCK, UNDO, CHANGE, LOG */ | |
163 | + return(DB_SUCCESS); | |
164 | + } | |
165 | + | |
166 | err = lock_clust_rec_modify_check_and_lock(flags, block, | |
167 | rec, index, offsets, thr); | |
168 | ||
169 | @@ -2823,6 +2876,11 @@ | |
170 | rec_t* rec; | |
171 | ulint err; | |
172 | ||
173 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
174 | + /* skip LOCK, CHANGE, LOG */ | |
175 | + return(DB_SUCCESS); | |
176 | + } | |
177 | + | |
178 | block = btr_cur_get_block(cursor); | |
179 | rec = btr_cur_get_rec(cursor); | |
180 | ||
181 | --- a/storage/innodb_plugin/handler/ha_innodb.cc | |
182 | +++ b/storage/innodb_plugin/handler/ha_innodb.cc | |
183 | @@ -369,6 +369,12 @@ | |
184 | "The value 3 regards innodb_flush_log_at_trx_commit (default).", | |
185 | NULL, NULL, 3, 0, 3, 0); | |
186 | ||
187 | +static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG, | |
188 | + "In the transaction after enabled, UPDATE, INSERT and DELETE only move the cursor to the records " | |
189 | + "and do nothing other operations (no changes, no ibuf, no undo, no transaction log) in the transaction. " | |
190 | + "This is to cause replication prefetch IO. ATTENTION: the transaction started after enabled is affected.", | |
191 | + NULL, NULL, FALSE); | |
192 | + | |
193 | ||
194 | static handler *innobase_create_handler(handlerton *hton, | |
195 | TABLE_SHARE *table, | |
196 | @@ -1400,6 +1406,8 @@ | |
197 | trx->check_unique_secondary = !thd_test_options( | |
198 | thd, OPTION_RELAXED_UNIQUE_CHECKS); | |
199 | ||
200 | + trx->fake_changes = THDVAR(thd, fake_changes); | |
201 | + | |
202 | #ifdef EXTENDED_SLOWLOG | |
203 | if (thd_log_slow_verbosity(thd) & SLOG_V_INNODB) { | |
204 | trx->take_stats = TRUE; | |
205 | @@ -2816,6 +2824,11 @@ | |
206 | trx_search_latch_release_if_reserved(trx); | |
207 | } | |
208 | ||
209 | + if (trx->fake_changes && (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { | |
210 | + innobase_rollback(hton, thd, all); /* rollback implicitly */ | |
211 | + thd->main_da.reset_diagnostics_area(); /* because debug assertion code complains, if something left */ | |
212 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
213 | + } | |
214 | /* The flag trx->active_trans is set to 1 in | |
215 | ||
216 | 1. ::external_lock(), | |
217 | @@ -7141,6 +7154,12 @@ | |
218 | ||
219 | trx = innobase_trx_allocate(thd); | |
220 | ||
221 | + if (trx->fake_changes) { | |
222 | + innobase_commit_low(trx); | |
223 | + trx_free_for_mysql(trx); | |
224 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
225 | + } | |
226 | + | |
227 | /* Latch the InnoDB data dictionary exclusively so that no deadlocks | |
228 | or lock waits can happen in it during a table create operation. | |
229 | Drop table etc. do this latching in row0mysql.c. */ | |
230 | @@ -7346,6 +7365,10 @@ | |
231 | DBUG_RETURN(HA_ERR_CRASHED); | |
232 | } | |
233 | ||
234 | + if (prebuilt->trx->fake_changes) { | |
235 | + goto fallback; | |
236 | + } | |
237 | + | |
238 | /* Truncate the table in InnoDB */ | |
239 | ||
240 | error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx); | |
241 | @@ -7406,6 +7429,12 @@ | |
242 | ||
243 | trx = innobase_trx_allocate(thd); | |
244 | ||
245 | + if (trx->fake_changes) { | |
246 | + innobase_commit_low(trx); | |
247 | + trx_free_for_mysql(trx); | |
248 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
249 | + } | |
250 | + | |
251 | name_len = strlen(name); | |
252 | ||
253 | ut_a(name_len < 1000); | |
254 | @@ -7494,6 +7523,12 @@ | |
255 | trx->mysql_thd = NULL; | |
256 | #else | |
257 | trx = innobase_trx_allocate(thd); | |
258 | + if (trx->fake_changes) { | |
259 | + my_free(namebuf, MYF(0)); | |
260 | + innobase_commit_low(trx); | |
261 | + trx_free_for_mysql(trx); | |
262 | + return; /* ignore */ | |
263 | + } | |
264 | #endif | |
265 | row_drop_database_for_mysql(namebuf, trx); | |
266 | my_free(namebuf, MYF(0)); | |
267 | @@ -7601,6 +7636,11 @@ | |
268 | trx_search_latch_release_if_reserved(parent_trx); | |
269 | ||
270 | trx = innobase_trx_allocate(thd); | |
271 | + if (trx->fake_changes) { | |
272 | + innobase_commit_low(trx); | |
273 | + trx_free_for_mysql(trx); | |
274 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
275 | + } | |
276 | ||
277 | error = innobase_rename_table(trx, from, to, TRUE); | |
278 | ||
279 | @@ -10373,6 +10413,10 @@ | |
280 | return(0); | |
281 | } | |
282 | ||
283 | + if (trx->fake_changes) { | |
284 | + return(0); | |
285 | + } | |
286 | + | |
287 | thd_get_xid(thd, (MYSQL_XID*) &trx->xid); | |
288 | ||
289 | /* Release a possible FIFO ticket and search latch. Since we will | |
290 | @@ -11905,6 +11949,7 @@ | |
291 | MYSQL_SYSVAR(use_purge_thread), | |
292 | MYSQL_SYSVAR(pass_corrupt_table), | |
293 | MYSQL_SYSVAR(lazy_drop_table), | |
294 | + MYSQL_SYSVAR(fake_changes), | |
295 | NULL | |
296 | }; | |
297 | ||
298 | --- a/storage/innodb_plugin/handler/handler0alter.cc | |
299 | +++ b/storage/innodb_plugin/handler/handler0alter.cc | |
300 | @@ -652,6 +652,9 @@ | |
301 | /* In case MySQL calls this in the middle of a SELECT query, release | |
302 | possible adaptive hash latch to avoid deadlocks of threads. */ | |
303 | trx_search_latch_release_if_reserved(prebuilt->trx); | |
304 | + if (prebuilt->trx->fake_changes) { | |
305 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
306 | + } | |
307 | ||
308 | /* Check if the index name is reserved. */ | |
309 | if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) { | |
310 | @@ -678,6 +681,13 @@ | |
311 | /* Create a background transaction for the operations on | |
312 | the data dictionary tables. */ | |
313 | trx = innobase_trx_allocate(user_thd); | |
314 | + if (trx->fake_changes) { | |
315 | + mem_heap_free(heap); | |
316 | + trx_general_rollback_for_mysql(trx, NULL); | |
317 | + trx_free_for_mysql(trx); | |
318 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
319 | + } | |
320 | + | |
321 | trx_start_if_not_started(trx); | |
322 | ||
323 | /* Create table containing all indexes to be built in this | |
324 | @@ -964,6 +974,10 @@ | |
325 | trx_search_latch_release_if_reserved(prebuilt->trx); | |
326 | trx = prebuilt->trx; | |
327 | ||
328 | + if (trx->fake_changes) { | |
329 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
330 | + } | |
331 | + | |
332 | /* Test and mark all the indexes to be dropped */ | |
333 | ||
334 | row_mysql_lock_data_dictionary(trx); | |
335 | @@ -1168,6 +1182,12 @@ | |
336 | /* Create a background transaction for the operations on | |
337 | the data dictionary tables. */ | |
338 | trx = innobase_trx_allocate(user_thd); | |
339 | + if (trx->fake_changes) { | |
340 | + trx_general_rollback_for_mysql(trx, NULL); | |
341 | + trx_free_for_mysql(trx); | |
342 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
343 | + } | |
344 | + | |
345 | trx_start_if_not_started(trx); | |
346 | ||
347 | /* Flag this transaction as a dictionary operation, so that | |
348 | --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c | |
349 | +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c | |
350 | @@ -2613,6 +2613,8 @@ | |
351 | ||
352 | ut_a(trx_sys_multiple_tablespace_format); | |
353 | ||
354 | + ut_ad(!(thr_get_trx(thr)->fake_changes)); | |
355 | + | |
356 | do_merge = FALSE; | |
357 | ||
358 | mutex_enter(&ibuf_mutex); | |
359 | --- a/storage/innodb_plugin/include/trx0trx.h | |
360 | +++ b/storage/innodb_plugin/include/trx0trx.h | |
361 | @@ -509,6 +509,7 @@ | |
362 | 150 bytes in the undo log size as then | |
363 | we skip XA steps */ | |
364 | ulint flush_log_at_trx_commit_session; | |
365 | + ulint fake_changes; | |
366 | ulint flush_log_later;/* In 2PC, we hold the | |
367 | prepare_commit mutex across | |
368 | both phases. In that case, we | |
369 | --- a/storage/innodb_plugin/lock/lock0lock.c | |
370 | +++ b/storage/innodb_plugin/lock/lock0lock.c | |
371 | @@ -3907,6 +3907,10 @@ | |
372 | ||
373 | trx = thr_get_trx(thr); | |
374 | ||
375 | + if (trx->fake_changes && mode == LOCK_IX) { | |
376 | + mode = LOCK_IS; | |
377 | + } | |
378 | + | |
379 | lock_mutex_enter_kernel(); | |
380 | ||
381 | /* Look for stronger locks the same trx already has on the table */ | |
382 | @@ -5108,6 +5112,11 @@ | |
383 | } | |
384 | ||
385 | trx = thr_get_trx(thr); | |
386 | + | |
387 | + if (trx->fake_changes) { | |
388 | + return(DB_SUCCESS); | |
389 | + } | |
390 | + | |
391 | next_rec = page_rec_get_next_const(rec); | |
392 | next_rec_heap_no = page_rec_get_heap_no(next_rec); | |
393 | ||
394 | @@ -5276,6 +5285,10 @@ | |
395 | return(DB_SUCCESS); | |
396 | } | |
397 | ||
398 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
399 | + return(DB_SUCCESS); | |
400 | + } | |
401 | + | |
402 | heap_no = rec_offs_comp(offsets) | |
403 | ? rec_get_heap_no_new(rec) | |
404 | : rec_get_heap_no_old(rec); | |
405 | @@ -5334,6 +5347,10 @@ | |
406 | return(DB_SUCCESS); | |
407 | } | |
408 | ||
409 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
410 | + return(DB_SUCCESS); | |
411 | + } | |
412 | + | |
413 | heap_no = page_rec_get_heap_no(rec); | |
414 | ||
415 | /* Another transaction cannot have an implicit lock on the record, | |
416 | @@ -5421,6 +5438,10 @@ | |
417 | return(DB_SUCCESS); | |
418 | } | |
419 | ||
420 | + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { | |
421 | + mode = LOCK_S; | |
422 | + } | |
423 | + | |
424 | heap_no = page_rec_get_heap_no(rec); | |
425 | ||
426 | lock_mutex_enter_kernel(); | |
427 | @@ -5498,6 +5519,10 @@ | |
428 | return(DB_SUCCESS); | |
429 | } | |
430 | ||
431 | + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { | |
432 | + mode = LOCK_S; | |
433 | + } | |
434 | + | |
435 | heap_no = page_rec_get_heap_no(rec); | |
436 | ||
437 | lock_mutex_enter_kernel(); | |
438 | --- a/storage/innodb_plugin/que/que0que.c | |
439 | +++ b/storage/innodb_plugin/que/que0que.c | |
440 | @@ -1418,6 +1418,12 @@ | |
441 | ||
442 | ut_a(trx->error_state == DB_SUCCESS); | |
443 | ||
444 | + if (trx->fake_changes) { | |
445 | + /* fake_changes should not access to system tables */ | |
446 | + fprintf(stderr, "InnoDB: ERROR: innodb_fake_changes tried to access to system tables.\n"); | |
447 | + return(DB_ERROR); | |
448 | + } | |
449 | + | |
450 | if (reserve_dict_mutex) { | |
451 | mutex_enter(&dict_sys->mutex); | |
452 | } | |
453 | --- a/storage/innodb_plugin/row/row0ins.c | |
454 | +++ b/storage/innodb_plugin/row/row0ins.c | |
455 | @@ -1512,6 +1512,11 @@ | |
456 | if (UNIV_LIKELY_NULL(heap)) { | |
457 | mem_heap_free(heap); | |
458 | } | |
459 | + | |
460 | + if (trx->fake_changes) { | |
461 | + err = DB_SUCCESS; | |
462 | + } | |
463 | + | |
464 | return(err); | |
465 | } | |
466 | ||
467 | @@ -2014,7 +2019,7 @@ | |
468 | } | |
469 | ||
470 | btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, | |
471 | - mode | BTR_INSERT | ignore_sec_unique, | |
472 | + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT | ignore_sec_unique), | |
473 | &cursor, 0, __FILE__, __LINE__, &mtr); | |
474 | ||
475 | if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) { | |
476 | @@ -2074,7 +2079,7 @@ | |
477 | ||
478 | btr_cur_search_to_nth_level(index, 0, entry, | |
479 | PAGE_CUR_LE, | |
480 | - mode | BTR_INSERT, | |
481 | + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT), | |
482 | &cursor, 0, | |
483 | __FILE__, __LINE__, &mtr); | |
484 | } | |
485 | @@ -2162,6 +2167,22 @@ | |
486 | mtr_commit(&mtr); | |
487 | ||
488 | if (UNIV_LIKELY_NULL(big_rec)) { | |
489 | + | |
490 | + if (thr_get_trx(thr)->fake_changes) { | |
491 | + /* skip store extern */ | |
492 | + if (modify) { | |
493 | + dtuple_big_rec_free(big_rec); | |
494 | + } else { | |
495 | + dtuple_convert_back_big_rec(index, entry, big_rec); | |
496 | + } | |
497 | + | |
498 | + if (UNIV_LIKELY_NULL(heap)) { | |
499 | + mem_heap_free(heap); | |
500 | + } | |
501 | + | |
502 | + return(err); | |
503 | + } | |
504 | + | |
505 | mtr_start(&mtr); | |
506 | ||
507 | btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, | |
508 | --- a/storage/innodb_plugin/row/row0mysql.c | |
509 | +++ b/storage/innodb_plugin/row/row0mysql.c | |
510 | @@ -1189,6 +1189,7 @@ | |
511 | prebuilt->table->stat_n_rows--; | |
512 | } | |
513 | ||
514 | + if (!(trx->fake_changes)) | |
515 | row_update_statistics_if_needed(prebuilt->table); | |
516 | trx->op_info = ""; | |
517 | ||
518 | @@ -1449,6 +1450,7 @@ | |
519 | that changes indexed columns, UPDATEs that change only non-indexed | |
520 | columns would not affect statistics. */ | |
521 | if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { | |
522 | + if (!(trx->fake_changes)) | |
523 | row_update_statistics_if_needed(prebuilt->table); | |
524 | } | |
525 | ||
526 | @@ -1667,6 +1669,7 @@ | |
527 | srv_n_rows_updated++; | |
528 | } | |
529 | ||
530 | + if (!(trx->fake_changes)) | |
531 | row_update_statistics_if_needed(table); | |
532 | ||
533 | return(err); | |
534 | --- a/storage/innodb_plugin/row/row0upd.c | |
535 | +++ b/storage/innodb_plugin/row/row0upd.c | |
536 | @@ -1591,8 +1591,9 @@ | |
537 | ||
538 | mtr_start(&mtr); | |
539 | ||
540 | - found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur, | |
541 | - &mtr); | |
542 | + found = row_search_index_entry(index, entry, | |
543 | + trx->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF, | |
544 | + &pcur, &mtr); | |
545 | btr_cur = btr_pcur_get_btr_cur(&pcur); | |
546 | ||
547 | rec = btr_cur_get_rec(btr_cur); | |
548 | @@ -1822,9 +1823,11 @@ | |
549 | the previous invocation of this function. Mark the | |
550 | off-page columns in the entry inherited. */ | |
551 | ||
552 | + if (!(trx->fake_changes)) { | |
553 | change_ownership = row_upd_clust_rec_by_insert_inherit( | |
554 | NULL, NULL, entry, node->update); | |
555 | ut_a(change_ownership); | |
556 | + } | |
557 | /* fall through */ | |
558 | case UPD_NODE_INSERT_CLUSTERED: | |
559 | /* A lock wait occurred in row_ins_index_entry() in | |
560 | @@ -1854,7 +1857,7 @@ | |
561 | delete-marked old record, mark them disowned by the | |
562 | old record and owned by the new entry. */ | |
563 | ||
564 | - if (rec_offs_any_extern(offsets)) { | |
565 | + if (rec_offs_any_extern(offsets) && !(trx->fake_changes)) { | |
566 | change_ownership = row_upd_clust_rec_by_insert_inherit( | |
567 | rec, offsets, entry, node->update); | |
568 | ||
569 | @@ -1982,7 +1985,8 @@ | |
570 | the same transaction do not modify the record in the meantime. | |
571 | Therefore we can assert that the restoration of the cursor succeeds. */ | |
572 | ||
573 | - ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); | |
574 | + ut_a(btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_TREE, | |
575 | + pcur, mtr)); | |
576 | ||
577 | ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), | |
578 | dict_table_is_comp(index->table))); | |
579 | @@ -1990,7 +1994,8 @@ | |
580 | err = btr_cur_pessimistic_update( | |
581 | BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, | |
582 | &heap, &big_rec, node->update, node->cmpl_info, thr, mtr); | |
583 | - if (big_rec) { | |
584 | + /* skip store extern for fake_changes */ | |
585 | + if (big_rec && !(thr_get_trx(thr)->fake_changes)) { | |
586 | ulint offsets_[REC_OFFS_NORMAL_SIZE]; | |
587 | rec_t* rec; | |
588 | rec_offs_init(offsets_); | |
589 | @@ -2132,7 +2137,8 @@ | |
590 | ||
591 | ut_a(pcur->rel_pos == BTR_PCUR_ON); | |
592 | ||
593 | - success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); | |
594 | + success = btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF, | |
595 | + pcur, mtr); | |
596 | ||
597 | if (!success) { | |
598 | err = DB_RECORD_NOT_FOUND; | |
599 | --- a/storage/innodb_plugin/trx/trx0trx.c | |
600 | +++ b/storage/innodb_plugin/trx/trx0trx.c | |
601 | @@ -114,6 +114,8 @@ | |
602 | ||
603 | trx->flush_log_at_trx_commit_session = 3; /* means to use innodb_flush_log_at_trx_commit value */ | |
604 | ||
605 | + trx->fake_changes = FALSE; | |
606 | + | |
607 | trx->check_foreigns = TRUE; | |
608 | trx->check_unique_secondary = TRUE; | |
609 | ||
610 | --- /dev/null | |
611 | +++ b/mysql-test/r/percona_innodb_fake_changes.result | |
612 | @@ -0,0 +1,55 @@ | |
613 | +DROP TABLE IF EXISTS t1; | |
614 | +# Checking variables | |
615 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
616 | +Variable_name Value | |
617 | +innodb_fake_changes OFF | |
618 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
619 | +VARIABLE_VALUE | |
620 | +OFF | |
621 | +SET innodb_fake_changes=1; | |
622 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
623 | +Variable_name Value | |
624 | +innodb_fake_changes ON | |
625 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
626 | +VARIABLE_VALUE | |
627 | +ON | |
628 | +SET innodb_fake_changes=default; | |
629 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
630 | +Variable_name Value | |
631 | +innodb_fake_changes OFF | |
632 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
633 | +VARIABLE_VALUE | |
634 | +OFF | |
635 | +# Explicit COMMIT should fail when innodb_fake_changes is enabled | |
636 | +# DML should be fine | |
637 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
638 | +INSERT INTO t1 VALUES (1); | |
639 | +SET autocommit=0; | |
640 | +SET innodb_fake_changes=1; | |
641 | +BEGIN; | |
642 | +INSERT INTO t1 VALUES (2); | |
643 | +UPDATE t1 SET a=0; | |
644 | +DELETE FROM t1 LIMIT 1; | |
645 | +SELECT * FROM t1; | |
646 | +a | |
647 | +1 | |
648 | +COMMIT; | |
649 | +ERROR HY000: Got error 131 during COMMIT | |
650 | +SET innodb_fake_changes=default; | |
651 | +DROP TABLE t1; | |
652 | +# DDL must result in error | |
653 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
654 | +SET autocommit=0; | |
655 | +SET innodb_fake_changes=1; | |
656 | +BEGIN; | |
657 | +CREATE TABLE t2 (a INT) ENGINE=InnoDB; | |
658 | +ERROR HY000: Can't create table 'test.t2' (errno: 131) | |
659 | +DROP TABLE t1; | |
660 | +ERROR 42S02: Unknown table 't1' | |
661 | +TRUNCATE TABLE t1; | |
662 | +ERROR HY000: Got error 131 during COMMIT | |
663 | +ALTER TABLE t1 ENGINE=MyISAM; | |
664 | +ERROR HY000: Got error 131 during COMMIT | |
665 | +ROLLBACK; | |
666 | +SET innodb_fake_changes=default; | |
667 | +DROP TABLE t1; | |
668 | --- /dev/null | |
669 | +++ b/mysql-test/r/percona_innodb_fake_changes_locks.result | |
670 | @@ -0,0 +1,19 @@ | |
671 | +DROP TABLE IF EXISTS t1; | |
672 | +# Verifying that X_LOCK not acquired | |
673 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
674 | +INSERT INTO t1 VALUES (1); | |
675 | +SET autocommit=0; | |
676 | +SET innodb_fake_changes=1; | |
677 | +BEGIN; | |
678 | +SELECT * FROM t1 FOR UPDATE; | |
679 | +a | |
680 | +1 | |
681 | +SET innodb_lock_wait_timeout=3; | |
682 | +UPDATE t1 SET a=2; | |
683 | +ERROR HY000: Lock wait timeout exceeded; try restarting transaction | |
684 | +SELECT * FROM t1 LOCK IN SHARE MODE; | |
685 | +a | |
686 | +1 | |
687 | +ROLLBACK; | |
688 | +SET innodb_fake_changes=default; | |
689 | +DROP TABLE t1; | |
690 | --- /dev/null | |
691 | +++ b/mysql-test/t/percona_innodb_fake_changes.test | |
692 | @@ -0,0 +1,49 @@ | |
693 | +--source include/have_innodb_plugin.inc | |
694 | + | |
695 | +--disable_warnings | |
696 | +DROP TABLE IF EXISTS t1; | |
697 | +--enable_warnings | |
698 | + | |
699 | + | |
700 | +--echo # Checking variables | |
701 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
702 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
703 | +SET innodb_fake_changes=1; | |
704 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
705 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
706 | +SET innodb_fake_changes=default; | |
707 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
708 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
709 | + | |
710 | +--echo # Explicit COMMIT should fail when innodb_fake_changes is enabled | |
711 | +--echo # DML should be fine | |
712 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
713 | +INSERT INTO t1 VALUES (1); | |
714 | +SET autocommit=0; | |
715 | +SET innodb_fake_changes=1; | |
716 | +BEGIN; | |
717 | +INSERT INTO t1 VALUES (2); | |
718 | +UPDATE t1 SET a=0; | |
719 | +DELETE FROM t1 LIMIT 1; | |
720 | +SELECT * FROM t1; | |
721 | +--error 1180 | |
722 | +COMMIT; | |
723 | +SET innodb_fake_changes=default; | |
724 | +DROP TABLE t1; | |
725 | + | |
726 | +--echo # DDL must result in error | |
727 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
728 | +SET autocommit=0; | |
729 | +SET innodb_fake_changes=1; | |
730 | +BEGIN; | |
731 | +--error 1005 | |
732 | +CREATE TABLE t2 (a INT) ENGINE=InnoDB; | |
733 | +--error 1051 | |
734 | +DROP TABLE t1; | |
735 | +--error 1180 | |
736 | +TRUNCATE TABLE t1; | |
737 | +--error 1180 | |
738 | +ALTER TABLE t1 ENGINE=MyISAM; | |
739 | +ROLLBACK; | |
740 | +SET innodb_fake_changes=default; | |
741 | +DROP TABLE t1; | |
742 | --- /dev/null | |
743 | +++ b/mysql-test/t/percona_innodb_fake_changes_locks.test | |
744 | @@ -0,0 +1,24 @@ | |
745 | +--source include/have_innodb_plugin.inc | |
746 | + | |
747 | +--disable_warnings | |
748 | +DROP TABLE IF EXISTS t1; | |
749 | +--enable_warnings | |
750 | + | |
751 | +--echo # Verifying that X_LOCK not acquired | |
752 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
753 | +INSERT INTO t1 VALUES (1); | |
754 | +--connect (conn1,localhost,root,,) | |
755 | +--connection conn1 | |
756 | +SET autocommit=0; | |
757 | +SET innodb_fake_changes=1; | |
758 | +BEGIN; | |
759 | +SELECT * FROM t1 FOR UPDATE; | |
760 | +--connection default | |
761 | +SET innodb_lock_wait_timeout=3; | |
762 | +--error 1205 | |
763 | +UPDATE t1 SET a=2; | |
764 | +SELECT * FROM t1 LOCK IN SHARE MODE; | |
765 | +--connection conn1 | |
766 | +ROLLBACK; | |
767 | +SET innodb_fake_changes=default; | |
768 | +DROP TABLE t1; |