Skip to content

Commit 0121d5a

Browse files
committed
Merge 10.2 into 10.3
2 parents 63027a5 + c55de8d commit 0121d5a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2161
-905
lines changed

extra/mariabackup/backup_copy.cc

Lines changed: 271 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
5858
#include "backup_mysql.h"
5959
#include <btr0btr.h>
6060

61+
#define ROCKSDB_BACKUP_DIR "#rocksdb"
62+
6163
/* list of files to sync for --rsync mode */
6264
static std::set<std::string> rsync_list;
6365
/* locations of tablespaces read from .isl files */
@@ -66,6 +68,21 @@ static std::map<std::string, std::string> tablespace_locations;
6668
/* Whether LOCK BINLOG FOR BACKUP has been issued during backup */
6769
bool binlog_locked;
6870

71+
static void rocksdb_create_checkpoint();
72+
static bool has_rocksdb_plugin();
73+
static void copy_or_move_dir(const char *from, const char *to, bool copy, bool allow_hardlinks);
74+
static void rocksdb_backup_checkpoint();
75+
static void rocksdb_copy_back();
76+
77+
static bool is_abs_path(const char *path)
78+
{
79+
#ifdef _WIN32
80+
return path[0] && path[1] == ':' && (path[2] == '/' || path[2] == '\\');
81+
#else
82+
return path[0] == '/';
83+
#endif
84+
}
85+
6986
/************************************************************************
7087
Struct represents file or directory. */
7188
struct datadir_node_t {
@@ -1138,7 +1155,8 @@ bool
11381155
copy_or_move_file(const char *src_file_path,
11391156
const char *dst_file_path,
11401157
const char *dst_dir,
1141-
uint thread_n)
1158+
uint thread_n,
1159+
bool copy = xtrabackup_copy_back)
11421160
{
11431161
ds_ctxt_t *datasink = ds_data; /* copy to datadir by default */
11441162
char filedir[FN_REFLEN];
@@ -1186,7 +1204,7 @@ copy_or_move_file(const char *src_file_path,
11861204
free(link_filepath);
11871205
}
11881206

1189-
ret = (xtrabackup_copy_back ?
1207+
ret = (copy ?
11901208
copy_file(datasink, src_file_path, dst_file_path, thread_n) :
11911209
move_file(datasink, src_file_path, dst_file_path,
11921210
dst_dir, thread_n));
@@ -1371,6 +1389,10 @@ bool backup_start()
13711389
return false;
13721390
}
13731391

1392+
if (has_rocksdb_plugin()) {
1393+
rocksdb_create_checkpoint();
1394+
}
1395+
13741396
// There is no need to stop slave thread before coping non-Innodb data when
13751397
// --no-lock option is used because --no-lock option requires that no DDL or
13761398
// DML to non-transaction tables can occur.
@@ -1456,6 +1478,10 @@ bool backup_finish()
14561478
}
14571479
}
14581480

1481+
if (has_rocksdb_plugin()) {
1482+
rocksdb_backup_checkpoint();
1483+
}
1484+
14591485
msg_ts("Backup created in directory '%s'\n", xtrabackup_target_dir);
14601486
if (mysql_binlog_position != NULL) {
14611487
msg("MySQL binlog position: %s\n", mysql_binlog_position);
@@ -1771,6 +1797,16 @@ copy_back()
17711797
int i_tmp;
17721798
bool is_ibdata_file;
17731799

1800+
if (strstr(node.filepath,"/" ROCKSDB_BACKUP_DIR "/")
1801+
#ifdef _WIN32
1802+
|| strstr(node.filepath,"\\" ROCKSDB_BACKUP_DIR "\\")
1803+
#endif
1804+
)
1805+
{
1806+
// copied at later step
1807+
continue;
1808+
}
1809+
17741810
/* create empty directories */
17751811
if (node.is_empty_dir) {
17761812
char path[FN_REFLEN];
@@ -1855,6 +1891,8 @@ copy_back()
18551891
}
18561892
}
18571893

