Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mysql-test/suite/backup/backup_rocksdb.opt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--plugin-load-add=$HA_ROCKSDB_SO
61 changes: 61 additions & 0 deletions mysql-test/suite/backup/backup_rocksdb.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
CREATE TABLE ti(a INT PRIMARY KEY, b CHAR(255) DEFAULT '' NOT NULL, INDEX(b))
ENGINE=INNODB;
INSERT INTO ti SET a=1;
CREATE TABLE tr(a INT PRIMARY KEY, b CHAR(200)) ENGINE=ROCKSDB;
INSERT INTO tr VALUES (1,'r-one'),(2,'r-two'),(3,'r-three');
SET GLOBAL rocksdb_force_flush_memtable_now=1;
BACKUP SERVER TO 'target_dir';
INSERT INTO tr VALUES (4,'r-four');
INSERT INTO ti VALUES (2,'two');
# restart: --defaults-file=MYSQLTEST_VARDIR/tmp/backup_rocksdb_dir/backup.cnf --datadir=MYSQLTEST_VARDIR/tmp/backup_rocksdb_dir --plugin-load-add=ha_rocksdb.so
SELECT * FROM ti;
a b
1
SELECT * FROM tr;
a b
1 r-one
2 r-two
3 r-three
# restart on the original datadir
# restart
SELECT * FROM ti;
a b
1
2 two
SELECT * FROM tr;
a b
1 r-one
2 r-two
3 r-three
4 r-four
#
# BACKUP SERVER WITH ... N CONCURRENT (streamed oldgnu tar)
#
BACKUP SERVER WITH 2 CONCURRENT 'rstream.bat';
INSERT INTO tr VALUES (5,'r-five');
INSERT INTO ti VALUES (3,'three');
# restart: --defaults-file=MYSQLTEST_VARDIR/tmp/backup_rocksdb_stream/backup.cnf --datadir=MYSQLTEST_VARDIR/tmp/backup_rocksdb_stream --plugin-load-add=ha_rocksdb.so
SELECT * FROM ti;
a b
1
2 two
SELECT * FROM tr;
a b
1 r-one
2 r-two
3 r-three
4 r-four
# restart
SELECT * FROM ti;
a b
1
3 three
2 two
SELECT * FROM tr;
a b
1 r-one
2 r-two
3 r-three
4 r-four
5 r-five
DROP TABLE ti, tr;
76 changes: 76 additions & 0 deletions mysql-test/suite/backup/backup_rocksdb.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
--source include/have_rocksdb.inc
--source include/have_innodb.inc

CREATE TABLE ti(a INT PRIMARY KEY, b CHAR(255) DEFAULT '' NOT NULL, INDEX(b))
ENGINE=INNODB;
INSERT INTO ti SET a=1;

CREATE TABLE tr(a INT PRIMARY KEY, b CHAR(200)) ENGINE=ROCKSDB;
INSERT INTO tr VALUES (1,'r-one'),(2,'r-two'),(3,'r-three');
SET GLOBAL rocksdb_force_flush_memtable_now=1;

--let $targetdir=$MYSQLTEST_VARDIR/tmp/backup_rocksdb_dir
--error 0,1
--rmdir $targetdir
--replace_result $targetdir target_dir
--eval BACKUP SERVER TO '$targetdir'
--file_exists $targetdir/#rocksdb

INSERT INTO tr VALUES (4,'r-four');
INSERT INTO ti VALUES (2,'two');

--exec cat $MYSQLTEST_VARDIR/my.cnf >> $targetdir/backup.cnf
--let $restart_parameters=--defaults-file=$targetdir/backup.cnf --datadir=$targetdir --plugin-load-add=$HA_ROCKSDB_SO
--source include/restart_mysqld.inc

SELECT * FROM ti;
SELECT * FROM tr;

--echo # restart on the original datadir
--let $restart_parameters=
--source include/restart_mysqld.inc
SELECT * FROM ti;
SELECT * FROM tr;
--rmdir $targetdir

--echo #
--echo # BACKUP SERVER WITH ... N CONCURRENT (streamed oldgnu tar)
--echo #
--remove_files_wildcard $MYSQL_TMP_DIR/. rstream.bat
--write_file $MYSQL_TMP_DIR/rstream.bat
#!/bin/sh
exec cat > $MYSQL_TMP_DIR/$1.tar
EOF
--let $script=/bin/sh $MYSQL_TMP_DIR/rstream.bat

