Optimize access checking.

This commit is contained in:
Vitaly Baranov 2020-02-01 17:30:26 +03:00
parent caeed69fe0
commit 63079c40c2
2 changed files with 30 additions and 21 deletions

View File

@ -4,6 +4,7 @@
#include <Core/Settings.h>
#include <Poco/Logger.h>
#include <common/logger_useful.h>
#include <boost/smart_ptr/make_shared_object.hpp>
#include <assert.h>
@ -81,7 +82,9 @@ namespace
AccessRightsContext::AccessRightsContext()
{
result_access_cache[0].emplace().grant(AccessType::ALL);
auto everything_granted = boost::make_shared<AccessRights>();
everything_granted->grant(AccessType::ALL);
result_access_cache[0] = std::move(everything_granted);
}
@ -102,9 +105,8 @@ AccessRightsContext::AccessRightsContext(const ClientInfo & client_info_, const
template <int mode, typename... Args>
bool AccessRightsContext::checkImpl(Poco::Logger * log_, const AccessFlags & access, const Args &... args) const
{
std::lock_guard lock{mutex};
const auto & result_access = calculateResultAccess();
bool is_granted = result_access.isGranted(access, args...);
auto result_access = calculateResultAccess();
bool is_granted = result_access->isGranted(access, args...);
if (trace_log)
LOG_TRACE(trace_log, "Access " << (is_granted ? "granted" : "denied") << ": " << (AccessRightsElement{access, args...}.toString()));
@ -129,7 +131,7 @@ bool AccessRightsContext::checkImpl(Poco::Logger * log_, const AccessFlags & acc
LOG_WARNING(log_, msg + formatSkippedMessage(args...));
};
if (readonly && calculateResultAccess(false, allow_ddl, allow_introspection).isGranted(access, args...))
if (readonly && calculateResultAccess(false, allow_ddl, allow_introspection)->isGranted(access, args...))
{
if (interface == ClientInfo::Interface::HTTP && http_method == ClientInfo::HTTPMethod::GET)
show_error(
@ -139,11 +141,11 @@ bool AccessRightsContext::checkImpl(Poco::Logger * log_, const AccessFlags & acc
else
show_error("Cannot execute query in readonly mode", ErrorCodes::READONLY);
}
else if (!allow_ddl && calculateResultAccess(readonly, true, allow_introspection).isGranted(access, args...))
else if (!allow_ddl && calculateResultAccess(readonly, true, allow_introspection)->isGranted(access, args...))
{
show_error("Cannot execute query. DDL queries are prohibited for the user", ErrorCodes::QUERY_IS_PROHIBITED);
}
else if (!allow_introspection && calculateResultAccess(readonly, allow_ddl, true).isGranted(access, args...))
else if (!allow_introspection && calculateResultAccess(readonly, allow_ddl, true)->isGranted(access, args...))
{
show_error("Introspection functions are disabled, because setting 'allow_introspection_functions' is set to 0", ErrorCodes::FUNCTION_NOT_ALLOWED);
}
@ -227,25 +229,32 @@ bool AccessRightsContext::isGranted(Poco::Logger * log_, const AccessRightsEleme
bool AccessRightsContext::isGranted(Poco::Logger * log_, const AccessRightsElements & access) const { return checkImpl<LOG_WARNING_IF_ACCESS_DENIED>(log_, access); }
const AccessRights & AccessRightsContext::calculateResultAccess() const
boost::shared_ptr<const AccessRights> AccessRightsContext::calculateResultAccess() const
{
if (result_access_cache[0])
return *result_access_cache[0];
auto res = result_access_cache[0].load();
if (res)
return res;
return calculateResultAccess(readonly, allow_ddl, allow_introspection);
}
const AccessRights & AccessRightsContext::calculateResultAccess(UInt64 readonly_, bool allow_ddl_, bool allow_introspection_) const
boost::shared_ptr<const AccessRights> AccessRightsContext::calculateResultAccess(UInt64 readonly_, bool allow_ddl_, bool allow_introspection_) const
{
size_t cache_index = static_cast<size_t>(readonly_ != readonly)
+ static_cast<size_t>(allow_ddl_ != allow_ddl) * 2 +
+ static_cast<size_t>(allow_introspection_ != allow_introspection) * 3;
assert(cache_index < std::size(result_access_cache));
auto & cached_result = result_access_cache[cache_index];
auto cached = result_access_cache[cache_index].load();
if (cached)
return cached;
if (cached_result)
return *cached_result;
auto & result = cached_result.emplace();
std::lock_guard lock{mutex};
cached = result_access_cache[cache_index].load();
if (cached)
return cached;
auto result_ptr = boost::make_shared<AccessRights>();
auto & result = *result_ptr;
result = granted_to_user;
@ -272,7 +281,8 @@ const AccessRights & AccessRightsContext::calculateResultAccess(UInt64 readonly_
if (!allow_introspection_)
result.fullRevoke(AccessType::INTROSPECTION);
return result;
result_access_cache[cache_index].store(result_ptr);
return std::move(result_ptr);
}
}

View File

@ -2,15 +2,14 @@
#include <Access/AccessRights.h>
#include <Interpreters/ClientInfo.h>
#include <boost/smart_ptr/atomic_shared_ptr.hpp>
#include <mutex>
#include <optional>
namespace Poco { class Logger; }
namespace DB
{
class Exception;
struct Settings;
@ -63,8 +62,8 @@ private:
template <int mode>
bool checkImpl(Poco::Logger * log_, const AccessRightsElements & access) const;
const AccessRights & calculateResultAccess() const;
const AccessRights & calculateResultAccess(UInt64 readonly_, bool allow_ddl_, bool allow_introspection_) const;
boost::shared_ptr<const AccessRights> calculateResultAccess() const;
boost::shared_ptr<const AccessRights> calculateResultAccess(UInt64 readonly_, bool allow_ddl_, bool allow_introspection_) const;
const String user_name;
const AccessRights granted_to_user;
@ -75,7 +74,7 @@ private:
const ClientInfo::Interface interface = ClientInfo::Interface::TCP;
const ClientInfo::HTTPMethod http_method = ClientInfo::HTTPMethod::UNKNOWN;
Poco::Logger * const trace_log = nullptr;
mutable std::optional<AccessRights> result_access_cache[4];
mutable boost::atomic_shared_ptr<const AccessRights> result_access_cache[4];
mutable std::mutex mutex;
};