Merge 10.2 into bb-10.2-ext

This commit is contained in:
Marko Mäkelä 2017-06-19 16:56:13 +03:00
commit 3a7201ea92
61 changed files with 286 additions and 4423 deletions

View File

@ -1774,7 +1774,7 @@ copy_back()
const char *ext_list[] = {"backup-my.cnf", "xtrabackup_logfile", const char *ext_list[] = {"backup-my.cnf", "xtrabackup_logfile",
"xtrabackup_binary", "xtrabackup_binlog_info", "xtrabackup_binary", "xtrabackup_binlog_info",
"xtrabackup_checkpoints", ".qp", ".pmap", ".tmp", "xtrabackup_checkpoints", ".qp", ".pmap", ".tmp",
".xbcrypt", NULL}; NULL};
const char *filename; const char *filename;
char c_tmp; char c_tmp;
int i_tmp; int i_tmp;
@ -1807,7 +1807,7 @@ copy_back()
filename = base_name(node.filepath); filename = base_name(node.filepath);
/* skip .qp and .xbcrypt files */ /* skip .qp files */
if (filename_matches(filename, ext_list)) { if (filename_matches(filename, ext_list)) {
continue; continue;
} }
@ -1899,24 +1899,8 @@ decrypt_decompress_file(const char *filepath, uint thread_n)
cmd << IF_WIN("type ","cat ") << filepath; cmd << IF_WIN("type ","cat ") << filepath;
if (ends_with(filepath, ".xbcrypt") && opt_decrypt) {
cmd << " | xbcrypt --decrypt --encrypt-algo="
<< xtrabackup_encrypt_algo_names[opt_decrypt_algo];
if (xtrabackup_encrypt_key) {
cmd << " --encrypt-key=" << xtrabackup_encrypt_key;
} else {
cmd << " --encrypt-key-file="
<< xtrabackup_encrypt_key_file;
}
dest_filepath[strlen(dest_filepath) - 8] = 0;
message << "decrypting";
needs_action = true;
}
if (opt_decompress if (opt_decompress
&& (ends_with(filepath, ".qp") && ends_with(filepath, ".qp")) {
|| (ends_with(filepath, ".qp.xbcrypt")
&& opt_decrypt))) {
cmd << " | qpress -dio "; cmd << " | qpress -dio ";
dest_filepath[strlen(dest_filepath) - 3] = 0; dest_filepath[strlen(dest_filepath) - 3] = 0;
if (needs_action) { if (needs_action) {
@ -1967,8 +1951,7 @@ decrypt_decompress_thread_func(void *arg)
continue; continue;
} }
if (!ends_with(node.filepath, ".qp") if (!ends_with(node.filepath, ".qp")) {
&& !ends_with(node.filepath, ".xbcrypt")) {
continue; continue;
} }

View File

@ -1435,9 +1435,7 @@ write_xtrabackup_info(MYSQL *connection)
"partial = %s\n" "partial = %s\n"
"incremental = %s\n" "incremental = %s\n"
"format = %s\n" "format = %s\n"
"compact = %s\n" "compressed = %s\n",
"compressed = %s\n"
"encrypted = %s\n",
uuid, /* uuid */ uuid, /* uuid */
opt_history ? opt_history : "", /* name */ opt_history ? opt_history : "", /* name */
tool_name, /* tool_name */ tool_name, /* tool_name */
@ -1455,9 +1453,7 @@ write_xtrabackup_info(MYSQL *connection)
is_partial? "Y" : "N", is_partial? "Y" : "N",
xtrabackup_incremental ? "Y" : "N", /* incremental */ xtrabackup_incremental ? "Y" : "N", /* incremental */
xb_stream_name[xtrabackup_stream_fmt], /* format */ xb_stream_name[xtrabackup_stream_fmt], /* format */
"N", /* compact */ xtrabackup_compress ? "compressed" : "N"); /* compressed */
xtrabackup_compress ? "compressed" : "N", /* compressed */
xtrabackup_encrypt ? "Y" : "N"); /* encrypted */
if (!opt_history) { if (!opt_history) {
goto cleanup; goto cleanup;
@ -1483,9 +1479,7 @@ write_xtrabackup_info(MYSQL *connection)
"partial ENUM('Y', 'N') DEFAULT NULL," "partial ENUM('Y', 'N') DEFAULT NULL,"
"incremental ENUM('Y', 'N') DEFAULT NULL," "incremental ENUM('Y', 'N') DEFAULT NULL,"
"format ENUM('file', 'tar', 'xbstream') DEFAULT NULL," "format ENUM('file', 'tar', 'xbstream') DEFAULT NULL,"
"compact ENUM('Y', 'N') DEFAULT NULL," "compressed ENUM('Y', 'N') DEFAULT NULL"
"compressed ENUM('Y', 'N') DEFAULT NULL,"
"encrypted ENUM('Y', 'N') DEFAULT NULL"
") CHARACTER SET utf8 ENGINE=innodb", false); ") CHARACTER SET utf8 ENGINE=innodb", false);
@ -1495,8 +1489,8 @@ write_xtrabackup_info(MYSQL *connection)
<< "uuid, name, tool_name, tool_command, tool_version," << "uuid, name, tool_name, tool_command, tool_version,"
<< "ibbackup_version, server_version, start_time, end_time," << "ibbackup_version, server_version, start_time, end_time,"
<< "lock_time, binlog_pos, innodb_from_lsn, innodb_to_lsn," << "lock_time, binlog_pos, innodb_from_lsn, innodb_to_lsn,"
<< "partial, incremental, format, compact, compressed, " << "partial, incremental, format, compressed) "
<< "encrypted) values(" << "values("
<< escape_and_quote(connection, uuid) << "," << escape_and_quote(connection, uuid) << ","
<< escape_and_quote(connection, opt_history) << "," << escape_and_quote(connection, opt_history) << ","
<< escape_and_quote(connection, tool_name) << "," << escape_and_quote(connection, tool_name) << ","
@ -1513,9 +1507,7 @@ write_xtrabackup_info(MYSQL *connection)
<< ESCAPE_BOOL(is_partial) << "," << ESCAPE_BOOL(is_partial) << ","
<< ESCAPE_BOOL(xtrabackup_incremental)<< "," << ESCAPE_BOOL(xtrabackup_incremental)<< ","
<< escape_and_quote(connection,xb_stream_name[xtrabackup_stream_fmt]) <<"," << escape_and_quote(connection,xb_stream_name[xtrabackup_stream_fmt]) <<","
<< ESCAPE_BOOL(false) << "," << ESCAPE_BOOL(xtrabackup_compress) << ")";
<< ESCAPE_BOOL(xtrabackup_compress) << ","
<< ESCAPE_BOOL(xtrabackup_encrypt) <<")";
xb_mysql_query(mysql_connection, oss.str().c_str(), false); xb_mysql_query(mysql_connection, oss.str().c_str(), false);
@ -1581,14 +1573,6 @@ char *make_argv(char *buf, size_t len, int argc, char **argv)
if (strncmp(*argv, "--password", strlen("--password")) == 0) { if (strncmp(*argv, "--password", strlen("--password")) == 0) {
arg = "--password=..."; arg = "--password=...";
} }
if (strncmp(*argv, "--encrypt-key",
strlen("--encrypt-key")) == 0) {
arg = "--encrypt-key=...";
}
if (strncmp(*argv, "--encrypt_key",
strlen("--encrypt_key")) == 0) {
arg = "--encrypt_key=...";
}
left-= ut_snprintf(buf + len - left, left, left-= ut_snprintf(buf + len - left, left,
"%s%c", arg, argc > 1 ? ' ' : 0); "%s%c", arg, argc > 1 ? ' ' : 0);
++argv; --argc; ++argv; --argc;

View File

@ -1,665 +0,0 @@
/******************************************************
Copyright (c) 2017 Percona LLC and/or its affiliates.
Encryption datasink implementation for XtraBackup.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#include <my_base.h>
#include "common.h"
#include "datasink.h"
#include "xbcrypt.h"
#include "xbcrypt_common.h"
#include "crc_glue.h"
typedef struct {
pthread_t id;
uint num;
pthread_mutex_t ctrl_mutex;
pthread_cond_t ctrl_cond;
pthread_mutex_t data_mutex;
pthread_cond_t data_cond;
my_bool started;
my_bool data_avail;
my_bool cancelled;
my_bool failed;
const uchar *from;
size_t from_len;
uchar *to;
size_t to_len;
size_t to_size;
const uchar *iv;
size_t iv_len;
unsigned long long offset;
my_bool hash_appended;
gcry_cipher_hd_t cipher_handle;
xb_rcrypt_result_t parse_result;
} crypt_thread_ctxt_t;
typedef struct {
crypt_thread_ctxt_t *threads;
uint nthreads;
int encrypt_algo;
size_t chunk_size;
char *encrypt_key;
char *encrypt_key_file;
} ds_decrypt_ctxt_t;
typedef struct {
ds_decrypt_ctxt_t *crypt_ctxt;
size_t bytes_processed;
ds_file_t *dest_file;
uchar *buf;
size_t buf_len;
size_t buf_size;
} ds_decrypt_file_t;
int ds_decrypt_encrypt_threads = 1;
static ds_ctxt_t *decrypt_init(const char *root);
static ds_file_t *decrypt_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat);
static int decrypt_write(ds_file_t *file, const void *buf, size_t len);
static int decrypt_close(ds_file_t *file);
static void decrypt_deinit(ds_ctxt_t *ctxt);
datasink_t datasink_decrypt = {
&decrypt_init,
&decrypt_open,
&decrypt_write,
&decrypt_close,
&decrypt_deinit
};
static crypt_thread_ctxt_t *create_worker_threads(uint n);
static void destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n);
static void *decrypt_worker_thread_func(void *arg);
static
ds_ctxt_t *
decrypt_init(const char *root)
{
ds_ctxt_t *ctxt;
ds_decrypt_ctxt_t *decrypt_ctxt;
crypt_thread_ctxt_t *threads;
if (xb_crypt_init(NULL)) {
return NULL;
}
/* Create and initialize the worker threads */
threads = create_worker_threads(ds_decrypt_encrypt_threads);
if (threads == NULL) {
msg("decrypt: failed to create worker threads.\n");
return NULL;
}
ctxt = (ds_ctxt_t *) my_malloc(sizeof(ds_ctxt_t) +
sizeof(ds_decrypt_ctxt_t),
MYF(MY_FAE));
decrypt_ctxt = (ds_decrypt_ctxt_t *) (ctxt + 1);
decrypt_ctxt->threads = threads;
decrypt_ctxt->nthreads = ds_decrypt_encrypt_threads;
ctxt->ptr = decrypt_ctxt;
ctxt->root = my_strdup(root, MYF(MY_FAE));
return ctxt;
}
static
ds_file_t *
decrypt_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
{
ds_ctxt_t *dest_ctxt;
ds_decrypt_ctxt_t *crypt_ctxt;
ds_decrypt_file_t *crypt_file;
char new_name[FN_REFLEN];
ds_file_t *file;
xb_ad(ctxt->pipe_ctxt != NULL);
dest_ctxt = ctxt->pipe_ctxt;
crypt_ctxt = (ds_decrypt_ctxt_t *) ctxt->ptr;
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) +
sizeof(ds_decrypt_file_t),
MYF(MY_FAE|MY_ZEROFILL));
crypt_file = (ds_decrypt_file_t *) (file + 1);
/* Remove the .xbcrypt extension from the filename */
strncpy(new_name, path, FN_REFLEN);
new_name[strlen(new_name) - 8] = 0;
crypt_file->dest_file = ds_open(dest_ctxt, new_name, mystat);
if (crypt_file->dest_file == NULL) {
msg("decrypt: ds_open(\"%s\") failed.\n", new_name);
goto err;
}
crypt_file->crypt_ctxt = crypt_ctxt;
crypt_file->buf = NULL;
crypt_file->buf_size = 0;
crypt_file->buf_len = 0;
file->ptr = crypt_file;
file->path = crypt_file->dest_file->path;
return file;
err:
if (crypt_file->dest_file) {
ds_close(crypt_file->dest_file);
}
my_free(file);
return NULL;
}
#define CHECK_BUF_SIZE(ptr, size, buf, len) \
if (ptr + size - buf > (ssize_t) len) { \
result = XB_CRYPT_READ_INCOMPLETE; \
goto exit; \
}
static
xb_rcrypt_result_t
parse_xbcrypt_chunk(crypt_thread_ctxt_t *thd, const uchar *buf, size_t len,
size_t *bytes_processed)
{
const uchar *ptr;
uint version;
ulong checksum, checksum_exp;
ulonglong tmp;
xb_rcrypt_result_t result = XB_CRYPT_READ_CHUNK;
*bytes_processed = 0;
ptr = buf;
CHECK_BUF_SIZE(ptr, XB_CRYPT_CHUNK_MAGIC_SIZE, buf, len);
if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC3,
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) {
version = 3;
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC2,
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) {
version = 2;
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC1,
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) {
version = 1;
} else {
msg("%s:%s: wrong chunk magic at offset 0x%llx.\n",
my_progname, __FUNCTION__, thd->offset);
result = XB_CRYPT_READ_ERROR;
goto exit;
}
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE;
thd->offset += XB_CRYPT_CHUNK_MAGIC_SIZE;
CHECK_BUF_SIZE(ptr, 8, buf, len);
tmp = uint8korr(ptr); /* reserved */
ptr += 8;
thd->offset += 8;
CHECK_BUF_SIZE(ptr, 8, buf, len);
tmp = uint8korr(ptr); /* original size */
ptr += 8;
if (tmp > INT_MAX) {
msg("%s:%s: invalid original size at offset 0x%llx.\n",
my_progname, __FUNCTION__, thd->offset);
result = XB_CRYPT_READ_ERROR;
goto exit;
}
thd->offset += 8;
thd->to_len = (size_t)tmp;
if (thd->to_size < thd->to_len + XB_CRYPT_HASH_LEN) {
thd->to = (uchar *) my_realloc(
thd->to,
thd->to_len + XB_CRYPT_HASH_LEN,
MYF(MY_FAE | MY_ALLOW_ZERO_PTR));
thd->to_size = thd->to_len;
}
CHECK_BUF_SIZE(ptr, 8, buf, len);
tmp = uint8korr(ptr); /* encrypted size */
ptr += 8;
if (tmp > INT_MAX) {
msg("%s:%s: invalid encrypted size at offset 0x%llx.\n",
my_progname, __FUNCTION__, thd->offset);
result = XB_CRYPT_READ_ERROR;
goto exit;
}
thd->offset += 8;
thd->from_len = (size_t)tmp;
xb_a(thd->from_len <= thd->to_len + XB_CRYPT_HASH_LEN);
CHECK_BUF_SIZE(ptr, 4, buf, len);
checksum_exp = uint4korr(ptr); /* checksum */
ptr += 4;
thd->offset += 4;
/* iv size */
if (version == 1) {
thd->iv_len = 0;
thd->iv = NULL;
} else {
CHECK_BUF_SIZE(ptr, 8, buf, len);
tmp = uint8korr(ptr);
if (tmp > INT_MAX) {
msg("%s:%s: invalid iv size at offset 0x%llx.\n",
my_progname, __FUNCTION__, thd->offset);
result = XB_CRYPT_READ_ERROR;
goto exit;
}
ptr += 8;
thd->offset += 8;
thd->iv_len = (size_t)tmp;
}
if (thd->iv_len > 0) {
CHECK_BUF_SIZE(ptr, thd->iv_len, buf, len);
thd->iv = ptr;
ptr += thd->iv_len;
}
/* for version euqals 2 we need to read in the iv data but do not init
CTR with it */
if (version == 2) {
thd->iv_len = 0;
thd->iv = 0;
}
if (thd->from_len > 0) {
CHECK_BUF_SIZE(ptr, thd->from_len, buf, len);
thd->from = ptr;
ptr += thd->from_len;
}
xb_ad(thd->from_len <= thd->to_len);
checksum = crc32_iso3309(0, thd->from, thd->from_len);
if (checksum != checksum_exp) {
msg("%s:%s invalid checksum at offset 0x%llx, "
"expected 0x%lx, actual 0x%lx.\n", my_progname,
__FUNCTION__, thd->offset, checksum_exp, checksum);
result = XB_CRYPT_READ_ERROR;
goto exit;
}
thd->offset += thd->from_len;
thd->hash_appended = version > 2;
exit:
*bytes_processed = (size_t) (ptr - buf);
return result;
}
static
int
decrypt_write(ds_file_t *file, const void *buf, size_t len)
{
ds_decrypt_file_t *crypt_file;
ds_decrypt_ctxt_t *crypt_ctxt;
crypt_thread_ctxt_t *threads;
crypt_thread_ctxt_t *thd;
uint nthreads;
uint i;
size_t bytes_processed;
xb_rcrypt_result_t parse_result = XB_CRYPT_READ_CHUNK;
my_bool err = FALSE;
crypt_file = (ds_decrypt_file_t *) file->ptr;
crypt_ctxt = crypt_file->crypt_ctxt;
threads = crypt_ctxt->threads;
nthreads = crypt_ctxt->nthreads;
if (crypt_file->buf_len > 0) {
thd = threads;
pthread_mutex_lock(&thd->ctrl_mutex);
do {
if (parse_result == XB_CRYPT_READ_INCOMPLETE) {
crypt_file->buf_size = crypt_file->buf_size * 2;
crypt_file->buf = (uchar *) my_realloc(
crypt_file->buf,
crypt_file->buf_size,
MYF(MY_FAE|MY_ALLOW_ZERO_PTR));
}
memcpy(crypt_file->buf + crypt_file->buf_len,
buf, MY_MIN(crypt_file->buf_size -
crypt_file->buf_len, len));
parse_result = parse_xbcrypt_chunk(
thd, crypt_file->buf,
crypt_file->buf_size, &bytes_processed);
if (parse_result == XB_CRYPT_READ_ERROR) {
pthread_mutex_unlock(&thd->ctrl_mutex);
return 1;
}
} while (parse_result == XB_CRYPT_READ_INCOMPLETE &&
crypt_file->buf_size < len);
if (parse_result != XB_CRYPT_READ_CHUNK) {
msg("decrypt: incomplete data.\n");
pthread_mutex_unlock(&thd->ctrl_mutex);
return 1;
}
pthread_mutex_lock(&thd->data_mutex);
thd->data_avail = TRUE;
pthread_cond_signal(&thd->data_cond);
pthread_mutex_unlock(&thd->data_mutex);
len -= bytes_processed - crypt_file->buf_len;
buf += bytes_processed - crypt_file->buf_len;
/* reap */
pthread_mutex_lock(&thd->data_mutex);
while (thd->data_avail == TRUE) {
pthread_cond_wait(&thd->data_cond,
&thd->data_mutex);
}
if (thd->failed) {
msg("decrypt: failed to decrypt chunk.\n");
err = TRUE;
}
xb_a(thd->to_len > 0);
if (!err &&
ds_write(crypt_file->dest_file, thd->to, thd->to_len)) {
msg("decrypt: write to destination failed.\n");
err = TRUE;
}
crypt_file->bytes_processed += thd->from_len;
pthread_mutex_unlock(&thd->data_mutex);
pthread_mutex_unlock(&thd->ctrl_mutex);
crypt_file->buf_len = 0;
if (err) {
return 1;
}
}
while (parse_result == XB_CRYPT_READ_CHUNK && len > 0) {
uint max_thread;
for (i = 0; i < nthreads; i++) {
thd = threads + i;
pthread_mutex_lock(&thd->ctrl_mutex);
parse_result = parse_xbcrypt_chunk(
thd, buf, len, &bytes_processed);
if (parse_result == XB_CRYPT_READ_ERROR) {
pthread_mutex_unlock(&thd->ctrl_mutex);
err = TRUE;
break;
}
thd->parse_result = parse_result;
if (parse_result != XB_CRYPT_READ_CHUNK) {
pthread_mutex_unlock(&thd->ctrl_mutex);
break;
}
pthread_mutex_lock(&thd->data_mutex);
thd->data_avail = TRUE;
pthread_cond_signal(&thd->data_cond);
pthread_mutex_unlock(&thd->data_mutex);
len -= bytes_processed;
buf += bytes_processed;
}
max_thread = (i < nthreads) ? i : nthreads - 1;
/* Reap and write decrypted data */
for (i = 0; i <= max_thread; i++) {
thd = threads + i;
if (thd->parse_result != XB_CRYPT_READ_CHUNK) {
break;
}
pthread_mutex_lock(&thd->data_mutex);
while (thd->data_avail == TRUE) {
pthread_cond_wait(&thd->data_cond,
&thd->data_mutex);
}
if (thd->failed) {
msg("decrypt: failed to decrypt chunk.\n");
err = TRUE;
}
xb_a(thd->to_len > 0);
if (!err && ds_write(crypt_file->dest_file, thd->to,
thd->to_len)) {
msg("decrypt: write to destination failed.\n");
err = TRUE;
}
crypt_file->bytes_processed += thd->from_len;
pthread_mutex_unlock(&thd->data_mutex);
pthread_mutex_unlock(&thd->ctrl_mutex);
}
if (err) {
return 1;
}
}
if (parse_result == XB_CRYPT_READ_INCOMPLETE && len > 0) {
crypt_file->buf_len = len;
if (crypt_file->buf_size < len) {
crypt_file->buf = (uchar *) my_realloc(
crypt_file->buf,
crypt_file->buf_len,
MYF(MY_FAE | MY_ALLOW_ZERO_PTR));
crypt_file->buf_size = len;
}
memcpy(crypt_file->buf, buf, len);
}
return 0;
}
static
int
decrypt_close(ds_file_t *file)
{
ds_decrypt_file_t *crypt_file;
ds_file_t *dest_file;
int rc = 0;
crypt_file = (ds_decrypt_file_t *) file->ptr;
dest_file = crypt_file->dest_file;
if (ds_close(dest_file)) {
rc = 1;
}
my_free(crypt_file->buf);
my_free(file);
return rc;
}
static
void
decrypt_deinit(ds_ctxt_t *ctxt)
{
ds_decrypt_ctxt_t *crypt_ctxt;
xb_ad(ctxt->pipe_ctxt != NULL);
crypt_ctxt = (ds_decrypt_ctxt_t *) ctxt->ptr;
destroy_worker_threads(crypt_ctxt->threads, crypt_ctxt->nthreads);
my_free(ctxt->root);
my_free(ctxt);
}
static
crypt_thread_ctxt_t *
create_worker_threads(uint n)
{
crypt_thread_ctxt_t *threads;
uint i;
threads = (crypt_thread_ctxt_t *)
my_malloc(sizeof(crypt_thread_ctxt_t) * n,
MYF(MY_FAE | MY_ZEROFILL));
for (i = 0; i < n; i++) {
crypt_thread_ctxt_t *thd = threads + i;
thd->num = i + 1;
/* Initialize the control mutex and condition var */
if (pthread_mutex_init(&thd->ctrl_mutex, NULL) ||
pthread_cond_init(&thd->ctrl_cond, NULL)) {
goto err;
}
/* Initialize and data mutex and condition var */
if (pthread_mutex_init(&thd->data_mutex, NULL) ||
pthread_cond_init(&thd->data_cond, NULL)) {
goto err;
}
xb_crypt_cipher_open(&thd->cipher_handle);
pthread_mutex_lock(&thd->ctrl_mutex);
if (pthread_create(&thd->id, NULL, decrypt_worker_thread_func,
thd)) {
msg("decrypt: pthread_create() failed: "
"errno = %d\n", errno);
goto err;
}
}
/* Wait for the threads to start */
for (i = 0; i < n; i++) {
crypt_thread_ctxt_t *thd = threads + i;
while (thd->started == FALSE)
pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex);
pthread_mutex_unlock(&thd->ctrl_mutex);
}
return threads;
err:
return NULL;
}
static
void
destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n)
{
uint i;
for (i = 0; i < n; i++) {
crypt_thread_ctxt_t *thd = threads + i;
pthread_mutex_lock(&thd->data_mutex);
threads[i].cancelled = TRUE;
pthread_cond_signal(&thd->data_cond);
pthread_mutex_unlock(&thd->data_mutex);
pthread_join(thd->id, NULL);
pthread_cond_destroy(&thd->data_cond);
pthread_mutex_destroy(&thd->data_mutex);
pthread_cond_destroy(&thd->ctrl_cond);
pthread_mutex_destroy(&thd->ctrl_mutex);
xb_crypt_cipher_close(thd->cipher_handle);
my_free(thd->to);
}
my_free(threads);
}
static
void *
decrypt_worker_thread_func(void *arg)
{
crypt_thread_ctxt_t *thd = (crypt_thread_ctxt_t *) arg;
pthread_mutex_lock(&thd->ctrl_mutex);
pthread_mutex_lock(&thd->data_mutex);
thd->started = TRUE;
pthread_cond_signal(&thd->ctrl_cond);
pthread_mutex_unlock(&thd->ctrl_mutex);
while (1) {
thd->data_avail = FALSE;
pthread_cond_signal(&thd->data_cond);
while (!thd->data_avail && !thd->cancelled) {
pthread_cond_wait(&thd->data_cond, &thd->data_mutex);
}
if (thd->cancelled)
break;
if (xb_crypt_decrypt(thd->cipher_handle, thd->from,
thd->from_len, thd->to, &thd->to_len,
thd->iv, thd->iv_len,
thd->hash_appended)) {
thd->failed = TRUE;
continue;
}
}
pthread_mutex_unlock(&thd->data_mutex);
return NULL;
}

