Skip to content

Commit c143ff2

Browse files
MDEV-39092 BACKUP SERVER of ENGINE=Aria to the local file system
Enable backup for non-Apple systems. Copy non-Aria-specific files *.frm and db.opt as part of Aria backup.
1 parent b0f350f commit c143ff2

9 files changed

Lines changed: 319 additions & 189 deletions

File tree

include/my_backup.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*****************************************************************************
2+
Copyright (c) 2026 MariaDB plc.
3+
4+
This program is free software; you can redistribute it and/or modify it under
5+
the terms of the GNU General Public License as published by the Free Software
6+
Foundation; version 2 of the License.
7+
8+
This program is distributed in the hope that it will be useful, but WITHOUT
9+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11+
12+
You should have received a copy of the GNU General Public License along with
13+
this program; if not, write to the Free Software Foundation, Inc.,
14+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
15+
16+
*****************************************************************************/
17+
18+
#pragma once
19+
20+
#include <cstdint>
21+
22+
namespace backup
23+
{
24+
25+
using target_dir_t= IF_WIN(const char*,int);
26+
27+
inline void* to_void_ptr(target_dir_t tgt) noexcept
28+
{
29+
return IF_WIN(const_cast<char*>, reinterpret_cast<void*>)(tgt);
30+
}
31+
32+
inline target_dir_t to_target_dir(void* ptr) noexcept
33+
{
34+
return IF_WIN(static_cast<const char*>(ptr),
35+
int(reinterpret_cast<uintptr_t>(ptr)));
36+
}
37+
38+
#ifndef _WIN32
39+
/** Copy a file.
40+
@param src source file descriptor
41+
@param dst target to append src to
42+
@return error code (negative)
43+
@retval 0 on success */
44+
int copy_file(int src, int dst) noexcept;
45+
46+
/** Copy the entire file.
47+
@param src source file descriptor
48+
@param dst target to append src to
49+
@param size amount of data to be copied
50+
@return error code (negative)
51+
@retval 0 on success */
52+
int copy_file(int src, int dst, off_t size) noexcept;
53+
#endif // _WIN32
54+
}

mysys/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c my_default.c
4848
my_atomic_writes.c my_cpu.c my_likely.c my_largepage.c
4949
file_logger.c my_dlerror.c crc32/crc32c.cc
5050
my_timezone.cc my_compr_int.cc my_thread_name.cc
51-
my_virtual_mem.c)
51+
my_virtual_mem.c my_backup.cc)
5252

