]>
Commit | Line | Data |
---|---|---|
734d6226 AM |
1 | # name : innodb_fake_changes.patch |
2 | # introduced : 5.5.15 | |
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/innobase/btr/btr0cur.c | |
9 | +++ b/storage/innobase/btr/btr0cur.c | |
1bfc1981 | 10 | @@ -1158,6 +1158,11 @@ |
734d6226 AM |
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 | ||
1bfc1981 | 22 | @@ -1289,7 +1294,7 @@ |
734d6226 AM |
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 | ||
1bfc1981 | 31 | @@ -1384,6 +1389,12 @@ |
734d6226 AM |
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 */ | |
1bfc1981 | 44 | @@ -1526,10 +1537,10 @@ |
734d6226 AM |
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 | |
1bfc1981 | 57 | @@ -1595,6 +1606,16 @@ |
734d6226 AM |
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 | ||
1bfc1981 | 74 | @@ -1651,6 +1672,11 @@ |
734d6226 AM |
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 | ||
1bfc1981 | 86 | @@ -1950,6 +1976,14 @@ |
734d6226 AM |
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 (!(flags & BTR_KEEP_SYS_FLAG)) { | |
99 | row_upd_rec_sys_fields(rec, NULL, | |
100 | index, offsets, trx, roll_ptr); | |
1bfc1981 | 101 | @@ -2059,7 +2093,7 @@ |
734d6226 AM |
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 | ||
1bfc1981 | 110 | @@ -2172,6 +2206,11 @@ |
734d6226 AM |
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). */ | |
1bfc1981 | 122 | @@ -2322,9 +2361,9 @@ |
734d6226 AM |
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 */ | |
1bfc1981 | 134 | @@ -2412,6 +2451,9 @@ |
734d6226 AM |
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); | |
1bfc1981 | 144 | @@ -2446,6 +2488,12 @@ |
734d6226 AM |
145 | } |
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 | |
1bfc1981 | 157 | @@ -2748,6 +2796,11 @@ |
734d6226 AM |
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 | ||
1bfc1981 | 169 | @@ -2882,6 +2935,11 @@ |
734d6226 AM |
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/innobase/handler/ha_innodb.cc | |
182 | +++ b/storage/innobase/handler/ha_innodb.cc | |
183 | @@ -488,6 +488,12 @@ | |
184 | " or 2 (write at commit, flush once per second).", | |
185 | NULL, NULL, 1, 0, 2, 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 | @@ -1689,6 +1695,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; | |
13ceb006 | 205 | @@ -3195,6 +3203,11 @@ |
734d6226 AM |
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->stmt_da->reset_diagnostics_area(); /* because debug assertion code complains, if something left */ | |
212 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
213 | + } | |
214 | /* Transaction is deregistered only in a commit or a rollback. If | |
215 | it is deregistered we know there cannot be resources to be freed | |
216 | and we could return immediately. For the time being, we play safe | |
29ffd636 | 217 | @@ -7543,6 +7556,12 @@ |
734d6226 AM |
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. */ | |
29ffd636 | 230 | @@ -7763,6 +7782,10 @@ |
734d6226 AM |
231 | DBUG_RETURN(HA_ERR_CRASHED); |
232 | } | |
233 | ||
234 | + if (prebuilt->trx->fake_changes) { | |
235 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
236 | + } | |
237 | + | |
238 | /* Truncate the table in InnoDB */ | |
239 | ||
240 | error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx); | |
29ffd636 | 241 | @@ -7819,6 +7842,12 @@ |
734d6226 AM |
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); | |
29ffd636 | 254 | @@ -7905,6 +7934,12 @@ |
734d6226 AM |
255 | trx->mysql_thd = NULL; |
256 | #else | |
257 | trx = innobase_trx_allocate(thd); | |
258 | + if (trx->fake_changes) { | |
259 | + my_free(namebuf); | |
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); | |
29ffd636 | 267 | @@ -8010,6 +8045,11 @@ |
734d6226 AM |
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 | ||
29ffd636 | 279 | @@ -10880,6 +10920,10 @@ |
734d6226 AM |
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 | |
29ffd636 AM |
290 | @@ -12480,6 +12524,7 @@ |
291 | #endif | |
734d6226 AM |
292 | MYSQL_SYSVAR(corrupt_table_action), |
293 | MYSQL_SYSVAR(lazy_drop_table), | |
294 | + MYSQL_SYSVAR(fake_changes), | |
295 | NULL | |
296 | }; | |
297 | ||
298 | --- a/storage/innobase/handler/handler0alter.cc | |
299 | +++ b/storage/innobase/handler/handler0alter.cc | |
300 | @@ -695,6 +695,10 @@ | |
301 | possible adaptive hash latch to avoid deadlocks of threads. */ | |
302 | trx_search_latch_release_if_reserved(prebuilt->trx); | |
303 | ||
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 | DBUG_RETURN(-1); | |
311 | @@ -732,6 +736,13 @@ | |
312 | /* Create a background transaction for the operations on | |
313 | the data dictionary tables. */ | |
314 | trx = innobase_trx_allocate(user_thd); | |
315 | + if (trx->fake_changes) { | |
316 | + mem_heap_free(heap); | |
317 | + trx_general_rollback_for_mysql(trx, NULL); | |
318 | + trx_free_for_mysql(trx); | |
319 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
320 | + } | |
321 | + | |
322 | trx_start_if_not_started(trx); | |
323 | ||
324 | /* Create table containing all indexes to be built in this | |
325 | @@ -1092,6 +1103,10 @@ | |
326 | trx_search_latch_release_if_reserved(prebuilt->trx); | |
327 | trx = prebuilt->trx; | |
328 | ||
329 | + if (trx->fake_changes) { | |
330 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
331 | + } | |
332 | + | |
333 | /* Test and mark all the indexes to be dropped */ | |
334 | ||
335 | row_mysql_lock_data_dictionary(trx); | |
336 | @@ -1296,6 +1311,12 @@ | |
337 | /* Create a background transaction for the operations on | |
338 | the data dictionary tables. */ | |
339 | trx = innobase_trx_allocate(user_thd); | |
340 | + if (trx->fake_changes) { | |
341 | + trx_general_rollback_for_mysql(trx, NULL); | |
342 | + trx_free_for_mysql(trx); | |
343 | + DBUG_RETURN(HA_ERR_WRONG_COMMAND); | |
344 | + } | |
345 | + | |
346 | trx_start_if_not_started(trx); | |
347 | ||
348 | /* Flag this transaction as a dictionary operation, so that | |
349 | --- a/storage/innobase/ibuf/ibuf0ibuf.c | |
350 | +++ b/storage/innobase/ibuf/ibuf0ibuf.c | |
1bfc1981 | 351 | @@ -3424,6 +3424,8 @@ |
734d6226 AM |
352 | |
353 | ut_a(trx_sys_multiple_tablespace_format); | |
354 | ||
355 | + ut_ad(!(thr_get_trx(thr)->fake_changes)); | |
356 | + | |
357 | do_merge = FALSE; | |
358 | ||
359 | /* Perform dirty reads of ibuf->size and ibuf->max_size, to | |
360 | --- a/storage/innobase/include/trx0trx.h | |
361 | +++ b/storage/innobase/include/trx0trx.h | |
362 | @@ -512,6 +512,7 @@ | |
363 | FALSE, one can save CPU time and about | |
364 | 150 bytes in the undo log size as then | |
365 | we skip XA steps */ | |
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 | --- a/storage/innobase/lock/lock0lock.c | |
371 | +++ b/storage/innobase/lock/lock0lock.c | |
372 | @@ -3912,6 +3912,10 @@ | |
373 | ||
374 | trx = thr_get_trx(thr); | |
375 | ||
376 | + if (trx->fake_changes && mode == LOCK_IX) { | |
377 | + mode = LOCK_IS; | |
378 | + } | |
379 | + | |
380 | lock_mutex_enter_kernel(); | |
381 | ||
382 | /* Look for stronger locks the same trx already has on the table */ | |
383 | @@ -5114,6 +5118,11 @@ | |
384 | } | |
385 | ||
386 | trx = thr_get_trx(thr); | |
387 | + | |
388 | + if (trx->fake_changes) { | |
389 | + return(DB_SUCCESS); | |
390 | + } | |
391 | + | |
392 | next_rec = page_rec_get_next_const(rec); | |
393 | next_rec_heap_no = page_rec_get_heap_no(next_rec); | |
394 | ||
395 | @@ -5282,6 +5291,10 @@ | |
396 | return(DB_SUCCESS); | |
397 | } | |
398 | ||
399 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
400 | + return(DB_SUCCESS); | |
401 | + } | |
402 | + | |
403 | heap_no = rec_offs_comp(offsets) | |
404 | ? rec_get_heap_no_new(rec) | |
405 | : rec_get_heap_no_old(rec); | |
406 | @@ -5340,6 +5353,10 @@ | |
407 | return(DB_SUCCESS); | |
408 | } | |
409 | ||
410 | + if (thr && thr_get_trx(thr)->fake_changes) { | |
411 | + return(DB_SUCCESS); | |
412 | + } | |
413 | + | |
414 | heap_no = page_rec_get_heap_no(rec); | |
415 | ||
416 | /* Another transaction cannot have an implicit lock on the record, | |
417 | @@ -5427,6 +5444,10 @@ | |
418 | return(DB_SUCCESS); | |
419 | } | |
420 | ||
421 | + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { | |
422 | + mode = LOCK_S; | |
423 | + } | |
424 | + | |
425 | heap_no = page_rec_get_heap_no(rec); | |
426 | ||
427 | lock_mutex_enter_kernel(); | |
428 | @@ -5503,6 +5524,10 @@ | |
429 | return(DB_SUCCESS); | |
430 | } | |
431 | ||
432 | + if (thr && thr_get_trx(thr)->fake_changes && mode == LOCK_X) { | |
433 | + mode = LOCK_S; | |
434 | + } | |
435 | + | |
436 | heap_no = page_rec_get_heap_no(rec); | |
437 | ||
438 | lock_mutex_enter_kernel(); | |
439 | --- a/storage/innobase/que/que0que.c | |
440 | +++ b/storage/innobase/que/que0que.c | |
441 | @@ -1417,6 +1417,12 @@ | |
442 | ||
443 | ut_a(trx->error_state == DB_SUCCESS); | |
444 | ||
445 | + if (trx->fake_changes) { | |
446 | + /* fake_changes should not access to system tables */ | |
447 | + fprintf(stderr, "InnoDB: ERROR: innodb_fake_changes tried to access to system tables.\n"); | |
448 | + return(DB_ERROR); | |
449 | + } | |
450 | + | |
451 | if (reserve_dict_mutex) { | |
452 | mutex_enter(&dict_sys->mutex); | |
453 | } | |
454 | --- a/storage/innobase/row/row0ins.c | |
455 | +++ b/storage/innobase/row/row0ins.c | |
13ceb006 | 456 | @@ -1505,6 +1505,11 @@ |
734d6226 AM |
457 | if (UNIV_LIKELY_NULL(heap)) { |
458 | mem_heap_free(heap); | |
459 | } | |
460 | + | |
461 | + if (trx->fake_changes) { | |
462 | + err = DB_SUCCESS; | |
463 | + } | |
464 | + | |
465 | return(err); | |
466 | } | |
467 | ||
13ceb006 | 468 | @@ -2010,7 +2015,7 @@ |
734d6226 AM |
469 | } |
470 | ||
471 | btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, | |
472 | - search_mode, | |
473 | + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : search_mode, | |
474 | &cursor, 0, __FILE__, __LINE__, &mtr); | |
475 | ||
476 | if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) { | |
13ceb006 | 477 | @@ -2070,7 +2075,7 @@ |
734d6226 AM |
478 | |
479 | btr_cur_search_to_nth_level(index, 0, entry, | |
480 | PAGE_CUR_LE, | |
481 | - mode | BTR_INSERT, | |
482 | + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT), | |
483 | &cursor, 0, | |
484 | __FILE__, __LINE__, &mtr); | |
485 | } | |
13ceb006 | 486 | @@ -2124,6 +2129,22 @@ |
734d6226 AM |
487 | if (UNIV_LIKELY_NULL(big_rec)) { |
488 | rec_t* rec; | |
489 | ulint* offsets; | |
490 | + | |
491 | + if (thr_get_trx(thr)->fake_changes) { | |
492 | + /* skip store extern */ | |
493 | + if (modify) { | |
494 | + dtuple_big_rec_free(big_rec); | |
495 | + } else { | |
496 | + dtuple_convert_back_big_rec(index, entry, big_rec); | |
497 | + } | |
498 | + | |
499 | + if (UNIV_LIKELY_NULL(heap)) { | |
500 | + mem_heap_free(heap); | |
501 | + } | |
502 | + | |
503 | + return(err); | |
504 | + } | |
505 | + | |
506 | mtr_start(&mtr); | |
507 | ||
508 | btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, | |
509 | --- a/storage/innobase/row/row0mysql.c | |
510 | +++ b/storage/innobase/row/row0mysql.c | |
511 | @@ -1246,6 +1246,7 @@ | |
512 | prebuilt->table->stat_n_rows--; | |
513 | } | |
514 | ||
515 | + if (!(trx->fake_changes)) | |
516 | row_update_statistics_if_needed(prebuilt->table); | |
517 | trx->op_info = ""; | |
518 | ||
519 | @@ -1505,6 +1506,7 @@ | |
520 | that changes indexed columns, UPDATEs that change only non-indexed | |
521 | columns would not affect statistics. */ | |
522 | if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { | |
523 | + if (!(trx->fake_changes)) | |
524 | row_update_statistics_if_needed(prebuilt->table); | |
525 | } | |
526 | ||
527 | @@ -1722,6 +1724,7 @@ | |
528 | srv_n_rows_updated++; | |
529 | } | |
530 | ||
531 | + if (!(trx->fake_changes)) | |
532 | row_update_statistics_if_needed(table); | |
533 | ||
534 | return(err); | |
535 | --- a/storage/innobase/row/row0upd.c | |
536 | +++ b/storage/innobase/row/row0upd.c | |
537 | @@ -1603,7 +1603,8 @@ | |
538 | mode |= BTR_DELETE_MARK; | |
539 | } | |
540 | ||
541 | - search_result = row_search_index_entry(index, entry, mode, | |
542 | + search_result = row_search_index_entry(index, entry, | |
543 | + trx->fake_changes ? BTR_SEARCH_LEAF : mode, | |
544 | &pcur, &mtr); | |
545 | ||
546 | btr_cur = btr_pcur_get_btr_cur(&pcur); | |
547 | @@ -1850,9 +1851,11 @@ | |
548 | the previous invocation of this function. Mark the | |
549 | off-page columns in the entry inherited. */ | |
550 | ||
551 | + if (!(trx->fake_changes)) { | |
552 | change_ownership = row_upd_clust_rec_by_insert_inherit( | |
553 | NULL, NULL, entry, node->update); | |
554 | ut_a(change_ownership); | |
555 | + } | |
556 | /* fall through */ | |
557 | case UPD_NODE_INSERT_CLUSTERED: | |
558 | /* A lock wait occurred in row_ins_index_entry() in | |
559 | @@ -1882,7 +1885,7 @@ | |
560 | delete-marked old record, mark them disowned by the | |
561 | old record and owned by the new entry. */ | |
562 | ||
563 | - if (rec_offs_any_extern(offsets)) { | |
564 | + if (rec_offs_any_extern(offsets) && !(trx->fake_changes)) { | |
565 | change_ownership = row_upd_clust_rec_by_insert_inherit( | |
566 | rec, offsets, entry, node->update); | |
567 | ||
568 | @@ -2012,7 +2015,8 @@ | |
569 | the same transaction do not modify the record in the meantime. | |
570 | Therefore we can assert that the restoration of the cursor succeeds. */ | |
571 | ||
572 | - ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); | |
573 | + ut_a(btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_TREE, | |
574 | + pcur, mtr)); | |
575 | ||
576 | ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), | |
577 | dict_table_is_comp(index->table))); | |
578 | @@ -2022,7 +2026,8 @@ | |
579 | node->cmpl_info, thr, mtr); | |
580 | mtr_commit(mtr); | |
581 | ||
582 | - if (err == DB_SUCCESS && big_rec) { | |
583 | + /* skip store extern for fake_changes */ | |
584 | + if (err == DB_SUCCESS && big_rec && !(thr_get_trx(thr)->fake_changes)) { | |
585 | ulint offsets_[REC_OFFS_NORMAL_SIZE]; | |
586 | rec_t* rec; | |
587 | rec_offs_init(offsets_); | |
588 | @@ -2146,7 +2151,8 @@ | |
589 | ||
590 | ut_a(pcur->rel_pos == BTR_PCUR_ON); | |
591 | ||
592 | - success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); | |
593 | + success = btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF, | |
594 | + pcur, mtr); | |
595 | ||
596 | if (!success) { | |
597 | err = DB_RECORD_NOT_FOUND; | |
598 | --- a/storage/innobase/trx/trx0trx.c | |
599 | +++ b/storage/innobase/trx/trx0trx.c | |
600 | @@ -121,6 +121,8 @@ | |
601 | ||
602 | trx->support_xa = TRUE; | |
603 | ||
604 | + trx->fake_changes = FALSE; | |
605 | + | |
606 | trx->check_foreigns = TRUE; | |
607 | trx->check_unique_secondary = TRUE; | |
608 | ||
609 | --- /dev/null | |
610 | +++ b/mysql-test/r/percona_innodb_fake_changes.result | |
611 | @@ -0,0 +1,55 @@ | |
612 | +DROP TABLE IF EXISTS t1; | |
613 | +# Checking variables | |
614 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
615 | +Variable_name Value | |
616 | +innodb_fake_changes OFF | |
617 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
618 | +VARIABLE_VALUE | |
619 | +OFF | |
620 | +SET innodb_fake_changes=1; | |
621 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
622 | +Variable_name Value | |
623 | +innodb_fake_changes ON | |
624 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
625 | +VARIABLE_VALUE | |
626 | +ON | |
627 | +SET innodb_fake_changes=default; | |
628 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
629 | +Variable_name Value | |
630 | +innodb_fake_changes OFF | |
631 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
632 | +VARIABLE_VALUE | |
633 | +OFF | |
634 | +# Explicit COMMIT should fail when innodb_fake_changes is enabled | |
635 | +# DML should be fine | |
636 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
637 | +INSERT INTO t1 VALUES (1); | |
638 | +SET autocommit=0; | |
639 | +SET innodb_fake_changes=1; | |
640 | +BEGIN; | |
641 | +INSERT INTO t1 VALUES (2); | |
642 | +UPDATE t1 SET a=0; | |
643 | +DELETE FROM t1 LIMIT 1; | |
644 | +SELECT * FROM t1; | |
645 | +a | |
646 | +1 | |
647 | +COMMIT; | |
648 | +ERROR HY000: Got error 131 during COMMIT | |
649 | +SET innodb_fake_changes=default; | |
650 | +DROP TABLE t1; | |
651 | +# DDL must result in error | |
652 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
653 | +SET autocommit=0; | |
654 | +SET innodb_fake_changes=1; | |
655 | +BEGIN; | |
656 | +CREATE TABLE t2 (a INT) ENGINE=InnoDB; | |
657 | +ERROR HY000: Can't create table 'test.t2' (errno: 131) | |
658 | +DROP TABLE t1; | |
659 | +ERROR 42S02: Unknown table 't1' | |
660 | +TRUNCATE TABLE t1; | |
661 | +ERROR HY000: Got error 131 during COMMIT | |
662 | +ALTER TABLE t1 ENGINE=MyISAM; | |
663 | +ERROR HY000: Got error 131 during COMMIT | |
664 | +ROLLBACK; | |
665 | +SET innodb_fake_changes=default; | |
666 | +DROP TABLE t1; | |
667 | --- /dev/null | |
668 | +++ b/mysql-test/r/percona_innodb_fake_changes_locks.result | |
669 | @@ -0,0 +1,19 @@ | |
670 | +DROP TABLE IF EXISTS t1; | |
671 | +# Verifying that X_LOCK not acquired | |
672 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
673 | +INSERT INTO t1 VALUES (1); | |
674 | +SET autocommit=0; | |
675 | +SET innodb_fake_changes=1; | |
676 | +BEGIN; | |
677 | +SELECT * FROM t1 FOR UPDATE; | |
678 | +a | |
679 | +1 | |
680 | +SET innodb_lock_wait_timeout=3; | |
681 | +UPDATE t1 SET a=2; | |
682 | +ERROR HY000: Lock wait timeout exceeded; try restarting transaction | |
683 | +SELECT * FROM t1 LOCK IN SHARE MODE; | |
684 | +a | |
685 | +1 | |
686 | +ROLLBACK; | |
687 | +SET innodb_fake_changes=default; | |
688 | +DROP TABLE t1; | |
689 | --- /dev/null | |
690 | +++ b/mysql-test/t/percona_innodb_fake_changes.test | |
691 | @@ -0,0 +1,49 @@ | |
692 | +--source include/have_innodb.inc | |
693 | + | |
694 | +--disable_warnings | |
695 | +DROP TABLE IF EXISTS t1; | |
696 | +--enable_warnings | |
697 | + | |
698 | + | |
699 | +--echo # Checking variables | |
700 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
701 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
702 | +SET innodb_fake_changes=1; | |
703 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
704 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
705 | +SET innodb_fake_changes=default; | |
706 | +SHOW VARIABLES LIKE 'innodb_fake_changes'; | |
707 | +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME='innodb_fake_changes'; | |
708 | + | |
709 | +--echo # Explicit COMMIT should fail when innodb_fake_changes is enabled | |
710 | +--echo # DML should be fine | |
711 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
712 | +INSERT INTO t1 VALUES (1); | |
713 | +SET autocommit=0; | |
714 | +SET innodb_fake_changes=1; | |
715 | +BEGIN; | |
716 | +INSERT INTO t1 VALUES (2); | |
717 | +UPDATE t1 SET a=0; | |
718 | +DELETE FROM t1 LIMIT 1; | |
719 | +SELECT * FROM t1; | |
720 | +--error 1180 | |
721 | +COMMIT; | |
722 | +SET innodb_fake_changes=default; | |
723 | +DROP TABLE t1; | |
724 | + | |
725 | +--echo # DDL must result in error | |
726 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
727 | +SET autocommit=0; | |
728 | +SET innodb_fake_changes=1; | |
729 | +BEGIN; | |
730 | +--error 1005 | |
731 | +CREATE TABLE t2 (a INT) ENGINE=InnoDB; | |
732 | +--error 1051 | |
733 | +DROP TABLE t1; | |
734 | +--error 1180 | |
735 | +TRUNCATE TABLE t1; | |
736 | +--error 1180 | |
737 | +ALTER TABLE t1 ENGINE=MyISAM; | |
738 | +ROLLBACK; | |
739 | +SET innodb_fake_changes=default; | |
740 | +DROP TABLE t1; | |
741 | --- /dev/null | |
742 | +++ b/mysql-test/t/percona_innodb_fake_changes_locks.test | |
743 | @@ -0,0 +1,24 @@ | |
744 | +--source include/have_innodb.inc | |
745 | + | |
746 | +--disable_warnings | |
747 | +DROP TABLE IF EXISTS t1; | |
748 | +--enable_warnings | |
749 | + | |
750 | +--echo # Verifying that X_LOCK not acquired | |
751 | +CREATE TABLE t1 (a INT) ENGINE=InnoDB; | |
752 | +INSERT INTO t1 VALUES (1); | |
753 | +--connect (conn1,localhost,root,,) | |
754 | +--connection conn1 | |
755 | +SET autocommit=0; | |
756 | +SET innodb_fake_changes=1; | |
757 | +BEGIN; | |
758 | +SELECT * FROM t1 FOR UPDATE; | |
759 | +--connection default | |
760 | +SET innodb_lock_wait_timeout=3; | |
761 | +--error 1205 | |
762 | +UPDATE t1 SET a=2; | |
763 | +SELECT * FROM t1 LOCK IN SHARE MODE; | |
764 | +--connection conn1 | |
765 | +ROLLBACK; | |
766 | +SET innodb_fake_changes=default; | |
767 | +DROP TABLE t1; |