--replace_result $script rstream.bat
eval BACKUP SERVER WITH 2 CONCURRENT '$script';
--remove_file $MYSQL_TMP_DIR/rstream.bat

INSERT INTO tr VALUES (5,'r-five');
INSERT INTO ti VALUES (3,'three');

--let $target_directory=$MYSQLTEST_VARDIR/tmp/backup_rocksdb_stream
--error 0,1
--rmdir $target_directory
--mkdir $target_directory
--exec tar xf $MYSQL_TMP_DIR/1.tar -C $target_directory
--exec tar xf $MYSQL_TMP_DIR/2.tar -C $target_directory
--file_exists $target_directory/#rocksdb
--exec cat $MYSQLTEST_VARDIR/my.cnf >> $target_directory/backup.cnf

--let $restart_parameters=--defaults-file=$target_directory/backup.cnf --datadir=$target_directory --plugin-load-add=$HA_ROCKSDB_SO
--source include/restart_mysqld.inc
SELECT * FROM ti;
SELECT * FROM tr;

--remove_file $MYSQL_TMP_DIR/1.tar
--remove_file $MYSQL_TMP_DIR/2.tar

--let $restart_parameters=
--source include/restart_mysqld.inc
SELECT * FROM ti;
SELECT * FROM tr;

DROP TABLE ti, tr;
--rmdir $target_directory
1 change: 1 addition & 0 deletions mysql-test/suite/backup/suite.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ my $have_tar = `tar --version 2>&1` =~ /tar .*\d\.\d/;
sub skip_combinations {
my %skip;
$skip{'backup_stream.test'} = 'needs cat,tar' unless $have_cat && $have_tar;
$skip{'backup_rocksdb.test'} = 'needs cat,tar' unless $have_cat && $have_tar;
%skip;
}

Expand Down
2 changes: 2 additions & 0 deletions storage/rocksdb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ SET(ROCKSDB_SE_SOURCES
rdb_sst_info.h
rdb_converter.cc
rdb_converter.h
rdb_backup_server.cc
rdb_backup_server.h
)

# MariaDB: the following is added in build_rocksdb.cmake, when appropriate:
Expand Down
91 changes: 57 additions & 34 deletions storage/rocksdb/ha_rocksdb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
/* MyRocks includes */
#include "./event_listener.h"
#include "./ha_rocksdb_proto.h"
#include "./rdb_backup_server.h"
#include "./logger.h"
#include "./nosql_access.h"
#include "./rdb_cf_manager.h"
Expand Down Expand Up @@ -371,6 +372,41 @@ static std::string rdb_normalize_dir(std::string dir) {
return dir;
}

/** Create a RocksDB checkpoint (a consistent, hardlink-based
snapshot of the live database) in @checkpoint_dir.
@return HA_EXIT_SUCCESS on success
@return HA_EXIT_FAILURE otherwise (my_error() has already been
raised via rdb_error_to_mysql()). */
int rdb_create_checkpoint(const char *checkpoint_dir_raw)
{
if (!checkpoint_dir_raw || rdb == nullptr)
return HA_EXIT_FAILURE;

std::string checkpoint_dir = rdb_normalize_dir(checkpoint_dir_raw);
// NO_LINT_DEBUG
sql_print_information("RocksDB: creating checkpoint in directory : %s\n",
checkpoint_dir.c_str());
rocksdb::Checkpoint *checkpoint;
auto status = rocksdb::Checkpoint::Create(rdb, &checkpoint);
// We can only return HA_EXIT_FAILURE/HA_EXIT_SUCCESS here which is why
// the return code is ignored, but by calling into rdb_error_to_mysql,
// it will call my_error for us, which will propogate up to the client.
int rc __attribute__((__unused__));
if (status.ok()) {
status = checkpoint->CreateCheckpoint(checkpoint_dir.c_str());

delete checkpoint;
if (status.ok()) {
// NO_LINT_DEBUG
sql_print_information("RocksDB: created checkpoint in directory : %s\n",
checkpoint_dir.c_str());
return HA_EXIT_SUCCESS;
}
}
rc = ha_rocksdb::rdb_error_to_mysql(status);
return HA_EXIT_FAILURE;
}

