Merge pull request #36133 from Algunenano/osx_atomic_exchange

Add support for atomic exchange in OSX
This commit is contained in:
tavplubix 2022-04-12 14:10:36 +03:00 committed by GitHub
commit 2e95e0db3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 12 deletions

View File

@ -1,4 +1,4 @@
#include <Common/renameat2.h> #include <Common/atomicRename.h>
#include <Common/Exception.h> #include <Common/Exception.h>
#include <Common/VersionNumber.h> #include <Common/VersionNumber.h>
#include <Poco/Environment.h> #include <Poco/Environment.h>
@ -55,7 +55,7 @@ namespace ErrorCodes
namespace DB namespace DB
{ {
static bool supportsRenameat2Impl() static bool supportsAtomicRenameImpl()
{ {
VersionNumber renameat2_minimal_version(3, 15, 0); VersionNumber renameat2_minimal_version(3, 15, 0);
VersionNumber linux_version(Poco::Environment::osVersion()); 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) static bool renameat2(const std::string & old_path, const std::string & new_path, int flags)
{ {
if (!supportsRenameat2()) if (!supportsAtomicRename())
return false; return false;
if (old_path.empty() || new_path.empty()) if (old_path.empty() || new_path.empty())
throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot rename {} to {}: path is empty", old_path, new_path); 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); 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 <dlfcn.h> // For dlsym
#include <stdio.h> // For renamex_np
#include <string.h> // 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<function_type>(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; return supports;
} }
@ -114,7 +174,7 @@ static bool renameat2(const std::string &, const std::string &, int)
return false; return false;
} }
bool supportsRenameat2() bool supportsAtomicRename()
{ {
return false; return false;
} }

View File

@ -6,7 +6,7 @@ namespace DB
{ {
/// Returns true, if the following functions supported by the system /// 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 /// 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); void renameNoReplace(const std::string & old_path, const std::string & new_path);

View File

@ -4,7 +4,7 @@
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
#include <IO/ReadBufferFromFile.h> #include <IO/ReadBufferFromFile.h>
#include <Parsers/formatAST.h> #include <Parsers/formatAST.h>
#include <Common/renameat2.h> #include <Common/atomicRename.h>
#include <Storages/StorageMaterializedView.h> #include <Storages/StorageMaterializedView.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/ExternalDictionariesLoader.h> #include <Interpreters/ExternalDictionariesLoader.h>
@ -158,7 +158,7 @@ void DatabaseAtomic::renameTable(ContextPtr local_context, const String & table_
return; return;
} }
if (exchange && !supportsRenameat2()) if (exchange && !supportsAtomicRename())
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "RENAME EXCHANGE is not supported"); throw Exception(ErrorCodes::NOT_IMPLEMENTED, "RENAME EXCHANGE is not supported");
auto & other_db = dynamic_cast<DatabaseAtomic &>(to_database); auto & other_db = dynamic_cast<DatabaseAtomic &>(to_database);

View File

@ -6,7 +6,7 @@
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Common/filesystemHelpers.h> #include <Common/filesystemHelpers.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
#include <Common/renameat2.h> #include <Common/atomicRename.h>
#include <Disks/IO/createReadBufferFromFileBase.h> #include <Disks/IO/createReadBufferFromFileBase.h>
#include <fstream> #include <fstream>

View File

@ -12,7 +12,7 @@
#include <Parsers/formatAST.h> #include <Parsers/formatAST.h>
#include <IO/ReadHelpers.h> #include <IO/ReadHelpers.h>
#include <Poco/DirectoryIterator.h> #include <Poco/DirectoryIterator.h>
#include <Common/renameat2.h> #include <Common/atomicRename.h>
#include <Common/CurrentMetrics.h> #include <Common/CurrentMetrics.h>
#include <base/logger_useful.h> #include <base/logger_useful.h>
#include <Poco/Util/AbstractConfiguration.h> #include <Poco/Util/AbstractConfiguration.h>

View File

@ -8,7 +8,7 @@
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>
#include <Common/Macros.h> #include <Common/Macros.h>
#include <Common/randomSeed.h> #include <Common/randomSeed.h>
#include <Common/renameat2.h> #include <Common/atomicRename.h>
#include <Common/hex.h> #include <Common/hex.h>
#include <Core/Defines.h> #include <Core/Defines.h>