summaryrefslogtreecommitdiff
path: root/storage/xtradb
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2016-12-28 16:14:28 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2016-12-28 16:32:45 +0200
commit283e9cf4cbb34e1325699707068ab72ec3accfff (patch)
tree40d9660aefc4aae5c01ca7a4215d8f8911e61399 /storage/xtradb
parentd50cf42bc05b1faa5d39c766389ac345e119037e (diff)
downloadmariadb-git-283e9cf4cbb34e1325699707068ab72ec3accfff.tar.gz
MDEV-11656: 'Data structure corruption' IMPORT TABLESPACE doesn't work for encrypted InnoDB tables if space_id changed
Problem was that for encryption we use temporary scratch area for reading and writing tablespace pages. But if page was not really decrypted the correct updated page was not moved to scratch area that was then written. This can happen e.g. for page 0 as it is newer encrypted even if encryption is enabled and as we write the contents of old page 0 to tablespace it contained naturally incorrect space_id that is then later noted and error message was written. Updated page with correct space_id was lost. If tablespace is encrypted we use additional temporary scratch area where pages are read for decrypting readptr == crypt_io_buffer != io_buffer. Destination for decryption is a buffer pool block block->frame == dst == io_buffer that is updated. Pages that did not require decryption even when tablespace is marked as encrypted are not copied instead block->frame is set to src == readptr. If tablespace was encrypted we copy updated page to writeptr != io_buffer. This fixes above bug. For encryption we again use temporary scratch area writeptr != io_buffer == dst that is then written to the tablespace (1) For normal tables src == dst == writeptr ut_ad(!encrypted && !page_compressed ? src == dst && dst == writeptr + (i * size):1); (2) For page compressed tables src == dst == writeptr ut_ad(page_compressed && !encrypted ? src == dst && dst == writeptr + (i * size):1); (3) For encrypted tables src != dst != writeptr ut_ad(encrypted ? src != dst && dst != writeptr + (i * size):1);
Diffstat (limited to 'storage/xtradb')
-rw-r--r--storage/xtradb/fil/fil0fil.cc61
1 files changed, 53 insertions, 8 deletions
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index 5900bdb2140..e7da4569f0d 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -6594,6 +6594,7 @@ fil_iterate(
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
byte* io_buffer = iter.io_buffer;
+ bool row_compressed = false;
block->frame = io_buffer;
@@ -6606,6 +6607,7 @@ fil_iterate(
/* Zip IO is done in the compressed page buffer. */
io_buffer = block->page.zip.data;
+ row_compressed = true;
} else {
io_buffer = iter.io_buffer;
}
@@ -6646,8 +6648,9 @@ fil_iterate(
for (ulint i = 0; i < n_pages_read; ++i) {
ulint size = iter.page_size;
dberr_t err = DB_SUCCESS;
- byte* src = (readptr + (i * size));
- byte* dst = (io_buffer + (i * size));
+ byte* src = readptr + (i * size);
+ byte* dst = io_buffer + (i * size);
+ bool frame_changed = false;
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
@@ -6671,8 +6674,12 @@ fil_iterate(
if (decrypted) {
updated = true;
} else {
- /* TODO: remove unnecessary memcpy's */
- memcpy(dst, src, size);
+ if (!page_compressed && !row_compressed) {
+ block->frame = src;
+ frame_changed = true;
+ } else {
+ memcpy(dst, src, size);
+ }
}
}
@@ -6697,7 +6704,45 @@ fil_iterate(
buf_block_set_state(block, BUF_BLOCK_NOT_USED);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
- src = (io_buffer + (i * size));
+ /* If tablespace is encrypted we use additional
+ temporary scratch area where pages are read
+ for decrypting readptr == crypt_io_buffer != io_buffer.
+
+ Destination for decryption is a buffer pool block
+ block->frame == dst == io_buffer that is updated.
+ Pages that did not require decryption even when
+ tablespace is marked as encrypted are not copied
+ instead block->frame is set to src == readptr.
+
+ For encryption we again use temporary scratch area
+ writeptr != io_buffer == dst
+ that is then written to the tablespace
+
+ (1) For normal tables io_buffer == dst == writeptr
+ (2) For only page compressed tables
+ io_buffer == dst == writeptr
+ (3) For encrypted (and page compressed)
+ readptr != io_buffer == dst != writeptr
+ */
+
+ ut_ad(!encrypted && !page_compressed ?
+ src == dst && dst == writeptr + (i * size):1);
+ ut_ad(page_compressed && !encrypted ?
+ src == dst && dst == writeptr + (i * size):1);
+ ut_ad(encrypted ?
+ src != dst && dst != writeptr + (i * size):1);
+
+ if (encrypted) {
+ memcpy(writeptr + (i * size),
+ row_compressed ? block->page.zip.data :
+ block->frame, size);
+ }
+
+ if (frame_changed) {
+ block->frame = dst;
+ }
+
+ src = io_buffer + (i * size);
if (page_compressed) {
ulint len = 0;
@@ -6718,7 +6763,7 @@ fil_iterate(
write it back. Note that we should not encrypt the
buffer that is in buffer pool. */
if (decrypted && encrypted) {
- unsigned char *dest = (writeptr + (i * size));
+ byte *dest = writeptr + (i * size);
ulint space = mach_read_from_4(
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET);
@@ -6900,9 +6945,9 @@ fil_tablespace_iterate(
void* crypt_io_buffer = NULL;
if (iter.crypt_data != NULL) {
crypt_io_buffer = mem_alloc(
- iter.n_io_buffers * UNIV_PAGE_SIZE);
+ (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.crypt_io_buffer = static_cast<byte*>(
- crypt_io_buffer);
+ ut_align(crypt_io_buffer, UNIV_PAGE_SIZE));
}
err = fil_iterate(iter, &block, callback);