5353
IF (WIN32)
5454
SET (MYSYS_SOURCES ${MYSYS_SOURCES}

mysys/my_backup.cc

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#include "my_global.h"
2+
#include "my_backup.h"
3+
4+
#ifdef __APPLE__
5+
# include <sys/attr.h>
6+
# include <sys/clonefile.h>
7+
# include <copyfile.h>
8+
#elif defined __linux__
9+
# include <sys/sendfile.h>
10+
#elif !defined _WIN32
11+
# include <sys/mman.h>
12+
#endif
13+
14+
namespace
15+
{
16+
#if !(defined __APPLE__ || defined _WIN32)
17+
18+
using copying_step= ssize_t(int,int,size_t,off_t*);
19+
template<copying_step step>
20+
static ssize_t copy(int in_fd, int out_fd, off_t c) noexcept
21+
{
22+
ssize_t ret;
23+
for (off_t offset{0};;)
24+
{
25+
off_t count= c;
26+
if (count > INT_MAX >> 20 << 20)
27+
count = INT_MAX >> 20 << 20;
28+
ret= step(in_fd, out_fd, size_t(count), &offset);
29+
if (ret < 0)
30+
break;
31+
c-= ret;
32+
if (!c)
33+
return 0;
34+
if (!ret)
35+
return -1;
36+
}
37+
return ret;
38+
}
39+
# if defined __linux__ || defined __FreeBSD__
40+
/* Copy between files in a single (type of) file system */
41+
static inline ssize_t
42+
copy_step(int in_fd, int out_fd, size_t count, off_t *offset) noexcept
43+
{
44+
return copy_file_range(in_fd, offset, out_fd, nullptr, count, 0);
45+
}
46+
# define cfr(src,dst,size) copy<copy_step>(src, dst, size)
47+
# endif
48+
# ifdef __linux__
49+
/* Copy a file to a stream or to a regular file. */
50+
static inline ssize_t
51+
send_step(int in_fd, int out_fd, size_t count, off_t *offset) noexcept
52+
{
53+
return sendfile(out_fd, in_fd, offset, count);
54+
}
55+
# else
56+
/** Copy a file using a memory mapping.
57+
@param in_fd source file
58+
@param out_fd destination
59+
@param count number of bytes to copy
60+
@return error code
61+
@retval 0 on success
62+
@retval 1 if a memory mapping failed */
63+
static ssize_t mmap_copy(int in_fd, int out_fd, off_t count)
64+
{
65+
#if SIZEOF_SIZE_T < 8
66+
if (count != ssize_t(count))
67+
return 1;
68+
#endif
69+
void *p= mmap(nullptr, count, PROT_READ, MAP_SHARED, in_fd, 0);
70+
if (p == MAP_FAILED)
71+
return 1;
72+
ssize_t ret;
73+
size_t c= size_t(count);
74+
for (const char *b= static_cast<const char*>(p);; b+= ret)
75+
{
76+
ret= write(out_fd, b, std::min(c, size_t(INT_MAX >> 20 << 20)));
77+
if (ret < 0)
78+
break;
79+
c-= ret;
80+
if (!c)
81+
{
82+
ret= 0;
83+
break;
84+
}
85+
if (!ret)
86+
{
87+
ret= -1;
88+
break;
89+
}
90+
}
91+
munmap(p, count);
92+
return ret;
93+
}
94+
95+
static ssize_t pread_write(int in_fd, int out_fd, off_t count) noexcept
96+
{
97+
constexpr size_t READ_WRITE_SIZE= 65536;
98+
char *b= static_cast<char*>(aligned_malloc(READ_WRITE_SIZE, 4096));
99+
if (!b)
100+
return -1;
101+
ssize_t ret;
102+
for (off_t o= 0;; o+= ret)
103+
{
104+
ret= pread(in_fd, b, ssize_t(std::min(count, off_t{READ_WRITE_SIZE})), o);
105+
if (ret > 0)
106+
ret= write(out_fd, b, ret);
107+
if (ret < 0)
108+
break;
109+
count-= ret;
110+
if (!count)
111+
{
112+
ret= 0;
113+
break;
114+
}
115+
if (!ret)
116+
{
117+
ret= -1;
118+
break;
119+
}
120+
}
121+
aligned_free(b);
122+
return ret;
123+
}
124+
# endif
125+
#endif
126+
}
127+
128+
namespace backup
129+
{
130+
131+
#ifndef _WIN32
132+
/** Copy a file.
133+
@param src source file descriptor
134+
@param dst target to append src to
135+
@return error code (negative)
136+
@retval 0 on success */
137+
int copy_file(int src, int dst) noexcept
138+
{
139+
#ifdef __APPLE__
140+
return fcopyfile(src, dst, nullptr, COPYFILE_ALL | COPYFILE_CLONE);
141+
#else
142+
return copy_file(src, dst, lseek(src, 0, SEEK_END));
143+
#endif
144+
}
145+
146+
/** Copy a file.
147+
@param src source file descriptor
148+
@param dst target to append src to
149+
@param size amount of data to be copied
150+
@return error code (negative)
151+
@retval 0 on success */
152+
int copy_file(int src, int dst, off_t size) noexcept
153+
{
154+
#ifdef __APPLE__
155+
return fcopyfile(src, dst, nullptr, COPYFILE_ALL | COPYFILE_CLONE);
156+
#else
157+
ssize_t ret;
158+
# ifdef cfr
159+
if (!(ret= cfr(src, dst, size)))
160+
return int(ret);
161+
# ifdef __linux__
162+
if (errno == EOPNOTSUPP)
163+
# endif
164+
# endif
165+
# ifdef __linux__ // starting with Linux 2.6.33, we can rely on sendfile(2)
166+
ret= copy<send_step>(src, dst, size);
167+
# else
168+
if ((ret= mmap_copy(src, dst, size)) == 1)
169+
ret= pread_write(src, dst, size);
170+
# endif
171+
DBUG_ASSERT(ret <= 0);
172+
return int(ret);
173+
#endif
174+
}
175+
#endif
176+
}

sql/handler.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "sql_analyze_stmt.h" // for Exec_time_tracker
3939

4040
#include <my_compare.h>
41+
#include <my_backup.h>
4142
#include <ft_global.h>
4243
#include <keycache.h>
4344
#include <mysql/psi/mysql_table.h>
@@ -1905,7 +1906,7 @@ struct handlerton : public transaction_participant
19051906
@return error code
19061907
@retval 0 on success
19071908
*/
1908-
int (*backup_start)(THD *thd, IF_WIN(const char*,int) target);
1909+
int (*backup_start)(THD *thd, backup::target_dir_t target);
19091910
/**
19101911
Process a file that was collected in backup_start().
19111912
@param thd current session
@@ -1928,7 +1929,7 @@ struct handlerton : public transaction_participant
19281929
@return error code
19291930
@retval 0 on success
19301931
*/
1931-
int (*backup_finalize)(THD *thd, IF_WIN(const char*,int) target);
1932+
int (*backup_finalize)(THD *thd, backup::target_dir_t target);
19321933

19331934
/**********************************************************************
19341935
WSREP specific

sql/sql_backup.cc

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@
1919
#include "sql_class.h"
2020
#include "sql_backup.h"
2121
#include "sql_parse.h"
22+
#include "my_backup.h"
23+
24+
using namespace backup;
2225

2326
static my_bool backup_start(THD *thd, plugin_ref plugin, void *dst) noexcept
2427
{
2528
handlerton *hton= plugin_hton(plugin);
2629
if (hton->backup_start)
27-
return hton->backup_start(thd,
28-
IF_WIN(static_cast<const char*>(dst),
29-
int(reinterpret_cast<uintptr_t>(dst))));
30+
return hton->backup_start(thd, to_target_dir(dst));
3031
return false;
3132
}
3233

@@ -53,9 +54,7 @@ static my_bool backup_finalize(THD *thd, plugin_ref plugin, void *dst) noexcept
5354
{
5455
handlerton *hton= plugin_hton(plugin);
5556
if (hton->backup_finalize)
56-
return hton->backup_finalize
57-
(thd, IF_WIN(static_cast<const char*>(dst),
58-
int(reinterpret_cast<uintptr_t>(dst))));
57+
return hton->backup_finalize(thd, to_target_dir(dst));
5958
return 0;
6059
}
6160

@@ -97,13 +96,14 @@ bool Sql_cmd_backup::execute(THD *thd)
9796
my_error(EE_CANT_MKDIR, MYF(ME_BELL), target.str, errno);
9897
goto err_exit;
9998
}
99+
#else
100+
const char *const dir= target.str;
100101
#endif
101102

102103
bool fail= plugin_foreach_with_mask(thd, backup_start,
103104
MYSQL_STORAGE_ENGINE_PLUGIN,
104105
PLUGIN_IS_DELETED|PLUGIN_IS_READY,
105-
IF_WIN(const_cast<char*>(target.str),
106-
reinterpret_cast<void*>(dir)));
106+
to_void_ptr(dir));
107107

108108
/* The backup_step may be invoked in multiple concurrent threads.
109109
At the time backup_end is invoked, all backup_step will have to complete. */
@@ -123,8 +123,7 @@ bool Sql_cmd_backup::execute(THD *thd)
123123
thd->mdl_context.release_lock(mdl_request.ticket);
124124
plugin_foreach_with_mask(thd, backup_finalize, MYSQL_STORAGE_ENGINE_PLUGIN,
125125
PLUGIN_IS_DELETED|PLUGIN_IS_READY,
126-
IF_WIN(const_cast<char*>(target.str),
127-
reinterpret_cast<void*>(dir)));
126+
to_void_ptr(dir));
128127
#ifndef _WIN32
129128
close(dir);
130129
#endif

0 commit comments

Comments
 (0)