Skip to content

Commit 0ddbec4

Browse files
committed
MDEV-23335 MariaBackup Incremental Does Not Reflect Dropped/Created Databases
1 parent 489b556 commit 0ddbec4

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

extra/mariabackup/backup_copy.cc

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
5757
#include "backup_copy.h"
5858
#include "backup_mysql.h"
5959
#include <btr0btr.h>
60+
#ifdef _WIN32
61+
#include <direct.h> /* rmdir */
62+
#endif
6063

6164
#define ROCKSDB_BACKUP_DIR "#rocksdb"
6265

@@ -1623,7 +1626,49 @@ bool backup_finish()
16231626
return(true);
16241627
}
16251628

1626-
bool
1629+
1630+
/*
1631+
Drop all empty database directories in the base backup
1632+
that do not exists in the icremental backup.
1633+
1634+
This effectively re-plays all DROP DATABASE statements happened
1635+
in between base backup and incremental backup creation time.
1636+
1637+
Note, only checking if base_dir/db/ is empty is not enough,
1638+
because inc_dir/db/db.opt might have been dropped for some reasons,
1639+
which may also result into empty base_dir/db/.
1640+
1641+
Only the fact that at the same time:
1642+
- base_dir/db/ exists
1643+
- inc_dir/db/ does not exist
1644+
means that DROP DATABASE happened.
1645+
*/
1646+
static void
1647+
ibx_incremental_drop_databases(const char *base_dir,
1648+
const char *inc_dir)
1649+
{
1650+
datadir_node_t node;
1651+
datadir_node_init(&node);
1652+
datadir_iter_t *it = datadir_iter_new(base_dir);
1653+
1654+
while (datadir_iter_next(it, &node)) {
1655+
if (node.is_empty_dir) {
1656+
char path[FN_REFLEN];
1657+
snprintf(path, sizeof(path), "%s/%s",
1658+
inc_dir, node.filepath_rel);
1659+
if (!directory_exists(path, false)) {
1660+
msg("Removing %s", node.filepath);
1661+
rmdir(node.filepath);
1662+
}
1663+
}
1664+
1665+
}
1666+
datadir_iter_free(it);
1667+
datadir_node_free(&node);
1668+
}
1669+
1670+
1671+
static bool
16271672
ibx_copy_incremental_over_full()
16281673
{
16291674
const char *ext_list[] = {"frm", "isl", "MYD", "MYI", "MAD", "MAI",
@@ -1706,6 +1751,8 @@ ibx_copy_incremental_over_full()
17061751
}
17071752
copy_or_move_dir(path, ROCKSDB_BACKUP_DIR, true, true);
17081753
}
1754+
ibx_incremental_drop_databases(xtrabackup_target_dir,
1755+
xtrabackup_incremental_dir);
17091756
}
17101757

17111758

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
call mtr.add_suppression("InnoDB: New log files created");
2+
#
3+
# Start of 10.3 tests
4+
#
5+
#
6+
# MDEV-23335 MariaBackup Incremental Does Not Reflect Dropped/Created Databases
7+
#
8+
CREATE DATABASE db1;
9+
CREATE DATABASE db2;
10+
CREATE TABLE db1.t1 (a INT) ENGINE=MyISAM;
11+
CREATE TABLE db1.t2 (a INT) ENGINE=InnoDB;
12+
# Create base backup
13+
DROP DATABASE db1;
14+
# Create incremental backup
15+
# Remove incremental_dir/db2/db.opt file to make incremental_dir/db2/ empty
16+
# Prepare base backup, apply incremental one
17+
# shutdown server
18+
# remove datadir
19+
# xtrabackup move back
20+
# restart server
21+
# Expect no 'db1' in the output, because it was really dropped.
22+
# Expect 'db2' in the ouput, because it was not dropped!
23+
# (its incremental directory was emptied only)
24+
SHOW DATABASES LIKE 'db%';
25+
Database (db%)
26+
db2
27+
DROP DATABASE db2;
28+
#
29+
# End of 10.3 tests
30+
#
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
--source include/have_innodb.inc
2+
call mtr.add_suppression("InnoDB: New log files created");
3+
4+
--echo #
5+
--echo # Start of 10.3 tests
6+
--echo #
7+
8+
--echo #
9+
--echo # MDEV-23335 MariaBackup Incremental Does Not Reflect Dropped/Created Databases
10+
--echo #
11+
12+
--let $datadir=`SELECT @@datadir`
13+
--let $basedir=$MYSQLTEST_VARDIR/tmp/backup
14+
--let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1
15+
16+
# Create two databases:
17+
# - db1 is dropped normally below
18+
# - db2 is used to cover a corner case: its db.opt file is removed
19+
20+
# Incremental backup contains:
21+
# - no directory for db1
22+
# - an empty directory for db2 (after we remove db2/db.opt)
23+
24+
25+
CREATE DATABASE db1;
26+
CREATE DATABASE db2;
27+
28+
# Add some tables to db1
29+
CREATE TABLE db1.t1 (a INT) ENGINE=MyISAM;
30+
CREATE TABLE db1.t2 (a INT) ENGINE=InnoDB;
31+
32+
--echo # Create base backup
33+
--disable_result_log
34+
--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir
35+
--enable_result_log
36+
37+
DROP DATABASE db1;
38+
39+
--echo # Create incremental backup
40+
--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir
41+
42+
--echo # Remove incremental_dir/db2/db.opt file to make incremental_dir/db2/ empty
43+
--remove_file $incremental_dir/db2/db.opt
44+
45+
46+
--echo # Prepare base backup, apply incremental one
47+
--disable_result_log
48+
--exec $XTRABACKUP --prepare --target-dir=$basedir
49+
--exec $XTRABACKUP --prepare --target-dir=$basedir --incremental-dir=$incremental_dir
50+
--enable_result_log
51+
52+
--let $targetdir=$basedir
53+
--source include/restart_and_restore.inc
54+
--enable_result_log
55+
56+
--echo # Expect no 'db1' in the output, because it was really dropped.
57+
--echo # Expect 'db2' in the ouput, because it was not dropped!
58+
--echo # (its incremental directory was emptied only)
59+
60+
SHOW DATABASES LIKE 'db%';
61+
DROP DATABASE db2;
62+
63+
--rmdir $basedir
64+
--rmdir $incremental_dir
65+
66+
--echo #
67+
--echo # End of 10.3 tests
68+
--echo #

0 commit comments

Comments
 (0)