1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file row/row0quiesce.cc |
22 | Quiesce a tablespace. |
23 | |
24 | Created 2012-02-08 by Sunny Bains. |
25 | *******************************************************/ |
26 | |
27 | #include "ha_prototypes.h" |
28 | |
29 | #include "row0quiesce.h" |
30 | #include "row0mysql.h" |
31 | #include "ibuf0ibuf.h" |
32 | #include "srv0start.h" |
33 | #include "trx0purge.h" |
34 | #include "fsp0sysspace.h" |
35 | |
36 | #ifdef HAVE_MY_AES_H |
37 | #include <my_aes.h> |
38 | #endif |
39 | |
40 | /*********************************************************************//** |
41 | Write the meta data (index user fields) config file. |
42 | @return DB_SUCCESS or error code. */ |
43 | static MY_ATTRIBUTE((nonnull, warn_unused_result)) |
44 | dberr_t |
45 | row_quiesce_write_index_fields( |
46 | /*===========================*/ |
47 | const dict_index_t* index, /*!< in: write the meta data for |
48 | this index */ |
49 | FILE* file, /*!< in: file to write to */ |
50 | THD* thd) /*!< in/out: session */ |
51 | { |
52 | byte row[sizeof(ib_uint32_t) * 2]; |
53 | |
54 | for (ulint i = 0; i < index->n_fields; ++i) { |
55 | byte* ptr = row; |
56 | const dict_field_t* field = &index->fields[i]; |
57 | |
58 | mach_write_to_4(ptr, field->prefix_len); |
59 | ptr += sizeof(ib_uint32_t); |
60 | |
61 | mach_write_to_4(ptr, field->fixed_len); |
62 | |
63 | DBUG_EXECUTE_IF("ib_export_io_write_failure_9" , |
64 | close(fileno(file));); |
65 | |
66 | if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { |
67 | |
68 | ib_senderrf( |
69 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
70 | (ulong) errno, strerror(errno), |
71 | "while writing index fields." ); |
72 | |
73 | return(DB_IO_ERROR); |
74 | } |
75 | |
76 | /* Include the NUL byte in the length. */ |
77 | ib_uint32_t len = static_cast<ib_uint32_t>(strlen(field->name) + 1); |
78 | ut_a(len > 1); |
79 | |
80 | mach_write_to_4(row, len); |
81 | |
82 | DBUG_EXECUTE_IF("ib_export_io_write_failure_10" , |
83 | close(fileno(file));); |
84 | |
85 | if (fwrite(row, 1, sizeof(len), file) != sizeof(len) |
86 | || fwrite(field->name, 1, len, file) != len) { |
87 | |
88 | ib_senderrf( |
89 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
90 | (ulong) errno, strerror(errno), |
91 | "while writing index column." ); |
92 | |
93 | return(DB_IO_ERROR); |
94 | } |
95 | } |
96 | |
97 | return(DB_SUCCESS); |
98 | } |
99 | |
100 | /*********************************************************************//** |
101 | Write the meta data config file index information. |
102 | @return DB_SUCCESS or error code. */ |
103 | static MY_ATTRIBUTE((nonnull, warn_unused_result)) |
104 | dberr_t |
105 | row_quiesce_write_indexes( |
106 | /*======================*/ |
107 | const dict_table_t* table, /*!< in: write the meta data for |
108 | this table */ |
109 | FILE* file, /*!< in: file to write to */ |
110 | THD* thd) /*!< in/out: session */ |
111 | { |
112 | { |
113 | byte row[sizeof(ib_uint32_t)]; |
114 | |
115 | /* Write the number of indexes in the table. */ |
116 | mach_write_to_4(row, UT_LIST_GET_LEN(table->indexes)); |
117 | |
118 | DBUG_EXECUTE_IF("ib_export_io_write_failure_11" , |
119 | close(fileno(file));); |
120 | |
121 | if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { |
122 | ib_senderrf( |
123 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
124 | (ulong) errno, strerror(errno), |
125 | "while writing index count." ); |
126 | |
127 | return(DB_IO_ERROR); |
128 | } |
129 | } |
130 | |
131 | dberr_t err = DB_SUCCESS; |
132 | |
133 | /* Write the index meta data. */ |
134 | for (const dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); |
135 | index != 0 && err == DB_SUCCESS; |
136 | index = UT_LIST_GET_NEXT(indexes, index)) { |
137 | |
138 | byte* ptr; |
139 | byte row[sizeof(index_id_t) |
140 | + sizeof(ib_uint32_t) * 8]; |
141 | |
142 | ptr = row; |
143 | |
144 | ut_ad(sizeof(index_id_t) == 8); |
145 | mach_write_to_8(ptr, index->id); |
146 | ptr += sizeof(index_id_t); |
147 | |
148 | mach_write_to_4(ptr, table->space->id); |
149 | ptr += sizeof(ib_uint32_t); |
150 | |
151 | mach_write_to_4(ptr, index->page); |
152 | ptr += sizeof(ib_uint32_t); |
153 | |
154 | mach_write_to_4(ptr, index->type); |
155 | ptr += sizeof(ib_uint32_t); |
156 | |
157 | mach_write_to_4(ptr, index->trx_id_offset); |
158 | ptr += sizeof(ib_uint32_t); |
159 | |
160 | mach_write_to_4(ptr, index->n_user_defined_cols); |
161 | ptr += sizeof(ib_uint32_t); |
162 | |
163 | mach_write_to_4(ptr, index->n_uniq); |
164 | ptr += sizeof(ib_uint32_t); |
165 | |
166 | mach_write_to_4(ptr, index->n_nullable); |
167 | ptr += sizeof(ib_uint32_t); |
168 | |
169 | mach_write_to_4(ptr, index->n_fields); |
170 | |
171 | DBUG_EXECUTE_IF("ib_export_io_write_failure_12" , |
172 | close(fileno(file));); |
173 | |
174 | if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { |
175 | |
176 | ib_senderrf( |
177 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
178 | (ulong) errno, strerror(errno), |
179 | "while writing index meta-data." ); |
180 | |
181 | return(DB_IO_ERROR); |
182 | } |
183 | |
184 | /* Write the length of the index name. |
185 | NUL byte is included in the length. */ |
186 | ib_uint32_t len = static_cast<ib_uint32_t>(strlen(index->name) + 1); |
187 | ut_a(len > 1); |
188 | |
189 | mach_write_to_4(row, len); |
190 | |
191 | DBUG_EXECUTE_IF("ib_export_io_write_failure_1" , |
192 | close(fileno(file));); |
193 | |
194 | if (fwrite(row, 1, sizeof(len), file) != sizeof(len) |
195 | || fwrite(index->name, 1, len, file) != len) { |
196 | |
197 | ib_senderrf( |
198 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
199 | (ulong) errno, strerror(errno), |
200 | "while writing index name." ); |
201 | |
202 | return(DB_IO_ERROR); |
203 | } |
204 | |
205 | err = row_quiesce_write_index_fields(index, file, thd); |
206 | } |
207 | |
208 | return(err); |
209 | } |
210 | |
211 | /*********************************************************************//** |
212 | Write the meta data (table columns) config file. Serialise the contents of |
213 | dict_col_t structure, along with the column name. All fields are serialized |
214 | as ib_uint32_t. |
215 | @return DB_SUCCESS or error code. */ |
216 | static MY_ATTRIBUTE((nonnull, warn_unused_result)) |
217 | dberr_t |
218 | row_quiesce_write_table( |
219 | /*====================*/ |
220 | const dict_table_t* table, /*!< in: write the meta data for |
221 | this table */ |
222 | FILE* file, /*!< in: file to write to */ |
223 | THD* thd) /*!< in/out: session */ |
224 | { |
225 | dict_col_t* col; |
226 | byte row[sizeof(ib_uint32_t) * 7]; |
227 | |
228 | col = table->cols; |
229 | |
230 | for (ulint i = 0; i < table->n_cols; ++i, ++col) { |
231 | byte* ptr = row; |
232 | |
233 | mach_write_to_4(ptr, col->prtype); |
234 | ptr += sizeof(ib_uint32_t); |
235 | |
236 | mach_write_to_4(ptr, col->mtype); |
237 | ptr += sizeof(ib_uint32_t); |
238 | |
239 | mach_write_to_4(ptr, col->len); |
240 | ptr += sizeof(ib_uint32_t); |
241 | |
242 | /* FIXME: This will not work if mbminlen>4. |
243 | This field is also redundant, because the lengths |
244 | are a property of the character set encoding, which |
245 | in turn is encodedin prtype above. */ |
246 | mach_write_to_4(ptr, ulint(col->mbmaxlen * 5 + col->mbminlen)); |
247 | ptr += sizeof(ib_uint32_t); |
248 | |
249 | mach_write_to_4(ptr, col->ind); |
250 | ptr += sizeof(ib_uint32_t); |
251 | |
252 | mach_write_to_4(ptr, col->ord_part); |
253 | ptr += sizeof(ib_uint32_t); |
254 | |
255 | mach_write_to_4(ptr, col->max_prefix); |
256 | |
257 | DBUG_EXECUTE_IF("ib_export_io_write_failure_2" , |
258 | close(fileno(file));); |
259 | |
260 | if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { |
261 | ib_senderrf( |
262 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
263 | (ulong) errno, strerror(errno), |
264 | "while writing table column data." ); |
265 | |
266 | return(DB_IO_ERROR); |
267 | } |
268 | |
269 | /* Write out the column name as [len, byte array]. The len |
270 | includes the NUL byte. */ |
271 | ib_uint32_t len; |
272 | const char* col_name; |
273 | |
274 | col_name = dict_table_get_col_name(table, dict_col_get_no(col)); |
275 | |
276 | /* Include the NUL byte in the length. */ |
277 | len = static_cast<ib_uint32_t>(strlen(col_name) + 1); |
278 | ut_a(len > 1); |
279 | |
280 | mach_write_to_4(row, len); |
281 | |
282 | DBUG_EXECUTE_IF("ib_export_io_write_failure_3" , |
283 | close(fileno(file));); |
284 | |
285 | if (fwrite(row, 1, sizeof(len), file) != sizeof(len) |
286 | || fwrite(col_name, 1, len, file) != len) { |
287 | |
288 | ib_senderrf( |
289 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
290 | (ulong) errno, strerror(errno), |
291 | "while writing column name." ); |
292 | |
293 | return(DB_IO_ERROR); |
294 | } |
295 | } |
296 | |
297 | return(DB_SUCCESS); |
298 | } |
299 | |
300 | /*********************************************************************//** |
301 | Write the meta data config file header. |
302 | @return DB_SUCCESS or error code. */ |
303 | static MY_ATTRIBUTE((nonnull, warn_unused_result)) |
304 | dberr_t |
305 | ( |
306 | /*=====================*/ |
307 | const dict_table_t* table, /*!< in: write the meta data for |
308 | this table */ |
309 | FILE* file, /*!< in: file to write to */ |
310 | THD* thd) /*!< in/out: session */ |
311 | { |
312 | byte value[sizeof(ib_uint32_t)]; |
313 | |
314 | /* Write the meta-data version number. */ |
315 | mach_write_to_4(value, IB_EXPORT_CFG_VERSION_V1); |
316 | |
317 | DBUG_EXECUTE_IF("ib_export_io_write_failure_4" , close(fileno(file));); |
318 | |
319 | if (fwrite(&value, 1, sizeof(value), file) != sizeof(value)) { |
320 | ib_senderrf( |
321 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
322 | (ulong) errno, strerror(errno), |
323 | "while writing meta-data version number." ); |
324 | |
325 | return(DB_IO_ERROR); |
326 | } |
327 | |
328 | /* Write the server hostname. */ |
329 | ib_uint32_t len; |
330 | const char* hostname = server_get_hostname(); |
331 | |
332 | /* Play it safe and check for NULL. */ |
333 | if (hostname == 0) { |
334 | static const char NullHostname[] = "Hostname unknown" ; |
335 | |
336 | ib::warn() << "Unable to determine server hostname." ; |
337 | |
338 | hostname = NullHostname; |
339 | } |
340 | |
341 | /* The server hostname includes the NUL byte. */ |
342 | len = static_cast<ib_uint32_t>(strlen(hostname) + 1); |
343 | mach_write_to_4(value, len); |
344 | |
345 | DBUG_EXECUTE_IF("ib_export_io_write_failure_5" , close(fileno(file));); |
346 | |
347 | if (fwrite(&value, 1, sizeof(value), file) != sizeof(value) |
348 | || fwrite(hostname, 1, len, file) != len) { |
349 | |
350 | ib_senderrf( |
351 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
352 | (ulong) errno, strerror(errno), |
353 | "while writing hostname." ); |
354 | |
355 | return(DB_IO_ERROR); |
356 | } |
357 | |
358 | /* The table name includes the NUL byte. */ |
359 | ut_a(table->name.m_name != NULL); |
360 | len = static_cast<ib_uint32_t>(strlen(table->name.m_name) + 1); |
361 | |
362 | /* Write the table name. */ |
363 | mach_write_to_4(value, len); |
364 | |
365 | DBUG_EXECUTE_IF("ib_export_io_write_failure_6" , close(fileno(file));); |
366 | |
367 | if (fwrite(&value, 1, sizeof(value), file) != sizeof(value) |
368 | || fwrite(table->name.m_name, 1, len, file) != len) { |
369 | |
370 | ib_senderrf( |
371 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
372 | (ulong) errno, strerror(errno), |
373 | "while writing table name." ); |
374 | |
375 | return(DB_IO_ERROR); |
376 | } |
377 | |
378 | byte row[sizeof(ib_uint32_t) * 3]; |
379 | |
380 | /* Write the next autoinc value. */ |
381 | mach_write_to_8(row, table->autoinc); |
382 | |
383 | DBUG_EXECUTE_IF("ib_export_io_write_failure_7" , close(fileno(file));); |
384 | |
385 | if (fwrite(row, 1, sizeof(ib_uint64_t), file) != sizeof(ib_uint64_t)) { |
386 | ib_senderrf( |
387 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
388 | (ulong) errno, strerror(errno), |
389 | "while writing table autoinc value." ); |
390 | |
391 | return(DB_IO_ERROR); |
392 | } |
393 | |
394 | byte* ptr = row; |
395 | |
396 | /* Write the system page size. */ |
397 | mach_write_to_4(ptr, srv_page_size); |
398 | ptr += sizeof(ib_uint32_t); |
399 | |
400 | /* Write the table->flags. */ |
401 | mach_write_to_4(ptr, table->flags); |
402 | ptr += sizeof(ib_uint32_t); |
403 | |
404 | /* Write the number of columns in the table. */ |
405 | mach_write_to_4(ptr, table->n_cols); |
406 | |
407 | DBUG_EXECUTE_IF("ib_export_io_write_failure_8" , close(fileno(file));); |
408 | |
409 | if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) { |
410 | ib_senderrf( |
411 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
412 | (ulong) errno, strerror(errno), |
413 | "while writing table meta-data." ); |
414 | |
415 | return(DB_IO_ERROR); |
416 | } |
417 | |
418 | return(DB_SUCCESS); |
419 | } |
420 | |
421 | /*********************************************************************//** |
422 | Write the table meta data after quiesce. |
423 | @return DB_SUCCESS or error code */ |
424 | static MY_ATTRIBUTE((nonnull, warn_unused_result)) |
425 | dberr_t |
426 | row_quiesce_write_cfg( |
427 | /*==================*/ |
428 | dict_table_t* table, /*!< in: write the meta data for |
429 | this table */ |
430 | THD* thd) /*!< in/out: session */ |
431 | { |
432 | dberr_t err; |
433 | char name[OS_FILE_MAX_PATH]; |
434 | |
435 | srv_get_meta_data_filename(table, name, sizeof(name)); |
436 | |
437 | ib::info() << "Writing table metadata to '" << name << "'" ; |
438 | |
439 | FILE* file = fopen(name, "w+b" ); |
440 | |
441 | if (file == NULL) { |
442 | ib_errf(thd, IB_LOG_LEVEL_WARN, ER_CANT_CREATE_FILE, |
443 | name, errno, strerror(errno)); |
444 | |
445 | err = DB_IO_ERROR; |
446 | } else { |
447 | err = row_quiesce_write_header(table, file, thd); |
448 | |
449 | if (err == DB_SUCCESS) { |
450 | err = row_quiesce_write_table(table, file, thd); |
451 | } |
452 | |
453 | if (err == DB_SUCCESS) { |
454 | err = row_quiesce_write_indexes(table, file, thd); |
455 | } |
456 | |
457 | if (fflush(file) != 0) { |
458 | |
459 | char msg[BUFSIZ]; |
460 | |
461 | snprintf(msg, sizeof(msg), "%s flush() failed" , name); |
462 | |
463 | ib_senderrf( |
464 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
465 | (ulong) errno, strerror(errno), msg); |
466 | } |
467 | |
468 | if (fclose(file) != 0) { |
469 | char msg[BUFSIZ]; |
470 | |
471 | snprintf(msg, sizeof(msg), "%s flose() failed" , name); |
472 | |
473 | ib_senderrf( |
474 | thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR, |
475 | (ulong) errno, strerror(errno), msg); |
476 | } |
477 | } |
478 | |
479 | return(err); |
480 | } |
481 | |
482 | /*********************************************************************//** |
483 | Check whether a table has an FTS index defined on it. |
484 | @return true if an FTS index exists on the table */ |
485 | static |
486 | bool |
487 | row_quiesce_table_has_fts_index( |
488 | /*============================*/ |
489 | const dict_table_t* table) /*!< in: quiesce this table */ |
490 | { |
491 | bool exists = false; |
492 | |
493 | dict_mutex_enter_for_mysql(); |
494 | |
495 | for (const dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); |
496 | index != 0; |
497 | index = UT_LIST_GET_NEXT(indexes, index)) { |
498 | |
499 | if (index->type & DICT_FTS) { |
500 | exists = true; |
501 | break; |
502 | } |
503 | } |
504 | |
505 | dict_mutex_exit_for_mysql(); |
506 | |
507 | return(exists); |
508 | } |
509 | |
510 | /*********************************************************************//** |
511 | Quiesce the tablespace that the table resides in. */ |
512 | void |
513 | row_quiesce_table_start( |
514 | /*====================*/ |
515 | dict_table_t* table, /*!< in: quiesce this table */ |
516 | trx_t* trx) /*!< in/out: transaction/session */ |
517 | { |
518 | ut_a(trx->mysql_thd != 0); |
519 | ut_a(srv_n_purge_threads > 0); |
520 | ut_ad(!srv_read_only_mode); |
521 | |
522 | ut_a(trx->mysql_thd != 0); |
523 | |
524 | ut_ad(table->space != NULL); |
525 | ib::info() << "Sync to disk of " << table->name << " started." ; |
526 | |
527 | if (srv_undo_sources) { |
528 | purge_sys.stop(); |
529 | } |
530 | |
531 | for (ulint count = 0; |
532 | ibuf_merge_space(table->space->id) != 0 |
533 | && !trx_is_interrupted(trx); |
534 | ++count) { |
535 | if (!(count % 20)) { |
536 | ib::info() << "Merging change buffer entries for " |
537 | << table->name; |
538 | } |
539 | } |
540 | |
541 | if (!trx_is_interrupted(trx)) { |
542 | { |
543 | FlushObserver observer(table->space, trx, NULL); |
544 | buf_LRU_flush_or_remove_pages(table->space->id, |
545 | &observer); |
546 | } |
547 | |
548 | if (trx_is_interrupted(trx)) { |
549 | |
550 | ib::warn() << "Quiesce aborted!" ; |
551 | |
552 | } else if (row_quiesce_write_cfg(table, trx->mysql_thd) |
553 | != DB_SUCCESS) { |
554 | |
555 | ib::warn() << "There was an error writing to the" |
556 | " meta data file" ; |
557 | } else { |
558 | ib::info() << "Table " << table->name |
559 | << " flushed to disk" ; |
560 | } |
561 | } else { |
562 | ib::warn() << "Quiesce aborted!" ; |
563 | } |
564 | |
565 | dberr_t err = row_quiesce_set_state(table, QUIESCE_COMPLETE, trx); |
566 | ut_a(err == DB_SUCCESS); |
567 | } |
568 | |
569 | /*********************************************************************//** |
570 | Cleanup after table quiesce. */ |
571 | void |
572 | row_quiesce_table_complete( |
573 | /*=======================*/ |
574 | dict_table_t* table, /*!< in: quiesce this table */ |
575 | trx_t* trx) /*!< in/out: transaction/session */ |
576 | { |
577 | ulint count = 0; |
578 | |
579 | ut_a(trx->mysql_thd != 0); |
580 | |
581 | /* We need to wait for the operation to complete if the |
582 | transaction has been killed. */ |
583 | |
584 | while (table->quiesce != QUIESCE_COMPLETE) { |
585 | |
586 | /* Print a warning after every minute. */ |
587 | if (!(count % 60)) { |
588 | ib::warn() << "Waiting for quiesce of " << table->name |
589 | << " to complete" ; |
590 | } |
591 | |
592 | /* Sleep for a second. */ |
593 | os_thread_sleep(1000000); |
594 | |
595 | ++count; |
596 | } |
597 | |
598 | if (!opt_bootstrap) { |
599 | /* Remove the .cfg file now that the user has resumed |
600 | normal operations. Otherwise it will cause problems when |
601 | the user tries to drop the database (remove directory). */ |
602 | char cfg_name[OS_FILE_MAX_PATH]; |
603 | |
604 | srv_get_meta_data_filename(table, cfg_name, sizeof(cfg_name)); |
605 | |
606 | os_file_delete_if_exists(innodb_data_file_key, cfg_name, NULL); |
607 | |
608 | ib::info() << "Deleting the meta-data file '" << cfg_name << "'" ; |
609 | } |
610 | |
611 | if (srv_undo_sources) { |
612 | purge_sys.resume(); |
613 | } |
614 | |
615 | dberr_t err = row_quiesce_set_state(table, QUIESCE_NONE, trx); |
616 | ut_a(err == DB_SUCCESS); |
617 | } |
618 | |
619 | /*********************************************************************//** |
620 | Set a table's quiesce state. |
621 | @return DB_SUCCESS or error code. */ |
622 | dberr_t |
623 | row_quiesce_set_state( |
624 | /*==================*/ |
625 | dict_table_t* table, /*!< in: quiesce this table */ |
626 | ib_quiesce_t state, /*!< in: quiesce state to set */ |
627 | trx_t* trx) /*!< in/out: transaction */ |
628 | { |
629 | ut_a(srv_n_purge_threads > 0); |
630 | |
631 | if (srv_read_only_mode) { |
632 | |
633 | ib_senderrf(trx->mysql_thd, |
634 | IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE); |
635 | |
636 | return(DB_UNSUPPORTED); |
637 | |
638 | } else if (table->is_temporary()) { |
639 | |
640 | ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_WARN, |
641 | ER_CANNOT_DISCARD_TEMPORARY_TABLE); |
642 | |
643 | return(DB_UNSUPPORTED); |
644 | } else if (table->space->id == TRX_SYS_SPACE) { |
645 | |
646 | char table_name[MAX_FULL_NAME_LEN + 1]; |
647 | |
648 | innobase_format_name( |
649 | table_name, sizeof(table_name), |
650 | table->name.m_name); |
651 | |
652 | ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_WARN, |
653 | ER_TABLE_IN_SYSTEM_TABLESPACE, table_name); |
654 | |
655 | return(DB_UNSUPPORTED); |
656 | } else if (row_quiesce_table_has_fts_index(table)) { |
657 | |
658 | ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_WARN, |
659 | ER_NOT_SUPPORTED_YET, |
660 | "FLUSH TABLES on tables that have an FTS index." |
661 | " FTS auxiliary tables will not be flushed." ); |
662 | |
663 | } else if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) { |
664 | /* If this flag is set then the table may not have any active |
665 | FTS indexes but it will still have the auxiliary tables. */ |
666 | |
667 | ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_WARN, |
668 | ER_NOT_SUPPORTED_YET, |
669 | "FLUSH TABLES on a table that had an FTS index," |
670 | " created on a hidden column, the" |
671 | " auxiliary tables haven't been dropped as yet." |
672 | " FTS auxiliary tables will not be flushed." ); |
673 | } |
674 | |
675 | row_mysql_lock_data_dictionary(trx); |
676 | |
677 | dict_table_x_lock_indexes(table); |
678 | |
679 | switch (state) { |
680 | case QUIESCE_START: |
681 | break; |
682 | |
683 | case QUIESCE_COMPLETE: |
684 | ut_a(table->quiesce == QUIESCE_START); |
685 | break; |
686 | |
687 | case QUIESCE_NONE: |
688 | ut_a(table->quiesce == QUIESCE_COMPLETE); |
689 | break; |
690 | } |
691 | |
692 | table->quiesce = state; |
693 | |
694 | dict_table_x_unlock_indexes(table); |
695 | |
696 | row_mysql_unlock_data_dictionary(trx); |
697 | |
698 | return(DB_SUCCESS); |
699 | } |
700 | |
701 | |