Skip to content

Commit 26573de

Browse files
AliSQLAliSQL
authored andcommitted
Support AliSQL TokuDB tables online full backup
This backup strategy depends heavily on tokudb_checkpoint_lock of TokuDB SE, and can be summarized as: 1. take TokuDB checkpoint lock 2. FTWRL to get a consistent point of all storage engines 3. copy TokuDB redo logs to backup dir(after copyied .MYD, .MYI, .frm, etc.) 4. UNLOCK TABLES 5. copy TokuDB data files to backup dir 6. release TokuDB checkpoint lock
1 parent 8e6fe07 commit 26573de

File tree

9 files changed

+407
-1
lines changed

9 files changed

+407
-1
lines changed

storage/innobase/xtrabackup/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ INSTALL_SCRIPT(${CMAKE_CURRENT_BINARY_DIR}/xbcloud_osenv
2525

2626
ADD_SUBDIRECTORY(src)
2727
ADD_SUBDIRECTORY(test)
28-
ADD_SUBDIRECTORY(doc/source)
28+
# disable documentation build
29+
# ADD_SUBDIRECTORY(doc/source)

storage/innobase/xtrabackup/src/backup_copy.cc

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
5555
#include "common.h"
5656
#include "backup_copy.h"
5757
#include "backup_mysql.h"
58+
#include <regex.h> /* for TokuDB log name */
5859

5960

6061
/* list of files to sync for --rsync mode */
@@ -408,6 +409,45 @@ datadir_iter_next(datadir_iter_t *it, datadir_node_t *node)
408409
return(ret);
409410
}
410411

412+
/************************************************************************
413+
Get next TokuDB file in datadir.
414+
TokuDB data and log files are both put in datadir, not under database dir(like
415+
InnoDB or MyISAM), so we add this new function alternative to
416+
datadir_iter_next(). Maybe in future, TokuDB data files will put in database
417+
dir, we'll remove this function. */
418+
static
419+
bool
420+
datadir_iter_next_tokudb(datadir_iter_t *it, datadir_node_t *node)
421+
{
422+
423+
while (fil_file_readdir_next_file(&it->err, it->datadir_path,
424+
it->dir, &it->dbinfo) == 0) {
425+
426+
/* TokuDB data and log files are both FILE type, and
427+
we don't need DIR. */
428+
if (it->dbinfo.type == OS_FILE_TYPE_DIR
429+
|| it->dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
430+
continue;
431+
}
432+
433+
/* We found a symlink or a file */
434+
make_path_n(2, &it->filepath, &it->filepath_len,
435+
it->datadir_path, it->dbinfo.name);
436+
make_path_n(1, &it->filepath_rel, &it->filepath_rel_len,
437+
it->dbinfo.name);
438+
439+
it->is_file = true;
440+
it->is_empty_dir = false;
441+
442+
datadir_node_fill(node, it);
443+
444+
return(true);
445+
}
446+
447+
/* datadir iterate finished */
448+
return(false);
449+
}
450+
411451
/************************************************************************
412452
Interface to read MySQL data file sequentially. One should open file
413453
with datafile_open to get cursor and close the cursor with
@@ -750,6 +790,31 @@ filename_matches(const char *filename, const char **ext_list)
750790
return(false);
751791
}
752792

793+
/************************************************************************
794+
Check if file name matches given set of Regular Expressions
795+
@return true if match. */
796+
static
797+
bool
798+
filename_matches_regex(const char *filename, const char **pattern_list)
799+
{
800+
regex_t re;
801+
const char **pattern;
802+
803+
for (pattern = pattern_list; *pattern; pattern++) {
804+
regcomp(&re, *pattern, REG_EXTENDED|REG_NOSUB);
805+
806+
/* match found */
807+
if (regexec(&re, filename, 0, NULL, 0) == 0) {
808+
regfree(&re);
809+
return(true);
810+
}
811+
812+
/* re must be freed before next compile */
813+
regfree(&re);
814+
}
815+
816+
return(false);
817+
}
753818

754819
/************************************************************************
755820
Copy data file for backup. Also check if it is allowed to copy by
@@ -1281,9 +1346,90 @@ backup_files(const char *from, bool prep_mode)
12811346
return(ret);
12821347
}
12831348

1349+
bool
1350+
backup_tokudb_log_files(const char *from)
1351+
{
1352+
bool ret = true;
1353+
datadir_iter_t *it;
1354+
datadir_node_t node;
1355+
const char *pattern_list[] = {".*\\.tokulog[[:digit:]]+$", /* redo log */
1356+
".*\\.directory", /* table dictionary */
1357+
".*\\.rollback", /* undo log */
1358+
".*\\.environment", /* meta info */
1359+
NULL};
1360+
1361+
/* Must have TokuDB SE enabled. */
1362+
ut_ad(have_tokudb);
1363+
1364+
msg_ts("Starting to backup TokuDB log files under '%s'\n", from);
1365+
1366+
datadir_node_init(&node);
1367+
it = datadir_iter_new(from);
1368+
1369+
while (datadir_iter_next_tokudb(it, &node)) {
1370+
1371+
if (!filename_matches_regex(node.filepath, pattern_list)) {
1372+
continue;
1373+
}
1374+
1375+
if (!(ret = copy_file(ds_data, node.filepath, node.filepath, 1))) {
1376+
msg_ts("Error: Failed to copy file %s\n", node.filepath);
1377+
goto out;
1378+
}
1379+
}
1380+
1381+
msg_ts("Finished backing up TokuDB log files\n");
1382+
1383+
out:
1384+
datadir_iter_free(it);
1385+
datadir_node_free(&node);
1386+
1387+
return(ret);
1388+
}
1389+
1390+
bool
1391+
backup_tokudb_data_files(const char *from)
1392+
{
1393+
bool ret = true;
1394+
datadir_iter_t *it;
1395+
datadir_node_t node;
1396+
const char *ext_list[] = {"tokudb", NULL};
1397+
1398+
/* Must have TokuDB SE enabled. */
1399+
ut_ad(have_tokudb);
1400+
1401+
msg_ts("Starting to backup TokuDB data files under '%s'\n", from);
1402+
1403+
datadir_node_init(&node);
1404+
it = datadir_iter_new(from);
1405+
1406+
while (datadir_iter_next_tokudb(it, &node)) {
1407+
1408+
if (!filename_matches(node.filepath, ext_list)) {
1409+
continue;
1410+
}
1411+
1412+
if (!(ret = copy_file(ds_data, node.filepath, node.filepath, 1))) {
1413+
msg_ts("Error: Failed to copy file %s\n", node.filepath);
1414+
goto out;
1415+
}
1416+
}
1417+
1418+
msg_ts("Finished backing up TokuDB data files\n");
1419+
out:
1420+
datadir_iter_free(it);
1421+
datadir_node_free(&node);
1422+
1423+
return(ret);
1424+
}
1425+
12841426
bool
12851427
backup_start()
12861428
{
1429+
if (have_tokudb) {
1430+
lock_tokudb_checkpoint(mysql_connection);
1431+
}
1432+
12871433
if (!opt_no_lock) {
12881434
if (opt_safe_slave_backup) {
12891435
if (!wait_for_safe_slave(mysql_connection)) {
@@ -1350,6 +1496,24 @@ backup_start()
13501496
"FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS", false);
13511497
}
13521498

1499+
if (have_tokudb) {
1500+
1501+
if (!strcmp(fil_path_to_mysql_datadir,
1502+
tokudb_log_path_to_mysql_datadir)) {
1503+
1504+
/* tokudb_log_dir and datadir are same dir */
1505+
if (!backup_tokudb_log_files(fil_path_to_mysql_datadir))
1506+
return(false);
1507+
}
1508+
else {
1509+
1510+
/* tokudb_log_dir and datadir are different dir */
1511+
if (!backup_tokudb_log_files(fil_path_to_mysql_datadir) ||
1512+
!backup_tokudb_log_files(tokudb_log_path_to_mysql_datadir))
1513+
return(false);
1514+
}
1515+
}
1516+
13531517
return(true);
13541518
}
13551519

@@ -1384,6 +1548,14 @@ backup_finish()
13841548
}
13851549
}
13861550

1551+
/* Backup TokuDB data files */
1552+
if (have_tokudb) {
1553+
if(!backup_tokudb_data_files(tokudb_data_path_to_mysql_datadir)) {
1554+
return(false);
1555+
}
1556+
unlock_tokudb_checkpoint(mysql_connection);
1557+
}
1558+
13871559
msg_ts("Backup created in directory '%s'\n", xtrabackup_target_dir);
13881560
if (mysql_binlog_position != NULL) {
13891561
msg("MySQL binlog position: %s\n", mysql_binlog_position);

0 commit comments

Comments
 (0)