1894+
rocksdb_copy_back();
1895+
18581896
cleanup:
18591897
if (it != NULL) {
18601898
datadir_iter_free(it);
@@ -2031,3 +2069,234 @@ static bool backup_files_from_datadir(const char *dir_path)
20312069
os_file_closedir(dir);
20322070
return ret;
20332071
}
2072+
2073+
2074+
static int rocksdb_remove_checkpoint_directory()
2075+
{
2076+
xb_mysql_query(mysql_connection, "set global rocksdb_remove_mariabackup_checkpoint=ON", false);
2077+
return 0;
2078+
}
2079+
2080+
static bool has_rocksdb_plugin()
2081+
{
2082+
static bool first_time = true;
2083+
static bool has_plugin= false;
2084+
if (!first_time || !xb_backup_rocksdb)
2085+
return has_plugin;
2086+
2087+
const char *query = "SELECT COUNT(*) FROM information_schema.plugins WHERE plugin_name='rocksdb'";
2088+
MYSQL_RES* result = xb_mysql_query(mysql_connection, query, true);
2089+
MYSQL_ROW row = mysql_fetch_row(result);
2090+
if (row)
2091+
has_plugin = !strcmp(row[0], "1");
2092+
mysql_free_result(result);
2093+
first_time = false;
2094+
return has_plugin;
2095+
}
2096+
2097+
static char *trim_trailing_dir_sep(char *path)
2098+
{
2099+
size_t path_len = strlen(path);
2100+
while (path_len)
2101+
{
2102+
char c = path[path_len - 1];
2103+
if (c == '/' IF_WIN(|| c == '\\', ))
2104+
path_len--;
2105+
else
2106+
break;
2107+
}
2108+
path[path_len] = 0;
2109+
return path;
2110+
}
2111+
2112+
/*
2113+
Create a file hardlink.
2114+
@return true on success, false on error.
2115+
*/
2116+
static bool make_hardlink(const char *from_path, const char *to_path)
2117+
{
2118+
DBUG_EXECUTE_IF("no_hardlinks", return false;);
2119+
char to_path_full[FN_REFLEN];
2120+
if (!is_abs_path(to_path))
2121+
{
2122+
fn_format(to_path_full, to_path, ds_data->root, "", MYF(MY_RELATIVE_PATH));
2123+
}
2124+
else
2125+
{
2126+
strncpy(to_path_full, to_path, sizeof(to_path_full));
2127+
}
2128+
#ifdef _WIN32
2129+
return CreateHardLink(to_path_full, from_path, NULL);
2130+
#else
2131+
return !link(from_path, to_path_full);
2132+
#endif
2133+
}
2134+
2135+
/*
2136+
Copies or moves a directory (non-recursively so far).
2137+
Helper function used to backup rocksdb checkpoint, or copy-back the
2138+
rocksdb files.
2139+
2140+
Has optimization that allows to use hardlinks when possible
2141+
(source and destination are directories on the same device)
2142+
*/
2143+
static void copy_or_move_dir(const char *from, const char *to, bool do_copy, bool allow_hardlinks)
2144+
{
2145+
datadir_node_t node;
2146+
datadir_node_init(&node);
2147+
datadir_iter_t *it = datadir_iter_new(from, false);
2148+
2149+
while (datadir_iter_next(it, &node))
2150+
{
2151+
char to_path[FN_REFLEN];
2152+
const char *from_path = node.filepath;
2153+
snprintf(to_path, sizeof(to_path), "%s/%s", to, base_name(from_path));
2154+
bool rc = false;
2155+
if (do_copy && allow_hardlinks)
2156+
{
2157+
rc = make_hardlink(from_path, to_path);
2158+
if (rc)
2159+
{
2160+
msg_ts("[%02u] Creating hardlink from %s to %s\n",
2161+
1, from_path, to_path);
2162+
}
2163+
else
2164+
{
2165+
allow_hardlinks = false;
2166+
}
2167+
}
2168+
2169+
if (!rc)
2170+
{
2171+
rc = (do_copy ?
2172+
copy_file(ds_data, from_path, to_path, 1) :
2173+
move_file(ds_data, from_path, node.filepath_rel,
2174+
to, 1));
2175+
}
2176+
if (!rc)
2177+
exit(EXIT_FAILURE);
2178+
}
2179+
datadir_iter_free(it);
2180+
datadir_node_free(&node);
2181+
2182+
}
2183+
2184+
/*
2185+
Obtain user level lock , to protect the checkpoint directory of the server
2186+
from being user/overwritten by different backup processes, if backups are
2187+
running in parallel.
2188+
2189+
This lock will be acquired before rocksdb checkpoint is created, held
2190+
while all files from it are being copied to their final backup destination,
2191+
and finally released after the checkpoint is removed.
2192+
*/
2193+
static void rocksdb_lock_checkpoint()
2194+
{
2195+
msg_ts("Obtaining rocksdb checkpoint lock.\n");
2196+
MYSQL_RES *res =
2197+
xb_mysql_query(mysql_connection, "SELECT GET_LOCK('mariabackup_rocksdb_checkpoint',3600)", true, true);
2198+
2199+
MYSQL_ROW r = mysql_fetch_row(res);
2200+
if (r && r[0] && strcmp(r[0], "1"))
2201+
{
2202+
msg_ts("Could not obtain rocksdb checkpont lock\n");
2203+
exit(EXIT_FAILURE);
2204+
}
2205+
}
2206+
2207+
static void rocksdb_unlock_checkpoint()
2208+
{
2209+
xb_mysql_query(mysql_connection,
2210+
"SELECT RELEASE_LOCK('mariabackup_rocksdb_checkpoint')", false, true);
2211+
}
2212+
2213+
2214+
/*
2215+
Create temporary checkpoint in $rocksdb_datadir/mariabackup-checkpoint
2216+
directory.
2217+
A (user-level) lock named 'mariabackup_rocksdb_checkpoint' will also be
2218+
acquired be this function.
2219+
*/
2220+
#define MARIADB_CHECKPOINT_DIR "mariabackup-checkpoint"
2221+
static char rocksdb_checkpoint_dir[FN_REFLEN];
2222+
2223+
static void rocksdb_create_checkpoint()
2224+
{
2225+
MYSQL_RES *result = xb_mysql_query(mysql_connection, "SELECT @@rocksdb_datadir,@@datadir", true, true);
2226+
MYSQL_ROW row = mysql_fetch_row(result);
2227+
2228+
DBUG_ASSERT(row && row[0] && row[1]);
2229+
2230+
char *rocksdbdir = row[0];
2231+
char *datadir = row[1];
2232+
2233+
if (is_abs_path(rocksdbdir))
2234+
{
2235+
snprintf(rocksdb_checkpoint_dir, sizeof(rocksdb_checkpoint_dir),
2236+
"%s/" MARIADB_CHECKPOINT_DIR, trim_trailing_dir_sep(rocksdbdir));
2237+
}
2238+
else
2239+
{
2240+
snprintf(rocksdb_checkpoint_dir, sizeof(rocksdb_checkpoint_dir),
2241+
"%s/%s/" MARIADB_CHECKPOINT_DIR, trim_trailing_dir_sep(datadir),
2242+
trim_dotslash(rocksdbdir));
2243+
}
2244+
mysql_free_result(result);
2245+
2246+
#ifdef _WIN32
2247+
for (char *p = rocksdb_checkpoint_dir; *p; p++)
2248+
if (*p == '\\') *p = '/';
2249+
#endif
2250+
2251+
rocksdb_lock_checkpoint();
2252+
2253+
if (!access(rocksdb_checkpoint_dir, 0))
2254+
{
2255+
msg_ts("Removing rocksdb checkpoint from previous backup attempt.\n");
2256+
rocksdb_remove_checkpoint_directory();
2257+
}
2258+
2259+
char query[FN_REFLEN + 32];
2260+
snprintf(query, sizeof(query), "SET GLOBAL rocksdb_create_checkpoint='%s'", rocksdb_checkpoint_dir);
2261+
xb_mysql_query(mysql_connection, query, false, true);
2262+
}
2263+
2264+
/*
2265+
Copy files from rocksdb temporary checkpoint to final destination.
2266+
remove temp.checkpoint directory (in server's datadir)
2267+
and release user level lock acquired inside rocksdb_create_checkpoint().
2268+
*/
2269+
static void rocksdb_backup_checkpoint()
2270+
{
2271+
msg_ts("Backing up rocksdb files.\n");
2272+
char rocksdb_backup_dir[FN_REFLEN];
2273+
snprintf(rocksdb_backup_dir, sizeof(rocksdb_backup_dir), "%s/" ROCKSDB_BACKUP_DIR , xtrabackup_target_dir);
2274+
bool backup_to_directory = xtrabackup_backup && xtrabackup_stream_fmt == XB_STREAM_FMT_NONE;
2275+
if (backup_to_directory)
2276+
{
2277+
if (my_mkdir(rocksdb_backup_dir, 0777, MYF(0))){
2278+
msg_ts("Can't create rocksdb backup directory %s\n", rocksdb_backup_dir);
2279+
exit(EXIT_FAILURE);
2280+
}
2281+
}
2282+
copy_or_move_dir(rocksdb_checkpoint_dir, ROCKSDB_BACKUP_DIR, true, backup_to_directory);
2283+
rocksdb_remove_checkpoint_directory();
2284+
rocksdb_unlock_checkpoint();
2285+
}
2286+
2287+
/*
2288+
Copies #rocksdb directory to the $rockdb_data_dir, on copy-back
2289+
*/
2290+
static void rocksdb_copy_back() {
2291+
if (access(ROCKSDB_BACKUP_DIR, 0))
2292+
return;
2293+
char rocksdb_home_dir[FN_REFLEN];
2294+
if (xb_rocksdb_datadir && is_abs_path(xb_rocksdb_datadir)) {
2295+
strncpy(rocksdb_home_dir, xb_rocksdb_datadir, sizeof(rocksdb_home_dir));
2296+
} else {
2297+
snprintf(rocksdb_home_dir, sizeof(rocksdb_home_dir), "%s/%s", mysql_data_home,
2298+
xb_rocksdb_datadir?trim_dotslash(xb_rocksdb_datadir): ROCKSDB_BACKUP_DIR);
2299+
}
2300+
mkdirp(rocksdb_home_dir, 0777, MYF(0));
2301+
copy_or_move_dir(ROCKSDB_BACKUP_DIR, rocksdb_home_dir, xtrabackup_copy_back, xtrabackup_copy_back);
2302+
}

