Commit b46cf33a authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.2 into 10.3

parents 9fc1ef93 1cb218c3
...@@ -23,7 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA ...@@ -23,7 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
#include "common.h" #include "common.h"
#include "datasink.h" #include "datasink.h"
#include "ds_compress.h" #include "ds_compress.h"
#include "ds_archive.h"
#include "ds_xbstream.h" #include "ds_xbstream.h"
#include "ds_local.h" #include "ds_local.h"
#include "ds_stdout.h" #include "ds_stdout.h"
...@@ -45,13 +44,6 @@ ds_create(const char *root, ds_type_t type) ...@@ -45,13 +44,6 @@ ds_create(const char *root, ds_type_t type)
case DS_TYPE_LOCAL: case DS_TYPE_LOCAL:
ds = &datasink_local; ds = &datasink_local;
break; break;
case DS_TYPE_ARCHIVE:
#ifdef HAVE_LIBARCHIVE
ds = &datasink_archive;
#else
die("mariabackup was built without libarchive support");
#endif
break;
case DS_TYPE_XBSTREAM: case DS_TYPE_XBSTREAM:
ds = &datasink_xbstream; ds = &datasink_xbstream;
break; break;
......
...@@ -63,7 +63,6 @@ static inline int dummy_remove(const char *) { ...@@ -63,7 +63,6 @@ static inline int dummy_remove(const char *) {
typedef enum { typedef enum {
DS_TYPE_STDOUT, DS_TYPE_STDOUT,
DS_TYPE_LOCAL, DS_TYPE_LOCAL,
DS_TYPE_ARCHIVE,
DS_TYPE_XBSTREAM, DS_TYPE_XBSTREAM,
DS_TYPE_COMPRESS, DS_TYPE_COMPRESS,
DS_TYPE_ENCRYPT, DS_TYPE_ENCRYPT,
......
/******************************************************
Copyright (c) 2013 Percona LLC and/or its affiliates.
Streaming 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-1335 USA
*******************************************************/
#include <my_global.h>
#include <my_base.h>
#include <archive.h>
#include <archive_entry.h>
#include "common.h"
#include "datasink.h"
#if ARCHIVE_VERSION_NUMBER < 3000000
#define archive_write_add_filter_none(X) archive_write_set_compression_none(X)
#define archive_write_free(X) archive_write_finish(X)
#endif
typedef struct {
struct archive *archive;
ds_file_t *dest_file;
pthread_mutex_t mutex;
} ds_archive_ctxt_t;
typedef struct {
struct archive_entry *entry;
ds_archive_ctxt_t *archive_ctxt;
} ds_archive_file_t;
/***********************************************************************
General archive interface */
static ds_ctxt_t *archive_init(const char *root);
static ds_file_t *archive_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat);
static int archive_write(ds_file_t *file, const void *buf, size_t len);
static int archive_close(ds_file_t *file);
static void archive_deinit(ds_ctxt_t *ctxt);
datasink_t datasink_archive = {
&archive_init,
&archive_open,
&archive_write,
&archive_close,
&dummy_remove,
&archive_deinit
};
static
int
my_archive_open_callback(struct archive *a __attribute__((unused)),
void *data __attribute__((unused)))
{
return ARCHIVE_OK;
}
static
ssize_t
my_archive_write_callback(struct archive *a __attribute__((unused)),
void *data, const void *buffer, size_t length)
{
ds_archive_ctxt_t *archive_ctxt;
archive_ctxt = (ds_archive_ctxt_t *) data;
xb_ad(archive_ctxt != NULL);
xb_ad(archive_ctxt->dest_file != NULL);
if (!ds_write(archive_ctxt->dest_file, buffer, length)) {
return length;
}
return -1;
}
static
int
my_archive_close_callback(struct archive *a __attribute__((unused)),
void *data __attribute__((unused)))
{
return ARCHIVE_OK;
}
static
ds_ctxt_t *
archive_init(const char *root __attribute__((unused)))
{
ds_ctxt_t *ctxt;
ds_archive_ctxt_t *archive_ctxt;
struct archive *a;
ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_archive_ctxt_t),
MYF(MY_FAE));
archive_ctxt = (ds_archive_ctxt_t *)(ctxt + 1);
if (pthread_mutex_init(&archive_ctxt->mutex, NULL)) {
msg("archive_init: pthread_mutex_init() failed.\n");
goto err;
}
a = archive_write_new();
if (a == NULL) {
msg("archive_write_new() failed.\n");
goto err;
}
archive_ctxt->archive = a;
archive_ctxt->dest_file = NULL;
if(archive_write_add_filter_none(a) != ARCHIVE_OK ||
archive_write_set_format_pax_restricted(a) != ARCHIVE_OK ||
/* disable internal buffering so we don't have to flush the
output in xtrabackup */
archive_write_set_bytes_per_block(a, 0) != ARCHIVE_OK) {
msg("failed to set libarchive archive options: %s\n",
archive_error_string(a));
archive_write_free(a);
goto err;
}
if (archive_write_open(a, archive_ctxt, my_archive_open_callback,
my_archive_write_callback,
my_archive_close_callback) != ARCHIVE_OK) {
msg("cannot open output archive.\n");
return NULL;
}
ctxt->ptr = archive_ctxt;
return ctxt;
err:
my_free(ctxt);
return NULL;
}
static
ds_file_t *
archive_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
{
ds_archive_ctxt_t *archive_ctxt;
ds_ctxt_t *dest_ctxt;
ds_file_t *file;
ds_archive_file_t *archive_file;
struct archive *a;
struct archive_entry *entry;
xb_ad(ctxt->pipe_ctxt != NULL);
dest_ctxt = ctxt->pipe_ctxt;
archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr;
pthread_mutex_lock(&archive_ctxt->mutex);
if (archive_ctxt->dest_file == NULL) {
archive_ctxt->dest_file = ds_open(dest_ctxt, path, mystat);
if (archive_ctxt->dest_file == NULL) {
return NULL;
}
}
pthread_mutex_unlock(&archive_ctxt->mutex);
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) +
sizeof(ds_archive_file_t),
MYF(MY_FAE));
archive_file = (ds_archive_file_t *) (file + 1);
a = archive_ctxt->archive;
entry = archive_entry_new();
if (entry == NULL) {
msg("archive_entry_new() failed.\n");
goto err;
}
archive_entry_set_size(entry, mystat->st_size);
archive_entry_set_mode(entry, 0660);
archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_set_pathname(entry, path);
archive_entry_set_mtime(entry, mystat->st_mtime, 0);
archive_file->entry = entry;
archive_file->archive_ctxt = archive_ctxt;
if (archive_write_header(a, entry) != ARCHIVE_OK) {
msg("archive_write_header() failed.\n");
archive_entry_free(entry);
goto err;
}
file->ptr = archive_file;
file->path = archive_ctxt->dest_file->path;
return file;
err:
if (archive_ctxt->dest_file) {
ds_close(archive_ctxt->dest_file);
archive_ctxt->dest_file = NULL;
}
my_free(file);
return NULL;
}
static
int
archive_write(ds_file_t *file, const void *buf, size_t len)
{
ds_archive_file_t *archive_file;
struct archive *a;
archive_file = (ds_archive_file_t *) file->ptr;
a = archive_file->archive_ctxt->archive;
xb_ad(archive_file->archive_ctxt->dest_file != NULL);
if (archive_write_data(a, buf, len) < 0) {
msg("archive_write_data() failed: %s (errno = %d)\n",
archive_error_string(a), archive_errno(a));
return 1;
}
return 0;
}
static
int
archive_close(ds_file_t *file)
{
ds_archive_file_t *archive_file;
int rc = 0;
archive_file = (ds_archive_file_t *)file->ptr;
archive_entry_free(archive_file->entry);
my_free(file);
return rc;
}
static
void
archive_deinit(ds_ctxt_t *ctxt)
{
struct archive *a;
ds_archive_ctxt_t *archive_ctxt;
archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr;
a = archive_ctxt->archive;
if (archive_write_close(a) != ARCHIVE_OK) {
msg("archive_write_close() failed.\n");
}
archive_write_free(a);
if (archive_ctxt->dest_file) {
ds_close(archive_ctxt->dest_file);
archive_ctxt->dest_file = NULL;
}
pthread_mutex_destroy(&archive_ctxt->mutex);
my_free(ctxt);
}
/******************************************************
Copyright (c) 2013 Percona LLC and/or its affiliates.
Streaming 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-1335 USA
*******************************************************/
#ifndef DS_ARCHIVE_H
#define DS_ARCHIVE_H
#include "datasink.h"
extern datasink_t datasink_archive;
#endif
...@@ -126,15 +126,19 @@ xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) ...@@ -126,15 +126,19 @@ xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
pthread_mutex_lock(&stream_ctxt->mutex); pthread_mutex_lock(&stream_ctxt->mutex);
if (stream_ctxt->dest_file == NULL) { if (stream_ctxt->dest_file == NULL) {
stream_ctxt->dest_file = ds_open(dest_ctxt, path, mystat); stream_ctxt->dest_file = ds_open(dest_ctxt, path, mystat);
}
pthread_mutex_unlock(&stream_ctxt->mutex);
if (stream_ctxt->dest_file == NULL) { if (stream_ctxt->dest_file == NULL) {
return NULL; return NULL;
} }
}
pthread_mutex_unlock(&stream_ctxt->mutex);
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + file = (ds_file_t *) my_malloc(sizeof(ds_file_t) +
sizeof(ds_stream_file_t), sizeof(ds_stream_file_t),
MYF(MY_FAE)); MYF(MY_FAE));
if (!file) {
msg("my_malloc() failed.");
goto err;
}
stream_file = (ds_stream_file_t *) (file + 1); stream_file = (ds_stream_file_t *) (file + 1);
xbstream = stream_ctxt->xbstream; xbstream = stream_ctxt->xbstream;
......
...@@ -2261,7 +2261,7 @@ servers \- remote (federated) servers as \fBCREATE SERVER\fR\&. ...@@ -2261,7 +2261,7 @@ servers \- remote (federated) servers as \fBCREATE SERVER\fR\&.
.sp -1 .sp -1
.IP \(bu 2.3 .IP \(bu 2.3
.\} .\}
stats \- statistics tables, InnoDB and Engine Independent Table Statistics (EITS), are dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-into\fR is specified) statements without (re)creating tables\&. stats \- statistics tables, InnoDB and Engine Independent Table Statistics (EITS), are dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-ignore\fR is specified) statements without (re)creating tables\&.
.RE .RE
.RS 4 .RS 4
.ie n \{\ .ie n \{\
...@@ -2271,17 +2271,17 @@ stats \- statistics tables, InnoDB and Engine Independent Table Statistics (EITS ...@@ -2271,17 +2271,17 @@ stats \- statistics tables, InnoDB and Engine Independent Table Statistics (EITS
.sp -1 .sp -1
.IP \(bu 2.3 .IP \(bu 2.3
.\} .\}
timezones \- timezone related system tables dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-into\fR is specified) statements without (re)creating tables\&. timezones \- timezone related system tables dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-ignore\fR is specified) statements without (re)creating tables\&.
.RE .RE
.sp .sp
The format of the output is affected by \fB\-\-replace\fR and \fB\-\-insert\-into\fR\&. The \fB\-\-replace\fR option will output \fBCREATE OR REPLACE\fR The format of the output is affected by \fB\-\-replace\fR and \fB\-\-insert\-ignore\fR\&. The \fB\-\-replace\fR option will output \fBCREATE OR REPLACE\fR
forms of SQL, and also \fBDROP IF EXISTS\fR prior to \fBCREATE\fR, if a \fBCREATE OR REPLACE\fR option isn't available. forms of SQL, and also \fBDROP IF EXISTS\fR prior to \fBCREATE\fR, if a \fBCREATE OR REPLACE\fR option isn't available.
.sp .sp
With \fB\-\-system=user\fR (or \fBall\fR), and \fB\-\-replace\fR, SQL is generated to generate an error if attempting to import the dump with a connection user that is being replaced within the dump\&. With \fB\-\-system=user\fR (or \fBall\fR), and \fB\-\-replace\fR, SQL is generated to generate an error if attempting to import the dump with a connection user that is being replaced within the dump\&.
.sp .sp
The \fB\-\-insert\-into\fR option will cause \fBCREATE IF NOT EXIST\fR forms of SQL to generated if available. The \fB\-\-insert\-ignore\fR option will cause \fBCREATE IF NOT EXIST\fR forms of SQL to generated if available.
.sp .sp
For stats, and timezones, \fB\-\-replace\fR and \fB\-\-insert\-into\fR have the usual effects. For stats, and timezones, \fB\-\-replace\fR and \fB\-\-insert\-ignore\fR have the usual effects.
.sp .sp
Enabling specific options here will cause the relevant tables in the mysql database to be ignored when dumping the mysql database or \fB\-\-all\-databases\fR\&. Enabling specific options here will cause the relevant tables in the mysql database to be ignored when dumping the mysql database or \fB\-\-all\-databases\fR\&.
.sp .sp
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
CREATE TABLE t1 (a INT) ENGINE=MyISAM; CREATE TABLE t1 (a INT) ENGINE=MyISAM;
LOCK TABLE t1 READ; LOCK TABLE t1 READ;
connect con1,localhost,root,,test; connect con1,localhost,root,,test;
SET SESSION max_session_mem_used= 65536; SET SESSION max_session_mem_used= 45500;
LOCK TABLE t1 WRITE; LOCK TABLE t1 WRITE;
connection default; connection default;
SELECT * FROM t1; SELECT * FROM t1;
...@@ -13,7 +13,7 @@ a ...@@ -13,7 +13,7 @@ a
UNLOCK TABLES; UNLOCK TABLES;
connection con1; connection con1;
TRUNCATE TABLE t1; TRUNCATE TABLE t1;
ERROR HY000: The MariaDB server is running with the --max-thread-mem-used=65536 option so it cannot execute this statement ERROR HY000: The MariaDB server is running with the --max-thread-mem-used=45500 option so it cannot execute this statement
disconnect con1; disconnect con1;
connection default; connection default;
DROP TABLE t1; DROP TABLE t1;
......
...@@ -9,7 +9,7 @@ CREATE TABLE t1 (a INT) ENGINE=MyISAM; ...@@ -9,7 +9,7 @@ CREATE TABLE t1 (a INT) ENGINE=MyISAM;
LOCK TABLE t1 READ; LOCK TABLE t1 READ;
--connect (con1,localhost,root,,test) --connect (con1,localhost,root,,test)
SET SESSION max_session_mem_used= 65536; SET SESSION max_session_mem_used= 45500;
--send --send
LOCK TABLE t1 WRITE; LOCK TABLE t1 WRITE;
......
...@@ -19,7 +19,7 @@ innodb_system ...@@ -19,7 +19,7 @@ innodb_system
# Success! # Success!
# Now turn off encryption and wait for threads to decrypt everything # Now turn off encryption and wait for threads to decrypt everything
SET GLOBAL innodb_encrypt_tables = off; SET GLOBAL innodb_encrypt_tables = off;
# Wait max 10 min for key encryption threads to encrypt all spaces # Wait max 10 min for key encryption threads to decrypt all spaces
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0
AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry';
NAME NAME
......
...@@ -14,7 +14,9 @@ SHOW VARIABLES LIKE 'innodb_encrypt%'; ...@@ -14,7 +14,9 @@ SHOW VARIABLES LIKE 'innodb_encrypt%';
SET GLOBAL innodb_encrypt_tables = ON; SET GLOBAL innodb_encrypt_tables = ON;
--let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` let $undo_count= `select @@global.innodb_undo_tablespaces`;
--let $tables_count= `select count(*) + 1 + $undo_count from information_schema.tables where engine = 'InnoDB'`
--echo # Wait max 10 min for key encryption threads to encrypt all spaces --echo # Wait max 10 min for key encryption threads to encrypt all spaces
--let $wait_timeout= 600 --let $wait_timeout= 600
...@@ -33,7 +35,7 @@ AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NA ...@@ -33,7 +35,7 @@ AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NA
--echo # Now turn off encryption and wait for threads to decrypt everything --echo # Now turn off encryption and wait for threads to decrypt everything
SET GLOBAL innodb_encrypt_tables = off; SET GLOBAL innodb_encrypt_tables = off;
--echo # Wait max 10 min for key encryption threads to encrypt all spaces --echo # Wait max 10 min for key encryption threads to decrypt all spaces
--let $wait_timeout= 600 --let $wait_timeout= 600
--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
--source include/wait_condition.inc --source include/wait_condition.inc
......
DROP TABLE if exists t1; SET GLOBAL innodb_defragment_stats_accuracy = 20;
select @@global.innodb_stats_persistent; DELETE FROM mysql.innodb_index_stats;
@@global.innodb_stats_persistent
0
set global innodb_defragment_stats_accuracy = 20;
# Create table. # Create table.
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB; CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB;
# Populate data INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1_to_1024;
INSERT INTO t1 VALUES(1, REPEAT('A', 256));
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
# Not enough page splits to trigger persistent stats write yet. # Not enough page splits to trigger persistent stats write yet.
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
count(stat_value) = 0 count(stat_value) = 0
...@@ -27,7 +13,7 @@ count(stat_value) = 0 ...@@ -27,7 +13,7 @@ count(stat_value) = 0
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag');
count(stat_value) = 0 count(stat_value) = 0
1 1
INSERT INTO t1 (b) SELECT b from t1; INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1025_to_2048;
# Persistent stats recorded. # Persistent stats recorded.
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
count(stat_value) > 0 count(stat_value) > 0
...@@ -39,6 +25,7 @@ select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like ...@@ -39,6 +25,7 @@ select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like
count(stat_value) > 0 count(stat_value) > 0
1 1
# Delete some rows. # Delete some rows.
BEGIN;
delete from t1 where a between 100 * 20 and 100 * 20 + 30; delete from t1 where a between 100 * 20 and 100 * 20 + 30;
delete from t1 where a between 100 * 19 and 100 * 19 + 30; delete from t1 where a between 100 * 19 and 100 * 19 + 30;
delete from t1 where a between 100 * 18 and 100 * 18 + 30; delete from t1 where a between 100 * 18 and 100 * 18 + 30;
...@@ -59,8 +46,7 @@ delete from t1 where a between 100 * 4 and 100 * 4 + 30; ...@@ -59,8 +46,7 @@ delete from t1 where a between 100 * 4 and 100 * 4 + 30;
delete from t1 where a between 100 * 3 and 100 * 3 + 30; delete from t1 where a between 100 * 3 and 100 * 3 + 30;
delete from t1 where a between 100 * 2 and 100 * 2 + 30; delete from t1 where a between 100 * 2 and 100 * 2 + 30;
delete from t1 where a between 100 * 1 and 100 * 1 + 30; delete from t1 where a between 100 * 1 and 100 * 1 + 30;
# Server Restarted COMMIT;
# Confirm persistent stats still there after restart.
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
count(stat_value) > 0 count(stat_value) > 0
1 1
...@@ -73,9 +59,6 @@ count(stat_value) > 0 ...@@ -73,9 +59,6 @@ count(stat_value) > 0
optimize table t1; optimize table t1;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 optimize status OK test.t1 optimize status OK
select sleep(2);
sleep(2)
0
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
count(stat_value) > 0 count(stat_value) > 0
1 1
...@@ -108,9 +91,6 @@ count(stat_value) > 0 ...@@ -108,9 +91,6 @@ count(stat_value) > 0
1 1
# Table rename should cause stats rename. # Table rename should cause stats rename.
rename table t1 to t2; rename table t1 to t2;
select sleep(1);
sleep(1)
0
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
count(stat_value) = 0 count(stat_value) = 0
1 1
...@@ -129,47 +109,36 @@ count(stat_value) > 0 ...@@ -129,47 +109,36 @@ count(stat_value) > 0
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag');
count(stat_value) > 0 count(stat_value) > 0
1 1
# Drop index should cause stats drop. # Drop index should cause stats drop, but will not.
drop index SECOND on t2; drop index SECOND on t2;
select sleep(3); SELECT stat_name, stat_value>0 FROM mysql.innodb_index_stats
sleep(3) WHERE table_name like '%t2%' AND index_name='SECOND';
0 stat_name stat_value>0
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_page_split'); n_leaf_pages_defrag 1
count(stat_value) > 0 n_leaf_pages_reserved 1
1 n_page_split 1
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_pages_freed'); n_pages_freed 1
count(stat_value) > 0 #
1 # MDEV-26636: Statistics must not be written for temporary tables
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_leaf_pages_defrag'); #
count(stat_value) > 0 SET GLOBAL innodb_defragment_stats_accuracy = 1;
1 CREATE TEMPORARY TABLE t (a INT PRIMARY KEY, c CHAR(255) NOT NULL)
Server Restarted ENGINE=InnoDB;
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); INSERT INTO t SELECT seq, '' FROM seq_1_to_100;
count(stat_value) = 0 SELECT * FROM mysql.innodb_index_stats where table_name like '%t1%';
1 database_name table_name index_name last_update stat_name stat_value sample_size stat_description
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); SELECT table_name, index_name, stat_name, stat_value>0
count(stat_value) = 0 FROM mysql.innodb_index_stats;
1 table_name index_name stat_name stat_value>0
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); t2 PRIMARY n_leaf_pages_defrag 1
count(stat_value) = 0 t2 PRIMARY n_leaf_pages_reserved 1
1 t2 PRIMARY n_page_split 1
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); t2 PRIMARY n_pages_freed 1
count(stat_value) > 0 t2 SECOND n_leaf_pages_defrag 1
1 t2 SECOND n_leaf_pages_reserved 1
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); t2 SECOND n_page_split 1
count(stat_value) > 0 t2 SECOND n_pages_freed 1
1
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag');
count(stat_value) > 0
1
# Clean up # Clean up
DROP TABLE t2; DROP TABLE t2;
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); SELECT * FROM mysql.innodb_index_stats;
count(stat_value) = 0 database_name table_name index_name last_update stat_name stat_value sample_size stat_description
1
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed');
count(stat_value) = 0
1
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag');
count(stat_value) = 0
1
...@@ -9,28 +9,12 @@ SET @trunc_start= ...@@ -9,28 +9,12 @@ SET @trunc_start=
WHERE variable_name = 'innodb_undo_truncations'); WHERE variable_name = 'innodb_undo_truncations');
create table t1(keyc int primary key, c char(100)) engine = innodb; create table t1(keyc int primary key, c char(100)) engine = innodb;
create table t2(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb;
CREATE PROCEDURE populate_t1()
BEGIN
DECLARE i INT DEFAULT 1;
while (i <= 20000) DO
insert into t1 values (i, 'a');
SET i = i + 1;
END WHILE;
END |
CREATE PROCEDURE populate_t2()
BEGIN
DECLARE i INT DEFAULT 1;
while (i <= 20000) DO
insert into t2 values (i, 'a');
SET i = i + 1;
END WHILE;
END |
connect con1,localhost,root,,; connect con1,localhost,root,,;
begin; begin;
call populate_t1(); insert into t1 select seq,'a' from seq_1_to_20000;
connect con2,localhost,root,,; connect con2,localhost,root,,;
begin; begin;
call populate_t2(); insert into t2 select seq,'a' from seq_1_to_20000;
connection con1; connection con1;
update t1 set c = 'mysql'; update t1 set c = 'mysql';
connection con2; connection con2;
...@@ -52,8 +36,6 @@ commit; ...@@ -52,8 +36,6 @@ commit;
disconnect con2; disconnect con2;
connection default; connection default;
drop table t1, t2; drop table t1, t2;
drop PROCEDURE populate_t1;
drop PROCEDURE populate_t2;
InnoDB 0 transactions not purged InnoDB 0 transactions not purged
SET GLOBAL innodb_undo_logs = @save_undo_logs; SET GLOBAL innodb_undo_logs = @save_undo_logs;
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
......
--source include/have_innodb.inc --source include/have_innodb.inc
--source include/big_test.inc
--source include/not_valgrind.inc --source include/not_valgrind.inc
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/have_sequence.inc
--disable_warnings SET GLOBAL innodb_defragment_stats_accuracy = 20;
DROP TABLE if exists t1;
--enable_warnings
--disable_query_log DELETE FROM mysql.innodb_index_stats;
let $innodb_defragment_stats_accuracy_orig=`select @@innodb_defragment_stats_accuracy`;
--enable_query_log
select @@global.innodb_stats_persistent;
set global innodb_defragment_stats_accuracy = 20;
--echo # Create table. --echo # Create table.
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB; CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), KEY SECOND(a, b)) ENGINE=INNODB;
--echo # Populate data INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1_to_1024;
INSERT INTO t1 VALUES(1, REPEAT('A', 256));
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
INSERT INTO t1 (b) SELECT b from t1;
--echo # Not enough page splits to trigger persistent stats write yet. --echo # Not enough page splits to trigger persistent stats write yet.
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed');
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag');
INSERT INTO t1 (b) SELECT b from t1; INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1025_to_2048;
--echo # Persistent stats recorded. --echo # Persistent stats recorded.
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
...@@ -43,6 +25,7 @@ select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like ...@@ -43,6 +25,7 @@ select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag');
--echo # Delete some rows. --echo # Delete some rows.
BEGIN;
let $num_delete = 20; let $num_delete = 20;
while ($num_delete) while ($num_delete)
{ {
...@@ -50,17 +33,13 @@ while ($num_delete) ...@@ -50,17 +33,13 @@ while ($num_delete)
eval delete from t1 where a between $j and $j + 30; eval delete from t1 where a between $j and $j + 30;
dec $num_delete; dec $num_delete;
} }
COMMIT;
--source include/restart_mysqld.inc
--echo # Server Restarted
--echo # Confirm persistent stats still there after restart.
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed');
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag');
optimize table t1; optimize table t1;
select sleep(2);
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed');
...@@ -84,7 +63,6 @@ select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like ...@@ -84,7 +63,6 @@ select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like
--echo # Table rename should cause stats rename. --echo # Table rename should cause stats rename.
rename table t1 to t2; rename table t1 to t2;
select sleep(1);
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split');
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed');
...@@ -94,32 +72,30 @@ select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like ...@@ -94,32 +72,30 @@ select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed');
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag');
--echo # Drop index should cause stats drop. --echo # Drop index should cause stats drop, but will not.
drop index SECOND on t2; drop index SECOND on t2;
select sleep(3);
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_page_split'); --sorted_result
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_pages_freed'); SELECT stat_name, stat_value>0 FROM mysql.innodb_index_stats
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and index_name = 'SECOND' and stat_name in ('n_leaf_pages_defrag'); WHERE table_name like '%t2%' AND index_name='SECOND';
--echo #
--echo # MDEV-26636: Statistics must not be written for temporary tables
--echo #
SET GLOBAL innodb_defragment_stats_accuracy = 1;
CREATE TEMPORARY TABLE t (a INT PRIMARY KEY, c CHAR(255) NOT NULL)
ENGINE=InnoDB;
INSERT INTO t SELECT seq, '' FROM seq_1_to_100;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc
--echo Server Restarted
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); SELECT * FROM mysql.innodb_index_stats where table_name like '%t1%';
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed');
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag');
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); --sorted_result
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); SELECT table_name, index_name, stat_name, stat_value>0
select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); FROM mysql.innodb_index_stats;
--echo # Clean up --echo # Clean up
DROP TABLE t2; DROP TABLE t2;
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); SELECT * FROM mysql.innodb_index_stats;
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed');
select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag');
--disable_query_log
EVAL SET GLOBAL innodb_defragment_stats_accuracy = $innodb_defragment_stats_accuracy_orig;
--enable_query_log
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# --source include/innodb_page_size.inc # --source include/innodb_page_size.inc
--source include/innodb_page_size_small.inc --source include/innodb_page_size_small.inc
--source include/have_undo_tablespaces.inc --source include/have_undo_tablespaces.inc
--source include/have_sequence.inc
SET @save_undo_logs = @@GLOBAL.innodb_undo_logs; SET @save_undo_logs = @@GLOBAL.innodb_undo_logs;
SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency;
...@@ -25,37 +26,14 @@ WHERE variable_name = 'innodb_undo_truncations'); ...@@ -25,37 +26,14 @@ WHERE variable_name = 'innodb_undo_truncations');
create table t1(keyc int primary key, c char(100)) engine = innodb; create table t1(keyc int primary key, c char(100)) engine = innodb;
create table t2(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb;
# #
delimiter |;
CREATE PROCEDURE populate_t1()
BEGIN
DECLARE i INT DEFAULT 1;
while (i <= 20000) DO
insert into t1 values (i, 'a');
SET i = i + 1;
END WHILE;
END |
delimiter ;|
#
delimiter |;
CREATE PROCEDURE populate_t2()
BEGIN
DECLARE i INT DEFAULT 1;
while (i <= 20000) DO
insert into t2 values (i, 'a');
SET i = i + 1;
END WHILE;
END |
delimiter ;|
#
#
let DATADIR = `select @@datadir`; let DATADIR = `select @@datadir`;
connect (con1,localhost,root,,); connect (con1,localhost,root,,);
begin; begin;
send call populate_t1(); send insert into t1 select seq,'a' from seq_1_to_20000;
connect (con2,localhost,root,,); connect (con2,localhost,root,,);
begin; begin;
send call populate_t2(); send insert into t2 select seq,'a' from seq_1_to_20000;
connection con1; reap; send update t1 set c = 'mysql'; connection con1; reap; send update t1 set c = 'mysql';
connection con2; reap; send update t2 set c = 'mysql'; connection con2; reap; send update t2 set c = 'mysql';
...@@ -65,25 +43,12 @@ connection con1; reap; send delete from t1; ...@@ -65,25 +43,12 @@ connection con1; reap; send delete from t1;
connection con2; reap; delete from t2; connection con2; reap; delete from t2;
connection con1; reap; connection con1; reap;
let CHECKFILE = $MYSQL_TMP_DIR/check.txt;
perl;
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1)
= stat("$ENV{DATADIR}/undo001");
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2)
= stat("$ENV{DATADIR}/undo002");
open(OUT, ">$ENV{CHECKFILE}") || die;
print OUT "let \$size1='$size1,$size2';\n";
close(OUT);
EOF
SET GLOBAL innodb_undo_log_truncate = 1; SET GLOBAL innodb_undo_log_truncate = 1;
commit; disconnect con1; commit; disconnect con1;
connection con2; commit; disconnect con2; connection con2; commit; disconnect con2;
connection default; connection default;
drop table t1, t2; drop table t1, t2;
drop PROCEDURE populate_t1;
drop PROCEDURE populate_t2;
--source include/wait_all_purged.inc --source include/wait_all_purged.inc
...@@ -98,29 +63,6 @@ if (`select @@innodb_page_size IN (4096,8192,16384)`) ...@@ -98,29 +63,6 @@ if (`select @@innodb_page_size IN (4096,8192,16384)`)
source include/wait_condition.inc; source include/wait_condition.inc;
} }
--source $CHECKFILE
perl;
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1)
= stat("$ENV{DATADIR}/undo001");
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2)
= stat("$ENV{DATADIR}/undo002");
open(OUT, ">$ENV{CHECKFILE}") || die;
print OUT "let \$size2='$size1,$size2';\n";
close(OUT);
EOF
--source $CHECKFILE
--remove_file $CHECKFILE
if ($size1 == $size2)
{
# This fails for innodb_page_size=64k, occasionally also for 32k.
if (`select @@innodb_page_size IN (4096,8192,16384)`)
{
echo Truncation did not happen: $size1;
}
}
SET GLOBAL innodb_undo_logs = @save_undo_logs; SET GLOBAL innodb_undo_logs = @save_undo_logs;
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
SET GLOBAL innodb_undo_log_truncate = @save_truncate; SET GLOBAL innodb_undo_log_truncate = @save_truncate;
...@@ -949,8 +949,10 @@ then ...@@ -949,8 +949,10 @@ then
tmpdir=$(parse_cnf "$encgroups" 'tmpdir') tmpdir=$(parse_cnf "$encgroups" 'tmpdir')
if [ -z "$tmpdir" ]; then if [ -z "$tmpdir" ]; then
xtmpdir="$(mktemp -d)" xtmpdir="$(mktemp -d)"
else elif [ "$OS" = 'Linux' ]; then
xtmpdir=$(mktemp '-d' "--tmpdir=$tmpdir") xtmpdir=$(mktemp '-d' "--tmpdir=$tmpdir")
else
xtmpdir=$(TMPDIR="$tmpdir"; mktemp '-d')
fi fi
wsrep_log_info "Using '$xtmpdir' as mariabackup temporary directory" wsrep_log_info "Using '$xtmpdir' as mariabackup temporary directory"
......
...@@ -725,8 +725,10 @@ EOF ...@@ -725,8 +725,10 @@ EOF
tmpdir=$(parse_cnf '--mysqld|sst' 'tmpdir') tmpdir=$(parse_cnf '--mysqld|sst' 'tmpdir')
if [ -z "$tmpdir" ]; then if [ -z "$tmpdir" ]; then
tmpfile="$(mktemp)" tmpfile="$(mktemp)"
else elif [ "$OS" = 'Linux' ]; then
tmpfile=$(mktemp "--tmpdir=$tmpdir") tmpfile=$(mktemp "--tmpdir=$tmpdir")
else
tmpfile=$(TMPDIR="$tmpdir"; mktemp '-d')
fi fi
wsrep_log_info "Extracting binlog files:" wsrep_log_info "Extracting binlog files:"
......
...@@ -74,6 +74,9 @@ ...@@ -74,6 +74,9 @@
/* warning C4065: switch statement contains 'default' but no 'case' labels */ /* warning C4065: switch statement contains 'default' but no 'case' labels */
#pragma warning (disable : 4065) #pragma warning (disable : 4065)
#endif #endif
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wunused-label" /* yyexhaustedlab: */
#endif
int yylex(void *yylval, void *yythd); int yylex(void *yylval, void *yythd);
......
...@@ -74,6 +74,9 @@ ...@@ -74,6 +74,9 @@
/* warning C4065: switch statement contains 'default' but no 'case' labels */ /* warning C4065: switch statement contains 'default' but no 'case' labels */
#pragma warning (disable : 4065) #pragma warning (disable : 4065)
#endif #endif
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wunused-label" /* yyexhaustedlab: */
#endif
int yylex(void *yylval, void *yythd); int yylex(void *yylval, void *yythd);
......
...@@ -309,6 +309,7 @@ btr_defragment_save_defrag_stats_if_needed( ...@@ -309,6 +309,7 @@ btr_defragment_save_defrag_stats_if_needed(
{ {
if (srv_defragment_stats_accuracy != 0 // stats tracking disabled if (srv_defragment_stats_accuracy != 0 // stats tracking disabled
&& index->table->space_id != 0 // do not track system tables && index->table->space_id != 0 // do not track system tables
&& !index->table->is_temporary()
&& index->stat_defrag_modified_counter && index->stat_defrag_modified_counter
>= srv_defragment_stats_accuracy) { >= srv_defragment_stats_accuracy) {
dict_stats_defrag_pool_add(index); dict_stats_defrag_pool_add(index);
......
...@@ -858,11 +858,13 @@ fsp_try_extend_data_file(fil_space_t* space, fsp_header_t* header, mtr_t* mtr) ...@@ -858,11 +858,13 @@ fsp_try_extend_data_file(fil_space_t* space, fsp_header_t* header, mtr_t* mtr)
return(0); return(0);
} }
/* We ignore any fragments of a full megabyte when storing the size /* For the system tablespace, we ignore any fragments of a
to the space header */ full megabyte when storing the size to the space header */
space->size_in_header = ut_2pow_round( space->size_in_header = space->id
space->size, (1024 * 1024) / page_size.physical()); ? space->size
: ut_2pow_round(space->size,
(1024 * 1024) / page_size.physical());
mlog_write_ulint( mlog_write_ulint(
header + FSP_SIZE, space->size_in_header, MLOG_4BYTES, mtr); header + FSP_SIZE, space->size_in_header, MLOG_4BYTES, mtr);
...@@ -1294,7 +1296,7 @@ fsp_alloc_free_page( ...@@ -1294,7 +1296,7 @@ fsp_alloc_free_page(
/* It must be that we are extending a single-table tablespace /* It must be that we are extending a single-table tablespace
whose size is still < 64 pages */ whose size is still < 64 pages */
ut_a(!is_system_tablespace(space_id)); ut_a(!is_predefined_tablespace(space_id));
if (page_no >= FSP_EXTENT_SIZE) { if (page_no >= FSP_EXTENT_SIZE) {
ib::error() << "Trying to extend a single-table" ib::error() << "Trying to extend a single-table"
" tablespace " << space->name << " , by single" " tablespace " << space->name << " , by single"
...@@ -2381,14 +2383,14 @@ fseg_alloc_free_page_low( ...@@ -2381,14 +2383,14 @@ fseg_alloc_free_page_low(
return(NULL); return(NULL);
} }
if (space->size <= ret_page && !is_system_tablespace(space_id)) { if (space->size <= ret_page && !is_predefined_tablespace(space_id)) {
/* It must be that we are extending a single-table /* It must be that we are extending a single-table
tablespace whose size is still < 64 pages */ tablespace whose size is still < 64 pages */
if (ret_page >= FSP_EXTENT_SIZE) { if (ret_page >= FSP_EXTENT_SIZE) {
ib::error() << "Error (2): trying to extend" ib::error() << "Trying to extend '"
" a single-table tablespace " << space_id << space->chain.start->name
<< " by single page(s) though the" << "' by single page(s) though the"
<< " space size " << space->size << " space size " << space->size
<< ". Page no " << ret_page << "."; << ". Page no " << ret_page << ".";
ut_ad(!has_done_reservation); ut_ad(!has_done_reservation);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2009, Google Inc. Copyright (c) 2009, Google Inc.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, 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
...@@ -174,9 +174,15 @@ log_write_up_to( ...@@ -174,9 +174,15 @@ log_write_up_to(
/** write to the log file up to the last log entry. /** write to the log file up to the last log entry.
@param[in] sync whether we want the written log @param[in] sync whether we want the written log
also to be flushed to disk. */ also to be flushed to disk. */
void void log_buffer_flush_to_disk(bool sync= true);
log_buffer_flush_to_disk(
bool sync = true);
/** Prepare to invoke log_write_and_flush(), before acquiring log_sys.mutex. */
#define log_write_and_flush_prepare() log_write_mutex_enter()
/** Durably write the log up to log_sys.lsn and release log_sys.mutex. */
ATTRIBUTE_COLD void log_write_and_flush();
/****************************************************************//** /****************************************************************//**
This functions writes the log buffer to the log file and if 'flush' This functions writes the log buffer to the log file and if 'flush'
is set it forces a flush of the log file as well. This is meant to be is set it forces a flush of the log file as well. This is meant to be
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc. Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2020, MariaDB Corporation. Copyright (c) 2013, 2021, 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
...@@ -137,6 +137,10 @@ struct mtr_t { ...@@ -137,6 +137,10 @@ struct mtr_t {
/** Commit the mini-transaction. */ /** Commit the mini-transaction. */
void commit(); void commit();
/** Commit a mini-transaction that is shrinking a tablespace.
@param space tablespace that is being shrunk */
ATTRIBUTE_COLD void commit_shrink(fil_space_t &space);
/** Commit a mini-transaction that did not modify any pages, /** Commit a mini-transaction that did not modify any pages,
but generated some redo log on a higher level, such as but generated some redo log on a higher level, such as
MLOG_FILE_NAME records and a MLOG_CHECKPOINT marker. MLOG_FILE_NAME records and a MLOG_CHECKPOINT marker.
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, 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
...@@ -53,8 +53,8 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type) ...@@ -53,8 +53,8 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type)
/* If this mtr has x-fixed a clean page then we set /* If this mtr has x-fixed a clean page then we set
the made_dirty flag. This tells us if we need to the made_dirty flag. This tells us if we need to
grab log_flush_order_mutex at mtr_commit so that we grab log_sys.flush_order_mutex at mtr_t::commit() so that we
can insert the dirtied page to the flush list. */ can insert the dirtied page into the flush list. */
if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX) if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX)
&& !m_made_dirty) { && !m_made_dirty) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Google Inc. Copyright (c) 2009, Google Inc.
Copyright (c) 2014, 2020, MariaDB Corporation. Copyright (c) 2014, 2021, 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
...@@ -1048,14 +1048,103 @@ log_write_up_to( ...@@ -1048,14 +1048,103 @@ log_write_up_to(
/** write to the log file up to the last log entry. /** write to the log file up to the last log entry.
@param[in] sync whether we want the written log @param[in] sync whether we want the written log
also to be flushed to disk. */ also to be flushed to disk. */
void void log_buffer_flush_to_disk(bool sync)
log_buffer_flush_to_disk(
bool sync)
{ {
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
log_write_up_to(log_get_lsn(), sync); log_write_up_to(log_get_lsn(), sync);
} }
/** Durably write the log and release log_sys.mutex */
ATTRIBUTE_COLD void log_write_and_flush()
{
ut_ad(!srv_read_only_mode);
ut_ad(!recv_no_log_write);
ut_ad(!recv_recovery_is_on());
/* The following code is adapted from log_write_up_to(). */
DBUG_PRINT("ib_log", ("write " LSN_PF " to " LSN_PF,
log_sys.write_lsn, log_sys.lsn));
log_sys.n_pending_flushes++;
log_sys.current_flush_lsn= log_sys.lsn;
os_event_reset(log_sys.flush_event);
ut_ad(log_sys.buf_free != log_sys.buf_next_to_write);
ulint start_offset= log_sys.buf_next_to_write;
ulint end_offset= log_sys.buf_free;
ulint area_start= ut_2pow_round(start_offset, ulint(OS_FILE_LOG_BLOCK_SIZE));
ulint area_end= ut_calc_align(end_offset, ulint(OS_FILE_LOG_BLOCK_SIZE));
ulong write_ahead_size= srv_log_write_ahead_size;
log_block_set_flush_bit(log_sys.buf + area_start, TRUE);
log_block_set_checkpoint_no(log_sys.buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
log_sys.next_checkpoint_no);
lsn_t write_lsn= log_sys.lsn;
byte *write_buf= log_sys.buf;
ut_ad(area_end - area_start > 0);
log_buffer_switch();
log_sys.log.set_fields(log_sys.write_lsn);
/* Erase the end of the last log block. */
memset(write_buf + end_offset, 0,
~end_offset & (OS_FILE_LOG_BLOCK_SIZE - 1));
/* Calculate pad_size if needed. */
ulint pad_size= 0;
if (write_ahead_size > OS_FILE_LOG_BLOCK_SIZE)
{
lsn_t end_offset=
log_sys.log.calc_lsn_offset(ut_uint64_align_up(write_lsn,
OS_FILE_LOG_BLOCK_SIZE));
ulint end_offset_in_unit= (ulint) (end_offset % write_ahead_size);
if (end_offset_in_unit && (area_end - area_start) > end_offset_in_unit)
{
/* The first block in the unit was initialized after the last
writing. Needs to be written padded data once. */
pad_size= std::min<ulint>(ulint(write_ahead_size) - end_offset_in_unit,
srv_log_buffer_size - area_end);
memset(write_buf + area_end, 0, pad_size);
}
}
if (log_sys.is_encrypted())
log_crypt(write_buf + area_start, log_sys.write_lsn,
area_end - area_start);
/* Do the write to the log files */
log_write_buf(write_buf + area_start, area_end - area_start + pad_size,
#ifdef UNIV_DEBUG
pad_size,
#endif /* UNIV_DEBUG */
ut_uint64_align_down(log_sys.write_lsn,
OS_FILE_LOG_BLOCK_SIZE),
start_offset - area_start);
srv_stats.log_padded.add(pad_size);
log_sys.write_lsn= write_lsn;
log_write_mutex_exit();
/* Code adapted from log_write_flush_to_disk_low() */
ut_a(log_sys.n_pending_flushes == 1); /* No other threads here */
if (srv_file_flush_method != SRV_O_DSYNC)
fil_flush(SRV_LOG_SPACE_FIRST_ID);
log_sys.flushed_to_disk_lsn= log_sys.current_flush_lsn;
log_sys.n_pending_flushes--;
os_event_set(log_sys.flush_event);
const lsn_t flush_lsn= log_sys.flushed_to_disk_lsn;
log_mutex_exit();
innobase_mysql_log_notify(flush_lsn);
}
/****************************************************************//** /****************************************************************//**
This functions writes the log buffer to the log file and if 'flush' This functions writes the log buffer to the log file and if 'flush'
is set it forces a flush of the log file as well. This is meant to be is set it forces a flush of the log file as well. This is meant to be
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, 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
...@@ -463,6 +463,89 @@ mtr_t::commit() ...@@ -463,6 +463,89 @@ mtr_t::commit()
release_resources(); release_resources();
} }
#ifdef UNIV_DEBUG
/** Check that all pages belong to a shrunk tablespace. */
struct Shrink
{
const fil_space_t &space;
Shrink(const fil_space_t &space) : space(space) {}
bool operator()(const mtr_memo_slot_t *slot) const
{
if (!slot->object)
return true;
switch (slot->type) {
default:
ut_ad("invalid type" == 0);
return false;
case MTR_MEMO_MODIFY:
break;
case MTR_MEMO_SPACE_X_LOCK:
ut_ad(&space == slot->object);
return true;
case MTR_MEMO_PAGE_X_FIX:
case MTR_MEMO_PAGE_SX_FIX:
const buf_page_t &bpage= static_cast<buf_block_t*>(slot->object)->page;
const page_id_t &id= bpage.id;
if (id.space() == 0 && id.page_no() == TRX_SYS_PAGE_NO)
{
ut_ad(srv_is_undo_tablespace(space.id));
break;
}
ut_ad(id.space() == space.id);
ut_ad(id.page_no() < space.size);
ut_ad(bpage.state == BUF_BLOCK_FILE_PAGE);
ut_ad(!bpage.oldest_modification);
break;
}
return true;
}
};
#endif
/** Commit a mini-transaction that is shrinking a tablespace.
@param space tablespace that is being shrunk */
void mtr_t::commit_shrink(fil_space_t &space)
{
ut_ad(is_active());
ut_ad(!is_inside_ibuf());
ut_ad(!high_level_read_only);
ut_ad(m_modifications);
ut_ad(m_made_dirty);
ut_ad(!recv_recovery_is_on());
ut_ad(m_log_mode == MTR_LOG_ALL);
ut_ad(UT_LIST_GET_LEN(space.chain) == 1);
log_write_and_flush_prepare();
const lsn_t start_lsn= finish_write(prepare_write());
log_flush_order_mutex_enter();
/* Durably write the reduced FSP_SIZE before truncating the data file. */
log_write_and_flush();
os_file_truncate(space.chain.start->name, space.chain.start->handle,
os_offset_t(space.size) << srv_page_size_shift, true);
ut_d(m_memo.for_each_block_in_reverse(CIterate<Shrink>(space)));
m_memo.for_each_block_in_reverse(CIterate<const ReleaseBlocks>
(ReleaseBlocks(start_lsn, m_commit_lsn,
m_flush_observer)));
log_flush_order_mutex_exit();
mutex_enter(&fil_system.mutex);
ut_ad(space.is_being_truncated);
space.is_being_truncated= false;
space.set_stopping(false);
mutex_exit(&fil_system.mutex);
m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>());
srv_stats.log_write_requests.inc();
release_resources();
}
/** Commit a mini-transaction that did not modify any pages, /** Commit a mini-transaction that did not modify any pages,
but generated some redo log on a higher level, such as but generated some redo log on a higher level, such as
MLOG_FILE_NAME records and a MLOG_CHECKPOINT marker. MLOG_FILE_NAME records and a MLOG_CHECKPOINT marker.
......
...@@ -1665,7 +1665,6 @@ row_fts_merge_insert( ...@@ -1665,7 +1665,6 @@ row_fts_merge_insert(
aux_table = dict_table_open_on_name(aux_table_name, FALSE, FALSE, aux_table = dict_table_open_on_name(aux_table_name, FALSE, FALSE,
DICT_ERR_IGNORE_NONE); DICT_ERR_IGNORE_NONE);
ut_ad(aux_table != NULL); ut_ad(aux_table != NULL);
dict_table_close(aux_table, FALSE, FALSE);
aux_index = dict_table_get_first_index(aux_table); aux_index = dict_table_get_first_index(aux_table);
ut_ad(!aux_index->is_instant()); ut_ad(!aux_index->is_instant());
...@@ -1792,6 +1791,8 @@ row_fts_merge_insert( ...@@ -1792,6 +1791,8 @@ row_fts_merge_insert(
} }
exit: exit:
dict_table_close(aux_table, FALSE, FALSE);
fts_sql_commit(trx); fts_sql_commit(trx);
trx->op_info = ""; trx->op_info = "";
......
...@@ -1014,28 +1014,12 @@ trx_purge_initiate_truncate( ...@@ -1014,28 +1014,12 @@ trx_purge_initiate_truncate(
rseg->needs_purge = false; rseg->needs_purge = false;
} }
mtr.commit(); mtr.commit_shrink(*space);
/* Write-ahead the redo log record. */
log_write_up_to(mtr.commit_lsn(), true);
/* Trim the file size. */
os_file_truncate(file->name, file->handle,
os_offset_t(size) << srv_page_size_shift, true);
/* This is only executed by the srv_purge_coordinator_thread. */ /* No mutex; this is only updated by the purge coordinator. */
export_vars.innodb_undo_truncations++; export_vars.innodb_undo_truncations++;
/* In MDEV-8319 (10.5) we will PUNCH_HOLE the garbage if (purge_sys.rseg && purge_sys.rseg->last_page_no == FIL_NULL) {
(with write-ahead logging). */
mutex_enter(&fil_system.mutex);
ut_ad(space->is_being_truncated);
space->is_being_truncated = false;
space->set_stopping(false);
mutex_exit(&fil_system.mutex);
if (purge_sys.rseg != NULL
&& purge_sys.rseg->last_page_no == FIL_NULL) {
/* If purge_sys.rseg is pointing to rseg that was recently /* If purge_sys.rseg is pointing to rseg that was recently
truncated then move to next rseg element. truncated then move to next rseg element.
Note: Ideally purge_sys.rseg should be NULL because purge Note: Ideally purge_sys.rseg should be NULL because purge
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment