mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
This is based on a commit 281a0c9998
by Monty.
According to Monty, this:
- Galera should now be supported (needs testing)
- Enables ddl logging (so we can use it in the future)
- Flushes binary logs (we still must add code to copy them)
- mdl locks are consistent between mariadb-backup and backup command
- Give errors if backup command is done under a transaction, global
read lock or lock tables.
- Retry for MDL_BACKUP_WAIT_DDL (needed for
backup.backup_ddl_concurrent_verify)
Things to do (in addition to the things in Monty's earlier review):
- At backup_stage stage start, force rotate of aria log files. This
allows us to copy all old logs without any locks
- Copy all transactional tables and old aria logs under BACKUP_START (as
- maria-backup does)
- Copy the active aria log file under block commit (Only one file as aria
log rotation is disabled while backup is running.
- Improve speed of copying aria tables by copy files in up to 1M
blocks and run checksum on the blocks and only re-read blocks with
- wrong checksum.
- Copy non transactional files under BACKUP_START.
245 lines
7.9 KiB
C++
245 lines
7.9 KiB
C++
/* Copyright (c) 2026, MariaDB plc
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
#pragma once
|
|
#include "backup_stages.h"
|
|
#include <stdint.h>
|
|
|
|
/** BACKUP SERVER target */
|
|
struct backup_target
|
|
{
|
|
#ifdef _WIN32
|
|
/** Target directory path name, or nullptr if streaming */
|
|
const char *path;
|
|
bool operator==(const backup_target &o) const { return path == o.path; }
|
|
#else
|
|
/** Target directory descriptor, or -1 if streaming */
|
|
int fd;
|
|
bool operator==(const backup_target &o) const { return fd == o.fd; }
|
|
#endif
|
|
};
|
|
|
|
/** BACKUP SERVER worker specific context */
|
|
struct backup_sink
|
|
{
|
|
/** worker identifier: 0 to CONCURRENT-1 (the connection thread) */
|
|
int id;
|
|
#ifdef _WIN32
|
|
/** A value indicating an invalid stream */
|
|
static constexpr HANDLE NO_STREAM{INVALID_HANDLE_VALUE};
|
|
/** Target pipe, or NO_STREAM if path!=nullptr */
|
|
HANDLE stream;
|
|
#else
|
|
/** A value indicating an invalid file descriptor or stream */
|
|
static constexpr int NO_STREAM{-1};
|
|
/** Target pipe, or NO_STREAM if copying to a directory */
|
|
int stream;
|
|
#endif
|
|
/** storage engine context returned by handlerton::backup_start() */
|
|
void *ha_data;
|
|
};
|
|
|
|
/** A payload chunk in a sparse file that is being streamed */
|
|
struct backup_chunk
|
|
{
|
|
/** byte offset of the start of the payload, from the start of the file */
|
|
uint64_t offset;
|
|
/** length of the hole */
|
|
uint64_t length;
|
|
};
|
|
|
|
/** File descriptor */
|
|
typedef IF_WIN(HANDLE, int) backup_fd;
|
|
|
|
#ifdef _WIN32
|
|
/* Use CopyFileEx() to copy entire files */
|
|
#elif defined __APPLE__
|
|
/* You should invoke fclonefileat(2) manually before attempting
|
|
copy_entire_file() or backup::copy() */
|
|
# include <sys/attr.h>
|
|
# include <sys/clonefile.h>
|
|
# include <copyfile.h>
|
|
/** Copy an entire file.
|
|
@param src source file descriptor
|
|
@param dst target to append src to
|
|
@return error code (negative)
|
|
@retval 0 on success */
|
|
inline int copy_entire_file(int src, int dst) noexcept
|
|
{
|
|
return fcopyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_CLONE);
|
|
}
|
|
#else
|
|
/** Copy an entire file.
|
|
@param src source file descriptor
|
|
@param dst target to append src to
|
|
@return error code (non-positive)
|
|
@retval 0 on success */
|
|
int copy_entire_file(int src, int dst) noexcept;
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
struct native_file_handle;
|
|
#endif
|
|
namespace backup {
|
|
|
|
typedef IF_WIN(native_file_handle, int) handle;
|
|
|
|
/**
|
|
Copy a portion of a file.
|
|
@param src source file descriptor
|
|
@param dst target to append src to
|
|
@param start first offset to copy
|
|
@param end last offset to copy (exclusive)
|
|
@return error code (non-positive)
|
|
@retval 0 on success
|
|
*/
|
|
int copy(handle src, backup_fd dst, uint64_t start, uint64_t end) noexcept;
|
|
|
|
#ifndef _WIN32
|
|
/**
|
|
Copy or stream a file.
|
|
@param target BACKUP SERVER target (possibly, a directory)
|
|
@param sink per-thread context (possibly, a stream to write to)
|
|
@param src source file descriptor from open(), to be closed here
|
|
@param path file name
|
|
@return error code (also errno will be set)
|
|
@retval 0 on success
|
|
*/
|
|
int copy_or_stream(const backup_target &target, const backup_sink &sink,
|
|
int src, const char *path) noexcept;
|
|
#endif
|
|
|
|
/**
|
|
Copy or stream a file.
|
|
@param target BACKUP SERVER target (possibly, a directory)
|
|
@param sink per-thread context (possibly, a stream to write to)
|
|
@param path file name
|
|
@param dir_prefix length of the path prefix to omit from the backup
|
|
@return error code (also errno will be set)
|
|
@retval 0 on success
|
|
*/
|
|
int copy_or_stream(const backup_target &target, const backup_sink &sink,
|
|
const char *path, size_t dir_prefix= 0) noexcept;
|
|
|
|
/**
|
|
Append a file snippet to the stream,
|
|
after a corresponding call to backup_stream_start().
|
|
|
|
Note that tar uses 512-byte blocks. If end-start is not a multiple of
|
|
512 bytes, backup_stream_write() must be invoked to zero-pad the output.
|
|
@param src source file
|
|
@param stream backup stream
|
|
@param start first offset to copy
|
|
@param end last offset to copy (exclusive)
|
|
@return error code (non-positive)
|
|
@retval 0 on success
|
|
*/
|
|
int append(handle src, backup_fd stream, uint64_t start, uint64_t end)
|
|
noexcept;
|
|
}
|
|
|
|
#ifdef __linux__
|
|
/**
|
|
Try to copy a portion of a file via copy_file_range(2).
|
|
@param src source file descriptor
|
|
@param dst target to append src to
|
|
@param start first offset to copy
|
|
@param end last offset to copy (exclusive)
|
|
@return error code (non-positive)
|
|
@retval 0 on success
|
|
@retval 1 if a fallback to backup::copy() is needed
|
|
*/
|
|
int copy_file_range_try(int src, int dst, uint64_t start, uint64_t end)
|
|
noexcept;
|
|
# define copy_file_shortcut copy_file_range_try
|
|
#endif
|
|
|
|
/** Append to the configuration file.
|
|
@param target backup target directory
|
|
@param config the configuration file snippet to append
|
|
@param size length of the snippet
|
|
@return error code (non-positive)
|
|
@retval 0 on success */
|
|
int backup_config_append(IF_WIN(const char*, int) target,
|
|
const char *config, size_t size) noexcept;
|
|
|
|
/** Append to the configuration file.
|
|
@param target backup stream
|
|
@param config the configuration file snippet to append
|
|
@param size length of the snippet
|
|
@return error code (non-positive)
|
|
@retval 0 on success */
|
|
int backup_stream_config(backup_fd stream, const char *config, size_t size)
|
|
noexcept;
|
|
|
|
/** Start streaming a file.
|
|
@param target backup target
|
|
@param name file name
|
|
@param mode file access mode
|
|
@param size physical length of the file, in bytes
|
|
@param chunks payload chunks of a sparse file, or nullptr
|
|
@param n_chunks number of chunks; 0 unless sparse file
|
|
@return error code (non-positive)
|
|
@retval 0 on success */
|
|
int backup_stream_start(backup_fd stream,
|
|
const char *name, mode_t mode, uint64_t size,
|
|
const backup_chunk *chunks, size_t n_chunks) noexcept;
|
|
|
|
/**
|
|
Write data to a stream.
|
|
@param stream backup stream
|
|
@param buf source buffer
|
|
@param size length of the buffer (usually an integer multiple of 512)
|
|
@return error code (non-positive)
|
|
@retval 0 on success
|
|
*/
|
|
int backup_stream_write(backup_fd stream, const void *buf, size_t size)
|
|
noexcept;
|
|
|
|
/**
|
|
Zero-pad a the stream to a multiple of 512 bytes.
|
|
|
|
@param stream backup stream
|
|
@param written least significant bits of the number of payload appended
|
|
@return error code (non-positive)
|
|
@retval 0 on success
|
|
*/
|
|
int backup_stream_zeropad(backup_fd stream, size_t written) noexcept;
|
|
|
|
#ifdef _WIN32
|
|
# define backup_stream_append_async backup::append
|
|
#else
|
|
/**
|
|
Zero-copy append an immutable file snippet to a stream.
|
|
|
|
The caller guarantees that this section of the file will remain
|
|
intact until the stream is closed. This guarantee is needed
|
|
because the receiving end of the stream pipe might delay consuming
|
|
the data, and the operating system might point the pipe buffer
|
|
to the block cache for a long time.
|
|
|
|
Note that tar uses 512-byte blocks. If end-start is not a multiple of
|
|
512 bytes, backup_stream_zeropad() must be invoked.
|
|
@param src source file
|
|
@param stream backup stream
|
|
@param start first offset to copy
|
|
@param end last offset to copy (exclusive)
|
|
@return error code (non-positive)
|
|
@retval 0 on success
|
|
*/
|
|
int backup_stream_append_async(int src, int stream,
|
|
uint64_t start, uint64_t end) noexcept;
|
|
#endif
|