ClickHouse/libs/libzkutil/include/zkutil/ZooKeeper.h

209 lines
8.6 KiB
C
Raw Normal View History

2014-03-07 13:50:58 +00:00
#pragma once
#include <zkutil/Types.h>
#include <zkutil/KeeperException.h>
#include <Poco/Util/LayeredConfiguration.h>
2014-03-07 13:50:58 +00:00
namespace zkutil
{
const UInt32 DEFAULT_SESSION_TIMEOUT = 30000;
/** Сессия в ZooKeeper. Интерфейс существенно отличается от обычного API ZooKeeper.
* Вместо callback-ов для watch-ей используются std::future.
* Методы с названиями, не начинающимися с try, бросают исключение при любой ошибке.
* Методы с названиями, начинающимися с try, не бросают исключение только при перечисленных видах ошибок.
2014-03-07 13:50:58 +00:00
* Например, исключение бросается в любом случае, если сессия разорвалась или если не хватает прав или ресурсов.
*/
class ZooKeeper
{
public:
2014-04-24 08:27:39 +00:00
typedef Poco::SharedPtr<ZooKeeper> Ptr;
2014-03-07 13:50:58 +00:00
ZooKeeper(const std::string & hosts, int32_t sessionTimeoutMs = DEFAULT_SESSION_TIMEOUT, WatchFunction * watch = nullptr);
/** конфиг вида
<zookeeper>
<node>
<host>example1</host>
<port>2181</port>
</node>
<node>
<host>example2</host>
<port>2181</port>
</node>
<session_timeout_ms>30000</session_timeout_ms>
</zookeeper>
*/
ZooKeeper(const Poco::Util::AbstractConfiguration & config, const std::string & config_name,
WatchFunction * watch = nullptr);
2014-03-22 14:44:44 +00:00
~ZooKeeper();
2014-04-24 08:27:39 +00:00
/** Создает новую сессию с теми же параметрами. Можно использовать для переподключения, если сессия истекла.
* Новой сессии соответствует только возвращенный экземпляр ZooKeeper, этот экземпляр не изменяется.
*/
Ptr startNewSession() const;
2014-03-07 17:57:53 +00:00
/** Возвращает true, если сессия навсегда завершена.
2014-04-24 08:27:39 +00:00
* Это возможно только если соединение было установлено, потом разорвалось, потом снова восстановилось, но слишком поздно.
* Это достаточно редкая ситуация.
2014-03-07 17:57:53 +00:00
* С другой стороны, если, например, указан неправильный сервер или порт, попытки соединения будут продолжаться бесконечно,
2014-04-24 08:27:39 +00:00
* expired() будет возвращать false, и все вызовы будут выбрасывать исключение ConnectionLoss.
2014-03-07 17:57:53 +00:00
*/
2014-04-24 08:27:39 +00:00
bool expired();
2014-03-07 13:50:58 +00:00
void setDefaultACL(ACLs & acl);
ACLs getDefaultACL();
2014-03-07 13:50:58 +00:00
/** Создать znode. Используется ACL, выставленный вызовом setDefaultACL (по умолчанию, всем полный доступ).
* Если что-то пошло не так, бросить исключение.
*/
std::string create(const std::string & path, const std::string & data, CreateMode::type mode);
/** Не бросает исключение при следующих ошибках:
* - Нет родителя создаваемой ноды.
* - Родитель эфемерный.
* - Такая нода уже есть.
* При остальных ошибках бросает исключение.
*/
ReturnCode::type tryCreate(const std::string & path, const std::string & data, CreateMode::type mode, std::string & pathCreated);
2014-05-07 13:58:20 +00:00
ReturnCode::type tryCreate(const std::string & path, const std::string & data, CreateMode::type mode);
2014-03-07 13:50:58 +00:00
/** Удалить ноду, если ее версия равна version (если -1, подойдет любая версия).
*/
void remove(const std::string & path, int32_t version = -1);
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет.
* - У ноды другая версия.
* - У ноды есть дети.
*/
ReturnCode::type tryRemove(const std::string & path, int32_t version = -1);
bool exists(const std::string & path, Stat * stat = nullptr, WatchFuture * watch = nullptr);
2014-03-22 14:44:44 +00:00
std::string get(const std::string & path, Stat * stat = nullptr, WatchFuture * watch = nullptr);
2014-03-07 13:50:58 +00:00
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет. В таком случае возвращает false.
*/
bool tryGet(const std::string & path, std::string & res, Stat * stat = nullptr, WatchFuture * watch = nullptr);
2014-03-07 13:50:58 +00:00
void set(const std::string & path, const std::string & data,
int32_t version = -1, Stat * stat = nullptr);
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет.
* - У ноды другая версия.
*/
ReturnCode::type trySet(const std::string & path, const std::string & data,
int32_t version = -1, Stat * stat = nullptr);
2014-03-07 13:50:58 +00:00
Strings getChildren(const std::string & path,
Stat * stat = nullptr,
WatchFuture * watch = nullptr);
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет. В таком случае возвращает false.
*/
bool tryGetChildren(const std::string & path, Strings & res,
Stat * stat = nullptr,
WatchFuture * watch = nullptr);
2014-03-07 17:57:53 +00:00
void close();
/** Транзакционно выполняет несколько операций. При любой ошибке бросает исключение.
*/
OpResultsPtr multi(const Ops & ops);
/** Бросает исключение только если какая-нибудь операция вернула "неожиданную" ошибку - такую ошибку,
2014-03-22 14:44:44 +00:00
* увидев которую соответствующий метод try* бросил бы исключение. */
2014-04-09 15:52:47 +00:00
ReturnCode::type tryMulti(const Ops & ops, OpResultsPtr * out_results = nullptr);
2014-03-07 13:50:58 +00:00
2014-03-22 14:44:44 +00:00
/** Удаляет ноду вместе с поддеревом. Если в это время кто-то добавит иили удалит ноду в поддереве, результат не определен.
*/
void removeRecursive(const std::string & path);
2014-03-07 13:50:58 +00:00
private:
void init(const std::string & hosts, int32_t sessionTimeoutMs, WatchFunction * watch_);
2014-03-07 13:50:58 +00:00
friend struct StateWatch;
zk::ZooKeeper impl;
2014-04-25 13:55:15 +00:00
2014-05-13 10:10:26 +00:00
std::string hosts;
2014-04-25 13:55:15 +00:00
int32_t sessionTimeoutMs;
2014-03-07 13:50:58 +00:00
WatchFunction * state_watch;
2014-03-21 18:58:24 +00:00
Poco::FastMutex mutex;
ACLs default_acl;
2014-03-07 13:50:58 +00:00
SessionState::type session_state;
void stateChanged(WatchEvent::type event, SessionState::type state, const std::string& path);
/** Бросает исключение, если сессия истекла. Почему-то zkcpp этого не делает, а вместо этого виснет (смотри zkcpp_expiration_test).
* Не очень надежно: возможно, вызов к zkcpp все же может повиснуть, если между проверкой и вызовом состояние успеет поменяться.
* Если это окажется проблемой, возможно, стоит избавиться от zkcpp.
*/
void checkNotExpired();
void removeChildrenRecursive(const std::string & path);
2014-03-07 13:50:58 +00:00
};
2014-04-25 13:55:15 +00:00
typedef ZooKeeper::Ptr ZooKeeperPtr;
2014-03-22 14:44:44 +00:00
/** В конструкторе создает эфемерную ноду, в деструкторе - удаляет.
*/
class EphemeralNodeHolder
{
public:
typedef Poco::SharedPtr<EphemeralNodeHolder> Ptr;
EphemeralNodeHolder(const std::string & path_, ZooKeeper & zookeeper_, bool create, bool sequential, const std::string & data)
: path(path_), zookeeper(zookeeper_)
{
if (create)
2014-04-04 10:37:33 +00:00
path = zookeeper.create(path, data, sequential ? CreateMode::EphemeralSequential : CreateMode::Ephemeral);
}
std::string getPath() const
{
return path;
2014-03-22 14:44:44 +00:00
}
static Ptr create(const std::string & path, ZooKeeper & zookeeper, const std::string & data = "")
{
return new EphemeralNodeHolder(path, zookeeper, true, false, data);
}
static Ptr createSequential(const std::string & path, ZooKeeper & zookeeper, const std::string & data = "")
{
return new EphemeralNodeHolder(path, zookeeper, true, true, data);
}
static Ptr existing(const std::string & path, ZooKeeper & zookeeper)
{
return new EphemeralNodeHolder(path, zookeeper, false, false, "");
}
~EphemeralNodeHolder()
{
try
{
zookeeper.tryRemove(path);
}
catch (KeeperException) {}
}
private:
std::string path;
ZooKeeper & zookeeper;
};
typedef EphemeralNodeHolder::Ptr EphemeralNodeHolderPtr;
2014-03-07 13:50:58 +00:00
}