static int rocksdb_create_checkpoint(
THD *const thd MY_ATTRIBUTE((__unused__)),
struct st_mysql_sys_var *const var MY_ATTRIBUTE((__unused__)),
Expand All @@ -379,36 +415,7 @@ static int rocksdb_create_checkpoint(
char buf[FN_REFLEN];
int len = sizeof(buf);
const char *const checkpoint_dir_raw = value->val_str(value, buf, &len);
if (checkpoint_dir_raw) {
if (rdb != nullptr) {
std::string checkpoint_dir = rdb_normalize_dir(checkpoint_dir_raw);
// NO_LINT_DEBUG
sql_print_information("RocksDB: creating checkpoint in directory : %s\n",
checkpoint_dir.c_str());
rocksdb::Checkpoint *checkpoint;
auto status = rocksdb::Checkpoint::Create(rdb, &checkpoint);
// We can only return HA_EXIT_FAILURE/HA_EXIT_SUCCESS here which is why
// the return code is ignored, but by calling into rdb_error_to_mysql,
// it will call my_error for us, which will propogate up to the client.
int rc __attribute__((__unused__));
if (status.ok()) {
status = checkpoint->CreateCheckpoint(checkpoint_dir.c_str());
delete checkpoint;
if (status.ok()) {
// NO_LINT_DEBUG
sql_print_information(
"RocksDB: created checkpoint in directory : %s\n",
checkpoint_dir.c_str());
return HA_EXIT_SUCCESS;
} else {
rc = ha_rocksdb::rdb_error_to_mysql(status);
}
} else {
rc = ha_rocksdb::rdb_error_to_mysql(status);
}
}
}
return HA_EXIT_FAILURE;
return rdb_create_checkpoint(checkpoint_dir_raw);
}

/* This method is needed to indicate that the
Expand Down Expand Up @@ -725,6 +732,20 @@ static int rmdir_force(const char *dir) {
}


/** Remove a RocksDB checkpoint directory @checkpoint_dir.
The server owns these files, so removal always happens here rather
than by unlinking from the backup code directly. */
void rdb_remove_checkpoint(const char *checkpoint_dir) {
if (unlink(checkpoint_dir) == 0)
return;

rmdir_force(checkpoint_dir);
}

/* Return the configured RocksDB data directory (rocksdb_datadir). */
const char *rdb_get_datadir() { return rocksdb_datadir; }


static void rocksdb_remove_mariabackup_checkpoint(
my_core::THD *const,
struct st_mysql_sys_var *const ,
Expand All @@ -733,10 +754,7 @@ static void rocksdb_remove_mariabackup_checkpoint(

mariabackup_checkpoint_dir.append("/mariabackup-checkpoint");

if (unlink(mariabackup_checkpoint_dir.c_str()) == 0)
return;

rmdir_force(mariabackup_checkpoint_dir.c_str());
rdb_remove_checkpoint(mariabackup_checkpoint_dir.c_str());
}


Expand Down Expand Up @@ -5342,6 +5360,11 @@ static int rocksdb_init_func(void *const p) {
*/
rocksdb_hton->check_version = rocksdb_check_version;

/* BACKUP SERVER hooks (see rdb_backup_server.cc) */
rocksdb_hton->backup_start = rocksdb_backup_start;
rocksdb_hton->backup_step = rocksdb_backup_step;
rocksdb_hton->backup_end = rocksdb_backup_end;

rocksdb_hton->flags = HTON_TEMPORARY_NOT_SUPPORTED |
HTON_SUPPORTS_EXTENDED_KEYS | HTON_CAN_RECREATE;

Expand Down
7 changes: 7 additions & 0 deletions storage/rocksdb/ha_rocksdb_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ void rdb_get_global_perf_counters(Rdb_perf_counters *counters)

void rdb_queue_save_stats_request();

/** BACKUP SERVER: RocksDB checkpoint helpers, shared between the
ROCKSDB_CREATE_CHECKPOINT and ROCKSDB_REMOVE_MARIABACKUP_CHECKPOINT
system variables and the handlerton backup hooks. */
int rdb_create_checkpoint(const char *checkpoint_dir);
void rdb_remove_checkpoint(const char *checkpoint_dir);
const char *rdb_get_datadir();

/*
Access to singleton objects.
*/
Expand Down
Loading