extra/mariabackup/xtrabackup.cc

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ char *xtrabackup_tmpdir;
146146
char *xtrabackup_tables;
147147
char *xtrabackup_tables_file;
148148
char *xtrabackup_tables_exclude;
149+
char *xb_rocksdb_datadir;
150+
my_bool xb_backup_rocksdb = 1;
149151

150152
typedef std::list<regex_t> regex_list_t;
151153
static regex_list_t regex_include_list;
@@ -683,7 +685,9 @@ enum options_xtrabackup
683685
OPT_XTRA_TABLES_EXCLUDE,
684686
OPT_XTRA_DATABASES_EXCLUDE,
685687
OPT_PROTOCOL,
686-
OPT_LOCK_DDL_PER_TABLE
688+
OPT_LOCK_DDL_PER_TABLE,
689+
OPT_ROCKSDB_DATADIR,
690+
OPT_BACKUP_ROCKSDB
687691
};
688692

689693
struct my_option xb_client_options[] =
@@ -1182,7 +1186,7 @@ struct my_option xb_server_options[] =
11821186
"The algorithm InnoDB uses for page checksumming. [CRC32, STRICT_CRC32, "
11831187
"INNODB, STRICT_INNODB, NONE, STRICT_NONE]", &srv_checksum_algorithm,
11841188
&srv_checksum_algorithm, &innodb_checksum_algorithm_typelib, GET_ENUM,
1185-
REQUIRED_ARG, SRV_CHECKSUM_ALGORITHM_INNODB, 0, 0, 0, 0, 0},
1189+
REQUIRED_ARG, SRV_CHECKSUM_ALGORITHM_CRC32, 0, 0, 0, 0, 0},
11861190

