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