summaryrefslogtreecommitdiff
path: root/storage/innobase/row/row0merge.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row/row0merge.cc')
-rw-r--r--storage/innobase/row/row0merge.cc380
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) {