From 0f3224e172a077155f64897c8a3665fea6d5d892 Mon Sep 17 00:00:00 2001 From: Colin Patrick McCabe Date: Thu, 2 Jun 2011 16:40:44 -0700 Subject: [PATCH] rados_sync: in export, download, then rename Download files to a 'temporary' name and then rename them when they are complete. If the download gets aborted halfway through, this prevents rados sync from getting confused next time when it sees the downloaded file. This is similar to how rsync operates. Signed-off-by: Colin McCabe --- src/rados_sync.cc | 53 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/rados_sync.cc b/src/rados_sync.cc index d8b88396b40f9..e194adf70db42 100644 --- a/src/rados_sync.cc +++ b/src/rados_sync.cc @@ -42,6 +42,11 @@ static const char * const XATTR_FULLNAME = "user.rados_full_name"; static const char USER_XATTR_PREFIX[] = "user.rados."; static const size_t USER_XATTR_PREFIX_LEN = sizeof(USER_XATTR_PREFIX) / sizeof(USER_XATTR_PREFIX[0]) - 1; +/* It's important that RADOS_SYNC_TMP_SUFFIX contain at least one character + * that we wouldn't normally alllow in a file name-- in this case, $ */ +static const char * const RADOS_SYNC_TMP_SUFFIX = "$tmp"; +static const size_t RADOS_SYNC_TMP_SUFFIX_LEN = + sizeof(RADOS_SYNC_TMP_SUFFIX) / sizeof(RADOS_SYNC_TMP_SUFFIX[0]) - 1; static const char ERR_PREFIX[] = "[ERROR] "; @@ -65,6 +70,16 @@ static std::string get_user_xattr_name(const char *fs_xattr_name) return fs_xattr_name + USER_XATTR_PREFIX_LEN; } +/* Returns true if 'suffix' is a suffix of str */ +static bool is_suffix(const char *str, const char *suffix) +{ + size_t strlen_str = strlen(str); + size_t strlen_suffix = strlen(suffix); + if (strlen_str < strlen_suffix) + return false; + return (strcmp(str + (strlen_str - strlen_suffix), suffix) == 0); +} + /* Represents a directory in the filesystem that we export rados objects to (or * import them from.) */ @@ -193,6 +208,10 @@ public: c = '@'; need_hash = true; } + else if (c == '$') { + c = '@'; + need_hash = true; + } else if (c == ' ') { c = '_'; need_hash = true; @@ -502,12 +521,14 @@ public: return rados_time; } - int download(IoCtx &io_ctx, const char *file_name) + int download(IoCtx &io_ctx, const char *path) { - FILE *fp = fopen(file_name, "w"); + char tmp_path[strlen(path) + RADOS_SYNC_TMP_SUFFIX_LEN + 1]; + snprintf(tmp_path, sizeof(tmp_path), "%s%s", path, RADOS_SYNC_TMP_SUFFIX); + FILE *fp = fopen(tmp_path, "w"); if (!fp) { int err = errno; - cerr << ERR_PREFIX << "download: error opening '" << file_name << "':" + cerr << ERR_PREFIX << "download: error opening '" << tmp_path << "':" << cpp_strerror(err) << std::endl; return err; } @@ -529,7 +550,7 @@ public: size_t flen = fwrite(bl.c_str(), 1, rlen, fp); if (flen != (size_t)rlen) { int err = errno; - cerr << ERR_PREFIX << "download: fwrite(" << file_name << ") error: " + cerr << ERR_PREFIX << "download: fwrite(" << tmp_path << ") error: " << cpp_strerror(err) << std::endl; fclose(fp); return err; @@ -541,17 +562,23 @@ public: int res = fsetxattr(fd, XATTR_FULLNAME, rados_name, attr_sz, 0); if (res) { int err = errno; - cerr << ERR_PREFIX << "download: fsetxattr(" << file_name << ") error: " + cerr << ERR_PREFIX << "download: fsetxattr(" << tmp_path << ") error: " << cpp_strerror(err) << std::endl; fclose(fp); return err; } if (fclose(fp)) { int err = errno; - cerr << ERR_PREFIX << "download: fclose(" << file_name << ") error: " + cerr << ERR_PREFIX << "download: fclose(" << tmp_path << ") error: " << cpp_strerror(err) << std::endl; return err; } + if (rename(tmp_path, path)) { + int err = errno; + cerr << ERR_PREFIX << "download: rename(" << tmp_path << ", " + << path << ") error: " << cpp_strerror(err) << std::endl; + return err; + } return 0; } @@ -821,6 +848,7 @@ static int do_export(IoCtx& io_ctx, const char *dir_name, cout << "[xattr] " << rados_name << std::endl; } } + if (delete_after) { DirHolder dh; int err = dh.opendir(dir_name); @@ -835,6 +863,17 @@ static int do_export(IoCtx& io_ctx, const char *dir_name, break; if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) continue; + if (is_suffix(de->d_name, RADOS_SYNC_TMP_SUFFIX)) { + char path[strlen(dir_name) + strlen(de->d_name) + 2]; + snprintf("%s/%s", sizeof(path), dir_name, de->d_name); + if (unlink(path)) { + ret = errno; + cerr << ERR_PREFIX << "error unlinking temporary file '" << path << "': " + << cpp_strerror(ret) << std::endl; + return ret; + } + continue; + } auto_ptr lobj; ret = BackedUpObject::from_file(de->d_name, dir_name, lobj); if (ret) { @@ -897,6 +936,8 @@ static int do_import(IoCtx& io_ctx, const char *dir_name, break; if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) continue; + if (is_suffix(de->d_name, RADOS_SYNC_TMP_SUFFIX)) + continue; ret = BackedUpObject::from_file(de->d_name, dir_name, sobj); if (ret) { cerr << ERR_PREFIX << "BackedUpObject::from_file: got error " -- 2.39.5