summaryrefslogtreecommitdiff
path: root/storage/xtradb/log/log0log.cc
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2014-12-22 16:53:17 +0200
committerSergei Golubchik <serg@mariadb.org>2015-02-10 10:21:17 +0100
commitd7d589dc01f6d70d1518b74d46fd3b75e76267f5 (patch)
treef9df59951453660f0038ed78cf5ceadc852bf74c /storage/xtradb/log/log0log.cc
parent3a3ec744b5a31318a00821dc0ed6da8af49fda25 (diff)
downloadmariadb-git-d7d589dc01f6d70d1518b74d46fd3b75e76267f5.tar.gz
Push for testing of encryption
Diffstat (limited to 'storage/xtradb/log/log0log.cc')
-rw-r--r--storage/xtradb/log/log0log.cc159
1 files changed, 154 insertions, 5 deletions
diff --git a/storage/xtradb/log/log0log.cc b/storage/xtradb/log/log0log.cc
index 031926fd91f..9b33c7858bc 100644
--- a/storage/xtradb/log/log0log.cc
+++ b/storage/xtradb/log/log0log.cc
@@ -90,6 +90,10 @@ UNIV_INTERN log_t* log_sys = NULL;
UNIV_INTERN log_checksum_func_t log_checksum_algorithm_ptr =
log_block_calc_checksum_innodb;
+/* Next log block number to do dummy record filling if no log records written
+for a while */
+static ulint next_lbn_to_pad = 0;
+
#ifdef UNIV_PFS_RWLOCK
UNIV_INTERN mysql_pfs_key_t checkpoint_lock_key;
# ifdef UNIV_LOG_ARCHIVE
@@ -629,10 +633,9 @@ function_exit:
return(lsn);
}
-#ifdef UNIV_LOG_ARCHIVE
/******************************************************//**
Pads the current log block full with dummy log records. Used in producing
-consistent archived log files. */
+consistent archived log files and scrubbing redo log. */
static
void
log_pad_current_log_block(void)
@@ -667,7 +670,6 @@ log_pad_current_log_block(void)
ut_a(lsn % OS_FILE_LOG_BLOCK_SIZE == LOG_BLOCK_HDR_SIZE);
}
-#endif /* UNIV_LOG_ARCHIVE */
/******************************************************//**
Calculates the data capacity of a log group, when the log file headers are not
@@ -1003,6 +1005,7 @@ log_init(void)
/*----------------------------*/
log_sys->next_checkpoint_no = 0;
+ log_sys->redo_log_crypt_ver = UNENCRYPTED_KEY_VER;
log_sys->last_checkpoint_lsn = log_sys->lsn;
log_sys->n_pending_checkpoint_writes = 0;
@@ -1048,7 +1051,7 @@ log_init(void)
log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
log_sys->buf_free = LOG_BLOCK_HDR_SIZE;
- log_sys->lsn = LOG_START_LSN + LOG_BLOCK_HDR_SIZE;
+ log_sys->lsn = LOG_START_LSN + LOG_BLOCK_HDR_SIZE; // TODO(minliz): ensure various LOG_START_LSN?
MONITOR_SET(MONITOR_LSN_CHECKPOINT_AGE,
log_sys->lsn - log_sys->last_checkpoint_lsn);
@@ -1401,6 +1404,36 @@ log_block_store_checksum(
}
/******************************************************//**
+Encrypt one or more log block before it is flushed to disk
+@return true if encryption succeeds. */
+static
+bool
+log_group_encrypt_before_write(
+/*===========================*/
+ const log_group_t* group, /*!< in: log group to be flushed */
+ byte* block, /*!< in/out: pointer to a log block */
+ const ulint size) /*!< in: size of log blocks */
+
+{
+ Crypt_result result = AES_OK;
+
+ ut_ad(size % OS_FILE_LOG_BLOCK_SIZE == 0);
+ byte* dst_frame = (byte*)malloc(size);
+
+ //encrypt log blocks content
+ result = log_blocks_encrypt(block, size, dst_frame);
+
+ if (result == AES_OK)
+ {
+ ut_ad(block[0] == dst_frame[0]);
+ memcpy(block, dst_frame, size);
+ }
+ free(dst_frame);
+
+ return (result == AES_OK);
+}
+
+/******************************************************//**
Writes a buffer to a log file group. */
UNIV_INTERN
void
@@ -1506,6 +1539,15 @@ loop:
ut_a(next_offset / UNIV_PAGE_SIZE <= ULINT_MAX);
+ if (srv_encrypt_log &&
+ log_sys->redo_log_crypt_ver != UNENCRYPTED_KEY_VER &&
+ !log_group_encrypt_before_write(group, buf, write_len))
+ {
+ fprintf(stderr,
+ "\nInnodb redo log encryption failed.\n");
+ abort();
+ }
+
fil_io(OS_FILE_WRITE | OS_FILE_LOG, true, group->space_id, 0,
(ulint) (next_offset / UNIV_PAGE_SIZE),
(ulint) (next_offset % UNIV_PAGE_SIZE), write_len, buf,
@@ -2023,6 +2065,8 @@ log_group_checkpoint(
mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no);
mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn);
+ log_crypt_write_checkpoint_buf(buf);
+
lsn_offset = log_group_calc_lsn_offset(log_sys->next_checkpoint_lsn,
group);
mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET_LOW32,
@@ -2141,6 +2185,8 @@ log_reset_first_header_and_checkpoint(
mach_write_to_8(buf + LOG_CHECKPOINT_NO, 0);
mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn);
+ log_crypt_write_checkpoint_buf(buf);
+
mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET_LOW32,
LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE);
mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET_HIGH32, 0);
@@ -2295,7 +2341,6 @@ log_checkpoint(
}
log_sys->next_checkpoint_lsn = oldest_lsn;
-
#ifdef UNIV_DEBUG
if (log_debug_writes) {
fprintf(stderr, "Making checkpoint no "
@@ -2307,6 +2352,10 @@ log_checkpoint(
log_groups_write_checkpoint_info();
+ /* generate key version and key used to encrypt next log block */
+ log_crypt_set_ver_and_key(log_sys->redo_log_crypt_ver,
+ log_sys->redo_log_crypt_key);
+
MONITOR_INC(MONITOR_NUM_CHECKPOINT);
mutex_exit(&(log_sys->mutex));
@@ -2506,6 +2555,33 @@ loop:
}
/******************************************************//**
+Decrypt a specified log segment after they are read from a log file to a buffer.
+@return true if decryption succeeds. */
+static
+bool
+log_group_decrypt_after_read(
+/*==========================*/
+ const log_group_t* group, /*!< in: log group to be read from */
+ byte* frame, /*!< in/out: log segment */
+ const ulint size) /*!< in: log segment size */
+{
+ Crypt_result result;
+ ut_ad(size % OS_FILE_LOG_BLOCK_SIZE == 0);
+ byte* dst_frame = (byte*)malloc(size);
+
+ // decrypt log blocks content
+ result = log_blocks_decrypt(frame, size, dst_frame);
+
+ if (result == AES_OK)
+ {
+ memcpy(frame, dst_frame, size);
+ }
+ free(dst_frame);
+
+ return (result == AES_OK);
+}
+
+/******************************************************//**
Reads a specified log segment to a buffer. Optionally releases the log mutex
before the I/O. */
UNIV_INTERN
@@ -2565,6 +2641,13 @@ loop:
(ulint) (source_offset % UNIV_PAGE_SIZE),
len, buf, (type == LOG_ARCHIVE) ? &log_archive_io : NULL, 0);
+ if (recv_sys->recv_log_crypt_ver != UNENCRYPTED_KEY_VER &&
+ !log_group_decrypt_after_read(group, buf, len))
+ {
+ fprintf(stderr, "Innodb redo log decryption failed.\n");
+ abort();
+ }
+
start_lsn += len;
buf += len;
@@ -2857,6 +2940,14 @@ loop:
MONITOR_INC(MONITOR_LOG_IO);
+ if (srv_encrypt_log &&
+ log_sys->redo_log_crypt_ver != UNENCRYPTED_KEY_VER &&
+ !log_group_encrypt_before_write(group, buf, len))
+ {
+ fprintf(stderr, "Innodb redo log encryption failed.\n");
+ abort();
+ }
+
fil_io(OS_FILE_WRITE | OS_FILE_LOG, false, group->archive_space_id,
0,
(ulint) (next_offset / UNIV_PAGE_SIZE),
@@ -4074,4 +4165,62 @@ log_mem_free(void)
log_sys = NULL;
}
}
+
+/** Event to wake up the log scrub thread */
+UNIV_INTERN os_event_t log_scrub_event = NULL;
+
+UNIV_INTERN ibool srv_log_scrub_thread_active = FALSE;
+
+/*****************************************************************//*
+If no log record has been written for a while, fill current log
+block with dummy records. */
+static
+void
+log_scrub()
+/*=========*/
+{
+ ulint cur_lbn = log_block_convert_lsn_to_no(log_sys->lsn);
+ if (next_lbn_to_pad == cur_lbn)
+ {
+ log_pad_current_log_block();
+ }
+ next_lbn_to_pad = log_block_convert_lsn_to_no(log_sys->lsn);
+}
+
+/* log scrubbing interval in ms. */
+UNIV_INTERN ulonglong innodb_scrub_log_interval;
+
+/*****************************************************************//**
+This is the main thread for log scrub. It waits for an event and
+when waked up fills current log block with dummy records and
+sleeps again.
+@return this function does not return, it calls os_thread_exit() */
+extern "C" UNIV_INTERN
+os_thread_ret_t
+DECLARE_THREAD(log_scrub_thread)(
+/*===============================*/
+ void* arg __attribute__((unused))) /*!< in: a dummy parameter
+ required by os_thread_create */
+{
+ ut_ad(!srv_read_only_mode);
+
+ srv_log_scrub_thread_active = TRUE;
+
+ while(srv_shutdown_state == SRV_SHUTDOWN_NONE)
+ {
+ os_event_wait_time(log_scrub_event, innodb_scrub_log_interval * 1000);
+
+ log_scrub();
+
+ os_event_reset(log_scrub_event);
+ }
+
+ srv_log_scrub_thread_active = FALSE;
+
+ /* We count the number of threads in os_thread_exit(). A created
+ thread should always use that to exit and not use return() to exit. */
+ os_thread_exit(NULL);
+
+ OS_THREAD_DUMMY_RETURN;
+}
#endif /* !UNIV_HOTBACKUP */