2019-11-09 15:33:07 +00:00
|
|
|
#include <Access/MultipleAccessStorage.h>
|
2021-03-11 20:41:10 +00:00
|
|
|
#include <Access/Credentials.h>
|
2019-11-09 15:33:07 +00:00
|
|
|
#include <Common/Exception.h>
|
2021-11-18 20:54:18 +00:00
|
|
|
#include <Common/quoteString.h>
|
2021-10-02 07:13:14 +00:00
|
|
|
#include <base/range.h>
|
2022-06-15 18:25:13 +00:00
|
|
|
#include <base/insertAtEnd.h>
|
2020-08-05 19:54:06 +00:00
|
|
|
#include <boost/range/adaptor/map.hpp>
|
2020-10-04 18:00:56 +00:00
|
|
|
#include <boost/range/adaptor/reversed.hpp>
|
2020-08-05 19:54:06 +00:00
|
|
|
#include <boost/range/algorithm/copy.hpp>
|
|
|
|
#include <boost/range/algorithm/find.hpp>
|
2019-11-09 15:33:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2020-08-14 21:30:47 +00:00
|
|
|
extern const int ACCESS_ENTITY_ALREADY_EXISTS;
|
2021-12-12 10:14:03 +00:00
|
|
|
extern const int ACCESS_STORAGE_FOR_INSERTION_NOT_FOUND;
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
using Storage = IAccessStorage;
|
|
|
|
using StoragePtr = std::shared_ptr<Storage>;
|
|
|
|
using ConstStoragePtr = std::shared_ptr<const Storage>;
|
|
|
|
using Storages = std::vector<StoragePtr>;
|
2019-11-09 15:33:07 +00:00
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
|
|
|
|
MultipleAccessStorage::MultipleAccessStorage(const String & storage_name_)
|
2020-08-12 20:48:53 +00:00
|
|
|
: IAccessStorage(storage_name_)
|
2020-08-05 19:54:06 +00:00
|
|
|
, nested_storages(std::make_shared<Storages>())
|
2019-11-09 15:33:07 +00:00
|
|
|
, ids_cache(512 /* cache size */)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-10-04 18:00:56 +00:00
|
|
|
MultipleAccessStorage::~MultipleAccessStorage()
|
|
|
|
{
|
2020-10-06 15:37:35 +00:00
|
|
|
/// It's better to remove the storages in the reverse order because they could depend on each other somehow.
|
2020-10-04 19:56:25 +00:00
|
|
|
const auto storages = getStoragesPtr();
|
|
|
|
for (const auto & storage : *storages | boost::adaptors::reversed)
|
2020-10-04 18:00:56 +00:00
|
|
|
{
|
|
|
|
removeStorage(storage);
|
|
|
|
}
|
|
|
|
}
|
2019-11-09 15:33:07 +00:00
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
void MultipleAccessStorage::setStorages(const std::vector<StoragePtr> & storages)
|
|
|
|
{
|
2022-06-14 22:35:55 +00:00
|
|
|
std::lock_guard lock{mutex};
|
2020-08-05 19:54:06 +00:00
|
|
|
nested_storages = std::make_shared<const Storages>(storages);
|
|
|
|
ids_cache.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultipleAccessStorage::addStorage(const StoragePtr & new_storage)
|
|
|
|
{
|
2022-06-14 22:35:55 +00:00
|
|
|
std::lock_guard lock{mutex};
|
2020-08-05 19:54:06 +00:00
|
|
|
if (boost::range::find(*nested_storages, new_storage) != nested_storages->end())
|
|
|
|
return;
|
|
|
|
auto new_storages = std::make_shared<Storages>(*nested_storages);
|
|
|
|
new_storages->push_back(new_storage);
|
|
|
|
nested_storages = new_storages;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MultipleAccessStorage::removeStorage(const StoragePtr & storage_to_remove)
|
|
|
|
{
|
2022-06-14 22:35:55 +00:00
|
|
|
std::lock_guard lock{mutex};
|
2020-08-05 19:54:06 +00:00
|
|
|
auto it = boost::range::find(*nested_storages, storage_to_remove);
|
|
|
|
if (it == nested_storages->end())
|
|
|
|
return;
|
|
|
|
size_t index = it - nested_storages->begin();
|
|
|
|
auto new_storages = std::make_shared<Storages>(*nested_storages);
|
|
|
|
new_storages->erase(new_storages->begin() + index);
|
|
|
|
nested_storages = new_storages;
|
|
|
|
ids_cache.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<StoragePtr> MultipleAccessStorage::getStorages()
|
|
|
|
{
|
|
|
|
return *getStoragesPtr();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<ConstStoragePtr> MultipleAccessStorage::getStorages() const
|
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
std::vector<ConstStoragePtr> res;
|
|
|
|
res.reserve(storages->size());
|
|
|
|
boost::range::copy(*storages, std::back_inserter(res));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<const Storages> MultipleAccessStorage::getStoragesPtr()
|
|
|
|
{
|
|
|
|
return getStoragesInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<const Storages> MultipleAccessStorage::getStoragesInternal() const
|
|
|
|
{
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
return nested_storages;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-18 20:54:18 +00:00
|
|
|
std::optional<UUID> MultipleAccessStorage::findImpl(AccessEntityType type, const String & name) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
auto id = storage->find(type, name);
|
2019-11-09 15:33:07 +00:00
|
|
|
if (id)
|
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
ids_cache.set(*id, storage);
|
|
|
|
return id;
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-05 18:32:12 +00:00
|
|
|
return {};
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-18 20:54:18 +00:00
|
|
|
std::vector<UUID> MultipleAccessStorage::findAllImpl(AccessEntityType type) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
|
|
|
std::vector<UUID> all_ids;
|
2020-08-05 19:54:06 +00:00
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
auto ids = storage->findAll(type);
|
2019-11-09 15:33:07 +00:00
|
|
|
all_ids.insert(all_ids.end(), std::make_move_iterator(ids.begin()), std::make_move_iterator(ids.end()));
|
|
|
|
}
|
|
|
|
return all_ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-22 21:50:15 +00:00
|
|
|
bool MultipleAccessStorage::exists(const UUID & id) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
|
|
|
return findStorage(id) != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
StoragePtr MultipleAccessStorage::findStorage(const UUID & id)
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
StoragePtr from_cache;
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
from_cache = ids_cache.get(id);
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
2020-08-05 19:54:06 +00:00
|
|
|
if (from_cache && from_cache->exists(id))
|
|
|
|
return from_cache;
|
2019-11-09 15:33:07 +00:00
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
if (storage->exists(id))
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
ids_cache.set(id, storage);
|
|
|
|
return storage;
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
ConstStoragePtr MultipleAccessStorage::findStorage(const UUID & id) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
|
|
|
return const_cast<MultipleAccessStorage *>(this)->findStorage(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
StoragePtr MultipleAccessStorage::getStorage(const UUID & id)
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
auto storage = findStorage(id);
|
2019-11-09 15:33:07 +00:00
|
|
|
if (storage)
|
2020-08-05 19:54:06 +00:00
|
|
|
return storage;
|
2019-11-09 15:33:07 +00:00
|
|
|
throwNotFound(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
ConstStoragePtr MultipleAccessStorage::getStorage(const UUID & id) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
|
|
|
return const_cast<MultipleAccessStorage *>(this)->getStorage(id);
|
|
|
|
}
|
|
|
|
|
2021-12-11 16:29:38 +00:00
|
|
|
AccessEntityPtr MultipleAccessStorage::readImpl(const UUID & id, bool throw_if_not_exists) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2021-12-11 16:29:38 +00:00
|
|
|
if (auto storage = findStorage(id))
|
|
|
|
return storage->read(id, throw_if_not_exists);
|
|
|
|
|
|
|
|
if (throw_if_not_exists)
|
|
|
|
throwNotFound(id);
|
|
|
|
else
|
|
|
|
return nullptr;
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-06-15 18:25:13 +00:00
|
|
|
std::optional<std::pair<String, AccessEntityType>> MultipleAccessStorage::readNameWithTypeImpl(const UUID & id, bool throw_if_not_exists) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2021-12-11 16:29:38 +00:00
|
|
|
if (auto storage = findStorage(id))
|
2022-06-15 18:25:13 +00:00
|
|
|
return storage->readNameWithType(id, throw_if_not_exists);
|
2021-12-11 16:29:38 +00:00
|
|
|
|
|
|
|
if (throw_if_not_exists)
|
|
|
|
throwNotFound(id);
|
|
|
|
else
|
|
|
|
return std::nullopt;
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-22 22:14:11 +00:00
|
|
|
bool MultipleAccessStorage::isReadOnly() const
|
2020-02-26 10:50:13 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
2020-02-26 10:50:13 +00:00
|
|
|
{
|
2021-11-22 22:14:11 +00:00
|
|
|
if (!storage->isReadOnly())
|
|
|
|
return false;
|
2020-02-26 10:50:13 +00:00
|
|
|
}
|
2021-11-22 22:14:11 +00:00
|
|
|
return true;
|
2020-02-26 10:50:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-12 10:14:03 +00:00
|
|
|
bool MultipleAccessStorage::isReadOnly(const UUID & id) const
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2021-12-12 10:14:03 +00:00
|
|
|
auto storage = findStorage(id);
|
|
|
|
if (storage)
|
|
|
|
return storage->isReadOnly(id);
|
|
|
|
return false;
|
|
|
|
}
|
2020-08-05 19:54:06 +00:00
|
|
|
|
2021-12-12 10:14:03 +00:00
|
|
|
|
2022-09-16 11:19:39 +00:00
|
|
|
void MultipleAccessStorage::startPeriodicReloading()
|
2022-05-16 18:43:55 +00:00
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
2022-09-16 11:19:39 +00:00
|
|
|
storage->startPeriodicReloading();
|
2022-05-16 18:43:55 +00:00
|
|
|
}
|
|
|
|
|
2022-09-16 11:19:39 +00:00
|
|
|
void MultipleAccessStorage::stopPeriodicReloading()
|
2022-05-16 18:43:55 +00:00
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
2022-09-16 11:19:39 +00:00
|
|
|
storage->stopPeriodicReloading();
|
2022-05-16 18:43:55 +00:00
|
|
|
}
|
|
|
|
|
2022-09-16 11:19:39 +00:00
|
|
|
void MultipleAccessStorage::reload(ReloadMode reload_mode)
|
2022-05-16 18:43:55 +00:00
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
2022-09-16 11:19:39 +00:00
|
|
|
storage->reload(reload_mode);
|
2022-05-16 18:43:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-12 10:14:03 +00:00
|
|
|
std::optional<UUID> MultipleAccessStorage::insertImpl(const AccessEntityPtr & entity, bool replace_if_exists, bool throw_if_exists)
|
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
std::shared_ptr<IAccessStorage> storage_for_insertion;
|
2021-12-12 10:14:03 +00:00
|
|
|
|
|
|
|
auto storages = getStoragesInternal();
|
2020-08-05 19:54:06 +00:00
|
|
|
for (const auto & storage : *storages)
|
2020-02-26 10:50:13 +00:00
|
|
|
{
|
2021-12-11 22:18:10 +00:00
|
|
|
if (!storage->isReadOnly() || storage->find(entity->getType(), entity->getName()))
|
2020-02-26 10:50:13 +00:00
|
|
|
{
|
2020-08-05 19:54:06 +00:00
|
|
|
storage_for_insertion = storage;
|
2020-02-26 10:50:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-11-09 15:33:07 +00:00
|
|
|
|
2020-08-05 19:54:06 +00:00
|
|
|
if (!storage_for_insertion)
|
2021-12-12 10:14:03 +00:00
|
|
|
{
|
|
|
|
throw Exception(
|
|
|
|
ErrorCodes::ACCESS_STORAGE_FOR_INSERTION_NOT_FOUND,
|
|
|
|
"Could not insert {} because there is no writeable access storage in {}",
|
|
|
|
entity->formatTypeWithName(),
|
|
|
|
getStorageName());
|
|
|
|
}
|
2020-02-26 10:50:13 +00:00
|
|
|
|
2021-12-11 22:18:10 +00:00
|
|
|
auto id = storage_for_insertion->insert(entity, replace_if_exists, throw_if_exists);
|
|
|
|
if (id)
|
|
|
|
{
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
ids_cache.set(*id, storage_for_insertion);
|
|
|
|
}
|
2019-11-09 15:33:07 +00:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-12 13:19:07 +00:00
|
|
|
bool MultipleAccessStorage::removeImpl(const UUID & id, bool throw_if_not_exists)
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2021-12-12 13:19:07 +00:00
|
|
|
if (auto storage = findStorage(id))
|
|
|
|
return storage->remove(id, throw_if_not_exists);
|
|
|
|
|
|
|
|
if (throw_if_not_exists)
|
|
|
|
throwNotFound(id);
|
|
|
|
else
|
|
|
|
return false;
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-12 09:42:15 +00:00
|
|
|
bool MultipleAccessStorage::updateImpl(const UUID & id, const UpdateFunc & update_func, bool throw_if_not_exists)
|
2019-11-09 15:33:07 +00:00
|
|
|
{
|
2021-12-12 09:42:15 +00:00
|
|
|
auto storage_for_updating = findStorage(id);
|
|
|
|
if (!storage_for_updating)
|
|
|
|
{
|
|
|
|
if (throw_if_not_exists)
|
|
|
|
throwNotFound(id);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2020-08-14 21:30:47 +00:00
|
|
|
|
|
|
|
/// If the updating involves renaming check that the renamed entity will be accessible by name.
|
2020-08-05 19:54:06 +00:00
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
if ((storages->size() > 1) && (storages->front() != storage_for_updating))
|
2020-08-14 21:30:47 +00:00
|
|
|
{
|
2021-12-12 09:42:15 +00:00
|
|
|
if (auto old_entity = storage_for_updating->tryRead(id))
|
2020-08-14 21:30:47 +00:00
|
|
|
{
|
2021-12-12 09:42:15 +00:00
|
|
|
auto new_entity = update_func(old_entity);
|
|
|
|
if (new_entity->getName() != old_entity->getName())
|
2020-08-14 21:30:47 +00:00
|
|
|
{
|
2021-12-12 09:42:15 +00:00
|
|
|
for (const auto & storage : *storages)
|
2020-08-14 21:30:47 +00:00
|
|
|
{
|
2021-12-12 09:42:15 +00:00
|
|
|
if (storage == storage_for_updating)
|
|
|
|
break;
|
|
|
|
if (storage->find(new_entity->getType(), new_entity->getName()))
|
|
|
|
{
|
|
|
|
throw Exception(
|
|
|
|
old_entity->formatTypeWithName() + ": cannot rename to " + backQuote(new_entity->getName()) + " because "
|
|
|
|
+ new_entity->formatTypeWithName() + " already exists in " + storage->getStorageName(),
|
|
|
|
ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS);
|
|
|
|
}
|
2020-08-14 21:30:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-12 09:42:15 +00:00
|
|
|
return storage_for_updating->update(id, update_func, throw_if_not_exists);
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-14 14:32:58 +00:00
|
|
|
std::optional<UUID>
|
|
|
|
MultipleAccessStorage::authenticateImpl(const Credentials & credentials, const Poco::Net::IPAddress & address,
|
|
|
|
const ExternalAuthenticators & external_authenticators,
|
|
|
|
bool throw_if_user_not_exists,
|
|
|
|
bool allow_no_password, bool allow_plaintext_password) const
|
2020-09-17 09:58:34 +00:00
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
2022-01-13 11:11:23 +00:00
|
|
|
for (size_t i = 0; i != storages->size(); ++i)
|
2020-09-17 09:58:34 +00:00
|
|
|
{
|
2022-01-13 11:11:23 +00:00
|
|
|
const auto & storage = (*storages)[i];
|
|
|
|
bool is_last_storage = (i == storages->size() - 1);
|
2022-03-14 14:32:58 +00:00
|
|
|
auto id = storage->authenticate(credentials, address, external_authenticators,
|
|
|
|
(throw_if_user_not_exists && is_last_storage),
|
|
|
|
allow_no_password, allow_plaintext_password);
|
2021-12-13 08:27:23 +00:00
|
|
|
if (id)
|
2020-09-17 09:58:34 +00:00
|
|
|
{
|
|
|
|
std::lock_guard lock{mutex};
|
2021-12-13 08:27:23 +00:00
|
|
|
ids_cache.set(*id, storage);
|
2020-09-17 09:58:34 +00:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|
2021-12-13 08:27:23 +00:00
|
|
|
|
|
|
|
if (throw_if_user_not_exists)
|
|
|
|
throwNotFound(AccessEntityType::USER, credentials.getUserName());
|
|
|
|
else
|
|
|
|
return std::nullopt;
|
2020-09-17 09:58:34 +00:00
|
|
|
}
|
|
|
|
|
2022-06-15 18:25:13 +00:00
|
|
|
|
|
|
|
bool MultipleAccessStorage::isBackupAllowed() const
|
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
|
|
|
{
|
|
|
|
if (storage->isBackupAllowed())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool MultipleAccessStorage::isRestoreAllowed() const
|
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
|
|
|
for (const auto & storage : *storages)
|
|
|
|
{
|
|
|
|
if (storage->isRestoreAllowed())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-06-29 20:44:05 +00:00
|
|
|
void MultipleAccessStorage::backup(BackupEntriesCollector & backup_entries_collector, const String & data_path_in_backup, AccessEntityType type) const
|
2022-06-15 18:25:13 +00:00
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
2022-06-29 20:44:05 +00:00
|
|
|
bool allowed = false;
|
2022-06-19 13:48:52 +00:00
|
|
|
|
2022-06-15 18:25:13 +00:00
|
|
|
for (const auto & storage : *storages)
|
|
|
|
{
|
|
|
|
if (storage->isBackupAllowed())
|
|
|
|
{
|
2022-06-29 20:44:05 +00:00
|
|
|
storage->backup(backup_entries_collector, data_path_in_backup, type);
|
|
|
|
allowed = true;
|
2022-06-15 18:25:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-29 20:44:05 +00:00
|
|
|
if (!allowed)
|
2022-06-15 18:25:13 +00:00
|
|
|
throwBackupNotAllowed();
|
|
|
|
}
|
|
|
|
|
2022-06-29 20:44:05 +00:00
|
|
|
void MultipleAccessStorage::restoreFromBackup(RestorerFromBackup & restorer)
|
2022-06-15 18:25:13 +00:00
|
|
|
{
|
|
|
|
auto storages = getStoragesInternal();
|
2022-06-29 20:44:05 +00:00
|
|
|
|
2022-06-15 18:25:13 +00:00
|
|
|
for (const auto & storage : *storages)
|
|
|
|
{
|
|
|
|
if (storage->isRestoreAllowed())
|
|
|
|
{
|
2022-06-29 20:44:05 +00:00
|
|
|
storage->restoreFromBackup(restorer);
|
2022-06-15 18:25:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-06-29 20:44:05 +00:00
|
|
|
|
2022-06-30 08:10:12 +00:00
|
|
|
throwBackupNotAllowed();
|
2022-06-15 18:25:13 +00:00
|
|
|
}
|
|
|
|
|
2019-11-09 15:33:07 +00:00
|
|
|
}
|