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