diff options
Diffstat (limited to 'storage/innobase/row/row0merge.cc')
-rw-r--r-- | storage/innobase/row/row0merge.cc | 380 |
1 files changed, 316 insertions, 64 deletions
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index c1d3e08beaa..0669dfef34f 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2005, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2015, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -41,6 +42,7 @@ Completed by Sunny Bains and Marko Makela #include "handler0alter.h" #include "ha_prototypes.h" #include "math.h" /* log() */ +#include "fil0crypt.h" float my_log2f(float n) { @@ -76,6 +78,92 @@ UNIV_INTERN char srv_disable_sort_file_cache; /* Maximum pending doc memory limit in bytes for a fts tokenization thread */ #define FTS_PENDING_DOC_MEMORY_LIMIT 1000000 +/* Reserve free space from every block for key_version */ +#define ROW_MERGE_RESERVE_SIZE 4 + +/******************************************************//** +Encrypt a merge block. */ +static +void +row_merge_encrypt_buf( +/*==================*/ + fil_space_crypt_t* crypt_data, /*!< in: table crypt data */ + ulint offset, /*!< in: offset where to + write */ + ulint space, /*!< in: tablespace id */ + const byte* input_buf, /*!< in: input buffer */ + byte* crypted_buf) /*!< out: crypted buffer */ +{ + uint key_version; + uint dstlen=0; + os_offset_t ofs = (os_offset_t)srv_sort_buf_size * (os_offset_t)offset; + + key_version = encryption_key_get_latest_version(crypt_data->key_id); + + /* Store key_version at the begining of the input buffer */ + mach_write_to_4((byte *)crypted_buf, key_version); + + int rc = encryption_scheme_encrypt(input_buf+ROW_MERGE_RESERVE_SIZE, + srv_sort_buf_size-ROW_MERGE_RESERVE_SIZE, + crypted_buf+ROW_MERGE_RESERVE_SIZE, &dstlen, + crypt_data, key_version, + space, ofs, 0); + + if (! ((rc == MY_AES_OK) && ((ulint)dstlen == srv_sort_buf_size-ROW_MERGE_RESERVE_SIZE))) { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to encrypt data-block " + " src: %p srclen: %lu buf: %p buflen: %d." + " return-code: %d. Can't continue!\n", + input_buf, (size_t)srv_sort_buf_size, + crypted_buf, dstlen, rc); + ut_error; + } +} + +/******************************************************//** +Decrypt a merge block. */ +static +bool +row_merge_decrypt_buf( +/*==================*/ + fil_space_crypt_t* crypt_data, /*!< in: table crypt data */ + ulint offset, /*!< in: offset where to + write */ + ulint space, /*!< in: tablespace id */ + const byte* input_buf, /*!< in: input buffer */ + byte* crypted_buf) /*!< out: crypted buffer */ +{ + uint key_version; + uint dstlen=0; + os_offset_t ofs = (os_offset_t)srv_sort_buf_size * (os_offset_t)offset; + + /* Read key_version from begining of the buffer */ + key_version = mach_read_from_4((byte *)input_buf); + + if (key_version == 0) { + /* block not encrypted */ + return false; + } + + int rc = encryption_scheme_decrypt(input_buf+ROW_MERGE_RESERVE_SIZE, + srv_sort_buf_size-ROW_MERGE_RESERVE_SIZE, + crypted_buf+ROW_MERGE_RESERVE_SIZE, &dstlen, + crypt_data, key_version, + space, ofs, 0); + + if (! ((rc == MY_AES_OK) && ((ulint)dstlen == srv_sort_buf_size-ROW_MERGE_RESERVE_SIZE))) { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to encrypt data-block " + " src: %p srclen: %lu buf: %p buflen: %d." + " return-code: %d. Can't continue!\n", + input_buf, (size_t)srv_sort_buf_size, + crypted_buf, dstlen, rc); + ut_error; + } + + return true; +} + #ifdef UNIV_DEBUG /******************************************************//** Display a merge tuple. */ @@ -193,7 +281,7 @@ row_merge_buf_create( ulint buf_size; mem_heap_t* heap; - max_tuples = srv_sort_buf_size + max_tuples = (srv_sort_buf_size - ROW_MERGE_RESERVE_SIZE) / ut_max(1, dict_index_get_min_size(index)); buf_size = (sizeof *buf); @@ -608,8 +696,8 @@ row_merge_buf_add( ut_ad(data_size < srv_sort_buf_size); - /* Reserve one byte for the end marker of row_merge_block_t. */ - if (buf->total_size + data_size >= srv_sort_buf_size - 1) { + /* Reserve bytes for the end marker of row_merge_block_t. */ + if (buf->total_size + data_size >= (srv_sort_buf_size - ROW_MERGE_RESERVE_SIZE)) { DBUG_RETURN(0); } @@ -781,7 +869,7 @@ row_merge_buf_write( { const dict_index_t* index = buf->index; ulint n_fields= dict_index_get_n_fields(index); - byte* b = &block[0]; + byte* b = &block[ROW_MERGE_RESERVE_SIZE]; for (ulint i = 0; i < buf->n_tuples; i++) { const mtuple_t* entry = &buf->tuples[i]; @@ -800,7 +888,7 @@ row_merge_buf_write( /* Write an "end-of-chunk" marker. */ ut_a(b < &block[srv_sort_buf_size]); - ut_a(b == &block[0] + buf->total_size); + ut_a(b == &block[0] + buf->total_size + ROW_MERGE_RESERVE_SIZE); *b++ = 0; #ifdef UNIV_DEBUG_VALGRIND /* The rest of the block is uninitialized. Initialize it @@ -857,7 +945,10 @@ row_merge_read( ulint offset, /*!< in: offset where to read in number of row_merge_block_t elements */ - row_merge_block_t* buf) /*!< out: data */ + row_merge_block_t* buf, /*!< out: data */ + fil_space_crypt_t* crypt_data,/*!< in: table crypt data */ + row_merge_block_t* crypt_buf, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { os_offset_t ofs = ((os_offset_t) offset) * srv_sort_buf_size; ibool success; @@ -881,6 +972,13 @@ row_merge_read( success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf, ofs, srv_sort_buf_size); + /* For encrypted tables, decrypt data after reading and copy data */ + if (crypt_data && crypt_buf) { + if (row_merge_decrypt_buf(crypt_data, offset, space, buf, crypt_buf)) { + memcpy(buf, crypt_buf, srv_sort_buf_size); + } + } + #ifdef POSIX_FADV_DONTNEED /* Each block is read exactly once. Free up the file cache. */ posix_fadvise(fd, ofs, srv_sort_buf_size, POSIX_FADV_DONTNEED); @@ -903,18 +1001,32 @@ UNIV_INTERN ibool row_merge_write( /*============*/ - int fd, /*!< in: file descriptor */ - ulint offset, /*!< in: offset where to write, - in number of row_merge_block_t elements */ - const void* buf) /*!< in: data */ + int fd, /*!< in: file descriptor */ + ulint offset, /*!< in: offset where to write, + in number of row_merge_block_t elements */ + const void* buf, /*!< in: data */ + fil_space_crypt_t* crypt_data, /*!< in: table crypt data */ + void* crypt_buf, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { size_t buf_len = srv_sort_buf_size; os_offset_t ofs = buf_len * (os_offset_t) offset; ibool ret; + void* out_buf = (void *)buf; DBUG_EXECUTE_IF("row_merge_write_failure", return(FALSE);); - ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, ofs, buf_len); + /* For encrypted tables, encrypt data before writing */ + if (crypt_data && crypt_buf) { + row_merge_encrypt_buf(crypt_data, offset, space, (const byte *)buf, (byte *)crypt_buf); + out_buf = crypt_buf; + } else { + /* Mark block unencrypted */ + mach_write_to_4((byte *)out_buf, 0); + } + + ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), out_buf, ofs, buf_len); + #ifdef UNIV_DEBUG if (row_merge_print_block_write) { @@ -948,7 +1060,10 @@ row_merge_read_rec( const mrec_t** mrec, /*!< out: pointer to merge record, or NULL on end of list (non-NULL on I/O error) */ - ulint* offsets)/*!< out: offsets of mrec */ + ulint* offsets,/*!< out: offsets of mrec */ + fil_space_crypt_t* crypt_data,/*!< in: table crypt data */ + row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { ulint extra_size; ulint data_size; @@ -966,6 +1081,10 @@ row_merge_read_rec( ut_ad(*offsets == 1 + REC_OFFS_HEADER_SIZE + dict_index_get_n_fields(index)); + if (b == &block[0]) { + b+= ROW_MERGE_RESERVE_SIZE; + } + extra_size = *b++; if (UNIV_UNLIKELY(!extra_size)) { @@ -985,7 +1104,8 @@ row_merge_read_rec( /* Read another byte of extra_size. */ if (UNIV_UNLIKELY(b >= &block[srv_sort_buf_size])) { - if (!row_merge_read(fd, ++(*foffs), block)) { + if (!row_merge_read(fd, ++(*foffs), block, + crypt_data, crypt_block, space)) { err_exit: /* Signal I/O error. */ *mrec = b; @@ -993,7 +1113,7 @@ err_exit: } /* Wrap around to the beginning of the buffer. */ - b = &block[0]; + b = &block[ROW_MERGE_RESERVE_SIZE]; } extra_size = (extra_size & 0x7f) << 8; @@ -1014,13 +1134,14 @@ err_exit: ut_ad(avail_size < sizeof *buf); memcpy(*buf, b, avail_size); - if (!row_merge_read(fd, ++(*foffs), block)) { + if (!row_merge_read(fd, ++(*foffs), block, + crypt_data, crypt_block, space)) { goto err_exit; } /* Wrap around to the beginning of the buffer. */ - b = &block[0]; + b = &block[ROW_MERGE_RESERVE_SIZE]; /* Copy the record. */ memcpy(*buf + avail_size, b, extra_size - avail_size); @@ -1075,13 +1196,14 @@ err_exit: offsets[3] = (ulint) index; #endif /* UNIV_DEBUG */ - if (!row_merge_read(fd, ++(*foffs), block)) { + if (!row_merge_read(fd, ++(*foffs), block, + crypt_data, crypt_block, space)) { goto err_exit; } /* Wrap around to the beginning of the buffer. */ - b = &block[0]; + b = &block[ROW_MERGE_RESERVE_SIZE]; /* Copy the rest of the record. */ memcpy(*buf + avail_size, b, extra_size + data_size - avail_size); @@ -1157,7 +1279,10 @@ row_merge_write_rec( int fd, /*!< in: file descriptor */ ulint* foffs, /*!< in/out: file offset */ const mrec_t* mrec, /*!< in: record to write */ - const ulint* offsets)/*!< in: offsets of mrec */ + const ulint* offsets,/*!< in: offsets of mrec */ + fil_space_crypt_t* crypt_data,/*!< in: table crypt data */ + row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { ulint extra_size; ulint size; @@ -1178,6 +1303,10 @@ row_merge_write_rec( size = extra_size + (extra_size >= 0x80) + rec_offs_data_size(offsets); + if (b == &block[0]) { + b+= ROW_MERGE_RESERVE_SIZE; + } + if (UNIV_UNLIKELY(b + size >= &block[srv_sort_buf_size])) { /* The record spans two blocks. Copy it to the temporary buffer first. */ @@ -1192,14 +1321,15 @@ row_merge_write_rec( record to the head of the new block. */ memcpy(b, buf[0], avail_size); - if (!row_merge_write(fd, (*foffs)++, block)) { + if (!row_merge_write(fd, (*foffs)++, block, + crypt_data, crypt_block, space)) { return(NULL); } UNIV_MEM_INVALID(&block[0], srv_sort_buf_size); /* Copy the rest. */ - b = &block[0]; + b = &block[ROW_MERGE_RESERVE_SIZE]; memcpy(b, buf[0] + avail_size, size - avail_size); b += size - avail_size; } else { @@ -1218,10 +1348,13 @@ static byte* row_merge_write_eof( /*================*/ - row_merge_block_t* block, /*!< in/out: file buffer */ - byte* b, /*!< in: pointer to end of block */ - int fd, /*!< in: file descriptor */ - ulint* foffs) /*!< in/out: file offset */ + row_merge_block_t* block, /*!< in/out: file buffer */ + byte* b, /*!< in: pointer to end of block */ + int fd, /*!< in: file descriptor */ + ulint* foffs, /*!< in/out: file offset */ + fil_space_crypt_t* crypt_data, /*!< in: table crypt data */ + row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { ut_ad(block); ut_ad(b >= &block[0]); @@ -1234,20 +1367,27 @@ row_merge_write_eof( } #endif /* UNIV_DEBUG */ + if (b == &block[0]) { + b+= ROW_MERGE_RESERVE_SIZE; + } + *b++ = 0; UNIV_MEM_ASSERT_RW(&block[0], b - &block[0]); UNIV_MEM_ASSERT_W(&block[0], srv_sort_buf_size); + #ifdef UNIV_DEBUG_VALGRIND /* The rest of the block is uninitialized. Initialize it to avoid bogus warnings. */ memset(b, 0xff, &block[srv_sort_buf_size] - b); #endif /* UNIV_DEBUG_VALGRIND */ - if (!row_merge_write(fd, (*foffs)++, block)) { + if (!row_merge_write(fd, (*foffs)++, block, + crypt_data, crypt_block, space)) { return(NULL); } UNIV_MEM_INVALID(&block[0], srv_sort_buf_size); + return(&block[0]); } @@ -1292,7 +1432,11 @@ row_merge_read_clustered_index( ULINT_UNDEFINED if none is added */ ib_sequence_t& sequence,/*!< in/out: autoinc sequence */ row_merge_block_t* block, /*!< in/out: file buffer */ - float pct_cost) /*!< in: percent of task weight out of total alter job */ + float pct_cost, /*!< in: percent of task weight + out of total alter job */ + fil_space_crypt_t* crypt_data,/*!< in: crypt data or NULL */ + row_merge_block_t* crypt_block)/*!< in: in/out: crypted file + buffer */ { dict_index_t* clust_index; /* Clustered index */ mem_heap_t* row_heap; /* Heap memory to create @@ -1314,9 +1458,10 @@ row_merge_read_clustered_index( ib_int64_t sig_count = 0; mem_heap_t* conv_heap = NULL; - float curr_progress; + float curr_progress = 0.0; ib_int64_t read_rows = 0; - ib_int64_t table_total_rows; + ib_int64_t table_total_rows = 0; + DBUG_ENTER("row_merge_read_clustered_index"); ut_ad((old_table == new_table) == !col_map); @@ -1431,6 +1576,13 @@ row_merge_read_clustered_index( row_ext_t* ext; page_cur_t* cur = btr_pcur_get_page_cur(&pcur); + /* Do not continue if table pages are still encrypted */ + if (old_table->is_encrypted || new_table->is_encrypted) { + err = DB_DECRYPTION_FAILED; + trx->error_key_num = 0; + goto func_exit; + } + page_cur_move_to_next(cur); if (page_cur_is_after_last(cur)) { @@ -1800,14 +1952,15 @@ write_buffers: row_merge_buf_write(buf, file, block); - if (!row_merge_write(file->fd, file->offset++, - block)) { + if (!row_merge_write(file->fd, file->offset++, block, + crypt_data, crypt_block, new_table->space)) { err = DB_TEMP_FILE_WRITE_FAILURE; trx->error_key_num = i; break; } UNIV_MEM_INVALID(&block[0], srv_sort_buf_size); + merge_buf[i] = row_merge_buf_empty(buf); if (UNIV_LIKELY(row != NULL)) { @@ -1976,14 +2129,21 @@ wait_again: b2 = row_merge_write_rec(&block[2 * srv_sort_buf_size], \ &buf[2], b2, \ of->fd, &of->offset, \ - mrec##N, offsets##N); \ + mrec##N, offsets##N, \ + crypt_data, \ + crypt_block ? &crypt_block[2 * srv_sort_buf_size] : NULL , \ + space); \ if (UNIV_UNLIKELY(!b2 || ++of->n_rec > file->n_rec)) { \ goto corrupt; \ } \ b##N = row_merge_read_rec(&block[N * srv_sort_buf_size],\ &buf[N], b##N, INDEX, \ file->fd, foffs##N, \ - &mrec##N, offsets##N); \ + &mrec##N, offsets##N, \ + crypt_data, \ + crypt_block ? &crypt_block[N * srv_sort_buf_size] : NULL, \ + space); \ + \ if (UNIV_UNLIKELY(!b##N)) { \ if (mrec##N) { \ goto corrupt; \ @@ -1995,7 +2155,7 @@ wait_again: /*************************************************************//** Merge two blocks of records on disk and write a bigger block. @return DB_SUCCESS or error code */ -static __attribute__((nonnull, warn_unused_result)) +static __attribute__((nonnull(1,2,3,4,5,6), warn_unused_result)) dberr_t row_merge_blocks( /*=============*/ @@ -2008,7 +2168,11 @@ row_merge_blocks( source list in the file */ ulint* foffs1, /*!< in/out: offset of second source list in the file */ - merge_file_t* of) /*!< in/out: output file */ + merge_file_t* of, /*!< in/out: output file */ + fil_space_crypt_t* crypt_data,/*!< in: crypt data or NULL */ + row_merge_block_t* crypt_block,/*!< in: in/out: crypted file + buffer */ + ulint space) /*!< in: space id */ { mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ @@ -2039,8 +2203,10 @@ row_merge_blocks( /* Write a record and read the next record. Split the output file in two halves, which can be merged on the following pass. */ - if (!row_merge_read(file->fd, *foffs0, &block[0]) - || !row_merge_read(file->fd, *foffs1, &block[srv_sort_buf_size])) { + if (!row_merge_read(file->fd, *foffs0, &block[0], + crypt_data, crypt_block ? &crypt_block[0] : NULL, space) + || !row_merge_read(file->fd, *foffs1, &block[srv_sort_buf_size], + crypt_data, crypt_block ? &crypt_block[srv_sort_buf_size] : NULL, space)) { corrupt: mem_heap_free(heap); return(DB_CORRUPTION); @@ -2052,11 +2218,15 @@ corrupt: b0 = row_merge_read_rec( &block[0], &buf[0], b0, dup->index, - file->fd, foffs0, &mrec0, offsets0); + file->fd, foffs0, &mrec0, offsets0, + crypt_data, crypt_block ? &crypt_block[0] : NULL, space); + b1 = row_merge_read_rec( &block[srv_sort_buf_size], &buf[srv_sort_buf_size], b1, dup->index, - file->fd, foffs1, &mrec1, offsets1); + file->fd, foffs1, &mrec1, offsets1, + crypt_data, crypt_block ? &crypt_block[srv_sort_buf_size] : NULL, space); + if (UNIV_UNLIKELY(!b0 && mrec0) || UNIV_UNLIKELY(!b1 && mrec1)) { @@ -2098,15 +2268,18 @@ done0: done1: mem_heap_free(heap); + b2 = row_merge_write_eof(&block[2 * srv_sort_buf_size], - b2, of->fd, &of->offset); + b2, of->fd, &of->offset, + crypt_data, crypt_block ? &crypt_block[2 * srv_sort_buf_size] : NULL, space); + return(b2 ? DB_SUCCESS : DB_CORRUPTION); } /*************************************************************//** Copy a block of index entries. @return TRUE on success, FALSE on failure */ -static __attribute__((nonnull, warn_unused_result)) +static __attribute__((nonnull(1,2,3,4,5), warn_unused_result)) ibool row_merge_blocks_copy( /*==================*/ @@ -2114,7 +2287,10 @@ row_merge_blocks_copy( const merge_file_t* file, /*!< in: input file */ row_merge_block_t* block, /*!< in/out: 3 buffers */ ulint* foffs0, /*!< in/out: input file offset */ - merge_file_t* of) /*!< in/out: output file */ + merge_file_t* of, /*!< in/out: output file */ + fil_space_crypt_t* crypt_data,/*!< in: table crypt data */ + row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ @@ -2141,7 +2317,8 @@ row_merge_blocks_copy( /* Write a record and read the next record. Split the output file in two halves, which can be merged on the following pass. */ - if (!row_merge_read(file->fd, *foffs0, &block[0])) { + if (!row_merge_read(file->fd, *foffs0, &block[0], + crypt_data, crypt_block ? &crypt_block[0] : NULL, space)) { corrupt: mem_heap_free(heap); return(FALSE); @@ -2152,7 +2329,9 @@ corrupt: b2 = &block[2 * srv_sort_buf_size]; b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, - file->fd, foffs0, &mrec0, offsets0); + file->fd, foffs0, &mrec0, offsets0, + crypt_data, crypt_block ? &crypt_block[0] : NULL, space); + if (UNIV_UNLIKELY(!b0 && mrec0)) { goto corrupt; @@ -2171,15 +2350,18 @@ done0: (*foffs0)++; mem_heap_free(heap); + return(row_merge_write_eof(&block[2 * srv_sort_buf_size], - b2, of->fd, &of->offset) + b2, of->fd, &of->offset, + crypt_data, + crypt_block ? &crypt_block[2 * srv_sort_buf_size] : NULL, space) != NULL); } /*************************************************************//** Merge disk files. @return DB_SUCCESS or error code */ -static __attribute__((nonnull)) +static __attribute__((nonnull(1,2,3,4,5,6,7))) dberr_t row_merge( /*======*/ @@ -2192,9 +2374,12 @@ row_merge( int* tmpfd, /*!< in/out: temporary file handle */ ulint* num_run,/*!< in/out: Number of runs remain to be merged */ - ulint* run_offset) /*!< in/out: Array contains the + ulint* run_offset, /*!< in/out: Array contains the first offset number for each merge run */ + fil_space_crypt_t* crypt_data,/*!< in: table crypt data */ + row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { ulint foffs0; /*!< first input offset */ ulint foffs1; /*!< second input offset */ @@ -2207,6 +2392,10 @@ row_merge( UNIV_MEM_ASSERT_W(&block[0], 3 * srv_sort_buf_size); + if (crypt_block) { + UNIV_MEM_ASSERT_W(&crypt_block[0], 3 * srv_sort_buf_size); + } + ut_ad(ihalf < file->offset); of.fd = *tmpfd; @@ -2237,7 +2426,8 @@ row_merge( run_offset[n_run++] = of.offset; error = row_merge_blocks(dup, file, block, - &foffs0, &foffs1, &of); + &foffs0, &foffs1, &of, + crypt_data, crypt_block, space); if (error != DB_SUCCESS) { return(error); @@ -2257,7 +2447,8 @@ row_merge( run_offset[n_run++] = of.offset; if (!row_merge_blocks_copy(dup->index, file, block, - &foffs0, &of)) { + &foffs0, &of, + crypt_data, crypt_block, space)) { return(DB_CORRUPTION); } } @@ -2274,7 +2465,8 @@ row_merge( run_offset[n_run++] = of.offset; if (!row_merge_blocks_copy(dup->index, file, block, - &foffs1, &of)) { + &foffs1, &of, + crypt_data, crypt_block, space)) { return(DB_CORRUPTION); } } @@ -2329,7 +2521,10 @@ row_merge_sort( const float pct_progress, /*!< in: total progress percent until now */ - const float pct_cost) /*!< in: current progress percent */ + const float pct_cost, /*!< in: current progress percent */ + fil_space_crypt_t* crypt_data,/*!< in: table crypt data */ + row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { const ulint half = file->offset / 2; ulint num_runs; @@ -2381,7 +2576,8 @@ row_merge_sort( sql_print_information("InnoDB: Online DDL : merge-sorting current run %lu estimated %lu runs", cur_run, num_runs); error = row_merge(trx, dup, file, block, tmpfd, - &num_runs, run_offset); + &num_runs, run_offset, + crypt_data, crypt_block, space); if(update_progress) { merge_count++; @@ -2453,7 +2649,7 @@ row_merge_copy_blobs( Read sorted file containing index data tuples and insert these data tuples to the index @return DB_SUCCESS or error number */ -static __attribute__((nonnull, warn_unused_result)) +static __attribute__((nonnull(2,3,5), warn_unused_result)) dberr_t row_merge_insert_index_tuples( /*==========================*/ @@ -2464,7 +2660,11 @@ row_merge_insert_index_tuples( row_merge_block_t* block, /*!< in/out: file buffer */ const ib_int64_t table_total_rows, /*!< in: total rows of old table */ const float pct_progress, /*!< in: total progress percent until now */ - const float pct_cost) /*!< in: current progress percent */ + const float pct_cost, /*!< in: current progress percent + */ + fil_space_crypt_t* crypt_data,/*!< in: table crypt data */ + row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */ + ulint space) /*!< in: space id */ { const byte* b; mem_heap_t* heap; @@ -2495,9 +2695,10 @@ row_merge_insert_index_tuples( offsets[1] = dict_index_get_n_fields(index); } - b = block; + b = &block[0]; - if (!row_merge_read(fd, foffs, block)) { + if (!row_merge_read(fd, foffs, block, + crypt_data, crypt_block, space)) { error = DB_CORRUPTION; } else { buf = static_cast<mrec_buf_t*>( @@ -2513,7 +2714,8 @@ row_merge_insert_index_tuples( mtr_t mtr; b = row_merge_read_rec(block, buf, b, index, - fd, &foffs, &mrec, offsets); + fd, &foffs, &mrec, offsets, + crypt_data, crypt_block, space); if (UNIV_UNLIKELY(!b)) { /* End of list, or I/O error */ if (mrec) { @@ -3654,6 +3856,7 @@ row_merge_build_indexes( { merge_file_t* merge_files; row_merge_block_t* block; + row_merge_block_t* crypt_block; ulint block_size; ulint i; ulint j; @@ -3664,6 +3867,7 @@ row_merge_build_indexes( fts_psort_t* merge_info = NULL; ib_int64_t sig_count = 0; bool fts_psort_initiated = false; + fil_space_crypt_t * crypt_data = NULL; float total_static_cost = 0; float total_dynamic_cost = 0; @@ -3688,6 +3892,27 @@ row_merge_build_indexes( DBUG_RETURN(DB_OUT_OF_MEMORY); } + /* Get crypt data from tablespace if present. */ + crypt_data = fil_space_get_crypt_data(new_table->space); + crypt_block = NULL; + + /* If tablespace is encrypted, allocate additional buffer for + encryption/decryption. */ + if ((crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) || + (srv_encrypt_tables && + crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) { + + crypt_block = static_cast<row_merge_block_t*>( + os_mem_alloc_large(&block_size)); + + if (crypt_block == NULL) { + DBUG_RETURN(DB_OUT_OF_MEMORY); + } + } else { + /* Not needed */ + crypt_data = NULL; + } + trx_start_if_not_started_xa(trx); merge_files = static_cast<merge_file_t*>( @@ -3754,14 +3979,26 @@ row_merge_build_indexes( pct_cost = COST_READ_CLUSTERED_INDEX * 100 / (total_static_cost + total_dynamic_cost); + /* Do not continue if we can't encrypt table pages */ + if (old_table->is_encrypted || new_table->is_encrypted) { + error = DB_DECRYPTION_FAILED; + ib_push_warning(trx->mysql_thd, DB_DECRYPTION_FAILED, + "Table %s is encrypted but encryption service or" + " used key_id is not available. " + " Can't continue reading table.", + old_table->is_encrypted ? old_table->name : new_table->name); + goto func_exit; + } + /* Read clustered index of the table and create files for secondary index entries for merge sort */ error = row_merge_read_clustered_index( - trx, table, old_table, new_table, online, indexes, - fts_sort_idx, psort_info, merge_files, key_numbers, - n_indexes, add_cols, col_map, - add_autoinc, sequence, block, pct_cost); + trx, table, old_table, new_table, online, indexes, + fts_sort_idx, psort_info, merge_files, key_numbers, + n_indexes, add_cols, col_map, + add_autoinc, sequence, block, pct_cost, + crypt_data, crypt_block); pct_progress += pct_cost; @@ -3781,6 +4018,10 @@ row_merge_build_indexes( /* Now we have files containing index entries ready for sorting and inserting. */ + DBUG_EXECUTE_IF( + "ib_merge_wait_after_read", + os_thread_sleep(20000000);); /* 20 sec */ + for (i = 0; i < n_indexes; i++) { dict_index_t* sort_idx = indexes[i]; @@ -3874,8 +4115,10 @@ wait_again: buf, (i+1), n_indexes, pct_cost); error = row_merge_sort( - trx, &dup, &merge_files[i], - block, &tmpfd, true, pct_progress, pct_cost); + trx, &dup, &merge_files[i], + block, &tmpfd, true, + pct_progress, pct_cost, + crypt_data, crypt_block, new_table->space); pct_progress += pct_cost; @@ -3883,6 +4126,10 @@ wait_again: " merge-sorting index %s (%lu / %lu)", buf, (i+1), n_indexes); + DBUG_EXECUTE_IF( + "ib_merge_wait_after_sort", + os_thread_sleep(20000000);); /* 20 sec */ + if (error == DB_SUCCESS) { pct_cost = (COST_BUILD_INDEX_STATIC + (total_dynamic_cost * merge_files[i].offset / @@ -3898,7 +4145,8 @@ wait_again: error = row_merge_insert_index_tuples( trx->id, sort_idx, old_table, merge_files[i].fd, block, - merge_files[i].n_rec, pct_progress, pct_cost); + merge_files[i].n_rec, pct_progress, pct_cost, + crypt_data, crypt_block, new_table->space); pct_progress += pct_cost; sql_print_information("InnoDB: Online DDL : " @@ -3972,6 +4220,10 @@ func_exit: mem_free(merge_files); os_mem_free_large(block, block_size); + if (crypt_block) { + os_mem_free_large(crypt_block, block_size); + } + DICT_TF2_FLAG_UNSET(new_table, DICT_TF2_FTS_ADD_DOC_ID); if (online && old_table == new_table && error != DB_SUCCESS) { |