View File

@ -1,30 +0,0 @@
/******************************************************
Copyright (c) 2017 Percona LLC and/or its affiliates.
Encryption interface for XtraBackup.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#ifndef DS_DECRYPT_H
#define DS_DECRYPT_H
#include "datasink.h"
extern datasink_t datasink_decrypt;
extern int ds_decrypt_encrypt_threads;
#endif

View File

@ -1,446 +0,0 @@
/******************************************************
Copyright (c) 2013 Percona LLC and/or its affiliates.
Encryption datasink implementation for XtraBackup.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#include <my_base.h>
#include "common.h"
#include "datasink.h"
#include "xbcrypt_common.h"
#ifdef HAVE_GRYPT
#include "xbcrypt.h"
#define XB_CRYPT_CHUNK_SIZE ((size_t) (ds_encrypt_encrypt_chunk_size))
typedef struct {
pthread_t id;
uint num;
pthread_mutex_t ctrl_mutex;
pthread_cond_t ctrl_cond;
pthread_mutex_t data_mutex;
pthread_cond_t data_cond;
my_bool started;
my_bool data_avail;
my_bool cancelled;
const uchar *from;
size_t from_len;
uchar *to;
uchar *iv;
size_t to_len;
gcry_cipher_hd_t cipher_handle;
} crypt_thread_ctxt_t;
typedef struct {
crypt_thread_ctxt_t *threads;
uint nthreads;
} ds_encrypt_ctxt_t;
typedef struct {
xb_wcrypt_t *xbcrypt_file;
ds_encrypt_ctxt_t *crypt_ctxt;
size_t bytes_processed;
ds_file_t *dest_file;
} ds_encrypt_file_t;
/* Encryption options */
uint ds_encrypt_encrypt_threads;
ulonglong ds_encrypt_encrypt_chunk_size;
static ds_ctxt_t *encrypt_init(const char *root);
static ds_file_t *encrypt_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat);
static int encrypt_write(ds_file_t *file, const void *buf, size_t len);
static int encrypt_close(ds_file_t *file);
static void encrypt_deinit(ds_ctxt_t *ctxt);
datasink_t datasink_encrypt = {
&encrypt_init,
&encrypt_open,
&encrypt_write,
&encrypt_close,
&encrypt_deinit
};
static crypt_thread_ctxt_t *create_worker_threads(uint n);
static void destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n);
static void *encrypt_worker_thread_func(void *arg);
static uint encrypt_iv_len = 0;
static
ssize_t
my_xb_crypt_write_callback(void *userdata, const void *buf, size_t len)
{
ds_encrypt_file_t *encrypt_file;
encrypt_file = (ds_encrypt_file_t *) userdata;
xb_ad(encrypt_file != NULL);
xb_ad(encrypt_file->dest_file != NULL);
if (!ds_write(encrypt_file->dest_file, buf, len)) {
return len;
}
return -1;
}
static
ds_ctxt_t *
encrypt_init(const char *root)
{
ds_ctxt_t *ctxt;
ds_encrypt_ctxt_t *encrypt_ctxt;
crypt_thread_ctxt_t *threads;
if (xb_crypt_init(&encrypt_iv_len)) {
return NULL;
}
/* Create and initialize the worker threads */
threads = create_worker_threads(ds_encrypt_encrypt_threads);
if (threads == NULL) {
msg("encrypt: failed to create worker threads.\n");
return NULL;
}
ctxt = (ds_ctxt_t *) my_malloc(sizeof(ds_ctxt_t) +
sizeof(ds_encrypt_ctxt_t),
MYF(MY_FAE));
encrypt_ctxt = (ds_encrypt_ctxt_t *) (ctxt + 1);
encrypt_ctxt->threads = threads;
encrypt_ctxt->nthreads = ds_encrypt_encrypt_threads;
ctxt->ptr = encrypt_ctxt;
ctxt->root = my_strdup(root, MYF(MY_FAE));
return ctxt;
}
static
ds_file_t *
encrypt_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
{
ds_ctxt_t *dest_ctxt;
ds_encrypt_ctxt_t *crypt_ctxt;
ds_encrypt_file_t *crypt_file;
char new_name[FN_REFLEN];
ds_file_t *file;
xb_ad(ctxt->pipe_ctxt != NULL);
dest_ctxt = ctxt->pipe_ctxt;
crypt_ctxt = (ds_encrypt_ctxt_t *) ctxt->ptr;
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) +
sizeof(ds_encrypt_file_t),
MYF(MY_FAE|MY_ZEROFILL));
crypt_file = (ds_encrypt_file_t *) (file + 1);
/* Append the .xbcrypt extension to the filename */
fn_format(new_name, path, "", ".xbcrypt", MYF(MY_APPEND_EXT));
crypt_file->dest_file = ds_open(dest_ctxt, new_name, mystat);
if (crypt_file->dest_file == NULL) {
msg("encrypt: ds_open(\"%s\") failed.\n", new_name);
goto err;
}
crypt_file->crypt_ctxt = crypt_ctxt;
crypt_file->xbcrypt_file = xb_crypt_write_open(crypt_file,
my_xb_crypt_write_callback);
if (crypt_file->xbcrypt_file == NULL) {
msg("encrypt: xb_crypt_write_open() failed.\n");
goto err;
}
file->ptr = crypt_file;
file->path = crypt_file->dest_file->path;
return file;
err:
if (crypt_file->dest_file) {
ds_close(crypt_file->dest_file);
}
my_free(file);
return NULL;
}
static
int
encrypt_write(ds_file_t *file, const void *buf, size_t len)
{
ds_encrypt_file_t *crypt_file;
ds_encrypt_ctxt_t *crypt_ctxt;
crypt_thread_ctxt_t *threads;
crypt_thread_ctxt_t *thd;
uint nthreads;
uint i;
const uchar *ptr;
crypt_file = (ds_encrypt_file_t *) file->ptr;
crypt_ctxt = crypt_file->crypt_ctxt;
threads = crypt_ctxt->threads;
nthreads = crypt_ctxt->nthreads;
ptr = (const uchar *) buf;
while (len > 0) {
uint max_thread;
/* Send data to worker threads for encryption */
for (i = 0; i < nthreads; i++) {
size_t chunk_len;
thd = threads + i;
pthread_mutex_lock(&thd->ctrl_mutex);
chunk_len = (len > XB_CRYPT_CHUNK_SIZE) ?
XB_CRYPT_CHUNK_SIZE : len;
thd->from = ptr;
thd->from_len = chunk_len;
pthread_mutex_lock(&thd->data_mutex);
thd->data_avail = TRUE;
pthread_cond_signal(&thd->data_cond);
pthread_mutex_unlock(&thd->data_mutex);
len -= chunk_len;
if (len == 0) {
break;
}
ptr += chunk_len;
}
max_thread = (i < nthreads) ? i : nthreads - 1;
/* Reap and stream the encrypted data */
for (i = 0; i <= max_thread; i++) {
thd = threads + i;
pthread_mutex_lock(&thd->data_mutex);
while (thd->data_avail == TRUE) {
pthread_cond_wait(&thd->data_cond,
&thd->data_mutex);
}
xb_a(threads[i].to_len > 0);
if (xb_crypt_write_chunk(crypt_file->xbcrypt_file,
threads[i].to,
threads[i].from_len +
XB_CRYPT_HASH_LEN,
threads[i].to_len,
threads[i].iv,
encrypt_iv_len)) {
msg("encrypt: write to the destination file "
"failed.\n");
return 1;
}
crypt_file->bytes_processed += threads[i].from_len;
pthread_mutex_unlock(&threads[i].data_mutex);
pthread_mutex_unlock(&threads[i].ctrl_mutex);
}
}
return 0;
}
static
int
encrypt_close(ds_file_t *file)
{
ds_encrypt_file_t *crypt_file;
ds_file_t *dest_file;
int rc = 0;
crypt_file = (ds_encrypt_file_t *) file->ptr;
dest_file = crypt_file->dest_file;
rc = xb_crypt_write_close(crypt_file->xbcrypt_file);
if (ds_close(dest_file)) {
rc = 1;
}
my_free(file);
return rc;
}
static
void
encrypt_deinit(ds_ctxt_t *ctxt)
{
ds_encrypt_ctxt_t *crypt_ctxt;
xb_ad(ctxt->pipe_ctxt != NULL);
crypt_ctxt = (ds_encrypt_ctxt_t *) ctxt->ptr;
destroy_worker_threads(crypt_ctxt->threads, crypt_ctxt->nthreads);
my_free(ctxt->root);
my_free(ctxt);
}
static
crypt_thread_ctxt_t *
create_worker_threads(uint n)
{
crypt_thread_ctxt_t *threads;
uint i;
threads = (crypt_thread_ctxt_t *)
my_malloc(sizeof(crypt_thread_ctxt_t) * n, MYF(MY_FAE));
for (i = 0; i < n; i++) {
crypt_thread_ctxt_t *thd = threads + i;
thd->num = i + 1;
thd->started = FALSE;
thd->cancelled = FALSE;
thd->data_avail = FALSE;
thd->to = (uchar *) my_malloc(XB_CRYPT_CHUNK_SIZE +
XB_CRYPT_HASH_LEN, MYF(MY_FAE));
thd->iv = (uchar *) my_malloc(encrypt_iv_len, MYF(MY_FAE));
/* Initialize the control mutex and condition var */
if (pthread_mutex_init(&thd->ctrl_mutex, NULL) ||
pthread_cond_init(&thd->ctrl_cond, NULL)) {
goto err;
}
/* Initialize and data mutex and condition var */
if (pthread_mutex_init(&thd->data_mutex, NULL) ||
pthread_cond_init(&thd->data_cond, NULL)) {
goto err;
}
if (xb_crypt_cipher_open(&thd->cipher_handle)) {
goto err;
}
pthread_mutex_lock(&thd->ctrl_mutex);
if (pthread_create(&thd->id, NULL, encrypt_worker_thread_func,
thd)) {
msg("encrypt: pthread_create() failed: "
"errno = %d\n", errno);
goto err;
}
}
/* Wait for the threads to start */
for (i = 0; i < n; i++) {
crypt_thread_ctxt_t *thd = threads + i;
while (thd->started == FALSE)
pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex);
pthread_mutex_unlock(&thd->ctrl_mutex);
}
return threads;
err:
return NULL;
}
static
void
destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n)
{
uint i;
for (i = 0; i < n; i++) {
crypt_thread_ctxt_t *thd = threads + i;
pthread_mutex_lock(&thd->data_mutex);
threads[i].cancelled = TRUE;
pthread_cond_signal(&thd->data_cond);
pthread_mutex_unlock(&thd->data_mutex);
pthread_join(thd->id, NULL);
pthread_cond_destroy(&thd->data_cond);
pthread_mutex_destroy(&thd->data_mutex);
pthread_cond_destroy(&thd->ctrl_cond);
pthread_mutex_destroy(&thd->ctrl_mutex);
xb_crypt_cipher_close(thd->cipher_handle);
my_free(thd->to);
my_free(thd->iv);
}
my_free(threads);
}
static
void *
encrypt_worker_thread_func(void *arg)
{
crypt_thread_ctxt_t *thd = (crypt_thread_ctxt_t *) arg;
pthread_mutex_lock(&thd->ctrl_mutex);
pthread_mutex_lock(&thd->data_mutex);
thd->started = TRUE;
pthread_cond_signal(&thd->ctrl_cond);
pthread_mutex_unlock(&thd->ctrl_mutex);
while (1) {
thd->data_avail = FALSE;
pthread_cond_signal(&thd->data_cond);
while (!thd->data_avail && !thd->cancelled) {
pthread_cond_wait(&thd->data_cond, &thd->data_mutex);
}
if (thd->cancelled)
break;
thd->to_len = thd->from_len;
if (xb_crypt_encrypt(thd->cipher_handle, thd->from,
thd->from_len, thd->to, &thd->to_len,
thd->iv)) {
thd->to_len = 0;
continue;
}
}
pthread_mutex_unlock(&thd->data_mutex);
return NULL;
}
#endif /* HAVE_GCRYPT*/

View File

@ -1,33 +0,0 @@
/******************************************************
Copyright (c) 2013 Percona LLC and/or its affiliates.
Encryption interface for XtraBackup.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#ifndef DS_ENCRYPT_H
#define DS_ENCRYPT_H
#include "datasink.h"
#ifdef HAVE_GCRYPT
extern datasink_t datasink_encrypt;
#endif
/* Encryption options */
extern uint ds_encrypt_encrypt_threads;
extern ulonglong ds_encrypt_encrypt_chunk_size;
#endif

View File

@ -126,7 +126,6 @@ void encryption_plugin_prepare_init(int argc, char **argv)
if (!xb_plugin_load) if (!xb_plugin_load)
{ {
/* This prevents crashes e.g in --stats with wrong my.cnf*/
finalize_encryption_plugin(0); finalize_encryption_plugin(0);
return; return;
} }

View File

