Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 53 additions & 3 deletions storage/innobase/xtrabackup/src/backup_copy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <chrono>
#include <fstream>
#include <functional>
#include <iomanip>
#include <queue>
#include <set>
#include <sstream>
Expand Down Expand Up @@ -377,7 +378,8 @@ bool backup_file_print(const char *filename, const char *message, int len) {
stat.st_mtime = time(nullptr);
stat.st_size = len;

dstfile = ds_open(ds_data, filename, &stat);
dstfile = ds_open_track_uncomp(ds_data, filename, &stat,
xb_global_track_uncomp_bytes());
if (dstfile == NULL) {
xb::error() << "cannot open the destination stream for " << filename;
goto error;
Expand Down Expand Up @@ -576,7 +578,9 @@ bool copy_file(ds_ctxt_t *datasink, const char *src_file_path,

strncpy(dst_name, cursor.rel_path, sizeof(dst_name));

dstfile = ds_open(datasink, trim_dotslash(dst_file_path), &cursor.statinfo);
dstfile =
ds_open_track_uncomp(datasink, trim_dotslash(dst_file_path),
&cursor.statinfo, xb_global_track_uncomp_bytes());
if (dstfile == NULL) {
xb::error() << "cannot open the destination stream for " << dst_name;
goto error;
Expand Down Expand Up @@ -1594,7 +1598,51 @@ bool backup_start(Backup_context &context) {
return (true);
}

/* Finsh the backup. Release all locks. Write down backup metadata.
/** Report backup_size (and, under --compress, uncompressed_backup_size
and the compression ratio) to the error log. A successful backup run
must have produced on-disk output, so the leaf counter must be
non-zero; under --compress at least one top-level ds_open_track_uncomp()
must have enabled an uncomp_bytes counter, so xb_uncomp_bytes_counter
must be non-zero too. A zero value therefore indicates a silent
reporting bug: assert in debug, warn and skip in release to avoid
emitting misleading numbers (e.g. "Compression ratio: inf"). */
static void report_backup_size() {
const unsigned long long backup_size = get_final_backup_size();

ut_ad(backup_size > 0);
if (backup_size == 0) {
xb::warn() << "Backup size reporting failed: leaf counter returned 0";
return;
}

xb::info() << "Backup size: "
<< xtrabackup::utils::human_readable(backup_size) << " ("
<< backup_size << " bytes)";

if (xtrabackup_compress == XTRABACKUP_COMPRESS_NONE) {
return;
}

const unsigned long long uncompressed_backup_size =
get_uncompressed_backup_size();

ut_ad(uncompressed_backup_size > 0);
if (uncompressed_backup_size == 0) {
xb::warn() << "Uncompressed backup size reporting failed: metrics"
" counter is 0 despite --compress";
return;
}

xb::info() << "Uncompressed backup size: "
<< xtrabackup::utils::human_readable(uncompressed_backup_size)
<< " (" << uncompressed_backup_size << " bytes)";

const double ratio = (double)uncompressed_backup_size / (double)backup_size;
xb::info() << "Compression ratio: " << std::fixed << std::setprecision(2)
<< ratio << "x";
Comment thread
satya-bodapati marked this conversation as resolved.
}

/* Finish the backup. Release all locks. Write down backup metadata.
@return true if success. */
bool backup_finish(Backup_context &context) {
/* release all locks */
Expand Down Expand Up @@ -1650,6 +1698,8 @@ bool backup_finish(Backup_context &context) {
return (false);
}

report_backup_size();

return (true);
}

Expand Down
31 changes: 29 additions & 2 deletions storage/innobase/xtrabackup/src/backup_mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1849,6 +1849,11 @@ char *get_xtrabackup_info(MYSQL *connection) {
format_time(history_start_time, buf_start_time, time_buf_size);
format_time(history_end_time, buf_end_time, time_buf_size);

/* Sampled here, after all data has drained to the leaf (see the
reordering in xtrabackup_backup_func()). Embedded directly into
xtrabackup_info so consumers see the final on-disk byte count. */
const unsigned long long backup_size = get_final_backup_size();

Comment thread
satya-bodapati marked this conversation as resolved.
ut_a(uuid);
ut_a(server_version);
char *result = NULL;
Expand All @@ -1875,7 +1880,8 @@ char *get_xtrabackup_info(MYSQL *connection) {
"format = %s\n"
"compressed = %s\n"
"encrypted = %s\n"
"lock_ddl_type = %s\n",
"lock_ddl_type = %s\n"
"backup_size = %llu\n",
uuid, /* uuid */
opt_history ? opt_history : "", /* name */
tool_name, /* tool_name */
Expand All @@ -1901,10 +1907,31 @@ char *get_xtrabackup_info(MYSQL *connection) {
xtrabackup_compress ? "compressed" : "N", /* compressed */
xtrabackup_encrypt ? "Y" : "N", /* encrypted */
ddl_lock_type_to_str(static_cast<lock_ddl_type_t>(opt_lock_ddl))
.c_str()); /* lock-ddl */
.c_str(), /* lock-ddl */
backup_size); /* backup_size */

ut_a(ret != 0);

/* uncompressed_backup_size is only meaningful under --compress: it
reports the raw, pre-compression logical volume that fed the main
backup pipeline. Without --compress, logical == physical, and the
backup_size line above already captures it. */
if (xtrabackup_compress != XTRABACKUP_COMPRESS_NONE) {
const unsigned long long uncompressed_backup_size =
get_uncompressed_backup_size();

char *tmp = NULL;
int ret2 = asprintf(&tmp, "%suncompressed_backup_size = %llu\n", result,
uncompressed_backup_size);
if (ret2 < 0) {
xb::warn() << "Failed to append uncompressed_backup_size to"
<< " xtrabackup_info: " << strerror(errno);
} else {
free(result);
result = tmp;
}
}

free(server_version);
return result;
}
Expand Down
71 changes: 66 additions & 5 deletions storage/innobase/xtrabackup/src/datasink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,44 @@ ds_file_t *ds_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat) {
file = ctxt->datasink->open(ctxt, path, stat);
if (file != NULL) {
file->datasink = ctxt->datasink;
/* Save the ctxt this file is attached to so per-datasink state
(e.g. leaf bytes_written counters) can be reached from the write
paths via file->ctxt->ptr. Tracking defaults to off; callers that
want uncompressed-byte accounting call ds_track_uncomp() or use
the ds_open_track_uncomp() convenience. */
file->ctxt = ctxt;
file->uncomp_bytes = nullptr;
}

return file;
}

void ds_track_uncomp(ds_file_t *file, xb_uncomp_bytes *uncomp_bytes) {
if (file != nullptr) {
file->uncomp_bytes = uncomp_bytes;
}
}

ds_file_t *ds_open_track_uncomp(ds_ctxt_t *ctxt, const char *path,
MY_STAT *stat, xb_uncomp_bytes *uncomp_bytes) {
ds_file_t *file = ds_open(ctxt, path, stat);
ds_track_uncomp(file, uncomp_bytes);
return file;
}

/************************************************************************
Write to a datasink file.
@return 0 on success, 1 on error. */
int ds_write(ds_file_t *file, const void *buf, size_t len) {
return file->datasink->write(file, buf, len);
const int rc = file->datasink->write(file, buf, len);
/* Bump the backup-run uncompressed byte counter with the logical
byte count only on success. Wrapper-internal opens do not set
file->uncomp_bytes, so every logical byte is counted exactly once
at the top. */
if (rc == 0 && file->uncomp_bytes != nullptr) {
file->uncomp_bytes->add_uncompressed(len);
}
return rc;
}

/************************************************************************
Expand All @@ -139,11 +167,18 @@ Write sparse chunk if supported.
int ds_write_sparse(ds_file_t *file, const void *buf, size_t len,
size_t sparse_map_size, const ds_sparse_chunk_t *sparse_map,
bool punch_hole_supported) {
if (file->datasink->write_sparse != nullptr) {
return file->datasink->write_sparse(file, buf, len, sparse_map_size,
sparse_map, punch_hole_supported);
if (file->datasink->write_sparse == nullptr) {
return 1;
}
return 1;
const int rc = file->datasink->write_sparse(file, buf, len, sparse_map_size,
sparse_map, punch_hole_supported);
if (rc == 0 && file->uncomp_bytes != nullptr) {
/* `len` is the packed (hole-excluded) payload size: callers pre-pack
the buffer and pass its length here, and local_write_sparse writes
exactly that many bytes across the sparse_map chunks. */
file->uncomp_bytes->add_uncompressed(len);
}
return rc;
}

/************************************************************************
Expand All @@ -161,3 +196,29 @@ tmpfile). */
void ds_set_pipe(ds_ctxt_t *ctxt, ds_ctxt_t *pipe_ctxt) {
ctxt->pipe_ctxt = pipe_ctxt;
}

const ds_ctxt_t *ds_leaf(const ds_ctxt_t *head) {
const ds_ctxt_t *c = head;
if (c == nullptr) return nullptr;
while (c->pipe_ctxt != nullptr) {
c = c->pipe_ctxt;
}
return c;
}

bool ds_find_metric(const ds_ctxt_t *node, std::string_view name,
uint64_t *out) {
if (node == nullptr || node->datasink == nullptr ||
node->datasink->report_metrics == nullptr) {
return false;
}
std::vector<ds_metric> v;
node->datasink->report_metrics(node, v);
for (const auto &m : v) {
if (m.name == name) {
if (out != nullptr) *out = m.value;
return true;
}
}
return false;
}
Loading
Loading