diff options
Diffstat (limited to 'storage/innobase/row/row0merge.cc')
-rw-r--r-- | storage/innobase/row/row0merge.cc | 114 |
1 files changed, 90 insertions, 24 deletions
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index cf662cb1f88..244aa0a69f1 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -294,6 +294,7 @@ row_merge_buf_add( ulint len; const dict_col_t* col; ulint col_no; + ulint fixed_len; const dfield_t* row_field; ibool col_adjusted; @@ -435,9 +436,30 @@ row_merge_buf_add( ut_ad(len <= col->len || col->mtype == DATA_BLOB); - if (ifield->fixed_len) { - ut_ad(len == ifield->fixed_len); + fixed_len = ifield->fixed_len; + if (fixed_len && !dict_table_is_comp(index->table) + && DATA_MBMINLEN(col->mbminmaxlen) + != DATA_MBMAXLEN(col->mbminmaxlen)) { + /* CHAR in ROW_FORMAT=REDUNDANT is always + fixed-length, but in the temporary file it is + variable-length for variable-length character + sets. */ + fixed_len = 0; + } + + if (fixed_len) { +#ifdef UNIV_DEBUG + ulint mbminlen = DATA_MBMINLEN(col->mbminmaxlen); + ulint mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen); + + /* len should be between size calcualted base on + mbmaxlen and mbminlen */ + ut_ad(len <= fixed_len); + ut_ad(!mbmaxlen || len >= mbminlen + * (fixed_len / mbmaxlen)); + ut_ad(!dfield_is_ext(field)); +#endif /* UNIV_DEBUG */ } else if (dfield_is_ext(field)) { extra_size += 2; } else if (len < 128 @@ -464,12 +486,11 @@ row_merge_buf_add( ulint size; ulint extra; - size = rec_get_converted_size_comp(index, - REC_STATUS_ORDINARY, - entry, n_fields, &extra); + size = rec_get_converted_size_temp( + index, entry, n_fields, &extra); - ut_ad(data_size + extra_size + REC_N_NEW_EXTRA_BYTES == size); - ut_ad(extra_size + REC_N_NEW_EXTRA_BYTES == extra); + ut_ad(data_size + extra_size == size); + ut_ad(extra_size == extra); } #endif /* UNIV_DEBUG */ @@ -660,14 +681,9 @@ row_merge_buf_write( ulint extra_size; const dfield_t* entry = buf->tuples[i]; - size = rec_get_converted_size_comp(index, - REC_STATUS_ORDINARY, - entry, n_fields, - &extra_size); + size = rec_get_converted_size_temp( + index, entry, n_fields, &extra_size); ut_ad(size >= extra_size); - ut_ad(extra_size >= REC_N_NEW_EXTRA_BYTES); - extra_size -= REC_N_NEW_EXTRA_BYTES; - size -= REC_N_NEW_EXTRA_BYTES; /* Encode extra_size + 1 */ if (extra_size + 1 < 0x80) { @@ -680,9 +696,8 @@ row_merge_buf_write( ut_ad(b + size < &block[srv_sort_buf_size]); - rec_convert_dtuple_to_rec_comp(b + extra_size, 0, index, - REC_STATUS_ORDINARY, - entry, n_fields); + rec_convert_dtuple_to_temp(b + extra_size, index, + entry, n_fields); b += size; @@ -790,6 +805,8 @@ row_merge_read( os_offset_t ofs = ((os_offset_t) offset) * srv_sort_buf_size; ibool success; + DBUG_EXECUTE_IF("row_merge_read_failure", return(FALSE);); + #ifdef UNIV_DEBUG if (row_merge_print_block_read) { fprintf(stderr, "row_merge_read fd=%d ofs=%lu\n", @@ -839,6 +856,8 @@ row_merge_write( ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, ofs, buf_len); + DBUG_EXECUTE_IF("row_merge_write_failure", return(FALSE);); + #ifdef UNIV_DEBUG if (row_merge_print_block_write) { fprintf(stderr, "row_merge_write fd=%d ofs=%lu\n", @@ -951,7 +970,7 @@ err_exit: *mrec = *buf + extra_size; - rec_init_offsets_comp_ordinary(*mrec, 0, index, offsets); + rec_init_offsets_temp(*mrec, index, offsets); data_size = rec_offs_data_size(offsets); @@ -970,7 +989,7 @@ err_exit: *mrec = b + extra_size; - rec_init_offsets_comp_ordinary(*mrec, 0, index, offsets); + rec_init_offsets_temp(*mrec, index, offsets); data_size = rec_offs_data_size(offsets); ut_ad(extra_size + data_size < sizeof *buf); @@ -2449,7 +2468,7 @@ row_merge_drop_temp_indexes(void) /*********************************************************************//** Creates temporary merge files, and if UNIV_PFS_IO defined, register the file descriptor with Performance Schema. -@return File descriptor */ +@return file descriptor, or -1 on failure */ UNIV_INLINE int row_merge_file_create_low(void) @@ -2471,13 +2490,19 @@ row_merge_file_create_low(void) #ifdef UNIV_PFS_IO register_pfs_file_open_end(locker, fd); #endif + if (fd < 0) { + fprintf(stderr, + "InnoDB: Error: Cannot create temporary merge file\n"); + return(-1); + } return(fd); } /*********************************************************************//** -Create a merge file. */ +Create a merge file. +@return file descriptor, or -1 on failure */ UNIV_INTERN -void +int row_merge_file_create( /*==================*/ merge_file_t* merge_file) /*!< out: merge file structure */ @@ -2488,6 +2513,7 @@ row_merge_file_create( } merge_file->offset = 0; merge_file->n_rec = 0; + return(merge_file->fd); } /*********************************************************************//** @@ -2761,6 +2787,28 @@ row_merge_rename_tables( goto err_exit; } + /* Generate the redo logs for file operations */ + fil_mtr_rename_log(old_table->space, old_name, + new_table->space, new_table->name, tmp_name); + + /* What if the redo logs are flushed to disk here? This is + tested with following crash point */ + DBUG_EXECUTE_IF("bug14669848_precommit", log_buffer_flush_to_disk(); + DBUG_SUICIDE();); + + /* File operations cannot be rolled back. So, before proceeding + with file operations, commit the dictionary changes.*/ + trx_commit_for_mysql(trx); + + /* If server crashes here, the dictionary in InnoDB and MySQL + will differ. The .ibd files and the .frm files must be swapped + manually by the administrator. No loss of data. */ + DBUG_EXECUTE_IF("bug14669848", DBUG_SUICIDE();); + + /* Ensure that the redo logs are flushed to disk. The config + innodb_flush_log_at_trx_commit must not affect this. */ + log_buffer_flush_to_disk(); + /* The following calls will also rename the .ibd data files if the tables are stored in a single-table tablespace */ @@ -2935,7 +2983,7 @@ row_merge_build_indexes( ulint i; ulint j; ulint error; - int tmpfd; + int tmpfd = -1; dict_index_t* fts_sort_idx = NULL; fts_psort_t* psort_info = NULL; fts_psort_t* merge_info = NULL; @@ -2959,9 +3007,21 @@ row_merge_build_indexes( block = static_cast<row_merge_block_t*>( os_mem_alloc_large(&block_size)); + /* Initialize all the merge file descriptors, so that we + don't call row_merge_file_destroy() on uninitialized + merge file descriptor */ + for (i = 0; i < n_indexes; i++) { + merge_files[i].fd = -1; + } - row_merge_file_create(&merge_files[i]); + for (i = 0; i < n_indexes; i++) { + + if (row_merge_file_create(&merge_files[i]) < 0) + { + error = DB_OUT_OF_MEMORY; + goto func_exit; + } if (indexes[i]->type & DICT_FTS) { ibool opt_doc_id_size = FALSE; @@ -2982,6 +3042,12 @@ row_merge_build_indexes( tmpfd = row_merge_file_create_low(); + if (tmpfd < 0) + { + error = DB_OUT_OF_MEMORY; + goto func_exit; + } + /* Reset the MySQL row buffer that is used when reporting duplicate keys. */ innobase_rec_reset(table); |