@ -101,8 +101,6 @@ char *opt_ibx_login_path = NULL;
ulong opt_ibx_lock_wait_query_type; ulong opt_ibx_lock_wait_query_type;
ulong opt_ibx_kill_long_query_type; ulong opt_ibx_kill_long_query_type;
ulong opt_ibx_decrypt_algo = 0;
uint opt_ibx_kill_long_queries_timeout = 0; uint opt_ibx_kill_long_queries_timeout = 0;
uint opt_ibx_lock_wait_timeout = 0; uint opt_ibx_lock_wait_timeout = 0;
uint opt_ibx_lock_wait_threshold = 0; uint opt_ibx_lock_wait_threshold = 0;
@ -110,7 +108,6 @@ uint opt_ibx_debug_sleep_before_unlock = 0;
uint opt_ibx_safe_slave_backup_timeout = 0; uint opt_ibx_safe_slave_backup_timeout = 0;
const char *opt_ibx_history = NULL; const char *opt_ibx_history = NULL;
bool opt_ibx_decrypt = false;
char *opt_ibx_include = NULL; char *opt_ibx_include = NULL;
char *opt_ibx_databases = NULL; char *opt_ibx_databases = NULL;
@ -121,15 +118,9 @@ char *ibx_backup_directory = NULL;
/* copy of proxied xtrabackup options */ /* copy of proxied xtrabackup options */
my_bool ibx_xb_close_files; my_bool ibx_xb_close_files;
my_bool ibx_xtrabackup_compact;
const char *ibx_xtrabackup_compress_alg; const char *ibx_xtrabackup_compress_alg;
uint ibx_xtrabackup_compress_threads; uint ibx_xtrabackup_compress_threads;
ulonglong ibx_xtrabackup_compress_chunk_size; ulonglong ibx_xtrabackup_compress_chunk_size;
ulong ibx_xtrabackup_encrypt_algo;
char *ibx_xtrabackup_encrypt_key;
char *ibx_xtrabackup_encrypt_key_file;
uint ibx_xtrabackup_encrypt_threads;
ulonglong ibx_xtrabackup_encrypt_chunk_size;
my_bool ibx_xtrabackup_export; my_bool ibx_xtrabackup_export;
char *ibx_xtrabackup_extra_lsndir; char *ibx_xtrabackup_extra_lsndir;
char *ibx_xtrabackup_incremental_basedir; char *ibx_xtrabackup_incremental_basedir;
@ -138,8 +129,6 @@ my_bool ibx_xtrabackup_incremental_force_scan;
ulint ibx_xtrabackup_log_copy_interval; ulint ibx_xtrabackup_log_copy_interval;
char *ibx_xtrabackup_incremental; char *ibx_xtrabackup_incremental;
int ibx_xtrabackup_parallel; int ibx_xtrabackup_parallel;
my_bool ibx_xtrabackup_rebuild_indexes;
ulint ibx_xtrabackup_rebuild_threads;
char *ibx_xtrabackup_stream_str; char *ibx_xtrabackup_stream_str;
char *ibx_xtrabackup_tables_file; char *ibx_xtrabackup_tables_file;
long ibx_xtrabackup_throttle; long ibx_xtrabackup_throttle;
@ -201,7 +190,6 @@ enum innobackupex_options
OPT_NO_VERSION_CHECK, OPT_NO_VERSION_CHECK,
OPT_NO_BACKUP_LOCKS, OPT_NO_BACKUP_LOCKS,
OPT_DATABASES, OPT_DATABASES,
OPT_DECRYPT,
OPT_DECOMPRESS, OPT_DECOMPRESS,
/* options wich are passed directly to xtrabackup */ /* options wich are passed directly to xtrabackup */
@ -210,11 +198,6 @@ enum innobackupex_options
OPT_COMPRESS, OPT_COMPRESS,
OPT_COMPRESS_THREADS, OPT_COMPRESS_THREADS,
OPT_COMPRESS_CHUNK_SIZE, OPT_COMPRESS_CHUNK_SIZE,
OPT_ENCRYPT,
OPT_ENCRYPT_KEY,
OPT_ENCRYPT_KEY_FILE,
OPT_ENCRYPT_THREADS,
OPT_ENCRYPT_CHUNK_SIZE,
OPT_EXPORT, OPT_EXPORT,
OPT_EXTRA_LSNDIR, OPT_EXTRA_LSNDIR,
OPT_INCREMENTAL_BASEDIR, OPT_INCREMENTAL_BASEDIR,
@ -430,12 +413,6 @@ static struct my_option ibx_long_options[] =
(uchar*) &opt_ibx_incremental_history_uuid, 0, GET_STR, (uchar*) &opt_ibx_incremental_history_uuid, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"decrypt", OPT_DECRYPT, "Decrypts all files with the .xbcrypt "
"extension in a backup previously made with --encrypt option.",
&opt_ibx_decrypt_algo, &opt_ibx_decrypt_algo,
&xtrabackup_encrypt_algo_typelib, GET_ENUM, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"ftwrl-wait-query-type", OPT_LOCK_WAIT_QUERY_TYPE, {"ftwrl-wait-query-type", OPT_LOCK_WAIT_QUERY_TYPE,
"This option specifies which types of queries are allowed to complete " "This option specifies which types of queries are allowed to complete "
"before innobackupex will issue the global lock. Default is all.", "before innobackupex will issue the global lock. Default is all.",
@ -533,12 +510,6 @@ static struct my_option ibx_long_options[] =
(uchar*) &ibx_xb_close_files, (uchar*) &ibx_xb_close_files, 0, (uchar*) &ibx_xb_close_files, (uchar*) &ibx_xb_close_files, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"compact", OPT_COMPACT, "Create a compact backup with all secondary "
"index pages omitted. This option is passed directly to xtrabackup. "
"See xtrabackup documentation for details.",
(uchar*) &ibx_xtrabackup_compact, (uchar*) &ibx_xtrabackup_compact,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"compress", OPT_COMPRESS, "This option instructs xtrabackup to " {"compress", OPT_COMPRESS, "This option instructs xtrabackup to "
"compress backup copies of InnoDB data files. It is passed directly " "compress backup copies of InnoDB data files. It is passed directly "
"to the xtrabackup child process. Try 'xtrabackup --help' for more " "to the xtrabackup child process. Try 'xtrabackup --help' for more "
@ -560,46 +531,6 @@ static struct my_option ibx_long_options[] =
(uchar*) &ibx_xtrabackup_compress_chunk_size, (uchar*) &ibx_xtrabackup_compress_chunk_size,
0, GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0}, 0, GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0},
{"encrypt", OPT_ENCRYPT, "This option instructs xtrabackup to encrypt "
"backup copies of InnoDB data files using the algorithm specified in "
"the ENCRYPTION-ALGORITHM. It is passed directly to the xtrabackup "
"child process. Try 'xtrabackup --help' for more details.",
&ibx_xtrabackup_encrypt_algo, &ibx_xtrabackup_encrypt_algo,
&xtrabackup_encrypt_algo_typelib, GET_ENUM, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"encrypt-key", OPT_ENCRYPT_KEY, "This option instructs xtrabackup to "
"use the given ENCRYPTION-KEY when using the --encrypt or --decrypt "
"options. During backup it is passed directly to the xtrabackup child "
"process. Try 'xtrabackup --help' for more details.",
(uchar*) &ibx_xtrabackup_encrypt_key,
(uchar*) &ibx_xtrabackup_encrypt_key, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-key-file", OPT_ENCRYPT_KEY_FILE, "This option instructs "
"xtrabackup to use the encryption key stored in the given "
"ENCRYPTION-KEY-FILE when using the --encrypt or --decrypt options.",
(uchar*) &ibx_xtrabackup_encrypt_key_file,
(uchar*) &ibx_xtrabackup_encrypt_key_file, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-threads", OPT_ENCRYPT_THREADS,
"This option specifies the number of worker threads that will be used "
"for parallel encryption. It is passed directly to the xtrabackup "
"child process. Try 'xtrabackup --help' for more details.",
(uchar*) &ibx_xtrabackup_encrypt_threads,
(uchar*) &ibx_xtrabackup_encrypt_threads,
0, GET_UINT, REQUIRED_ARG, 1, 1, UINT_MAX, 0, 0, 0},
{"encrypt-chunk-size", OPT_ENCRYPT_CHUNK_SIZE,
"This option specifies the size of the internal working buffer for "
"each encryption thread, measured in bytes. It is passed directly to "
"the xtrabackup child process. Try 'xtrabackup --help' for more "
"details.",
(uchar*) &ibx_xtrabackup_encrypt_chunk_size,
(uchar*) &ibx_xtrabackup_encrypt_chunk_size,
0, GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0},
{"export", OPT_EXPORT, "This option is passed directly to xtrabackup's " {"export", OPT_EXPORT, "This option is passed directly to xtrabackup's "
"--export option. It enables exporting individual tables for import " "--export option. It enables exporting individual tables for import "
"into another server. See the xtrabackup documentation for details.", "into another server. See the xtrabackup documentation for details.",
@ -735,8 +666,6 @@ You can download full text of the license on http://www.gnu.org/licenses/gpl-2.0
SYNOPOSIS\n\ SYNOPOSIS\n\
\n\ \n\
innobackupex [--compress] [--compress-threads=NUMBER-OF-THREADS] [--compress-chunk-size=CHUNK-SIZE]\n\ innobackupex [--compress] [--compress-threads=NUMBER-OF-THREADS] [--compress-chunk-size=CHUNK-SIZE]\n\
[--encrypt=ENCRYPTION-ALGORITHM] [--encrypt-threads=NUMBER-OF-THREADS] [--encrypt-chunk-size=CHUNK-SIZE]\n\
[--encrypt-key=LITERAL-ENCRYPTION-KEY] | [--encryption-key-file=MY.KEY]\n\
[--include=REGEXP] [--user=NAME]\n\ [--include=REGEXP] [--user=NAME]\n\
[--password=WORD] [--port=PORT] [--socket=SOCKET]\n\ [--password=WORD] [--port=PORT] [--socket=SOCKET]\n\
[--no-timestamp] [--ibbackup=IBBACKUP-BINARY]\n\ [--no-timestamp] [--ibbackup=IBBACKUP-BINARY]\n\
@ -748,7 +677,7 @@ innobackupex [--compress] [--compress-threads=NUMBER-OF-THREADS] [--compress-chu
[--incremental] [--incremental-basedir]\n\ [--incremental] [--incremental-basedir]\n\
[--incremental-dir] [--incremental-force-scan] [--incremental-lsn]\n\ [--incremental-dir] [--incremental-force-scan] [--incremental-lsn]\n\
[--incremental-history-name=NAME] [--incremental-history-uuid=UUID]\n\ [--incremental-history-name=NAME] [--incremental-history-uuid=UUID]\n\
[--close-files] [--compact] \n\ [--close-files]\n\
BACKUP-ROOT-DIR\n\ BACKUP-ROOT-DIR\n\
\n\ \n\
innobackupex --apply-log [--use-memory=B]\n\ innobackupex --apply-log [--use-memory=B]\n\
@ -760,8 +689,7 @@ innobackupex --copy-back [--defaults-file=MY.CNF] [--defaults-group=GROUP-NAME]
\n\ \n\
innobackupex --move-back [--defaults-file=MY.CNF] [--defaults-group=GROUP-NAME] BACKUP-DIR\n\ innobackupex --move-back [--defaults-file=MY.CNF] [--defaults-group=GROUP-NAME] BACKUP-DIR\n\
\n\ \n\
innobackupex [--decompress] [--decrypt=ENCRYPTION-ALGORITHM]\n\ innobackupex [--decompress]\n\
[--encrypt-key=LITERAL-ENCRYPTION-KEY] | [--encryption-key-file=MY.KEY]\n\
[--parallel=NUMBER-OF-FORKS] BACKUP-DIR\n\ [--parallel=NUMBER-OF-FORKS] BACKUP-DIR\n\
\n\ \n\
DESCRIPTION\n\ DESCRIPTION\n\
@ -798,15 +726,12 @@ it moves files to their original locations rather than copies them. As this\n\
option removes backup files, it must be used with caution. It may be useful in\n\ option removes backup files, it must be used with caution. It may be useful in\n\
cases when there is not enough free disk space to copy files.\n\ cases when there is not enough free disk space to copy files.\n\
\n\ \n\
The --decompress --decrypt command will decrypt and/or decompress a backup made\n\ The --decompress command will decompress a backup made\n\
with the --compress and/or --encrypt options. When decrypting, the encryption\n\ with the --compress option. The\n\
algorithm and key used when the backup was taken MUST be provided via the\n\ --parallel option will allow multiple files to be decompressed\n\
specified options. --decrypt and --decompress may be used together at the same\n\
time to completely normalize a previously compressed and encrypted backup. The\n\
--parallel option will allow multiple files to be decrypted and/or decompressed\n\
simultaneously. In order to decompress, the qpress utility MUST be installed\n\ simultaneously. In order to decompress, the qpress utility MUST be installed\n\
and accessable within the path. This process will remove the original\n\ and accessable within the path. This process will remove the original\n\
compressed/encrypted files and leave the results in the same location.\n\ compressed files and leave the results in the same location.\n\
\n\ \n\
On success the exit code innobackupex is 0. A non-zero exit code \n\ On success the exit code innobackupex is 0. A non-zero exit code \n\
indicates an error.\n"); indicates an error.\n");
@ -839,14 +764,6 @@ ibx_get_one_option(int optid,
opt_ibx_history = ""; opt_ibx_history = "";
} }
break; break;
case OPT_DECRYPT:
if (argument == NULL) {
ibx_msg("Missing --decrypt argument, must specify a "
"valid encryption algorithm.\n");
return(1);
}
opt_ibx_decrypt = true;
break;
case OPT_STREAM: case OPT_STREAM:
if (!strcasecmp(argument, "xbstream")) if (!strcasecmp(argument, "xbstream"))
xtrabackup_stream_fmt = XB_STREAM_FMT_XBSTREAM; xtrabackup_stream_fmt = XB_STREAM_FMT_XBSTREAM;
@ -866,15 +783,6 @@ ibx_get_one_option(int optid,
} }
xtrabackup_compress = TRUE; xtrabackup_compress = TRUE;
break; break;
case OPT_ENCRYPT:
if (argument == NULL)
{
msg("Missing --encrypt argument, must specify a "
"valid encryption algorithm.\n");
return 1;
}
xtrabackup_encrypt = TRUE;
break;
case 'p': case 'p':
if (argument) if (argument)
{ {
@ -928,7 +836,7 @@ ibx_handle_options(int *argc, char ***argv)
ibx_mode = IBX_MODE_COPY_BACK; ibx_mode = IBX_MODE_COPY_BACK;
} else if (opt_ibx_move_back) { } else if (opt_ibx_move_back) {
ibx_mode = IBX_MODE_MOVE_BACK; ibx_mode = IBX_MODE_MOVE_BACK;
} else if (opt_ibx_decrypt || opt_ibx_decompress) { } else if (opt_ibx_decompress) {
ibx_mode = IBX_MODE_DECRYPT_DECOMPRESS; ibx_mode = IBX_MODE_DECRYPT_DECOMPRESS;
} else { } else {
ibx_mode = IBX_MODE_BACKUP; ibx_mode = IBX_MODE_BACKUP;
@ -1006,8 +914,6 @@ ibx_init()
opt_lock_wait_query_type = opt_ibx_lock_wait_query_type; opt_lock_wait_query_type = opt_ibx_lock_wait_query_type;
opt_kill_long_query_type = opt_ibx_kill_long_query_type; opt_kill_long_query_type = opt_ibx_kill_long_query_type;
opt_decrypt_algo = opt_ibx_decrypt_algo;
opt_kill_long_queries_timeout = opt_ibx_kill_long_queries_timeout; opt_kill_long_queries_timeout = opt_ibx_kill_long_queries_timeout;
opt_lock_wait_timeout = opt_ibx_lock_wait_timeout; opt_lock_wait_timeout = opt_ibx_lock_wait_timeout;
opt_lock_wait_threshold = opt_ibx_lock_wait_threshold; opt_lock_wait_threshold = opt_ibx_lock_wait_threshold;
@ -1015,18 +921,12 @@ ibx_init()
opt_safe_slave_backup_timeout = opt_ibx_safe_slave_backup_timeout; opt_safe_slave_backup_timeout = opt_ibx_safe_slave_backup_timeout;
opt_history = opt_ibx_history; opt_history = opt_ibx_history;
opt_decrypt = opt_ibx_decrypt;
/* setup xtrabackup options */ /* setup xtrabackup options */
xb_close_files = ibx_xb_close_files; xb_close_files = ibx_xb_close_files;
xtrabackup_compress_alg = ibx_xtrabackup_compress_alg; xtrabackup_compress_alg = ibx_xtrabackup_compress_alg;
xtrabackup_compress_threads = ibx_xtrabackup_compress_threads; xtrabackup_compress_threads = ibx_xtrabackup_compress_threads;
xtrabackup_compress_chunk_size = ibx_xtrabackup_compress_chunk_size; xtrabackup_compress_chunk_size = ibx_xtrabackup_compress_chunk_size;
xtrabackup_encrypt_algo = ibx_xtrabackup_encrypt_algo;
xtrabackup_encrypt_key = ibx_xtrabackup_encrypt_key;
xtrabackup_encrypt_key_file = ibx_xtrabackup_encrypt_key_file;
xtrabackup_encrypt_threads = ibx_xtrabackup_encrypt_threads;
xtrabackup_encrypt_chunk_size = ibx_xtrabackup_encrypt_chunk_size;
xtrabackup_export = ibx_xtrabackup_export; xtrabackup_export = ibx_xtrabackup_export;
xtrabackup_extra_lsndir = ibx_xtrabackup_extra_lsndir; xtrabackup_extra_lsndir = ibx_xtrabackup_extra_lsndir;
xtrabackup_incremental_basedir = ibx_xtrabackup_incremental_basedir; xtrabackup_incremental_basedir = ibx_xtrabackup_incremental_basedir;
@ -1107,7 +1007,7 @@ ibx_init()
case IBX_MODE_DECRYPT_DECOMPRESS: case IBX_MODE_DECRYPT_DECOMPRESS:
xtrabackup_decrypt_decompress = TRUE; xtrabackup_decrypt_decompress = TRUE;
xtrabackup_target_dir = ibx_position_arg; xtrabackup_target_dir = ibx_position_arg;
run = "decrypt and decompress"; run = "decompress";
break; break;
default: default:
ut_error; ut_error;

View File

@ -44,19 +44,6 @@ dberr_t* err, /*!< out: this is set to DB_ERROR if an error
os_file_dir_t dir, /*!< in: directory stream */ os_file_dir_t dir, /*!< in: directory stream */
os_file_stat_t* info) /*!< in/out: buffer where the os_file_stat_t* info) /*!< in/out: buffer where the
info is returned */; info is returned */;
buf_block_t* btr_node_ptr_get_child(
const rec_t* node_ptr,/*!< in: node pointer */
dict_index_t* index, /*!< in: index */
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
mtr_t* mtr) /*!< in: mtr */;
buf_block_t*
btr_root_block_get(
/*===============*/
const dict_index_t* index, /*!< in: index tree */
ulint mode, /*!< in: either RW_S_LATCH
or RW_X_LATCH */
mtr_t* mtr) /*!< in: mtr */;
fil_space_t* fil_space_t*
fil_space_get_by_name(const char *); fil_space_get_by_name(const char *);
ibool ibool

View File

@ -1,696 +0,0 @@
/******************************************************
Copyright (c) 2013 Percona LLC and/or its affiliates.
The xbcrypt utility: decrypt files in the XBCRYPT format.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#include <my_base.h>
#include <my_getopt.h>
#include "common.h"
#include "xbcrypt.h"
#include "xbcrypt_common.h"
#include "crc_glue.h"
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600)
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
#define XBCRYPT_VERSION "1.1"
typedef enum {
RUN_MODE_NONE,
RUN_MODE_ENCRYPT,
RUN_MODE_DECRYPT
} run_mode_t;
const char *xbcrypt_encrypt_algo_names[] =
{ "NONE", "AES128", "AES192", "AES256", NullS};
TYPELIB xbcrypt_encrypt_algo_typelib=
{array_elements(xbcrypt_encrypt_algo_names)-1,"",
xbcrypt_encrypt_algo_names, NULL};
static run_mode_t opt_run_mode = RUN_MODE_ENCRYPT;
static char *opt_input_file = NULL;
static char *opt_output_file = NULL;
static ulong opt_encrypt_algo;
static char *opt_encrypt_key_file = NULL;
static void *opt_encrypt_key = NULL;
static ulonglong opt_encrypt_chunk_size = 0;
static my_bool opt_verbose = FALSE;
static uint encrypt_algos[] = { GCRY_CIPHER_NONE,
GCRY_CIPHER_AES128,
GCRY_CIPHER_AES192,
GCRY_CIPHER_AES256 };
static int encrypt_algo = 0;
static int encrypt_mode = GCRY_CIPHER_MODE_CTR;
static uint encrypt_key_len = 0;
static size_t encrypt_iv_len = 0;
static struct my_option my_long_options[] =
{
{"help", '?', "Display this help and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"decrypt", 'd', "Decrypt data input to output.",
0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"input", 'i', "Optional input file. If not specified, input"
" will be read from standard input.",
&opt_input_file, &opt_input_file, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"output", 'o', "Optional output file. If not specified, output"
" will be written to standard output.",
&opt_output_file, &opt_output_file, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-algo", 'a', "Encryption algorithm.",
&opt_encrypt_algo, &opt_encrypt_algo, &xbcrypt_encrypt_algo_typelib,
GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-key", 'k', "Encryption key.",
&opt_encrypt_key, &opt_encrypt_key, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-key-file", 'f', "File which contains encryption key.",
&opt_encrypt_key_file, &opt_encrypt_key_file, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-chunk-size", 's', "Size of working buffer for encryption in"
" bytes. The default value is 64K.",
&opt_encrypt_chunk_size, &opt_encrypt_chunk_size, 0,
GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0},
{"verbose", 'v', "Display verbose status output.",
&opt_verbose, &opt_verbose,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
static
int
get_options(int *argc, char ***argv);
static
my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument __attribute__((unused)));
static
void
print_version(void);
static
void
usage(void);
static
int
mode_decrypt(File filein, File fileout);
static
int
mode_encrypt(File filein, File fileout);
int
main(int argc, char **argv)
{
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600)
gcry_error_t gcry_error;
#endif
File filein = 0;
File fileout = 0;
MY_INIT(argv[0]);
crc_init();
if (get_options(&argc, &argv)) {
goto err;
}
/* Acording to gcrypt docs (and my testing), setting up the threading
callbacks must be done first, so, lets give it a shot */
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600)
gcry_error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
if (gcry_error) {
msg("%s: unable to set libgcrypt thread cbs - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return 1;
}
#endif
/* Version check should be the very first call because it
makes sure that important subsystems are intialized. */
if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) {
const char *gcrypt_version;
gcrypt_version = gcry_check_version(NULL);
/* No other library has already initialized libgcrypt. */
if (!gcrypt_version) {
msg("%s: failed to initialize libgcrypt\n",
my_progname);
return 1;
} else if (opt_verbose) {
msg("%s: using gcrypt %s\n", my_progname,
gcrypt_version);
}
}
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
/* Determine the algorithm */
encrypt_algo = encrypt_algos[opt_encrypt_algo];
/* Set up the iv length */
encrypt_iv_len = gcry_cipher_get_algo_blklen(encrypt_algo);
/* Now set up the key */
if (opt_encrypt_key == NULL && opt_encrypt_key_file == NULL) {
msg("%s: no encryption key or key file specified.\n",
my_progname);
return 1;
} else if (opt_encrypt_key && opt_encrypt_key_file) {
msg("%s: both encryption key and key file specified.\n",
my_progname);
return 1;
} else if (opt_encrypt_key_file) {
if (!xb_crypt_read_key_file(opt_encrypt_key_file,
&opt_encrypt_key,
&encrypt_key_len)) {
msg("%s: unable to read encryption key file \"%s\".\n",
opt_encrypt_key_file, my_progname);
return 1;
}
} else {
encrypt_key_len = strlen(opt_encrypt_key);
}
if (opt_input_file) {
MY_STAT mystat;
if (opt_verbose)
msg("%s: input file \"%s\".\n", my_progname,
opt_input_file);
if (my_stat(opt_input_file, &mystat, MYF(MY_WME)) == NULL) {
goto err;
}
if (!MY_S_ISREG(mystat.st_mode)) {
msg("%s: \"%s\" is not a regular file, exiting.\n",
my_progname, opt_input_file);
goto err;
}
if ((filein = my_open(opt_input_file, O_RDONLY, MYF(MY_WME)))
< 0) {
msg("%s: failed to open \"%s\".\n", my_progname,
opt_input_file);
goto err;
}
} else {
if (opt_verbose)
msg("%s: input from standard input.\n", my_progname);
filein = fileno(stdin);
}
if (opt_output_file) {
if (opt_verbose)
msg("%s: output file \"%s\".\n", my_progname,
opt_output_file);
if ((fileout = my_create(opt_output_file, 0,
O_WRONLY|O_BINARY|O_EXCL|O_NOFOLLOW,
MYF(MY_WME))) < 0) {
msg("%s: failed to create output file \"%s\".\n",
my_progname, opt_output_file);
goto err;
}
} else {
if (opt_verbose)
msg("%s: output to standard output.\n", my_progname);
fileout = fileno(stdout);
}
if (opt_run_mode == RUN_MODE_DECRYPT
&& mode_decrypt(filein, fileout)) {
goto err;
} else if (opt_run_mode == RUN_MODE_ENCRYPT
&& mode_encrypt(filein, fileout)) {
goto err;
}
if (opt_input_file && filein) {
my_close(filein, MYF(MY_WME));
}
if (opt_output_file && fileout) {
my_close(fileout, MYF(MY_WME));
}
my_cleanup_options(my_long_options);
my_end(0);
return EXIT_SUCCESS;
err:
if (opt_input_file && filein) {
my_close(filein, MYF(MY_WME));
}
if (opt_output_file && fileout) {
my_close(fileout, MYF(MY_WME));
}
my_cleanup_options(my_long_options);
my_end(0);
exit(EXIT_FAILURE);
}
static
size_t
my_xb_crypt_read_callback(void *userdata, void *buf, size_t len)
{
File* file = (File *) userdata;
return xb_read_full(*file, buf, len);
}
static
int
mode_decrypt(File filein, File fileout)
{
xb_rcrypt_t *xbcrypt_file = NULL;
void *chunkbuf = NULL;
size_t chunksize;
size_t originalsize;
void *ivbuf = NULL;
size_t ivsize;
void *decryptbuf = NULL;
size_t decryptbufsize = 0;
ulonglong ttlchunksread = 0;
ulonglong ttlbytesread = 0;
xb_rcrypt_result_t result;
gcry_cipher_hd_t cipher_handle;
gcry_error_t gcry_error;
my_bool hash_appended;
if (encrypt_algo != GCRY_CIPHER_NONE) {
gcry_error = gcry_cipher_open(&cipher_handle,
encrypt_algo,
encrypt_mode, 0);
if (gcry_error) {
msg("%s:decrypt: unable to open libgcrypt"
" cipher - %s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return 1;
}
gcry_error = gcry_cipher_setkey(cipher_handle,
opt_encrypt_key,
encrypt_key_len);
if (gcry_error) {
msg("%s:decrypt: unable to set libgcrypt cipher"
"key - %s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
goto err;
}
}
/* Initialize the xb_crypt format reader */
xbcrypt_file = xb_crypt_read_open(&filein, my_xb_crypt_read_callback);
if (xbcrypt_file == NULL) {
msg("%s:decrypt: xb_crypt_read_open() failed.\n", my_progname);
goto err;
}
/* Walk the encrypted chunks, decrypting them and writing out */
while ((result = xb_crypt_read_chunk(xbcrypt_file, &chunkbuf,
&originalsize, &chunksize,
&ivbuf, &ivsize, &hash_appended))
== XB_CRYPT_READ_CHUNK) {
if (encrypt_algo != GCRY_CIPHER_NONE) {
gcry_error = gcry_cipher_reset(cipher_handle);
if (gcry_error) {
msg("%s:decrypt: unable to reset libgcrypt"
" cipher - %s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
goto err;
}
if (ivsize) {
gcry_error = gcry_cipher_setctr(cipher_handle,
ivbuf,
ivsize);
}
if (gcry_error) {
msg("%s:decrypt: unable to set cipher iv - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
continue;
}
if (decryptbufsize < originalsize) {
decryptbuf = my_realloc(decryptbuf,
originalsize,
MYF(MY_WME | MY_ALLOW_ZERO_PTR));
decryptbufsize = originalsize;
}
/* Try to decrypt it */
gcry_error = gcry_cipher_decrypt(cipher_handle,
decryptbuf,
originalsize,
chunkbuf,
chunksize);
if (gcry_error) {
msg("%s:decrypt: unable to decrypt chunk - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
gcry_cipher_close(cipher_handle);
goto err;
}
} else {
decryptbuf = chunkbuf;
}
if (hash_appended) {
uchar hash[XB_CRYPT_HASH_LEN];
originalsize -= XB_CRYPT_HASH_LEN;
/* ensure that XB_CRYPT_HASH_LEN is the correct length
of XB_CRYPT_HASH hashing algorithm output */
xb_a(gcry_md_get_algo_dlen(XB_CRYPT_HASH) ==
XB_CRYPT_HASH_LEN);
gcry_md_hash_buffer(XB_CRYPT_HASH, hash, decryptbuf,
originalsize);
if (memcmp(hash, (char *) decryptbuf + originalsize,
XB_CRYPT_HASH_LEN) != 0) {
msg("%s:%s invalid plaintext hash. "
"Wrong encrytion key specified?\n",
my_progname, __FUNCTION__);
result = XB_CRYPT_READ_ERROR;
goto err;
}
}
/* Write it out */
if (my_write(fileout, (const uchar *) decryptbuf, originalsize,
MYF(MY_WME | MY_NABP))) {
msg("%s:decrypt: unable to write output chunk.\n",
my_progname);
goto err;
}
ttlchunksread++;
ttlbytesread += chunksize;
if (opt_verbose)
msg("%s:decrypt: %llu chunks read, %llu bytes read\n.",
my_progname, ttlchunksread, ttlbytesread);
}
xb_crypt_read_close(xbcrypt_file);
if (encrypt_algo != GCRY_CIPHER_NONE)
gcry_cipher_close(cipher_handle);
if (decryptbuf && decryptbufsize)
my_free(decryptbuf);
if (opt_verbose)
msg("\n%s:decrypt: done\n", my_progname);
return 0;
err:
if (xbcrypt_file)
xb_crypt_read_close(xbcrypt_file);
if (encrypt_algo != GCRY_CIPHER_NONE)
gcry_cipher_close(cipher_handle);
if (decryptbuf && decryptbufsize)
my_free(decryptbuf);
return 1;
}
static
ssize_t
my_xb_crypt_write_callback(void *userdata, const void *buf, size_t len)
{
File* file = (File *) userdata;
ssize_t ret = my_write(*file, buf, len, MYF(MY_WME));
posix_fadvise(*file, 0, 0, POSIX_FADV_DONTNEED);
return ret;
}
static
int
mode_encrypt(File filein, File fileout)
{
size_t bytesread;
size_t chunkbuflen;
uchar *chunkbuf = NULL;
void *ivbuf = NULL;
size_t encryptbuflen = 0;
size_t encryptedlen = 0;
void *encryptbuf = NULL;
ulonglong ttlchunkswritten = 0;
ulonglong ttlbyteswritten = 0;
xb_wcrypt_t *xbcrypt_file = NULL;
gcry_cipher_hd_t cipher_handle;
gcry_error_t gcry_error;
if (encrypt_algo != GCRY_CIPHER_NONE) {
gcry_error = gcry_cipher_open(&cipher_handle,
encrypt_algo,
encrypt_mode, 0);
if (gcry_error) {
msg("%s:encrypt: unable to open libgcrypt cipher - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return 1;
}
gcry_error = gcry_cipher_setkey(cipher_handle,
opt_encrypt_key,
encrypt_key_len);
if (gcry_error) {
msg("%s:encrypt: unable to set libgcrypt cipher key - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
goto err;
}
}
posix_fadvise(filein, 0, 0, POSIX_FADV_SEQUENTIAL);
xbcrypt_file = xb_crypt_write_open(&fileout,
my_xb_crypt_write_callback);
if (xbcrypt_file == NULL) {
msg("%s:encrypt: xb_crypt_write_open() failed.\n",
my_progname);
goto err;
}
ivbuf = my_malloc(encrypt_iv_len, MYF(MY_FAE));
/* now read in data in chunk size, encrypt and write out */
chunkbuflen = opt_encrypt_chunk_size + XB_CRYPT_HASH_LEN;
chunkbuf = (uchar *) my_malloc(chunkbuflen, MYF(MY_FAE));
while ((bytesread = my_read(filein, chunkbuf, opt_encrypt_chunk_size,
MYF(MY_WME))) > 0) {
size_t origbuflen = bytesread + XB_CRYPT_HASH_LEN;
/* ensure that XB_CRYPT_HASH_LEN is the correct length
of XB_CRYPT_HASH hashing algorithm output */
xb_a(XB_CRYPT_HASH_LEN == gcry_md_get_algo_dlen(XB_CRYPT_HASH));
gcry_md_hash_buffer(XB_CRYPT_HASH, chunkbuf + bytesread,
chunkbuf, bytesread);
if (encrypt_algo != GCRY_CIPHER_NONE) {
gcry_error = gcry_cipher_reset(cipher_handle);
if (gcry_error) {
msg("%s:encrypt: unable to reset cipher - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
goto err;
}
xb_crypt_create_iv(ivbuf, encrypt_iv_len);
gcry_error = gcry_cipher_setctr(cipher_handle,
ivbuf,
encrypt_iv_len);
if (gcry_error) {
msg("%s:encrypt: unable to set cipher iv - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
continue;
}
if (encryptbuflen < origbuflen) {
encryptbuf = my_realloc(encryptbuf, origbuflen,
MYF(MY_WME | MY_ALLOW_ZERO_PTR));
encryptbuflen = origbuflen;
}
gcry_error = gcry_cipher_encrypt(cipher_handle,
encryptbuf,
encryptbuflen,
chunkbuf,
origbuflen);
encryptedlen = origbuflen;
if (gcry_error) {
msg("%s:encrypt: unable to encrypt chunk - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
gcry_cipher_close(cipher_handle);
goto err;
}
} else {
encryptedlen = origbuflen;
encryptbuf = chunkbuf;
}
if (xb_crypt_write_chunk(xbcrypt_file, encryptbuf,
bytesread + XB_CRYPT_HASH_LEN,
encryptedlen, ivbuf, encrypt_iv_len)) {
msg("%s:encrypt: abcrypt_write_chunk() failed.\n",
my_progname);
goto err;
}
ttlchunkswritten++;
ttlbyteswritten += encryptedlen;
if (opt_verbose)
msg("%s:encrypt: %llu chunks written, %llu bytes "
"written\n.", my_progname, ttlchunkswritten,
ttlbyteswritten);
}
my_free(ivbuf);
my_free(chunkbuf);
if (encryptbuf && encryptbuflen)
my_free(encryptbuf);
xb_crypt_write_close(xbcrypt_file);
if (encrypt_algo != GCRY_CIPHER_NONE)
gcry_cipher_close(cipher_handle);
if (opt_verbose)
msg("\n%s:encrypt: done\n", my_progname);
return 0;
err:
if (chunkbuf)
my_free(chunkbuf);
if (encryptbuf && encryptbuflen)
my_free(encryptbuf);
if (xbcrypt_file)
xb_crypt_write_close(xbcrypt_file);
if (encrypt_algo != GCRY_CIPHER_NONE)
gcry_cipher_close(cipher_handle);
return 1;
}
static
int
get_options(int *argc, char ***argv)
{
int ho_error;
if ((ho_error= handle_options(argc, argv, my_long_options,
get_one_option))) {
exit(EXIT_FAILURE);
}
return 0;
}
static
my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument __attribute__((unused)))
{
switch (optid) {
case 'd':
opt_run_mode = RUN_MODE_DECRYPT;
break;
case '?':
usage();
exit(0);
}
return FALSE;
}
static
void
print_version(void)
{
printf("%s Ver %s for %s (%s)\n", my_progname, XBCRYPT_VERSION,
SYSTEM_TYPE, MACHINE_TYPE);
}
static
void
usage(void)
{
print_version();
puts("Copyright (C) 2011 Percona Inc.");
puts("This software comes with ABSOLUTELY NO WARRANTY. "
"This is free software,\nand you are welcome to modify and "
"redistribute it under the GPL license.\n");
puts("Encrypt or decrypt files in the XBCRYPT format.\n");
puts("Usage: ");
printf(" %s [OPTIONS...]"
" # read data from specified input, encrypting or decrypting "
" and writing the result to the specified output.\n",
my_progname);
puts("\nOptions:");
my_print_help(my_long_options);
}

View File

@ -1,79 +0,0 @@
/******************************************************
Copyright (c) 2011 Percona LLC and/or its affiliates.
Encryption interface for XtraBackup.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#ifndef XBCRYPT_H
#define XBCRYPT_H
#include <my_base.h>
#include "common.h"
#define XB_CRYPT_CHUNK_MAGIC1 "XBCRYP01"
#define XB_CRYPT_CHUNK_MAGIC2 "XBCRYP02"
#define XB_CRYPT_CHUNK_MAGIC3 "XBCRYP03" /* must be same size as ^^ */
#define XB_CRYPT_CHUNK_MAGIC_CURRENT XB_CRYPT_CHUNK_MAGIC3
#define XB_CRYPT_CHUNK_MAGIC_SIZE (sizeof(XB_CRYPT_CHUNK_MAGIC1)-1)
#define XB_CRYPT_HASH GCRY_MD_SHA256
#define XB_CRYPT_HASH_LEN 32
/******************************************************************************
Write interface */
typedef struct xb_wcrypt_struct xb_wcrypt_t;
/* Callback on write for i/o, must return # of bytes written or -1 on error */
typedef ssize_t xb_crypt_write_callback(void *userdata,
const void *buf, size_t len);
xb_wcrypt_t *xb_crypt_write_open(void *userdata,
xb_crypt_write_callback *onwrite);
/* Takes buffer, original length, encrypted length iv and iv length, formats
output buffer and calls write callback.
Returns 0 on success, 1 on error */
int xb_crypt_write_chunk(xb_wcrypt_t *crypt, const void *buf, size_t olen,
size_t elen, const void *iv, size_t ivlen);
/* Returns 0 on success, 1 on error */
int xb_crypt_write_close(xb_wcrypt_t *crypt);
/******************************************************************************
Read interface */
typedef struct xb_rcrypt_struct xb_rcrypt_t;
/* Callback on read for i/o, must return # of bytes read or -1 on error */
typedef size_t xb_crypt_read_callback(void *userdata, void *buf, size_t len);
xb_rcrypt_t *xb_crypt_read_open(void *userdata,
xb_crypt_read_callback *onread);
typedef enum {
XB_CRYPT_READ_CHUNK,
XB_CRYPT_READ_INCOMPLETE,
XB_CRYPT_READ_EOF,
XB_CRYPT_READ_ERROR
} xb_rcrypt_result_t;
xb_rcrypt_result_t xb_crypt_read_chunk(xb_rcrypt_t *crypt, void **buf,
size_t *olen, size_t *elen, void **iv,
size_t *ivlen, my_bool *hash_appended);
int xb_crypt_read_close(xb_rcrypt_t *crypt);
#endif

View File

@ -1,328 +0,0 @@
/******************************************************
Copyright (c) 2013, 2017 Percona LLC and/or its affiliates.
Encryption configuration file interface for XtraBackup.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#include <my_base.h>
#include "common.h"
#include "xbcrypt.h"
#include "xbcrypt_common.h"
/* Encryption options */
char *ds_encrypt_key = NULL;
char *ds_encrypt_key_file = NULL;
ulong ds_encrypt_algo;
static uint encrypt_key_len;
static uint encrypt_iv_len;
static const uint encrypt_mode = GCRY_CIPHER_MODE_CTR;
static uint encrypt_algos[] = { GCRY_CIPHER_NONE, GCRY_CIPHER_AES128,
GCRY_CIPHER_AES192, GCRY_CIPHER_AES256 };
static uint encrypt_algo;
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600)
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
my_bool
xb_crypt_read_key_file(const char *filename, void** key, uint *keylength)
{
FILE *fp;
if (!(fp = my_fopen(filename, O_RDONLY, MYF(0)))) {
msg("%s:%s: unable to open config file \"%s\", errno(%d)\n",
my_progname, __FUNCTION__, filename, my_errno);
return FALSE;
}
fseek(fp, 0 , SEEK_END);
*keylength = ftell(fp);
rewind(fp);
*key = my_malloc(*keylength, MYF(MY_FAE));
*keylength = fread(*key, 1, *keylength, fp);
my_fclose(fp, MYF(0));
return TRUE;
}
void
xb_crypt_create_iv(void* ivbuf, size_t ivlen)
{
gcry_create_nonce(ivbuf, ivlen);
}
gcry_error_t
xb_crypt_init(uint *iv_len)
{
gcry_error_t gcry_error;
/* Acording to gcrypt docs (and my testing), setting up the threading
callbacks must be done first, so, lets give it a shot */
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600)
gcry_error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
if (gcry_error) {
msg("encryption: unable to set libgcrypt thread cbs - "
"%s : %s\n",
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
#endif
/* Version check should be the very next call because it
makes sure that important subsystems are intialized. */
if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) {
const char *gcrypt_version;
gcrypt_version = gcry_check_version(NULL);
/* No other library has already initialized libgcrypt. */
if (!gcrypt_version) {
msg("encryption: failed to initialize libgcrypt\n");
return 1;
} else {
msg("encryption: using gcrypt %s\n", gcrypt_version);
}
}
/* Disable the gcry secure memory, not dealing with this for now */
gcry_error = gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
if (gcry_error) {
msg("encryption: unable to disable libgcrypt secmem - "
"%s : %s\n",
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
/* Finalize gcry initialization. */
gcry_error = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
if (gcry_error) {
msg("encryption: unable to finish libgcrypt initialization - "
"%s : %s\n",
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
/* Determine the algorithm */
encrypt_algo = encrypt_algos[ds_encrypt_algo];
/* Set up the iv length */
encrypt_iv_len = gcry_cipher_get_algo_blklen(encrypt_algo);
xb_a(encrypt_iv_len > 0);
if (iv_len != NULL) {
*iv_len = encrypt_iv_len;
}
/* Now set up the key */
if (ds_encrypt_key == NULL &&
ds_encrypt_key_file == NULL) {
msg("encryption: no encryption key or key file specified.\n");
return gcry_error;
} else if (ds_encrypt_key && ds_encrypt_key_file) {
msg("encryption: both encryption key and key file specified.\n");
return gcry_error;
} else if (ds_encrypt_key_file) {
if (!xb_crypt_read_key_file(ds_encrypt_key_file,
(void**)&ds_encrypt_key,
&encrypt_key_len)) {
msg("encryption: unable to read encryption key file"
" \"%s\".\n", ds_encrypt_key_file);
return gcry_error;
}
} else if (ds_encrypt_key) {
encrypt_key_len = strlen(ds_encrypt_key);
} else {
msg("encryption: no encryption key or key file specified.\n");
return gcry_error;
}
return 0;
}
gcry_error_t
xb_crypt_cipher_open(gcry_cipher_hd_t *cipher_handle)
{
if (encrypt_algo != GCRY_CIPHER_NONE) {
gcry_error_t gcry_error;
gcry_error = gcry_cipher_open(cipher_handle,
encrypt_algo,
encrypt_mode, 0);
if (gcry_error) {
msg("encryption: unable to open libgcrypt"
" cipher - %s : %s\n",
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
gcry_cipher_close(*cipher_handle);
return gcry_error;
}
gcry_error = gcry_cipher_setkey(*cipher_handle,
ds_encrypt_key,
encrypt_key_len);
if (gcry_error) {
msg("encryption: unable to set libgcrypt"
" cipher key - %s : %s\n",
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
gcry_cipher_close(*cipher_handle);
return gcry_error;
}
return gcry_error;
}
return 0;
}
void
xb_crypt_cipher_close(gcry_cipher_hd_t cipher_handle)
{
if (encrypt_algo != GCRY_CIPHER_NONE)
gcry_cipher_close(cipher_handle);
}
gcry_error_t
xb_crypt_decrypt(gcry_cipher_hd_t cipher_handle, const uchar *from,
size_t from_len, uchar *to, size_t *to_len,
const uchar *iv, size_t iv_len, my_bool hash_appended)
{
*to_len = from_len;
if (encrypt_algo != GCRY_CIPHER_NONE) {
gcry_error_t gcry_error;
gcry_error = gcry_cipher_reset(cipher_handle);
if (gcry_error) {
msg("%s:encryption: unable to reset libgcrypt"
" cipher - %s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
if (iv_len > 0) {
gcry_error = gcry_cipher_setctr(cipher_handle,
iv, iv_len);
}
if (gcry_error) {
msg("%s:encryption: unable to set cipher iv - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
/* Try to decrypt it */
gcry_error = gcry_cipher_decrypt(cipher_handle, to, *to_len,
from, from_len);
if (gcry_error) {
msg("%s:encryption: unable to decrypt chunk - "
"%s : %s\n", my_progname,
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
gcry_cipher_close(cipher_handle);
return gcry_error;
}
if (hash_appended) {
uchar hash[XB_CRYPT_HASH_LEN];
*to_len -= XB_CRYPT_HASH_LEN;
/* ensure that XB_CRYPT_HASH_LEN is the correct length
of XB_CRYPT_HASH hashing algorithm output */
xb_ad(gcry_md_get_algo_dlen(XB_CRYPT_HASH) ==
XB_CRYPT_HASH_LEN);
gcry_md_hash_buffer(XB_CRYPT_HASH, hash, to,
*to_len);
if (memcmp(hash, (char *) to + *to_len,
XB_CRYPT_HASH_LEN) != 0) {
msg("%s:%s invalid plaintext hash. "
"Wrong encrytion key specified?\n",
my_progname, __FUNCTION__);
return 1;
}
}
} else {
memcpy(to, from, *to_len);
}
return 0;
}
gcry_error_t
xb_crypt_encrypt(gcry_cipher_hd_t cipher_handle, const uchar *from,
size_t from_len, uchar *to, size_t *to_len, uchar *iv)
{
gcry_error_t gcry_error;
/* ensure that XB_CRYPT_HASH_LEN is the correct length
of XB_CRYPT_HASH hashing algorithm output */
xb_ad(gcry_md_get_algo_dlen(XB_CRYPT_HASH) ==
XB_CRYPT_HASH_LEN);
memcpy(to, from, from_len);
gcry_md_hash_buffer(XB_CRYPT_HASH, to + from_len,
from, from_len);
*to_len = from_len;
if (encrypt_algo != GCRY_CIPHER_NONE) {
gcry_error = gcry_cipher_reset(cipher_handle);
if (gcry_error) {
msg("encrypt: unable to reset cipher - "
"%s : %s\n",
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
xb_crypt_create_iv(iv, encrypt_iv_len);
gcry_error = gcry_cipher_setctr(cipher_handle, iv,
encrypt_iv_len);
if (gcry_error) {
msg("encrypt: unable to set cipher ctr - "
"%s : %s\n",
gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
gcry_error = gcry_cipher_encrypt(cipher_handle, to,
*to_len + XB_CRYPT_HASH_LEN,
to,
from_len + XB_CRYPT_HASH_LEN);
if (gcry_error) {
msg("encrypt: unable to encrypt buffer - "
"%s : %s\n", gcry_strsource(gcry_error),
gcry_strerror(gcry_error));
return gcry_error;
}
} else {
memcpy(to, from, from_len + XB_CRYPT_HASH_LEN);
}
*to_len += XB_CRYPT_HASH_LEN;
return 0;
}
#endif

View File

@ -1,64 +0,0 @@
/******************************************************
Copyright (c) 2017 Percona LLC and/or its affiliates.
Encryption datasink implementation for XtraBackup.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#include <my_base.h>
#if HAVE_GCRYPT
#if GCC_VERSION >= 4002
/* Workaround to avoid "gcry_ac_* is deprecated" warnings in gcrypt.h */
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <gcrypt.h>
extern char *ds_encrypt_key;
extern char *ds_encrypt_key_file;
extern int ds_encrypt_threads;
extern ulong ds_encrypt_algo;
/******************************************************************************
Utility interface */
my_bool xb_crypt_read_key_file(const char *filename,
void** key, uint *keylength);
void xb_crypt_create_iv(void* ivbuf, size_t ivlen);
/* Initialize gcrypt and setup encryption key and IV lengths */
gcry_error_t
xb_crypt_init(uint *iv_len);
/* Setup gcrypt cipher */
gcry_error_t
xb_crypt_cipher_open(gcry_cipher_hd_t *cipher_handle);
/* Close gcrypt cipher */
void
xb_crypt_cipher_close(gcry_cipher_hd_t cipher_handle);
/* Decrypt buffer */
gcry_error_t
xb_crypt_decrypt(gcry_cipher_hd_t cipher_handle, const uchar *from,
size_t from_len, uchar *to, size_t *to_len, const uchar *iv,
size_t iv_len, my_bool hash_appended);
/* Encrypt buffer */
gcry_error_t
xb_crypt_encrypt(gcry_cipher_hd_t cipher_handle, const uchar *from,
size_t from_len, uchar *to, size_t *to_len, uchar *iv);
#endif

View File

@ -1,252 +0,0 @@
/******************************************************
Copyright (c) 2013 Percona LLC and/or its affiliates.
The xbcrypt format reader implementation.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#include "xbcrypt.h"
#include "crc_glue.h"
struct xb_rcrypt_struct {
void *userdata;
xb_crypt_read_callback *read;
void *buffer;
size_t bufsize;
void *ivbuffer;
size_t ivbufsize;
ulonglong offset;
};
xb_rcrypt_t *
xb_crypt_read_open(void *userdata, xb_crypt_read_callback *onread)
{
xb_rcrypt_t *crypt;
xb_ad(onread);
crypt = (xb_rcrypt_t *) my_malloc(sizeof(xb_rcrypt_t), MYF(MY_FAE));
crypt->userdata = userdata;
crypt->read = onread;
crypt->buffer = NULL;
crypt->bufsize = 0;
crypt->offset = 0;
crypt->ivbuffer = NULL;
crypt->ivbufsize = 0;
return crypt;
}
xb_rcrypt_result_t
xb_crypt_read_chunk(xb_rcrypt_t *crypt, void **buf, size_t *olen, size_t *elen,
void **iv, size_t *ivlen, my_bool *hash_appended)
{
uchar tmpbuf[XB_CRYPT_CHUNK_MAGIC_SIZE + 8 + 8 + 8 + 4];
uchar *ptr;
ulonglong tmp;
ulong checksum, checksum_exp, version;
size_t bytesread;
xb_rcrypt_result_t result = XB_CRYPT_READ_CHUNK;
if ((bytesread = crypt->read(crypt->userdata, tmpbuf, sizeof(tmpbuf)))
!= sizeof(tmpbuf)) {
if (bytesread == 0) {
result = XB_CRYPT_READ_EOF;
goto err;
} else {
msg("%s:%s: unable to read chunk header data at "
"offset 0x%llx.\n",
my_progname, __FUNCTION__, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
}
ptr = tmpbuf;
if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC3,
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) {
version = 3;
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC2,
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) {
version = 2;
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC1,
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) {
version = 1;
} else {
msg("%s:%s: wrong chunk magic at offset 0x%llx.\n",
my_progname, __FUNCTION__, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE;
crypt->offset += XB_CRYPT_CHUNK_MAGIC_SIZE;
tmp = uint8korr(ptr); /* reserved */
ptr += 8;
crypt->offset += 8;
tmp = uint8korr(ptr); /* original size */
ptr += 8;
if (tmp > INT_MAX) {
msg("%s:%s: invalid original size at offset 0x%llx.\n",
my_progname, __FUNCTION__, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
crypt->offset += 8;
*olen = (size_t)tmp;
tmp = uint8korr(ptr); /* encrypted size */
ptr += 8;
if (tmp > INT_MAX) {
msg("%s:%s: invalid encrypted size at offset 0x%llx.\n",
my_progname, __FUNCTION__, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
crypt->offset += 8;
*elen = (size_t)tmp;
checksum_exp = uint4korr(ptr); /* checksum */
ptr += 4;
crypt->offset += 4;
/* iv size */
if (version == 1) {
*ivlen = 0;
*iv = 0;
} else {
if ((bytesread = crypt->read(crypt->userdata, tmpbuf, 8))
!= 8) {
if (bytesread == 0) {
result = XB_CRYPT_READ_EOF;
goto err;
} else {
msg("%s:%s: unable to read chunk iv size at "
"offset 0x%llx.\n",
my_progname, __FUNCTION__, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
}
tmp = uint8korr(tmpbuf);
if (tmp > INT_MAX) {
msg("%s:%s: invalid iv size at offset 0x%llx.\n",
my_progname, __FUNCTION__, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
crypt->offset += 8;
*ivlen = (size_t)tmp;
}
if (*ivlen > crypt->ivbufsize) {
crypt->ivbuffer = my_realloc(crypt->ivbuffer, *ivlen,
MYF(MY_WME | MY_ALLOW_ZERO_PTR));
if (crypt->ivbuffer == NULL) {
msg("%s:%s: failed to increase iv buffer to "
"%llu bytes.\n", my_progname, __FUNCTION__,
(ulonglong)*ivlen);
result = XB_CRYPT_READ_ERROR;
goto err;
}
crypt->ivbufsize = *ivlen;
}
if (*ivlen > 0) {
if (crypt->read(crypt->userdata, crypt->ivbuffer, *ivlen)
!= *ivlen) {
msg("%s:%s: failed to read %lld bytes for chunk iv "
"at offset 0x%llx.\n", my_progname, __FUNCTION__,
(ulonglong)*ivlen, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
*iv = crypt->ivbuffer;
}
/* for version euqals 2 we need to read in the iv data but do not init
CTR with it */
if (version == 2) {
*ivlen = 0;
*iv = 0;
}
if (*olen > crypt->bufsize) {
crypt->buffer = my_realloc(crypt->buffer, *olen,
MYF(MY_WME | MY_ALLOW_ZERO_PTR));
if (crypt->buffer == NULL) {
msg("%s:%s: failed to increase buffer to "
"%llu bytes.\n", my_progname, __FUNCTION__,
(ulonglong)*olen);
result = XB_CRYPT_READ_ERROR;
goto err;
}
crypt->bufsize = *olen;
}
if (*elen > 0) {
if (crypt->read(crypt->userdata, crypt->buffer, *elen)
!= *elen) {
msg("%s:%s: failed to read %lld bytes for chunk payload "
"at offset 0x%llx.\n", my_progname, __FUNCTION__,
(ulonglong)*elen, crypt->offset);
result = XB_CRYPT_READ_ERROR;
goto err;
}
}
checksum = crc32_iso3309(0, crypt->buffer, *elen);
if (checksum != checksum_exp) {
msg("%s:%s invalid checksum at offset 0x%llx, "
"expected 0x%lx, actual 0x%lx.\n", my_progname, __FUNCTION__,
crypt->offset, checksum_exp, checksum);
result = XB_CRYPT_READ_ERROR;
goto err;
}
crypt->offset += *elen;
*buf = crypt->buffer;
*hash_appended = version > 2;
goto exit;
err:
*buf = NULL;
*olen = 0;
*elen = 0;
*ivlen = 0;
*iv = 0;
exit:
return result;
}
int xb_crypt_read_close(xb_rcrypt_t *crypt)
{
if (crypt->buffer)
my_free(crypt->buffer);
if (crypt->ivbuffer)
my_free(crypt->ivbuffer);
my_free(crypt);
return 0;
}

View File

@ -1,105 +0,0 @@
/******************************************************
Copyright (c) 2013 Percona LLC and/or its affiliates.
The xbcrypt format writer implementation.
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 Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/
#include "xbcrypt.h"
#include "crc_glue.h"
struct xb_wcrypt_struct {
void *userdata;
xb_crypt_write_callback *write;
};
xb_wcrypt_t *
xb_crypt_write_open(void *userdata, xb_crypt_write_callback *onwrite)
{
xb_wcrypt_t *crypt;
xb_ad(onwrite);
crypt = (xb_wcrypt_t *) my_malloc(sizeof(xb_wcrypt_t), MYF(MY_FAE));
crypt->userdata = userdata;
crypt->write = onwrite;
return crypt;
}
int xb_crypt_write_chunk(xb_wcrypt_t *crypt, const void *buf, size_t olen,
size_t elen, const void *iv, size_t ivlen)
{
uchar tmpbuf[XB_CRYPT_CHUNK_MAGIC_SIZE + 8 + 8 + 8 + 4 + 8];
uchar *ptr;
ulong checksum;
xb_ad(olen <= INT_MAX);
if (olen > INT_MAX)
return 0;
xb_ad(elen <= INT_MAX);
if (elen > INT_MAX)
return 0;
xb_ad(ivlen <= INT_MAX);
if (ivlen > INT_MAX)
return 0;
ptr = tmpbuf;
memcpy(ptr, XB_CRYPT_CHUNK_MAGIC_CURRENT, XB_CRYPT_CHUNK_MAGIC_SIZE);
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE;
int8store(ptr, (ulonglong)0); /* reserved */
ptr += 8;
int8store(ptr, (ulonglong)olen); /* original size */
ptr += 8;
int8store(ptr, (ulonglong)elen); /* encrypted (actual) size */
ptr += 8;
checksum = crc32_iso3309(0, buf, elen);
int4store(ptr, checksum); /* checksum */
ptr += 4;
int8store(ptr, (ulonglong)ivlen); /* iv size */
ptr += 8;
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf));
if (crypt->write(crypt->userdata, tmpbuf, ptr-tmpbuf) == -1)
return 1;
if (crypt->write(crypt->userdata, iv, ivlen) == -1)
return 1;
if (crypt->write(crypt->userdata, buf, elen) == -1)
return 1;
return 0;
}
int xb_crypt_write_close(xb_wcrypt_t *crypt)
{
my_free(crypt);
return 0;
}

View File

@ -25,9 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include <my_pthread.h> #include <my_pthread.h>
#include "common.h" #include "common.h"
#include "xbstream.h" #include "xbstream.h"
#include "xbcrypt_common.h"
#include "datasink.h" #include "datasink.h"
#include "ds_decrypt.h"
#include "crc_glue.h" #include "crc_glue.h"
#define XBSTREAM_VERSION "1.0" #define XBSTREAM_VERSION "1.0"
@ -41,33 +39,18 @@ typedef enum {
RUN_MODE_EXTRACT RUN_MODE_EXTRACT
} run_mode_t; } run_mode_t;
const char *xbstream_encrypt_algo_names[] =
{ "NONE", "AES128", "AES192", "AES256", NullS};
TYPELIB xbstream_encrypt_algo_typelib=
{array_elements(xbstream_encrypt_algo_names)-1,"",
xbstream_encrypt_algo_names, NULL};
/* Need the following definitions to avoid linking with ds_*.o and their link /* Need the following definitions to avoid linking with ds_*.o and their link
dependencies */ dependencies */
datasink_t datasink_archive; datasink_t datasink_archive;
datasink_t datasink_xbstream; datasink_t datasink_xbstream;
datasink_t datasink_compress; datasink_t datasink_compress;
datasink_t datasink_tmpfile; datasink_t datasink_tmpfile;
datasink_t datasink_encrypt;
datasink_t datasink_buffer; datasink_t datasink_buffer;
static run_mode_t opt_mode; static run_mode_t opt_mode;
static char * opt_directory = NULL; static char * opt_directory = NULL;
static my_bool opt_verbose = 0; static my_bool opt_verbose = 0;
static int opt_parallel = 1; static int opt_parallel = 1;
static ulong opt_encrypt_algo;
static char *opt_encrypt_key_file = NULL;
static void *opt_encrypt_key = NULL;
static int opt_encrypt_threads = 1;
enum {
OPT_ENCRYPT_THREADS = 256
};
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
@ -86,20 +69,6 @@ static struct my_option my_long_options[] =
{"parallel", 'p', "Number of worker threads for reading / writing.", {"parallel", 'p', "Number of worker threads for reading / writing.",
&opt_parallel, &opt_parallel, 0, GET_INT, REQUIRED_ARG, &opt_parallel, &opt_parallel, 0, GET_INT, REQUIRED_ARG,
1, 1, INT_MAX, 0, 0, 0}, 1, 1, INT_MAX, 0, 0, 0},
{"decrypt", 'd', "Decrypt files ending with .xbcrypt.",
&opt_encrypt_algo, &opt_encrypt_algo, &xbstream_encrypt_algo_typelib,
GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-key", 'k', "Encryption key.",
&opt_encrypt_key, &opt_encrypt_key, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-key-file", 'f', "File which contains encryption key.",
&opt_encrypt_key_file, &opt_encrypt_key_file, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"encrypt-threads", OPT_ENCRYPT_THREADS,
"Number of threads for parallel data encryption. "
"The default value is 1.",
&opt_encrypt_threads, &opt_encrypt_threads,
0, GET_INT, REQUIRED_ARG, 1, 1, INT_MAX, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
}; };
@ -108,7 +77,6 @@ typedef struct {
HASH *filehash; HASH *filehash;
xb_rstream_t *stream; xb_rstream_t *stream;
ds_ctxt_t *ds_ctxt; ds_ctxt_t *ds_ctxt;
ds_ctxt_t *ds_decrypt_ctxt;
pthread_mutex_t *mutex; pthread_mutex_t *mutex;
} extract_ctxt_t; } extract_ctxt_t;
@ -348,19 +316,6 @@ err:
return 1; return 1;
} }
/************************************************************************
Check if string ends with given suffix.
@return true if string ends with given suffix. */
static
my_bool
ends_with(const char *str, const char *suffix)
{
size_t suffix_len = strlen(suffix);
size_t str_len = strlen(str);
return(str_len >= suffix_len
&& strcmp(str + str_len - suffix_len, suffix) == 0);
}
static static
file_entry_t * file_entry_t *
file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen) file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen)
@ -380,11 +335,8 @@ file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen)
} }
entry->pathlen = pathlen; entry->pathlen = pathlen;
if (ctxt->ds_decrypt_ctxt && ends_with(path, ".xbcrypt")) { file = ds_open(ctxt->ds_ctxt, path, NULL);
file = ds_open(ctxt->ds_decrypt_ctxt, path, NULL);
} else {
file = ds_open(ctxt->ds_ctxt, path, NULL);
}
if (file == NULL) { if (file == NULL) {
msg("%s: failed to create file.\n", my_progname); msg("%s: failed to create file.\n", my_progname);
goto err; goto err;
@ -534,7 +486,6 @@ mode_extract(int n_threads, int argc __attribute__((unused)),
xb_rstream_t *stream = NULL; xb_rstream_t *stream = NULL;
HASH filehash; HASH filehash;
ds_ctxt_t *ds_ctxt = NULL; ds_ctxt_t *ds_ctxt = NULL;
ds_ctxt_t *ds_decrypt_ctxt = NULL;
extract_ctxt_t ctxt; extract_ctxt_t ctxt;
int i; int i;
pthread_t *tids = NULL; pthread_t *tids = NULL;
@ -574,7 +525,6 @@ mode_extract(int n_threads, int argc __attribute__((unused)),
ctxt.stream = stream; ctxt.stream = stream;
ctxt.filehash = &filehash; ctxt.filehash = &filehash;
ctxt.ds_ctxt = ds_ctxt; ctxt.ds_ctxt = ds_ctxt;
ctxt.ds_decrypt_ctxt = ds_decrypt_ctxt;
ctxt.mutex = &mutex; ctxt.mutex = &mutex;
tids = malloc(sizeof(pthread_t) * n_threads); tids = malloc(sizeof(pthread_t) * n_threads);
@ -604,9 +554,6 @@ exit:
if (ds_ctxt != NULL) { if (ds_ctxt != NULL) {
ds_destroy(ds_ctxt); ds_destroy(ds_ctxt);
} }
if (ds_decrypt_ctxt) {
ds_destroy(ds_decrypt_ctxt);
}
xb_stream_read_done(stream); xb_stream_read_done(stream);
return ret; return ret;

File diff suppressed because it is too large Load Diff

View File

@ -81,7 +81,6 @@ extern char *xtrabackup_tables_exclude;
extern char *xtrabackup_databases_exclude; extern char *xtrabackup_databases_exclude;
extern ibool xtrabackup_compress; extern ibool xtrabackup_compress;
extern ibool xtrabackup_encrypt;
extern my_bool xtrabackup_backup; extern my_bool xtrabackup_backup;
extern my_bool xtrabackup_prepare; extern my_bool xtrabackup_prepare;
@ -92,15 +91,10 @@ extern my_bool xtrabackup_decrypt_decompress;
extern char *innobase_data_file_path; extern char *innobase_data_file_path;
extern char *innobase_doublewrite_file; extern char *innobase_doublewrite_file;
extern char *xtrabackup_encrypt_key;
extern char *xtrabackup_encrypt_key_file;
extern longlong innobase_log_file_size; extern longlong innobase_log_file_size;
extern long innobase_log_files_in_group; extern long innobase_log_files_in_group;
extern longlong innobase_page_size; extern longlong innobase_page_size;
extern const char *xtrabackup_encrypt_algo_names[];
extern TYPELIB xtrabackup_encrypt_algo_typelib;
extern int xtrabackup_parallel; extern int xtrabackup_parallel;
extern my_bool xb_close_files; extern my_bool xb_close_files;
@ -113,9 +107,6 @@ extern "C"{
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
extern ulong xtrabackup_encrypt_algo;
extern uint xtrabackup_encrypt_threads;
extern ulonglong xtrabackup_encrypt_chunk_size;
extern my_bool xtrabackup_export; extern my_bool xtrabackup_export;
extern char *xtrabackup_incremental_basedir; extern char *xtrabackup_incremental_basedir;
extern char *xtrabackup_extra_lsndir; extern char *xtrabackup_extra_lsndir;
@ -158,8 +149,6 @@ extern TYPELIB query_type_typelib;
extern ulong opt_lock_wait_query_type; extern ulong opt_lock_wait_query_type;
extern ulong opt_kill_long_query_type; extern ulong opt_kill_long_query_type;
extern ulong opt_decrypt_algo;
extern uint opt_kill_long_queries_timeout; extern uint opt_kill_long_queries_timeout;
extern uint opt_lock_wait_timeout; extern uint opt_lock_wait_timeout;
extern uint opt_lock_wait_threshold; extern uint opt_lock_wait_threshold;
@ -167,7 +156,6 @@ extern uint opt_debug_sleep_before_unlock;
extern uint opt_safe_slave_backup_timeout; extern uint opt_safe_slave_backup_timeout;
extern const char *opt_history; extern const char *opt_history;
extern my_bool opt_decrypt;
enum binlog_info_enum { BINLOG_INFO_OFF, BINLOG_INFO_LOCKLESS, BINLOG_INFO_ON, enum binlog_info_enum { BINLOG_INFO_OFF, BINLOG_INFO_LOCKLESS, BINLOG_INFO_ON,
BINLOG_INFO_AUTO}; BINLOG_INFO_AUTO};

View File

@ -2448,6 +2448,15 @@ DROP TABLE t1;
# End of 10.1 tests # End of 10.1 tests
# #
# #
# MDEV-13064: assertion `n < m_size' fails in Item::split_sum_func2()
#
create table t1 (i int) engine=MyISAM;
insert into t1 value (1),(2);
select count(*)+sleep(0) from t1;
count(*)+sleep(0)
2
drop table t1;
#
# Start of 10.3 tests # Start of 10.3 tests
# #
# #

View File

@ -3049,3 +3049,21 @@ SET DEBUG_SYNC= 'RESET';
disconnect con1; disconnect con1;
disconnect con2; disconnect con2;
disconnect con3; disconnect con3;
#
# MDEV-12620 - set lock_wait_timeout = 1;flush tables with read lock;
# lock not released after timeout
#
CREATE TABLE t1(a INT) ENGINE=InnoDB;
SET debug_sync='open_tables_after_open_and_process_table SIGNAL ready WAIT_FOR go';
SELECT * FROM t1;
connect con1,localhost,root,,;
SET debug_sync='now WAIT_FOR ready';
SET lock_wait_timeout=1;
FLUSH TABLES WITH READ LOCK;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
SET debug_sync='now SIGNAL go';
connection default;
a
SET debug_sync='RESET';
DROP TABLE t1;
disconnect con1;

View File

@ -1,5 +1,5 @@
# Test resizing the InnoDB redo log. # Test resizing the InnoDB redo log.
--source include/have_innodb.inc --source include/innodb_page_size_small.inc
# Embedded server tests do not support restarting # Embedded server tests do not support restarting
--source include/not_embedded.inc --source include/not_embedded.inc
# DBUG_EXECUTE_IF is needed # DBUG_EXECUTE_IF is needed
@ -24,6 +24,12 @@ call mtr.add_suppression("InnoDB: Unable to open .*ib_logfile0. to check native
FLUSH TABLES; FLUSH TABLES;
--enable_query_log --enable_query_log
--let $restart_parameters= --innodb-thread-concurrency=1 --innodb-log-file-size=1m --innodb-log-files-in-group=2
--source include/restart_mysqld.inc
--let $restart_parameters= --innodb-thread-concurrency=100 --innodb-log-file-size=10M --innodb-log-files-in-group=2
--source include/restart_mysqld.inc
CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB;
BEGIN; BEGIN;
INSERT INTO t1 VALUES (42); INSERT INTO t1 VALUES (42);

View File

@ -13,7 +13,6 @@ INSERT INTO t VALUES(2);
echo # xtrabackup prepare; echo # xtrabackup prepare;
--disable_result_log --disable_result_log
exec $XTRABACKUP --prepare --target-dir=$targetdir; exec $XTRABACKUP --prepare --target-dir=$targetdir;
exec $XTRABACKUP --defaults-file=$targetdir/backup-my.cnf --stats --datadir=$targetdir;
-- source include/restart_and_restore.inc -- source include/restart_and_restore.inc
--enable_result_log --enable_result_log

View File

@ -27,11 +27,6 @@ echo # Prepare full backup, apply incremental one;
exec $XTRABACKUP --prepare --apply-log-only --target-dir=$basedir; exec $XTRABACKUP --prepare --apply-log-only --target-dir=$basedir;
exec $XTRABACKUP --prepare --target-dir=$basedir --incremental-dir=$incremental_dir; exec $XTRABACKUP --prepare --target-dir=$basedir --incremental-dir=$incremental_dir;
# stats also can support encryption, but needs plugin-load and plugin variables, they are stored in backup-my.cnf
# We need to prepare again to create log files though.
exec $XTRABACKUP --prepare --target-dir=$basedir;
exec $XTRABACKUP --defaults-file=$basedir/backup-my.cnf --stats --datadir=$basedir;
echo # Restore and check results; echo # Restore and check results;
let $targetdir=$basedir; let $targetdir=$basedir;
-- source include/restart_and_restore.inc -- source include/restart_and_restore.inc

View File

@ -19,7 +19,6 @@ echo # xtrabackup prepare;
--disable_result_log --disable_result_log
exec $XTRABACKUP --prepare --target-dir=$targetdir; exec $XTRABACKUP --prepare --target-dir=$targetdir;
exec $XTRABACKUP --defaults-file=$targetdir/backup-my.cnf --stats --datadir=$targetdir ;
-- source include/restart_and_restore.inc -- source include/restart_and_restore.inc
--enable_result_log --enable_result_log

View File

@ -26,7 +26,7 @@ three_attempts NOT INSTALLED AUTHENTICATION dialog_examples.so GPL
two_questions NOT INSTALLED AUTHENTICATION dialog_examples.so GPL two_questions NOT INSTALLED AUTHENTICATION dialog_examples.so GPL
show status like '%libraries%'; show status like '%libraries%';
Variable_name Value Variable_name Value
Opened_plugin_libraries 8 Opened_plugin_libraries 7
show plugins soname where library = 'ha_example.so'; show plugins soname where library = 'ha_example.so';
Name Status Type Library License Name Status Type Library License
EXAMPLE NOT INSTALLED STORAGE ENGINE ha_example.so GPL EXAMPLE NOT INSTALLED STORAGE ENGINE ha_example.so GPL

View File

@ -1778,8 +1778,8 @@ DEFAULT_VALUE 50331648
VARIABLE_SCOPE GLOBAL VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT VARIABLE_TYPE BIGINT
VARIABLE_COMMENT Size of each log file in a log group. VARIABLE_COMMENT Size of each log file in a log group.
NUMERIC_MIN_VALUE 4194304 NUMERIC_MIN_VALUE 1048576
NUMERIC_MAX_VALUE 9223372036854775807 NUMERIC_MAX_VALUE 549755813888
NUMERIC_BLOCK_SIZE 1048576 NUMERIC_BLOCK_SIZE 1048576
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY YES READ_ONLY YES

View File

@ -1692,6 +1692,17 @@ DROP TABLE t1;
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --echo #
--echo #
--echo # MDEV-13064: assertion `n < m_size' fails in Item::split_sum_func2()
--echo #
create table t1 (i int) engine=MyISAM;
insert into t1 value (1),(2);
select count(*)+sleep(0) from t1;
drop table t1;
--echo # --echo #
--echo # Start of 10.3 tests --echo # Start of 10.3 tests
--echo # --echo #

View File

@ -4075,6 +4075,30 @@ disconnect con2;
disconnect con3; disconnect con3;
--echo #
--echo # MDEV-12620 - set lock_wait_timeout = 1;flush tables with read lock;
--echo # lock not released after timeout
--echo #
CREATE TABLE t1(a INT) ENGINE=InnoDB;
SET debug_sync='open_tables_after_open_and_process_table SIGNAL ready WAIT_FOR go';
send SELECT * FROM t1;
connect (con1,localhost,root,,);
SET debug_sync='now WAIT_FOR ready';
# lock_wait_timeout should be 0 in 10.3, so that we don't have to wait at all
SET lock_wait_timeout=1;
--error ER_LOCK_WAIT_TIMEOUT
FLUSH TABLES WITH READ LOCK;
SET debug_sync='now SIGNAL go';
connection default;
reap;
SET debug_sync='RESET';
DROP TABLE t1;
disconnect con1;
# Check that all connections opened by test cases in this file are really # Check that all connections opened by test cases in this file are really
# gone so execution of other tests won't be affected by their presence. # gone so execution of other tests won't be affected by their presence.
--source include/wait_until_count_sessions.inc --source include/wait_until_count_sessions.inc

View File

@ -182,12 +182,6 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
outfile= &sort->io_cache; outfile= &sort->io_cache;
/*
Release InnoDB's adaptive hash index latch (if holding) before
running a sort.
*/
ha_release_temporary_latches(thd);
my_b_clear(&tempfile); my_b_clear(&tempfile);
my_b_clear(&buffpek_pointers); my_b_clear(&buffpek_pointers);
buffpek=0; buffpek=0;

View File

@ -2019,44 +2019,6 @@ commit_checkpoint_notify_ha(handlerton *hton, void *cookie)
} }
/**
@details
This function should be called when MySQL sends rows of a SELECT result set
or the EOF mark to the client. It releases a possible adaptive hash index
S-latch held by thd in InnoDB and also releases a possible InnoDB query
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a thd to
keep them over several calls of the InnoDB handler interface when a join
is executed. But when we let the control to pass to the client they have
to be released because if the application program uses mysql_use_result(),
it may deadlock on the S-latch if the application on another connection
performs another SQL query. In MySQL-4.1 this is even more important because
there a connection can have several SELECT queries open at the same time.
@param thd the thread handle of the current connection
@return
always 0
*/
int ha_release_temporary_latches(THD *thd)
{
Ha_trx_info *info;
/*
Note that below we assume that only transactional storage engines
may need release_temporary_latches(). If this will ever become false,
we could iterate on thd->open_tables instead (and remove duplicates
as if (!seen[hton->slot]) { seen[hton->slot]=1; ... }).
*/
for (info= thd->transaction.stmt.ha_list; info; info= info->next())
{
handlerton *hton= info->ht();
if (hton && hton->release_temporary_latches)
hton->release_temporary_latches(hton, thd);
}
return 0;
}
/** /**
Check if all storage engines used in transaction agree that after Check if all storage engines used in transaction agree that after
rollback to savepoint it is safe to release MDL locks acquired after rollback to savepoint it is safe to release MDL locks acquired after

View File

@ -1235,7 +1235,6 @@ struct handlerton
enum_binlog_command binlog_command, enum_binlog_command binlog_command,
const char *query, uint query_length, const char *query, uint query_length,
const char *db, const char *table_name); const char *db, const char *table_name);
int (*release_temporary_latches)(handlerton *hton, THD *thd);
/* /*
Get log status. Get log status.
@ -4352,9 +4351,6 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache);
int ha_repartition_key_cache(KEY_CACHE *key_cache); int ha_repartition_key_cache(KEY_CACHE *key_cache);
int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache);
/* report to InnoDB that control passes to the client */
int ha_release_temporary_latches(THD *thd);
/* transactions: interface to handlerton functions */ /* transactions: interface to handlerton functions */
int ha_start_consistent_snapshot(THD *thd); int ha_start_consistent_snapshot(THD *thd);
int ha_commit_or_rollback_by_xid(XID *xid, bool commit); int ha_commit_or_rollback_by_xid(XID *xid, bool commit);

View File

@ -561,8 +561,7 @@ Item::Item(THD *thd):
command => we should check thd->lex->current_select on zero (thd->lex command => we should check thd->lex->current_select on zero (thd->lex
can be uninitialised) can be uninitialised)
*/ */
if (thd->lex->current_select && if (thd->lex->current_select)
thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
{ {
enum_parsing_place place= enum_parsing_place place=
thd->lex->current_select->parsing_place; thd->lex->current_select->parsing_place;
@ -5764,7 +5763,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
SELECT_LEX *select= thd->lex->current_select; SELECT_LEX *select= thd->lex->current_select;
thd->change_item_tree(reference, thd->change_item_tree(reference,
select->parsing_place == IN_GROUP_BY && select->context_analysis_place == IN_GROUP_BY &&
alias_name_used ? *rf->ref : rf); alias_name_used ? *rf->ref : rf);
/* /*

View File

@ -71,7 +71,7 @@ Item_window_func::fix_fields(THD *thd, Item **ref)
{ {
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
enum_parsing_place place= thd->lex->current_select->parsing_place; enum_parsing_place place= thd->lex->current_select->context_analysis_place;
if (!(place == SELECT_LIST || place == IN_ORDER_BY)) if (!(place == SELECT_LIST || place == IN_ORDER_BY))
{ {

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. /* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2010, 2013, Monty Program Ab Copyright (c) 2010, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -1465,12 +1465,6 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.in_trans, (int)flags.in_trans,
(int)flags.autocommit)); (int)flags.autocommit));
/*
Make InnoDB to release the adaptive hash index latch before
acquiring the query cache mutex.
*/
ha_release_temporary_latches(thd);
/* /*
A table- or a full flush operation can potentially take a long time to A table- or a full flush operation can potentially take a long time to
finish. We choose not to wait for them and skip caching statements finish. We choose not to wait for them and skip caching statements

View File

@ -2818,13 +2818,6 @@ int select_send::send_data(List<Item> &items)
if (thd->killed == ABORT_QUERY) if (thd->killed == ABORT_QUERY)
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
/*
We may be passing the control from mysqld to the client: release the
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
by thd
*/
ha_release_temporary_latches(thd);
protocol->prepare_for_resend(); protocol->prepare_for_resend();
if (protocol->send_result_set_row(&items)) if (protocol->send_result_set_row(&items))
{ {
@ -2843,13 +2836,6 @@ int select_send::send_data(List<Item> &items)
bool select_send::send_eof() bool select_send::send_eof()
{ {
/*
We may be passing the control from mysqld to the client: release the
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
by thd
*/
ha_release_temporary_latches(thd);
/* /*
Don't send EOF if we're in error condition (which implies we've already Don't send EOF if we're in error condition (which implies we've already
sent or are sending an error) sent or are sending an error)

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2010, 2016, MariaDB Copyright (c) 2010, 2017, MariaDB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -3753,9 +3753,6 @@ int select_insert::send_data(List<Item> &values)
} }
} }
// Release latches in case bulk insert takes a long time
ha_release_temporary_latches(thd);
error= write_record(thd, table, &info); error= write_record(thd, table, &info);
table->auto_increment_field_not_null= FALSE; table->auto_increment_field_not_null= FALSE;

View File

@ -911,6 +911,7 @@ public:
/* reserved for exists 2 in */ /* reserved for exists 2 in */
uint select_n_reserved; uint select_n_reserved;
enum_parsing_place parsing_place; /* where we are parsing expression */ enum_parsing_place parsing_place; /* where we are parsing expression */
enum_parsing_place context_analysis_place; /* where we are in prepare */
bool with_sum_func; /* sum function indicator */ bool with_sum_func; /* sum function indicator */
ulong table_join_options; ulong table_join_options;

View File

@ -253,7 +253,8 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
NOTE: my_error() has been already called by reopen_tables() within NOTE: my_error() has been already called by reopen_tables() within
close_cached_tables(). close_cached_tables().
*/ */
result= 1; thd->global_read_lock.unlock_global_read_lock(thd);
return 1;
} }
if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed

View File

@ -648,17 +648,15 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
thd->lex->allow_sum_func|= (nesting_map)1 << select->nest_level; thd->lex->allow_sum_func|= (nesting_map)1 << select->nest_level;
save_place= thd->lex->current_select->parsing_place; save_place= thd->lex->current_select->context_analysis_place;
thd->lex->current_select->parsing_place= IN_ORDER_BY; thd->lex->current_select->context_analysis_place= IN_ORDER_BY;
res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
order); order);
thd->lex->current_select->parsing_place= save_place; thd->lex->allow_sum_func&= ~((nesting_map)1 << select->nest_level);
thd->lex->allow_sum_func&= ~((nesting_map)1 << select->nest_level); thd->lex->current_select->context_analysis_place= IN_GROUP_BY;
save_place= thd->lex->current_select->parsing_place;
thd->lex->current_select->parsing_place= IN_GROUP_BY;
res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields, res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields,
group, hidden_group_fields); group, hidden_group_fields);
thd->lex->current_select->parsing_place= save_place; thd->lex->current_select->context_analysis_place= save_place;
thd->lex->allow_sum_func|= (nesting_map)1 << select->nest_level; thd->lex->allow_sum_func|= (nesting_map)1 << select->nest_level;
res= res || setup_windows(thd, ref_pointer_array, tables, fields, all_fields, res= res || setup_windows(thd, ref_pointer_array, tables, fields, all_fields,
win_specs, win_funcs); win_specs, win_funcs);
@ -712,6 +710,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
if (select_lex->handle_derived(thd->lex, DT_PREPARE)) if (select_lex->handle_derived(thd->lex, DT_PREPARE))
DBUG_RETURN(1); DBUG_RETURN(1);
thd->lex->current_select->context_analysis_place= NO_MATTER;
thd->lex->current_select->is_item_list_lookup= 1; thd->lex->current_select->is_item_list_lookup= 1;
/* /*
If we have already executed SELECT, then it have not sense to prevent If we have already executed SELECT, then it have not sense to prevent
@ -801,12 +800,13 @@ JOIN::prepare(TABLE_LIST *tables_init,
ref_ptrs= ref_ptr_array_slice(0); ref_ptrs= ref_ptr_array_slice(0);
enum_parsing_place save_place= thd->lex->current_select->parsing_place; enum_parsing_place save_place=
thd->lex->current_select->parsing_place= SELECT_LIST; thd->lex->current_select->context_analysis_place;
thd->lex->current_select->context_analysis_place= SELECT_LIST;
if (setup_fields(thd, ref_ptrs, fields_list, MARK_COLUMNS_READ, if (setup_fields(thd, ref_ptrs, fields_list, MARK_COLUMNS_READ,
&all_fields, 1)) &all_fields, 1))
DBUG_RETURN(-1); DBUG_RETURN(-1);
thd->lex->current_select->parsing_place= save_place; thd->lex->current_select->context_analysis_place= save_place;
if (setup_without_group(thd, ref_ptrs, tables_list, if (setup_without_group(thd, ref_ptrs, tables_list,
select_lex->leaf_tables, fields_list, select_lex->leaf_tables, fields_list,
@ -22213,14 +22213,16 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order, List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool from_window_spec) bool from_window_spec)
{ {
enum_parsing_place parsing_place= thd->lex->current_select->parsing_place; enum_parsing_place context_analysis_place=
thd->lex->current_select->context_analysis_place;
thd->where="order clause"; thd->where="order clause";
for (; order; order=order->next) for (; order; order=order->next)
{ {
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
all_fields, FALSE, from_window_spec)) all_fields, FALSE, from_window_spec))
return 1; return 1;
if ((*order->item)->with_window_func && parsing_place != IN_ORDER_BY) if ((*order->item)->with_window_func &&
context_analysis_place != IN_ORDER_BY)
{ {
my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0)); my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0));
return 1; return 1;
@ -22262,7 +22264,8 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order, List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields, bool from_window_spec) bool *hidden_group_fields, bool from_window_spec)
{ {
enum_parsing_place parsing_place= thd->lex->current_select->parsing_place; enum_parsing_place context_analysis_place=
thd->lex->current_select->context_analysis_place;
*hidden_group_fields=0; *hidden_group_fields=0;
ORDER *ord; ORDER *ord;
@ -22278,14 +22281,14 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
all_fields, TRUE, from_window_spec)) all_fields, TRUE, from_window_spec))
return 1; return 1;
(*ord->item)->marker= UNDEF_POS; /* Mark found */ (*ord->item)->marker= UNDEF_POS; /* Mark found */
if ((*ord->item)->with_sum_func && parsing_place == IN_GROUP_BY) if ((*ord->item)->with_sum_func && context_analysis_place == IN_GROUP_BY)
{ {
my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name()); my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name());
return 1; return 1;
} }
if ((*ord->item)->with_window_func) if ((*ord->item)->with_window_func)
{ {
if (parsing_place == IN_GROUP_BY) if (context_analysis_place == IN_GROUP_BY)
my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0)); my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
else else
my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0)); my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0));

View File

@ -1,6 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
@ -991,11 +992,7 @@ BtrBulk::finish(dberr_t err)
ut_ad(err == DB_SUCCESS); ut_ad(err == DB_SUCCESS);
} }
#ifdef UNIV_DEBUG ut_ad(!sync_check_iterate(dict_sync_check()));
dict_sync_check check(true);
ut_ad(!sync_check_iterate(check));
#endif /* UNIV_DEBUG */
ut_ad(err != DB_SUCCESS || btr_validate_index(m_index, NULL, false)); ut_ad(err != DB_SUCCESS || btr_validate_index(m_index, NULL, false));
return(err); return(err);

View File

@ -1870,15 +1870,8 @@ buf_flush_batch(
counts */ counts */
{ {
ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST);
ut_ad(flush_type == BUF_FLUSH_LRU
#ifdef UNIV_DEBUG || !sync_check_iterate(dict_sync_check()));
{
dict_sync_check check(true);
ut_ad(flush_type != BUF_FLUSH_LIST
|| !sync_check_iterate(check));
}
#endif /* UNIV_DEBUG */
buf_pool_mutex_enter(buf_pool); buf_pool_mutex_enter(buf_pool);

View File

@ -6114,14 +6114,7 @@ dict_set_corrupted(
ut_ad(mutex_own(&dict_sys->mutex)); ut_ad(mutex_own(&dict_sys->mutex));
ut_ad(!dict_table_is_comp(dict_sys->sys_tables)); ut_ad(!dict_table_is_comp(dict_sys->sys_tables));
ut_ad(!dict_table_is_comp(dict_sys->sys_indexes)); ut_ad(!dict_table_is_comp(dict_sys->sys_indexes));
ut_ad(!sync_check_iterate(dict_sync_check()));
#ifdef UNIV_DEBUG
{
dict_sync_check check(true);
ut_ad(!sync_check_iterate(check));
}
#endif /* UNIV_DEBUG */
/* Mark the table as corrupted only if the clustered index /* Mark the table as corrupted only if the clustered index
is corrupted */ is corrupted */

View File

@ -1869,6 +1869,8 @@ void
innobase_srv_conc_exit_innodb( innobase_srv_conc_exit_innodb(
row_prebuilt_t* prebuilt) row_prebuilt_t* prebuilt)
{ {
ut_ad(!sync_check_iterate(sync_check()));
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (wsrep_on(prebuilt->trx->mysql_thd) && if (wsrep_on(prebuilt->trx->mysql_thd) &&
wsrep_thd_is_BF(prebuilt->trx->mysql_thd, FALSE)) { wsrep_thd_is_BF(prebuilt->trx->mysql_thd, FALSE)) {
@ -1877,13 +1879,6 @@ innobase_srv_conc_exit_innodb(
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
trx_t* trx = prebuilt->trx; trx_t* trx = prebuilt->trx;
#ifdef BTR_CUR_HASH_ADAPT
# ifdef UNIV_DEBUG
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
/* This is to avoid making an unnecessary function call. */ /* This is to avoid making an unnecessary function call. */
if (trx->declared_to_be_inside_innodb if (trx->declared_to_be_inside_innodb
@ -1901,13 +1896,7 @@ innobase_srv_conc_force_exit_innodb(
/*================================*/ /*================================*/
trx_t* trx) /*!< in: transaction handle */ trx_t* trx) /*!< in: transaction handle */
{ {
#ifdef BTR_CUR_HASH_ADAPT ut_ad(!sync_check_iterate(sync_check()));
# ifdef UNIV_DEBUG
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
/* This is to avoid making an unnecessary function call. */ /* This is to avoid making an unnecessary function call. */
if (trx->declared_to_be_inside_innodb) { if (trx->declared_to_be_inside_innodb) {
@ -1994,13 +1983,7 @@ const char*
thd_innodb_tmpdir( thd_innodb_tmpdir(
THD* thd) THD* thd)
{ {
#ifdef BTR_CUR_HASH_ADAPT ut_ad(!sync_check_iterate(sync_check()));
# ifdef UNIV_DEBUG
trx_t* trx = thd_to_trx(thd);
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
const char* tmp_dir = THDVAR(thd, tmpdir); const char* tmp_dir = THDVAR(thd, tmpdir);
@ -2035,28 +2018,6 @@ thd_to_trx_id(
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/********************************************************************//**
Call this function when mysqld passes control to the client. That is to
avoid deadlocks on the adaptive hash S-latch possibly held by thd. For more
documentation, see handler.cc.
@return 0 */
inline
int
innobase_release_temporary_latches(
/*===============================*/
handlerton* hton, /*!< in: handlerton */
THD* thd) /*!< in: MySQL thread */
{
DBUG_ASSERT(hton == innodb_hton_ptr);
if (!srv_was_started) {
} else if (trx_t* trx __attribute__((unused))= thd_to_trx(thd)) {
trx_assert_no_search_latch(trx);
}
return(0);
}
/********************************************************************//** /********************************************************************//**
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread. This function should be used time calls srv_active_wake_master_thread. This function should be used
@ -3384,7 +3345,6 @@ innobase_query_caching_of_table_permitted(
return(false); return(false);
} }
trx_assert_no_search_latch(trx);
innobase_srv_conc_force_exit_innodb(trx); innobase_srv_conc_force_exit_innodb(trx);
if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)
@ -3692,8 +3652,6 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/* Initialize the m_prebuilt struct much like it would be inited in /* Initialize the m_prebuilt struct much like it would be inited in
external_lock */ external_lock */
trx_assert_no_search_latch(m_prebuilt->trx);
innobase_srv_conc_force_exit_innodb(m_prebuilt->trx); innobase_srv_conc_force_exit_innodb(m_prebuilt->trx);
/* If the transaction is not started yet, start it */ /* If the transaction is not started yet, start it */
@ -3913,9 +3871,6 @@ innobase_init(
innobase_hton->flags = innobase_hton->flags =
HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS; HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS;
innobase_hton->release_temporary_latches =
innobase_release_temporary_latches;
#ifdef MYSQL_REPLACE_TRX_IN_THD #ifdef MYSQL_REPLACE_TRX_IN_THD
innobase_hton->replace_native_transaction_in_thd = innobase_hton->replace_native_transaction_in_thd =
innodb_replace_trx_in_thd; innodb_replace_trx_in_thd;
@ -4808,12 +4763,6 @@ innobase_commit_ordered(
trx = check_trx_exists(thd); trx = check_trx_exists(thd);
TrxInInnoDB trx_in_innodb(trx); TrxInInnoDB trx_in_innodb(trx);
/* Since we will reserve the kernel mutex, we must not be holding the
search system latch, or we will disobey the latching order. But we
already released it in innobase_xa_prepare() (if not before), so just
have an assert here.*/
trx_assert_no_search_latch(trx);
if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
/* We cannot throw error here; instead we will catch this error /* We cannot throw error here; instead we will catch this error
again in innobase_commit() and report it from there. */ again in innobase_commit() and report it from there. */
@ -5025,12 +4974,6 @@ innobase_rollback_trx(
DBUG_ENTER("innobase_rollback_trx"); DBUG_ENTER("innobase_rollback_trx");
DBUG_PRINT("trans", ("aborting transaction")); DBUG_PRINT("trans", ("aborting transaction"));
/* Release a possible FIFO ticket and search latch. Since we will
reserve the trx_sys->mutex, we have to release the search system
latch first to obey the latching order. */
trx_assert_no_search_latch(trx);
innobase_srv_conc_force_exit_innodb(trx); innobase_srv_conc_force_exit_innodb(trx);
/* If we had reserved the auto-inc lock for some table (if /* If we had reserved the auto-inc lock for some table (if
@ -6540,37 +6483,19 @@ initialize_auto_increment(dict_table_t* table, const Field* field)
dict_table_autoinc_unlock(table); dict_table_autoinc_unlock(table);
} }
/*****************************************************************//** /** Open an InnoDB table
Creates and opens a handle to a table which already exists in an InnoDB @param[in] name table name
database. @return error code
@return 1 if error, 0 if success */ @retval 0 on success */
int int
ha_innobase::open( ha_innobase::open(const char* name, int, uint)
/*==============*/
const char* name, /*!< in: table name */
int mode, /*!< in: not used */
uint test_if_locked) /*!< in: not used */
{ {
dict_table_t* ib_table; dict_table_t* ib_table;
char norm_name[FN_REFLEN]; char norm_name[FN_REFLEN];
THD* thd;
dict_err_ignore_t ignore_err = DICT_ERR_IGNORE_NONE; dict_err_ignore_t ignore_err = DICT_ERR_IGNORE_NONE;
DBUG_ENTER("ha_innobase::open"); DBUG_ENTER("ha_innobase::open");
UT_NOT_USED(mode);
UT_NOT_USED(test_if_locked);
thd = ha_thd();
/* Under some cases MySQL seems to call this function while
holding search latch(es). This breaks the latching order as
we acquire dict_sys->mutex below and leads to a deadlock. */
if (thd != NULL) {
innobase_release_temporary_latches(ht, thd);
}
normalize_table_name(norm_name, name); normalize_table_name(norm_name, name);
m_user_thd = NULL; m_user_thd = NULL;
@ -6585,6 +6510,7 @@ ha_innobase::open(
m_upd_buf_size = 0; m_upd_buf_size = 0;
char* is_part = is_partition(norm_name); char* is_part = is_partition(norm_name);
THD* thd = ha_thd();
/* Check whether FOREIGN_KEY_CHECKS is set to 0. If so, the table /* Check whether FOREIGN_KEY_CHECKS is set to 0. If so, the table
can be opened even if some FK indexes are missing. If not, the table can be opened even if some FK indexes are missing. If not, the table
@ -7055,12 +6981,6 @@ ha_innobase::close()
{ {
DBUG_ENTER("ha_innobase::close"); DBUG_ENTER("ha_innobase::close");
THD* thd = ha_thd();
if (thd != NULL) {
innobase_release_temporary_latches(ht, thd);
}
row_prebuilt_free(m_prebuilt, FALSE); row_prebuilt_free(m_prebuilt, FALSE);
if (m_upd_buf != NULL) { if (m_upd_buf != NULL) {
@ -13156,10 +13076,6 @@ create_table_info_t::initialize()
parent_trx = check_trx_exists(m_thd); parent_trx = check_trx_exists(m_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_assert_no_search_latch(parent_trx);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -14012,12 +13928,6 @@ innobase_drop_database(
THD* thd = current_thd; THD* thd = current_thd;
/* In case MySQL calls this in the middle of a SELECT
query, release possible adaptive hash latch to avoid
deadlocks of threads */
trx_assert_no_search_latch(check_trx_exists(thd));
ulint len = 0; ulint len = 0;
char* ptr = strend(path) - 2; char* ptr = strend(path) - 2;
@ -14751,12 +14661,7 @@ ha_innobase::info_low(
update_thd(ha_thd()); update_thd(ha_thd());
/* In case MySQL calls this in the middle of a SELECT query, release m_prebuilt->trx->op_info = "returning various info to MariaDB";
possible adaptive hash latch to avoid deadlocks of threads */
m_prebuilt->trx->op_info = (char*)"returning various info to MariaDB";
trx_assert_no_search_latch(m_prebuilt->trx);
ib_table = m_prebuilt->table; ib_table = m_prebuilt->table;
DBUG_ASSERT(ib_table->n_ref_count > 0); DBUG_ASSERT(ib_table->n_ref_count > 0);
@ -15603,12 +15508,7 @@ ha_innobase::update_table_comment(
update_thd(ha_thd()); update_thd(ha_thd());
m_prebuilt->trx->op_info = (char*)"returning table comment"; m_prebuilt->trx->op_info = "returning table comment";
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_assert_no_search_latch(m_prebuilt->trx);
#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \ #define SSTR( x ) reinterpret_cast< std::ostringstream & >( \
( std::ostringstream() << std::dec << x ) ).str() ( std::ostringstream() << std::dec << x ) ).str()
@ -15664,22 +15564,14 @@ ha_innobase::get_foreign_key_create_info(void)
update_thd(ha_thd()); update_thd(ha_thd());
m_prebuilt->trx->op_info = (char*)"getting info on foreign keys"; m_prebuilt->trx->op_info = "getting info on foreign keys";
/* In case MySQL calls this in the middle of a SELECT query,
release possible adaptive hash latch to avoid
deadlocks of threads */
trx_assert_no_search_latch(m_prebuilt->trx);
/* Output the data to a temporary string */ /* Output the data to a temporary string */
std::string str = dict_print_info_on_foreign_keys( std::string str = dict_print_info_on_foreign_keys(
TRUE, m_prebuilt->trx, TRUE, m_prebuilt->trx,
m_prebuilt->table); m_prebuilt->table);
m_prebuilt->trx->op_info = (char*)""; m_prebuilt->trx->op_info = "";
/* Allocate buffer for the string */ /* Allocate buffer for the string */
char* fk_str = (char*) my_malloc(str.length() + 1, MYF(0)); char* fk_str = (char*) my_malloc(str.length() + 1, MYF(0));
@ -16682,8 +16574,6 @@ innodb_show_status(
trx_t* trx = check_trx_exists(thd); trx_t* trx = check_trx_exists(thd);
trx_assert_no_search_latch(trx);
innobase_srv_conc_force_exit_innodb(trx); innobase_srv_conc_force_exit_innodb(trx);
TrxInInnoDB trx_in_innodb(trx); TrxInInnoDB trx_in_innodb(trx);
@ -17999,12 +17889,6 @@ innobase_xa_prepare(
thd_get_xid(thd, (MYSQL_XID*) trx->xid); thd_get_xid(thd, (MYSQL_XID*) trx->xid);
/* Release a possible FIFO ticket and search latch. Since we will
reserve the trx_sys->mutex, we have to release the search system
latch first to obey the latching order. */
trx_assert_no_search_latch(trx);
innobase_srv_conc_force_exit_innodb(trx); innobase_srv_conc_force_exit_innodb(trx);
TrxInInnoDB trx_in_innodb(trx); TrxInInnoDB trx_in_innodb(trx);
@ -21333,7 +21217,7 @@ static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size, static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Size of each log file in a log group.", "Size of each log file in a log group.",
NULL, NULL, 48*1024*1024L, 4*1024*1024L, LLONG_MAX, 1024*1024L); NULL, NULL, 48 << 20, 1 << 20, 512ULL << 30, 1 << 20);
static MYSQL_SYSVAR_ULONG(log_files_in_group, srv_n_log_files, static MYSQL_SYSVAR_ULONG(log_files_in_group, srv_n_log_files,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,

View File

@ -906,18 +906,6 @@ innodb_base_col_setup_for_stored(
/** whether this is a computed virtual column */ /** whether this is a computed virtual column */
#define innobase_is_v_fld(field) ((field)->vcol_info && !(field)->stored_in_db()) #define innobase_is_v_fld(field) ((field)->vcol_info && !(field)->stored_in_db())
/** Release temporary latches.
Call this function when mysqld passes control to the client. That is to
avoid deadlocks on the adaptive hash S-latch possibly held by thd. For more
documentation, see handler.cc.
@param[in] hton Handlerton.
@param[in] thd MySQL thread.
@return 0 */
int
innobase_release_temporary_latches(
handlerton* hton,
THD* thd);
/** Always normalize table name to lower case on Windows */ /** Always normalize table name to lower case on Windows */
#ifdef _WIN32 #ifdef _WIN32
#define normalize_table_name(norm_name, name) \ #define normalize_table_name(norm_name, name) \

View File

@ -932,7 +932,6 @@ ha_innopart::open(
{ {
dict_table_t* ib_table; dict_table_t* ib_table;
char norm_name[FN_REFLEN]; char norm_name[FN_REFLEN];
THD* thd;
DBUG_ENTER("ha_innopart::open"); DBUG_ENTER("ha_innopart::open");
@ -942,16 +941,11 @@ ha_innopart::open(
ut_ad(table->part_info != NULL); ut_ad(table->part_info != NULL);
m_part_info = table->part_info; m_part_info = table->part_info;
} }
thd = ha_thd();
/* Under some cases MySQL seems to call this function while /* Under some cases MySQL seems to call this function while
holding search latch(es). This breaks the latching order as holding search latch(es). This breaks the latching order as
we acquire dict_sys->mutex below and leads to a deadlock. */ we acquire dict_sys->mutex below and leads to a deadlock. */
if (thd != NULL) {
innobase_release_temporary_latches(ht, thd);
}
normalize_table_name(norm_name, name); normalize_table_name(norm_name, name);
m_user_thd = NULL; m_user_thd = NULL;
@ -1017,6 +1011,7 @@ share_error:
MONITOR_INC(MONITOR_TABLE_OPEN); MONITOR_INC(MONITOR_TABLE_OPEN);
bool no_tablespace; bool no_tablespace;
THD* thd = ha_thd();
/* TODO: Should we do this check for every partition during ::open()? */ /* TODO: Should we do this check for every partition during ::open()? */
/* TODO: refactor this in ha_innobase so it can increase code reuse. */ /* TODO: refactor this in ha_innobase so it can increase code reuse. */
@ -1372,15 +1367,8 @@ void ha_innopart::clear_ins_upd_nodes()
int int
ha_innopart::close() ha_innopart::close()
{ {
THD* thd;
DBUG_ENTER("ha_innopart::close"); DBUG_ENTER("ha_innopart::close");
thd = ha_thd();
if (thd != NULL) {
innobase_release_temporary_latches(ht, thd);
}
ut_ad(m_pcur_parts == NULL); ut_ad(m_pcur_parts == NULL);
ut_ad(m_clust_pcur_parts == NULL); ut_ad(m_clust_pcur_parts == NULL);
close_partitioning(); close_partitioning();
@ -3032,11 +3020,6 @@ ha_innopart::records_in_range(
m_prebuilt->trx->op_info = (char*)"estimating records in index range"; m_prebuilt->trx->op_info = (char*)"estimating records in index range";
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads. */
trx_assert_no_search_latch(m_prebuilt->trx);
active_index = keynr; active_index = keynr;
key = table->key_info + active_index; key = table->key_info + active_index;
@ -3171,11 +3154,6 @@ ha_innopart::estimate_rows_upper_bound()
m_prebuilt->trx->op_info = "calculating upper bound for table rows"; m_prebuilt->trx->op_info = "calculating upper bound for table rows";
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads. */
trx_assert_no_search_latch(m_prebuilt->trx);
for (uint i = m_part_info->get_first_used_partition(); for (uint i = m_part_info->get_first_used_partition();
i < m_tot_parts; i < m_tot_parts;
i = m_part_info->get_next_used_partition(i)) { i = m_part_info->get_next_used_partition(i)) {
@ -3287,12 +3265,7 @@ ha_innopart::info_low(
update_thd(ha_thd()); update_thd(ha_thd());
/* In case MySQL calls this in the middle of a SELECT query, release m_prebuilt->trx->op_info = "returning various info to MySQL";
possible adaptive hash latch to avoid deadlocks of threads. */
m_prebuilt->trx->op_info = (char*)"returning various info to MySQL";
trx_assert_no_search_latch(m_prebuilt->trx);
ut_ad(m_part_share->get_table_part(0)->n_ref_count > 0); ut_ad(m_part_share->get_table_part(0)->n_ref_count > 0);

View File

@ -591,7 +591,6 @@ ha_innobase::check_if_supported_inplace_alter(
} }
update_thd(); update_thd();
trx_assert_no_search_latch(m_prebuilt->trx);
/* Change on engine specific table options require rebuild of the /* Change on engine specific table options require rebuild of the
table */ table */

View File

@ -699,8 +699,7 @@ fill_innodb_trx_from_cache(
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
/* trx_adaptive_hash_latched */ /* trx_adaptive_hash_latched */
OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store( OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store(0, true));
row->trx_has_search_latch, true));
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
/* trx_is_read_only*/ /* trx_is_read_only*/

View File

@ -1,6 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
@ -479,11 +480,11 @@ void
log_free_check(void) log_free_check(void)
/*================*/ /*================*/
{ {
#ifdef UNIV_DEBUG
/* During row_log_table_apply(), this function will be called while we /* During row_log_table_apply(), this function will be called while we
are holding some latches. This is OK, as long as we are not holding are holding some latches. This is OK, as long as we are not holding
any latches on buffer blocks. */ any latches on buffer blocks. */
#ifdef UNIV_DEBUG
static const latch_level_t latches[] = { static const latch_level_t latches[] = {
SYNC_DICT, /* dict_sys->mutex during SYNC_DICT, /* dict_sys->mutex during
commit_try_rebuild() */ commit_try_rebuild() */
@ -491,13 +492,12 @@ log_free_check(void)
commit_try_rebuild() */ commit_try_rebuild() */
SYNC_INDEX_TREE /* index->lock */ SYNC_INDEX_TREE /* index->lock */
}; };
sync_allowed_latches check(
latches, latches + sizeof(latches)/sizeof(*latches));
ut_ad(!sync_check_iterate(check));
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
ut_ad(!sync_check_iterate(
sync_allowed_latches(latches,
latches + UT_ARR_SIZE(latches))));
if (log_sys->check_flush_or_checkpoint) { if (log_sys->check_flush_or_checkpoint) {
log_check_margins(); log_check_margins();

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. Copyright (c) 2017, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described Google, Inc. Those modifications are gratefully acknowledged and are described
@ -84,10 +84,10 @@ sync_check_find(latch_level_t level);
/** Checks that the level array for the current thread is empty. /** Checks that the level array for the current thread is empty.
Terminate iteration if the functor returns true. Terminate iteration if the functor returns true.
@param[in,out] functor called for each element. @param[in] functor called for each element.
@return true if the functor returns true */ @return true if the functor returns true for any element */
bool bool
sync_check_iterate(sync_check_functor_t& functor); sync_check_iterate(const sync_check_functor_t& functor);
/** Acquires the debug mutex. We cannot use the mutex defined in sync0sync, /** Acquires the debug mutex. We cannot use the mutex defined in sync0sync,
because the debug mutex is also acquired in sync0arr while holding the OS because the debug mutex is also acquired in sync0arr while holding the OS

View File

@ -1078,108 +1078,43 @@ struct latch_t {
/** Subclass this to iterate over a thread's acquired latch levels. */ /** Subclass this to iterate over a thread's acquired latch levels. */
struct sync_check_functor_t { struct sync_check_functor_t {
virtual ~sync_check_functor_t() { } virtual bool operator()(const latch_level_t) const = 0;
virtual bool operator()(const latch_level_t) = 0;
virtual bool result() const = 0;
}; };
#ifdef BTR_CUR_HASH_ADAPT /** Check that no latch is being held.
/** Functor to check whether the calling thread owns the btr search mutex. */ @tparam some_allowed whether some latches are allowed to be held */
struct btrsea_sync_check : public sync_check_functor_t { template<bool some_allowed = false>
struct sync_checker : public sync_check_functor_t
/** Constructor {
@param[in] has_search_latch true if owns the latch */
explicit btrsea_sync_check(bool has_search_latch)
:
m_result(),
m_has_search_latch(has_search_latch) { }
/** Destructor */
virtual ~btrsea_sync_check() { }
/** Called for every latch owned by the calling thread.
@param[in] level Level of the existing latch
@return true if the predicate check is successful */
virtual bool operator()(const latch_level_t level)
{
/* If calling thread doesn't hold search latch then
check if there are latch level exception provided. */
if (!m_has_search_latch
&& (level != SYNC_SEARCH_SYS
&& level != SYNC_FTS_CACHE)) {
m_result = true;
return(m_result);
}
return(false);
}
/** @return result from the check */
virtual bool result() const
{
return(m_result);
}
private:
/** True if all OK */
bool m_result;
/** If the caller owns the search latch */
const bool m_has_search_latch;
};
#endif /* BTR_CUR_HASH_ADAPT */
/** Functor to check for dictionay latching constraints. */
struct dict_sync_check : public sync_check_functor_t {
/** Constructor
@param[in] dict_mutex_allow true if the dict mutex
is allowed */
explicit dict_sync_check(bool dict_mutex_allowed)
:
m_result(),
m_dict_mutex_allowed(dict_mutex_allowed) { }
/** Destructor */
virtual ~dict_sync_check() { }
/** Check the latching constraints /** Check the latching constraints
@param[in] level The level held by the thread */ @param[in] level The level held by the thread
virtual bool operator()(const latch_level_t level) @return whether a latch violation was detected */
bool operator()(const latch_level_t level) const
{ {
if (!m_dict_mutex_allowed if (some_allowed) {
|| (level != SYNC_DICT switch (level) {
&& level != SYNC_DICT_OPERATION case SYNC_RECV_WRITER:
&& level != SYNC_FTS_CACHE /* This only happens in
/* This only happens in recv_apply_hashed_log_recs. */ recv_apply_hashed_log_recs. */
&& level != SYNC_RECV_WRITER case SYNC_DICT:
&& level != SYNC_NO_ORDER_CHECK)) { case SYNC_DICT_OPERATION:
case SYNC_FTS_CACHE:
m_result = true; case SYNC_NO_ORDER_CHECK:
return(false);
return(true); default:
return(true);
}
} }
return(false); return(true);
} }
/** @return the result of the check */
virtual bool result() const
{
return(m_result);
}
private:
/** True if all OK */
bool m_result;
/** True if it is OK to hold the dict mutex */
const bool m_dict_mutex_allowed;
}; };
/** The strict latch checker (no InnoDB latches may be held) */
typedef struct sync_checker<false> sync_check;
/** The sloppy latch checker (can hold InnoDB dictionary or SQL latches) */
typedef struct sync_checker<true> dict_sync_check;
/** Functor to check for given latching constraints. */ /** Functor to check for given latching constraints. */
struct sync_allowed_latches : public sync_check_functor_t { struct sync_allowed_latches : public sync_check_functor_t {
@ -1189,9 +1124,7 @@ struct sync_allowed_latches : public sync_check_functor_t {
sync_allowed_latches( sync_allowed_latches(
const latch_level_t* from, const latch_level_t* from,
const latch_level_t* to) const latch_level_t* to)
: : begin(from), end(to) { }
m_result(),
m_latches(from, to) { }
/** Checks whether the given latch_t violates the latch constraint. /** Checks whether the given latch_t violates the latch constraint.
This object maintains a list of allowed latch levels, and if the given This object maintains a list of allowed latch levels, and if the given
@ -1199,41 +1132,17 @@ struct sync_allowed_latches : public sync_check_functor_t {
then it is a violation. then it is a violation.
@param[in] latch The latch level to check @param[in] latch The latch level to check
@return true if there is a latch ordering violation */ @return true if there is a latch violation */
virtual bool operator()(const latch_level_t level) bool operator()(const latch_level_t level) const
{ {
for (latches_t::const_iterator it = m_latches.begin(); return(std::find(begin, end, level) == end);
it != m_latches.end();
++it) {
if (level == *it) {
m_result = false;
/* No violation */
return(false);
}
}
return(true);
}
/** @return the result of the check */
virtual bool result() const
{
return(m_result);
} }
private: private:
/** Save the result of validation check here /** First element in an array of allowed latch levels */
True if all OK */ const latch_level_t* const begin;
bool m_result; /** First element after the end of the array of allowed latch levels */
const latch_level_t* const end;
typedef std::vector<latch_level_t, ut_allocator<latch_level_t> >
latches_t;
/** List of latch levels that are allowed to be held */
latches_t m_latches;
}; };
/** Get the latch id from a latch name. /** Get the latch id from a latch name.

View File

@ -1,6 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
@ -162,10 +163,6 @@ struct i_s_trx_row_t {
/*!< check_foreigns in trx_t */ /*!< check_foreigns in trx_t */
const char* trx_foreign_key_error; const char* trx_foreign_key_error;
/*!< detailed_error in trx_t */ /*!< detailed_error in trx_t */
#ifdef BTR_CUR_HASH_ADAPT
ibool trx_has_search_latch;
/*!< has_search_latch in trx_t */
#endif /* BTR_CUR_HASH_ADAPT */
ulint trx_is_read_only; ulint trx_is_read_only;
/*!< trx_t::read_only */ /*!< trx_t::read_only */
ulint trx_is_autocommit_non_locking; ulint trx_is_autocommit_non_locking;

View File

@ -58,15 +58,6 @@ class FlushObserver;
/** Dummy session used currently in MySQL interface */ /** Dummy session used currently in MySQL interface */
extern sess_t* trx_dummy_sess; extern sess_t* trx_dummy_sess;
#ifdef BTR_CUR_HASH_ADAPT
/** Assert that the transaction is not holding the adaptive hash index latch.
@param[in] trx transaction */
# define trx_assert_no_search_latch(trx) \
ut_ad(!trx->has_search_latch)
#else /* BTR_CUR_HASH_ADAPT */
# define trx_assert_no_search_latch(trx)
#endif
/** Set flush observer for the transaction /** Set flush observer for the transaction
@param[in/out] trx transaction struct @param[in/out] trx transaction struct
@param[in] observer flush observer */ @param[in] observer flush observer */
@ -1072,11 +1063,6 @@ struct trx_t {
flush the log in flush the log in
trx_commit_complete_for_mysql() */ trx_commit_complete_for_mysql() */
ulint duplicates; /*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */ ulint duplicates; /*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */
#ifdef BTR_CUR_HASH_ADAPT
bool has_search_latch;
/*!< TRUE if this trx has latched the
search system latch in S-mode */
#endif /* BTR_CUR_HASH_ADAPT */
trx_dict_op_t dict_operation; /**< @see enum trx_dict_op_t */ trx_dict_op_t dict_operation; /**< @see enum trx_dict_op_t */
/* Fields protected by the srv_conc_mutex. */ /* Fields protected by the srv_conc_mutex. */
@ -1508,17 +1494,11 @@ private:
} }
/* Avoid excessive mutex acquire/release */ /* Avoid excessive mutex acquire/release */
if (++trx->in_depth > 1) { if (trx->in_depth++) {
/* The transaction is already inside InnoDB. */ /* The transaction is already inside InnoDB. */
ut_ad(trx->in_depth > 1);
return; return;
} }
/* Only the owning thread should release the latch. */
ut_ad(trx->in_depth == 1);
trx_assert_no_search_latch(trx);
trx_mutex_enter(trx); trx_mutex_enter(trx);
wait(trx); wait(trx);
@ -1543,16 +1523,10 @@ private:
ut_ad(trx->in_depth > 0); ut_ad(trx->in_depth > 0);
if (--trx->in_depth > 0) { if (--trx->in_depth) {
ut_ad(trx->in_depth);
return; return;
} }
/* Only the owning thread should release the latch. */
ut_ad(trx->in_depth == 0);
trx_assert_no_search_latch(trx);
trx_mutex_enter(trx); trx_mutex_enter(trx);
ut_ad((trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) > 0); ut_ad((trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) > 0);

View File

@ -677,14 +677,13 @@ log_set_capacity()
{ {
lsn_t margin; lsn_t margin;
ulint free; ulint free;
bool success = true;
lsn_t smallest_capacity;
log_mutex_enter(); lsn_t smallest_capacity = ((srv_log_file_size_requested
<< srv_page_size_shift)
smallest_capacity = log_group_get_capacity(&log_sys->log); - LOG_FILE_HDR_SIZE)
* srv_n_log_files;
/* Add extra safety */ /* Add extra safety */
smallest_capacity = smallest_capacity - smallest_capacity / 10; smallest_capacity -= smallest_capacity / 10;
/* For each OS thread we must reserve so much free space in the /* For each OS thread we must reserve so much free space in the
smallest log group that it can accommodate the log entries produced smallest log group that it can accommodate the log entries produced
@ -694,15 +693,20 @@ log_set_capacity()
free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency) free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)
+ LOG_CHECKPOINT_EXTRA_FREE; + LOG_CHECKPOINT_EXTRA_FREE;
if (free >= smallest_capacity / 2) { if (free >= smallest_capacity / 2) {
success = false; ib::error() << "Cannot continue operation. ib_logfiles are too"
" small for innodb_thread_concurrency="
goto failure; << srv_thread_concurrency << ". The combined size of"
} else { " ib_logfiles should be bigger than"
margin = smallest_capacity - free; " 200 kB * innodb_thread_concurrency. "
<< INNODB_PARAMETERS_MSG;
return(false);
} }
margin = smallest_capacity - free;
margin = margin - margin / 10; /* Add still some extra safety */ margin = margin - margin / 10; /* Add still some extra safety */
log_mutex_enter();
log_sys->log_group_capacity = smallest_capacity; log_sys->log_group_capacity = smallest_capacity;
log_sys->max_modified_age_async = margin log_sys->max_modified_age_async = margin
@ -714,19 +718,9 @@ log_set_capacity()
/ LOG_POOL_CHECKPOINT_RATIO_ASYNC; / LOG_POOL_CHECKPOINT_RATIO_ASYNC;
log_sys->max_checkpoint_age = margin; log_sys->max_checkpoint_age = margin;
failure:
log_mutex_exit(); log_mutex_exit();
if (!success) { return(true);
ib::error() << "Cannot continue operation. ib_logfiles are too"
" small for innodb_thread_concurrency="
<< srv_thread_concurrency << ". The combined size of"
" ib_logfiles should be bigger than"
" 200 kB * innodb_thread_concurrency. "
<< INNODB_PARAMETERS_MSG;
}
return(success);
} }
/** Initializes the redo logging subsystem. */ /** Initializes the redo logging subsystem. */

View File

@ -2231,16 +2231,7 @@ stop_for_a_while:
btr_pcur_store_position(&(plan->pcur), &mtr); btr_pcur_store_position(&(plan->pcur), &mtr);
mtr_commit(&mtr); mtr_commit(&mtr);
ut_ad(!sync_check_iterate(sync_check()));
#ifdef BTR_CUR_HASH_ADAPT
# ifdef UNIV_DEBUG
{
btrsea_sync_check check(true);
ut_ad(!sync_check_iterate(check));
}
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
err = DB_SUCCESS; err = DB_SUCCESS;
goto func_exit; goto func_exit;
@ -2258,14 +2249,7 @@ commit_mtr_for_a_while:
mtr_commit(&mtr); mtr_commit(&mtr);
mtr_has_extra_clust_latch = FALSE; mtr_has_extra_clust_latch = FALSE;
ut_ad(!sync_check_iterate(dict_sync_check()));
#ifdef UNIV_DEBUG
{
dict_sync_check check(true);
ut_ad(!sync_check_iterate(check));
}
#endif /* UNIV_DEBUG */
goto table_loop; goto table_loop;
@ -2280,20 +2264,13 @@ lock_wait_or_error:
mtr_commit(&mtr); mtr_commit(&mtr);
#ifdef UNIV_DEBUG
{
dict_sync_check check(true);
ut_ad(!sync_check_iterate(check));
}
#endif /* UNIV_DEBUG */
func_exit: func_exit:
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
if (search_latch_locked) { if (search_latch_locked) {
btr_search_s_unlock(index); btr_search_s_unlock(index);
} }
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
ut_ad(!sync_check_iterate(dict_sync_check()));
if (heap != NULL) { if (heap != NULL) {
mem_heap_free(heap); mem_heap_free(heap);
@ -3041,7 +3018,6 @@ row_sel_store_mysql_field_func(
mem_heap_t* heap; mem_heap_t* heap;
/* Copy an externally stored field to a temporary heap */ /* Copy an externally stored field to a temporary heap */
trx_assert_no_search_latch(prebuilt->trx);
ut_ad(field_no == templ->clust_rec_field_no); ut_ad(field_no == templ->clust_rec_field_no);
ut_ad(templ->type != DATA_POINT); ut_ad(templ->type != DATA_POINT);
@ -3928,11 +3904,7 @@ row_sel_try_search_shortcut_for_mysql(
ut_ad(!prebuilt->templ_contains_blob); ut_ad(!prebuilt->templ_contains_blob);
btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE, btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, pcur, BTR_SEARCH_LEAF, pcur, RW_S_LATCH, mtr);
(trx->has_search_latch)
? RW_S_LATCH
: 0,
mtr);
rec = btr_pcur_get_rec(pcur); rec = btr_pcur_get_rec(pcur);
if (!page_rec_is_user_rec(rec)) { if (!page_rec_is_user_rec(rec)) {
@ -4190,14 +4162,7 @@ row_search_mvcc(
DBUG_RETURN(DB_END_OF_INDEX); DBUG_RETURN(DB_END_OF_INDEX);
} }
#ifdef BTR_CUR_HASH_ADAPT ut_ad(!sync_check_iterate(sync_check()));
# ifdef UNIV_DEBUG
{
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
}
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
if (dict_table_is_discarded(prebuilt->table)) { if (dict_table_is_discarded(prebuilt->table)) {
@ -4222,8 +4187,6 @@ row_search_mvcc(
&& (prebuilt->read_just_key && (prebuilt->read_just_key
|| prebuilt->m_read_virtual_key); || prebuilt->m_read_virtual_key);
trx_assert_no_search_latch(trx);
/* Reset the new record lock info if srv_locks_unsafe_for_binlog /* Reset the new record lock info if srv_locks_unsafe_for_binlog
is set or session is using a READ COMMITED isolation level. Then is set or session is using a READ COMMITED isolation level. Then
we are able to remove the record locks set here on an individual we are able to remove the record locks set here on an individual
@ -4378,9 +4341,7 @@ row_search_mvcc(
and if we try that, we can deadlock on the adaptive and if we try that, we can deadlock on the adaptive
hash index semaphore! */ hash index semaphore! */
trx_assert_no_search_latch(trx);
rw_lock_s_lock(btr_get_search_latch(index)); rw_lock_s_lock(btr_get_search_latch(index));
trx->has_search_latch = true;
switch (row_sel_try_search_shortcut_for_mysql( switch (row_sel_try_search_shortcut_for_mysql(
&rec, prebuilt, &offsets, &heap, &rec, prebuilt, &offsets, &heap,
@ -4435,7 +4396,6 @@ row_search_mvcc(
err = DB_SUCCESS; err = DB_SUCCESS;
rw_lock_s_unlock(btr_get_search_latch(index)); rw_lock_s_unlock(btr_get_search_latch(index));
trx->has_search_latch = false;
goto func_exit; goto func_exit;
@ -4446,7 +4406,6 @@ row_search_mvcc(
err = DB_RECORD_NOT_FOUND; err = DB_RECORD_NOT_FOUND;
rw_lock_s_unlock(btr_get_search_latch(index)); rw_lock_s_unlock(btr_get_search_latch(index));
trx->has_search_latch = false;
/* NOTE that we do NOT store the cursor /* NOTE that we do NOT store the cursor
position */ position */
@ -4464,7 +4423,6 @@ row_search_mvcc(
mtr_start(&mtr); mtr_start(&mtr);
rw_lock_s_unlock(btr_get_search_latch(index)); rw_lock_s_unlock(btr_get_search_latch(index));
trx->has_search_latch = false;
} }
} }
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
@ -4472,8 +4430,6 @@ row_search_mvcc(
/*-------------------------------------------------------------*/ /*-------------------------------------------------------------*/
/* PHASE 3: Open or restore index cursor position */ /* PHASE 3: Open or restore index cursor position */
trx_assert_no_search_latch(trx);
spatial_search = dict_index_is_spatial(index) spatial_search = dict_index_is_spatial(index)
&& mode >= PAGE_CUR_CONTAIN; && mode >= PAGE_CUR_CONTAIN;
@ -5787,15 +5743,7 @@ func_exit:
} }
} }
#ifdef BTR_CUR_HASH_ADAPT ut_ad(!sync_check_iterate(sync_check()));
# ifdef UNIV_DEBUG
{
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
}
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
DEBUG_SYNC_C("innodb_row_search_for_mysql_exit"); DEBUG_SYNC_C("innodb_row_search_for_mysql_exit");

View File

@ -197,11 +197,6 @@ srv_conc_enter_innodb_with_atomics(
(void) my_atomic_addlint( (void) my_atomic_addlint(
&srv_conc.n_waiting, 1); &srv_conc.n_waiting, 1);
/* Release possible search system latch this
thread has */
trx_assert_no_search_latch(trx);
thd_wait_begin(trx->mysql_thd, THD_WAIT_USER_LOCK); thd_wait_begin(trx->mysql_thd, THD_WAIT_USER_LOCK);
notified_mysql = TRUE; notified_mysql = TRUE;
@ -257,15 +252,7 @@ srv_conc_enter_innodb(
{ {
trx_t* trx = prebuilt->trx; trx_t* trx = prebuilt->trx;
#ifdef BTR_CUR_HASH_ADAPT ut_ad(!sync_check_iterate(sync_check()));
# ifdef UNIV_DEBUG
{
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
}
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
srv_conc_enter_innodb_with_atomics(trx); srv_conc_enter_innodb_with_atomics(trx);
} }
@ -279,15 +266,7 @@ srv_conc_force_enter_innodb(
trx_t* trx) /*!< in: transaction object associated with the trx_t* trx) /*!< in: transaction object associated with the
thread */ thread */
{ {
#ifdef BTR_CUR_HASH_ADAPT ut_ad(!sync_check_iterate(sync_check()));
# ifdef UNIV_DEBUG
{
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
}
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
if (!srv_thread_concurrency) { if (!srv_thread_concurrency) {
@ -320,15 +299,7 @@ srv_conc_force_exit_innodb(
srv_conc_exit_innodb_with_atomics(trx); srv_conc_exit_innodb_with_atomics(trx);
#ifdef BTR_CUR_HASH_ADAPT ut_ad(!sync_check_iterate(sync_check()));
# ifdef UNIV_DEBUG
{
btrsea_sync_check check(trx->has_search_latch);
ut_ad(!sync_check_iterate(check));
}
# endif /* UNIV_DEBUG */
#endif /* BTR_CUR_HASH_ADAPT */
} }
/*********************************************************************//** /*********************************************************************//**

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. Copyright (c) 2017, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described Google, Inc. Those modifications are gratefully acknowledged and are described
@ -298,29 +298,23 @@ struct LatchDebug {
} }
/** Iterate over a thread's latches. /** Iterate over a thread's latches.
@param[in,out] functor The callback @param[in] functor The callback
@return true if the functor returns true. */ @return true if the functor returns true. */
bool for_each(sync_check_functor_t& functor) bool for_each(const sync_check_functor_t& functor)
UNIV_NOTHROW UNIV_NOTHROW
{ {
const Latches* latches = thread_latches(); if (const Latches* latches = thread_latches()) {
Latches::const_iterator end = latches->end();
for (Latches::const_iterator it = latches->begin();
it != end; ++it) {
if (latches == 0) { if (functor(it->m_level)) {
return(functor.result()); return(true);
} }
Latches::const_iterator end = latches->end();
for (Latches::const_iterator it = latches->begin();
it != end;
++it) {
if (functor(it->m_level)) {
break;
} }
} }
return(functor.result()); return(false);
} }
/** Removes a latch from the thread level array if it is found there. /** Removes a latch from the thread level array if it is found there.
@ -1215,13 +1209,12 @@ sync_check_find(latch_level_t level)
/** Iterate over the thread's latches. /** Iterate over the thread's latches.
@param[in,out] functor called for each element. @param[in,out] functor called for each element.
@return false if the sync debug hasn't been initialised @return true if the functor returns true for any element */
@return the value returned by the functor */
bool bool
sync_check_iterate(sync_check_functor_t& functor) sync_check_iterate(const sync_check_functor_t& functor)
{ {
if (LatchDebug::instance() != NULL) { if (LatchDebug* debug = LatchDebug::instance()) {
return(LatchDebug::instance()->for_each(functor)); return(debug->for_each(functor));
} }
return(false); return(false);

View File

@ -589,10 +589,6 @@ thd_done:
row->trx_foreign_key_error = NULL; row->trx_foreign_key_error = NULL;
} }
#ifdef BTR_CUR_HASH_ADAPT
row->trx_has_search_latch = (ibool) trx->has_search_latch;
#endif /* BTR_CUR_HASH_ADAPT */
row->trx_is_read_only = trx->read_only; row->trx_is_read_only = trx->read_only;
row->trx_is_autocommit_non_locking = trx_is_autocommit_non_locking(trx); row->trx_is_autocommit_non_locking = trx_is_autocommit_non_locking(trx);

View File

@ -272,8 +272,6 @@ struct TrxFactory {
ut_a(trx->lock.wait_lock == NULL); ut_a(trx->lock.wait_lock == NULL);
ut_a(trx->lock.wait_thr == NULL); ut_a(trx->lock.wait_thr == NULL);
trx_assert_no_search_latch(trx);
ut_a(trx->dict_operation_lock_mode == 0); ut_a(trx->dict_operation_lock_mode == 0);
if (trx->lock.lock_heap != NULL) { if (trx->lock.lock_heap != NULL) {
@ -341,9 +339,6 @@ struct TrxFactory {
ut_a(trx->lock.wait_thr == NULL); ut_a(trx->lock.wait_thr == NULL);
ut_a(trx->lock.wait_lock == NULL); ut_a(trx->lock.wait_lock == NULL);
trx_assert_no_search_latch(trx);
ut_a(trx->dict_operation_lock_mode == 0); ut_a(trx->dict_operation_lock_mode == 0);
ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
@ -2413,13 +2408,6 @@ state_ok:
(ulong) n_rec_locks); (ulong) n_rec_locks);
} }
#ifdef BTR_CUR_HASH_ADAPT
if (trx->has_search_latch) {
newline = TRUE;
fputs(", holds adaptive hash latch", f);
}
#endif /* BTR_CUR_HASH_ADAPT */
if (trx->undo_no != 0) { if (trx->undo_no != 0) {
newline = TRUE; newline = TRUE;
fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no); fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no);
@ -2551,11 +2539,6 @@ state_ok:
fprintf(f, "que state %lu ", (ulong) trx->lock.que_state); fprintf(f, "que state %lu ", (ulong) trx->lock.que_state);
} }
if (trx->has_search_latch) {
newline = TRUE;
fputs(", holds adaptive hash latch", f);
}
if (trx->undo_no != 0) { if (trx->undo_no != 0) {
newline = TRUE; newline = TRUE;
fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no); fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no);

View File

@ -1183,9 +1183,6 @@ int ha_myisam::repair(THD *thd, HA_CHECK &param, bool do_optimize)
share->state.dupp_key= MI_MAX_KEY; share->state.dupp_key= MI_MAX_KEY;
strmov(fixed_name,file->filename); strmov(fixed_name,file->filename);
// Release latches since this can take a long time
ha_release_temporary_latches(thd);
/* /*
Don't lock tables if we have used LOCK TABLE or if we come from Don't lock tables if we have used LOCK TABLE or if we come from
enable_index() enable_index()

View File

@ -2122,39 +2122,6 @@ ha_innobase::is_fake_change_enabled(THD* thd)
return(trx && UNIV_UNLIKELY(trx->fake_changes)); return(trx && UNIV_UNLIKELY(trx->fake_changes));
} }
/********************************************************************//**
In XtraDB it is impossible for a transaction to own a search latch outside of
InnoDB code, so there is nothing to release on demand. We keep this function to
simplify maintenance.
@return 0 */
static
int
innobase_release_temporary_latches(
/*===============================*/
handlerton* hton MY_ATTRIBUTE((unused)), /*!< in: handlerton */
THD* thd MY_ATTRIBUTE((unused))) /*!< in: MySQL thread */
{
#ifdef UNIV_DEBUG
DBUG_ASSERT(hton == innodb_hton_ptr);
if (!innodb_inited || thd == NULL) {
return(0);
}
trx_t* trx = thd_to_trx(thd);
if (trx != NULL) {
#ifdef UNIV_SYNC_DEBUG
ut_ad(!btr_search_own_any());
#endif
trx_search_latch_release_if_reserved(trx);
}
#endif
return(0);
}
/********************************************************************//** /********************************************************************//**
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread. This function should be used time calls srv_active_wake_master_thread. This function should be used
@ -3813,9 +3780,6 @@ innobase_init(
innobase_hton->flags = HTON_SUPPORTS_EXTENDED_KEYS | innobase_hton->flags = HTON_SUPPORTS_EXTENDED_KEYS |
HTON_SUPPORTS_FOREIGN_KEYS; HTON_SUPPORTS_FOREIGN_KEYS;
innobase_hton->release_temporary_latches =
innobase_release_temporary_latches;
innobase_hton->kill_query = innobase_kill_connection; innobase_hton->kill_query = innobase_kill_connection;
if (srv_file_per_table) if (srv_file_per_table)
@ -6262,9 +6226,6 @@ ha_innobase::open(
thd = ha_thd(); thd = ha_thd();
/* No-op in XtraDB */
innobase_release_temporary_latches(ht, thd);
normalize_table_name(norm_name, name); normalize_table_name(norm_name, name);
user_thd = NULL; user_thd = NULL;
@ -6724,9 +6685,6 @@ ha_innobase::close()
thd = ha_thd(); thd = ha_thd();
/* No-op in XtraDB */
innobase_release_temporary_latches(ht, thd);
row_prebuilt_free(prebuilt, FALSE); row_prebuilt_free(prebuilt, FALSE);
if (upd_buf != NULL) { if (upd_buf != NULL) {

View File

@ -860,43 +860,16 @@ ibool
log_calc_max_ages(void) log_calc_max_ages(void)
/*===================*/ /*===================*/
{ {
log_group_t* group;
lsn_t margin; lsn_t margin;
ulint free; ulint free;
ibool success = TRUE;
lsn_t smallest_capacity;
lsn_t archive_margin;
lsn_t smallest_archive_margin;
mutex_enter(&(log_sys->mutex)); lsn_t smallest_capacity = ((srv_log_file_size_requested
<< srv_page_size_shift)
group = UT_LIST_GET_FIRST(log_sys->log_groups); - LOG_FILE_HDR_SIZE)
* srv_n_log_files;
ut_ad(group);
smallest_capacity = LSN_MAX;
smallest_archive_margin = LSN_MAX;
while (group) {
if (log_group_get_capacity(group) < smallest_capacity) {
smallest_capacity = log_group_get_capacity(group);
}
archive_margin = log_group_get_capacity(group)
- (group->file_size - LOG_FILE_HDR_SIZE)
- LOG_ARCHIVE_EXTRA_MARGIN;
if (archive_margin < smallest_archive_margin) {
smallest_archive_margin = archive_margin;
}
group = UT_LIST_GET_NEXT(log_groups, group);
}
/* Add extra safety */ /* Add extra safety */
smallest_capacity = smallest_capacity - smallest_capacity / 10; smallest_capacity -= smallest_capacity / 10;
/* For each OS thread we must reserve so much free space in the /* For each OS thread we must reserve so much free space in the
smallest log group that it can accommodate the log entries produced smallest log group that it can accommodate the log entries produced
@ -906,15 +879,16 @@ log_calc_max_ages(void)
free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency) free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)
+ LOG_CHECKPOINT_EXTRA_FREE; + LOG_CHECKPOINT_EXTRA_FREE;
if (free >= smallest_capacity / 2) { if (free >= smallest_capacity / 2) {
success = FALSE; ib_logf(IB_LOG_LEVEL_FATAL,
"The combined size of ib_logfiles"
goto failure; " should be bigger than\n"
} else { "InnoDB: 200 kB * innodb_thread_concurrency.");
margin = smallest_capacity - free;
} }
margin = smallest_capacity - free;
margin = margin - margin / 10; /* Add still some extra safety */ margin = margin - margin / 10; /* Add still some extra safety */
mutex_enter(&log_sys->mutex);
log_sys->log_group_capacity = smallest_capacity; log_sys->log_group_capacity = smallest_capacity;
log_sys->max_modified_age_async = margin log_sys->max_modified_age_async = margin
@ -927,22 +901,17 @@ log_calc_max_ages(void)
log_sys->max_checkpoint_age = margin; log_sys->max_checkpoint_age = margin;
#ifdef UNIV_LOG_ARCHIVE #ifdef UNIV_LOG_ARCHIVE
log_sys->max_archived_lsn_age = smallest_archive_margin; lsn_t archive_margin = smallest_capacity
- (srv_log_file_size_requested - LOG_FILE_HDR_SIZE)
- LOG_ARCHIVE_EXTRA_MARGIN;
log_sys->max_archived_lsn_age = archive_margin;
log_sys->max_archived_lsn_age_async = smallest_archive_margin log_sys->max_archived_lsn_age_async = archive_margin
- smallest_archive_margin / LOG_ARCHIVE_RATIO_ASYNC; - archive_margin / LOG_ARCHIVE_RATIO_ASYNC;
#endif /* UNIV_LOG_ARCHIVE */ #endif /* UNIV_LOG_ARCHIVE */
failure: mutex_exit(&log_sys->mutex);
mutex_exit(&(log_sys->mutex));
if (!success) { return(true);
ib_logf(IB_LOG_LEVEL_FATAL,
"The combined size of ib_logfiles"
" should be bigger than\n"
"InnoDB: 200 kB * innodb_thread_concurrency.");
}
return(success);
} }
/******************************************************//** /******************************************************//**