11871191
{"innodb_undo_directory", OPT_INNODB_UNDO_DIRECTORY,
11881192
"Directory where undo tablespace files live, this path can be absolute.",
@@ -1227,6 +1231,17 @@ struct my_option xb_server_options[] =
12271231
(uchar*) &opt_lock_ddl_per_table, (uchar*) &opt_lock_ddl_per_table, 0,
12281232
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
12291233

1234+
{"rocksdb-datadir", OPT_ROCKSDB_DATADIR, "RocksDB data directory."
1235+
"This option is only used with --copy-back or --move-back option",
1236+
&xb_rocksdb_datadir, &xb_rocksdb_datadir,
1237+
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
1238+
1239+
{ "backup-rocksdb", OPT_BACKUP_ROCKSDB, "Backup rocksdb data, if rocksdb plugin is installed."
1240+
"Used only with --backup option. Can be useful for partial backups, to exclude all rocksdb data",
1241+
&xb_backup_rocksdb, &xb_backup_rocksdb,
1242+
0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 },
1243+
1244+
12301245
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
12311246
};
12321247

extra/mariabackup/xtrabackup.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ extern char *xtrabackup_incremental_basedir;
4444
extern char *innobase_data_home_dir;
4545
extern char *innobase_buffer_pool_filename;
4646
extern char *xb_plugin_dir;
47+
extern char *xb_rocksdb_datadir;
48+
extern my_bool xb_backup_rocksdb;
49+
4750
extern uint opt_protocol;
4851
extern ds_ctxt_t *ds_meta;
4952
extern ds_ctxt_t *ds_data;

0 commit comments

Comments
 (0)