diff --git a/src/Common/renameat2.cpp b/src/Common/atomicRename.cpp similarity index 68% rename from src/Common/renameat2.cpp rename to src/Common/atomicRename.cpp index 8ee9081af56..c63c0e05899 100644 --- a/src/Common/renameat2.cpp +++ b/src/Common/atomicRename.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -55,7 +55,7 @@ namespace ErrorCodes namespace DB { -static bool supportsRenameat2Impl() +static bool supportsAtomicRenameImpl() { VersionNumber renameat2_minimal_version(3, 15, 0); VersionNumber linux_version(Poco::Environment::osVersion()); @@ -64,7 +64,7 @@ static bool supportsRenameat2Impl() static bool renameat2(const std::string & old_path, const std::string & new_path, int flags) { - if (!supportsRenameat2()) + if (!supportsAtomicRename()) return false; if (old_path.empty() || new_path.empty()) throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot rename {} to {}: path is empty", old_path, new_path); @@ -93,9 +93,69 @@ static bool renameat2(const std::string & old_path, const std::string & new_path throwFromErrnoWithPath(fmt::format("Cannot rename {} to {}", old_path, new_path), new_path, ErrorCodes::SYSTEM_ERROR); } -bool supportsRenameat2() +bool supportsAtomicRename() { - static bool supports = supportsRenameat2Impl(); + static bool supports = supportsAtomicRenameImpl(); + return supports; +} + +} + +#elif defined(__APPLE__) + +// Includes +#include // For dlsym +#include // For renamex_np +#include // For stderror + +#ifndef RENAME_SWAP + #define RENAME_SWAP 0x00000002 +#endif +#ifndef RENAME_EXCL + #define RENAME_EXCL 0x00000004 +#endif + + +#define RENAME_NOREPLACE RENAME_EXCL +#define RENAME_EXCHANGE RENAME_SWAP + +namespace DB +{ + +static bool renameat2(const std::string & old_path, const std::string & new_path, int flags) +{ + using function_type = int (*)(const char * from, const char * to, unsigned int flags); + static function_type fun = reinterpret_cast(dlsym(RTLD_DEFAULT, "renamex_np")); + if (fun == nullptr) + return false; + + if (old_path.empty() || new_path.empty()) + throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot rename {} to {}: path is empty", old_path, new_path); + + if (0 == (*fun)(old_path.c_str(), new_path.c_str(), flags)) + return true; + int errnum = errno; + + if (errnum == ENOTSUP || errnum == EINVAL) + return false; + if (errnum == EEXIST) + throwFromErrno(fmt::format("Cannot rename {} to {} because the second path already exists", old_path, new_path), ErrorCodes::ATOMIC_RENAME_FAIL); + if (errnum == ENOENT) + throwFromErrno(fmt::format("Paths cannot be exchanged because {} or {} does not exist", old_path, new_path), ErrorCodes::ATOMIC_RENAME_FAIL); + throwFromErrnoWithPath( + fmt::format("Cannot rename {} to {}: {}", old_path, new_path, strerror(errnum)), new_path, ErrorCodes::SYSTEM_ERROR); +} + + +static bool supportsAtomicRenameImpl() +{ + auto fun = dlsym(RTLD_DEFAULT, "renamex_np"); + return fun != nullptr; +} + +bool supportsAtomicRename() +{ + static bool supports = supportsAtomicRenameImpl(); return supports; } @@ -114,7 +174,7 @@ static bool renameat2(const std::string &, const std::string &, int) return false; } -bool supportsRenameat2() +bool supportsAtomicRename() { return false; } diff --git a/src/Common/renameat2.h b/src/Common/atomicRename.h similarity index 95% rename from src/Common/renameat2.h rename to src/Common/atomicRename.h index 141c5d385c5..6da8a8f623b 100644 --- a/src/Common/renameat2.h +++ b/src/Common/atomicRename.h @@ -6,7 +6,7 @@ namespace DB { /// Returns true, if the following functions supported by the system -bool supportsRenameat2(); +bool supportsAtomicRename(); /// Atomically rename old_path to new_path. If new_path exists, do not overwrite it and throw exception void renameNoReplace(const std::string & old_path, const std::string & new_path); diff --git a/src/Databases/DatabaseAtomic.cpp b/src/Databases/DatabaseAtomic.cpp index adfcd83f5a7..622d38e01bd 100644 --- a/src/Databases/DatabaseAtomic.cpp +++ b/src/Databases/DatabaseAtomic.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -158,7 +158,7 @@ void DatabaseAtomic::renameTable(ContextPtr local_context, const String & table_ return; } - if (exchange && !supportsRenameat2()) + if (exchange && !supportsAtomicRename()) throw Exception(ErrorCodes::NOT_IMPLEMENTED, "RENAME EXCHANGE is not supported"); auto & other_db = dynamic_cast(to_database); diff --git a/src/Disks/DiskLocal.cpp b/src/Disks/DiskLocal.cpp index 8aad42ab475..d81782a8af1 100644 --- a/src/Disks/DiskLocal.cpp +++ b/src/Disks/DiskLocal.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Interpreters/DatabaseCatalog.cpp b/src/Interpreters/DatabaseCatalog.cpp index 2f51d942403..7513c3bf849 100644 --- a/src/Interpreters/DatabaseCatalog.cpp +++ b/src/Interpreters/DatabaseCatalog.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index f3953eb67fe..24c58c819a4 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include