2014-03-07 13:50:58 +00:00
|
|
|
|
#pragma once
|
2014-10-16 01:46:56 +00:00
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
|
#include <zkutil/Types.h>
|
|
|
|
|
#include <zkutil/KeeperException.h>
|
2014-03-13 14:49:17 +00:00
|
|
|
|
#include <Poco/Util/LayeredConfiguration.h>
|
2014-06-04 13:48:36 +00:00
|
|
|
|
#include <unordered_set>
|
2014-10-16 01:46:56 +00:00
|
|
|
|
#include <future>
|
2014-07-01 13:40:07 +00:00
|
|
|
|
#include <Yandex/logger_useful.h>
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace zkutil
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
const UInt32 DEFAULT_SESSION_TIMEOUT = 30000;
|
2014-11-26 18:58:31 +00:00
|
|
|
|
const UInt32 BIG_SESSION_TIMEOUT = 600000;
|
2014-06-27 17:52:50 +00:00
|
|
|
|
const UInt32 DEFAULT_RETRY_NUM = 3;
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-06-30 11:33:06 +00:00
|
|
|
|
struct WatchWithEvent;
|
2014-06-04 13:48:36 +00:00
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
|
/** Сессия в ZooKeeper. Интерфейс существенно отличается от обычного API ZooKeeper.
|
2014-07-01 08:50:03 +00:00
|
|
|
|
* Вместо callback-ов для watch-ей используются Poco::Event. Для указанного события вызывается set() только при первом вызове watch.
|
2014-06-26 19:08:48 +00:00
|
|
|
|
* Методы на чтение при восстанавливаемых ошибках OperationTimeout, ConnectionLoss пытаются еще retry_num раз.
|
|
|
|
|
* Методы на запись не пытаются повторить при восстанавливаемых ошибках, т.к. это приводит к проблеммам типа удаления дважды одного и того же.
|
|
|
|
|
*
|
|
|
|
|
* Методы с названиями, не начинающимися с 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-11-26 18:58:51 +00:00
|
|
|
|
ZooKeeper(const std::string & hosts, int32_t session_timeout_ms = DEFAULT_SESSION_TIMEOUT);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-03-13 14:56:31 +00:00
|
|
|
|
/** конфиг вида
|
|
|
|
|
<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>
|
|
|
|
|
*/
|
2014-07-08 12:45:10 +00:00
|
|
|
|
ZooKeeper(const Poco::Util::AbstractConfiguration & config, const std::string & config_name);
|
2014-11-26 18:58:31 +00:00
|
|
|
|
ZooKeeper(const Poco::Util::AbstractConfiguration & config, const std::string & config_name, int32_t session_timeout_ms);
|
2014-03-13 14:49:17 +00:00
|
|
|
|
|
2014-03-22 14:44:44 +00:00
|
|
|
|
~ZooKeeper();
|
|
|
|
|
|
2014-04-24 08:27:39 +00:00
|
|
|
|
/** Создает новую сессию с теми же параметрами. Можно использовать для переподключения, если сессия истекла.
|
|
|
|
|
* Новой сессии соответствует только возвращенный экземпляр ZooKeeper, этот экземпляр не изменяется.
|
|
|
|
|
*/
|
|
|
|
|
Ptr startNewSession() const;
|
|
|
|
|
|
2014-06-04 13:48:36 +00:00
|
|
|
|
int state();
|
|
|
|
|
|
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
|
|
|
|
|
2014-11-30 07:01:00 +00:00
|
|
|
|
ACLPtr getDefaultACL();
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-11-30 07:01:00 +00:00
|
|
|
|
void setDefaultACL(ACLPtr new_acl);
|
2014-03-07 19:18:48 +00:00
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
|
/** Создать znode. Используется ACL, выставленный вызовом setDefaultACL (по умолчанию, всем полный доступ).
|
|
|
|
|
* Если что-то пошло не так, бросить исключение.
|
|
|
|
|
*/
|
2014-06-04 13:48:36 +00:00
|
|
|
|
std::string create(const std::string & path, const std::string & data, int32_t mode);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
|
|
|
|
/** Не бросает исключение при следующих ошибках:
|
|
|
|
|
* - Нет родителя создаваемой ноды.
|
|
|
|
|
* - Родитель эфемерный.
|
|
|
|
|
* - Такая нода уже есть.
|
|
|
|
|
* При остальных ошибках бросает исключение.
|
|
|
|
|
*/
|
2014-06-04 13:48:36 +00:00
|
|
|
|
int32_t tryCreate(const std::string & path, const std::string & data, int32_t mode, std::string & pathCreated);
|
|
|
|
|
int32_t tryCreate(const std::string & path, const std::string & data, int32_t mode);
|
2014-07-03 17:24:17 +00:00
|
|
|
|
int32_t tryCreateWithRetries(const std::string & path, const std::string & data, int32_t mode,
|
|
|
|
|
std::string & pathCreated, size_t * attempt = nullptr);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-06-27 17:52:50 +00:00
|
|
|
|
/** создает Persistent ноду.
|
|
|
|
|
* Игнорирует, если нода уже создана.
|
|
|
|
|
* Пытается сделать retry при ConnectionLoss или OperationTimeout
|
|
|
|
|
*/
|
|
|
|
|
void createIfNotExists(const std::string & path, const std::string & data);
|
|
|
|
|
|
2014-08-11 14:05:38 +00:00
|
|
|
|
/** Создает всех еще не существующих предков ноды, с пустыми данными. Саму указанную ноду не создает.
|
|
|
|
|
*/
|
|
|
|
|
void createAncestors(const std::string & path);
|
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
|
/** Удалить ноду, если ее версия равна version (если -1, подойдет любая версия).
|
|
|
|
|
*/
|
|
|
|
|
void remove(const std::string & path, int32_t version = -1);
|
|
|
|
|
|
|
|
|
|
/** Не бросает исключение при следующих ошибках:
|
|
|
|
|
* - Такой ноды нет.
|
|
|
|
|
* - У ноды другая версия.
|
|
|
|
|
* - У ноды есть дети.
|
|
|
|
|
*/
|
2014-06-04 13:48:36 +00:00
|
|
|
|
int32_t tryRemove(const std::string & path, int32_t version = -1);
|
2014-07-02 15:04:42 +00:00
|
|
|
|
/// Если есть проблемы с сетью может сам удалить ноду и вернуть ZNONODE
|
2014-07-03 17:24:17 +00:00
|
|
|
|
int32_t tryRemoveWithRetries(const std::string & path, int32_t version = -1, size_t * attempt = nullptr);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-06-30 11:33:06 +00:00
|
|
|
|
bool exists(const std::string & path, Stat * stat = nullptr, EventPtr watch = nullptr);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-06-30 11:33:06 +00:00
|
|
|
|
std::string get(const std::string & path, Stat * stat = nullptr, EventPtr watch = nullptr);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
|
/** Не бросает исключение при следующих ошибках:
|
|
|
|
|
* - Такой ноды нет. В таком случае возвращает false.
|
|
|
|
|
*/
|
2014-06-30 11:33:06 +00:00
|
|
|
|
bool tryGet(const std::string & path, std::string & res, Stat * stat = nullptr, EventPtr 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);
|
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
|
/** Не бросает исключение при следующих ошибках:
|
|
|
|
|
* - Такой ноды нет.
|
|
|
|
|
* - У ноды другая версия.
|
|
|
|
|
*/
|
2014-06-04 13:48:36 +00:00
|
|
|
|
int32_t trySet(const std::string & path, const std::string & data,
|
2014-03-07 19:18:48 +00:00
|
|
|
|
int32_t version = -1, Stat * stat = nullptr);
|
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
|
Strings getChildren(const std::string & path,
|
|
|
|
|
Stat * stat = nullptr,
|
2014-06-30 11:33:06 +00:00
|
|
|
|
EventPtr watch = nullptr);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
|
/** Не бросает исключение при следующих ошибках:
|
2014-06-04 16:48:55 +00:00
|
|
|
|
* - Такой ноды нет.
|
2014-03-07 19:18:48 +00:00
|
|
|
|
*/
|
2014-06-04 13:48:36 +00:00
|
|
|
|
int32_t tryGetChildren(const std::string & path, Strings & res,
|
2014-03-07 19:18:48 +00:00
|
|
|
|
Stat * stat = nullptr,
|
2014-06-30 11:33:06 +00:00
|
|
|
|
EventPtr watch = nullptr);
|
2014-03-07 19:18:48 +00:00
|
|
|
|
|
|
|
|
|
/** Транзакционно выполняет несколько операций. При любой ошибке бросает исключение.
|
|
|
|
|
*/
|
|
|
|
|
OpResultsPtr multi(const Ops & ops);
|
|
|
|
|
|
|
|
|
|
/** Бросает исключение только если какая-нибудь операция вернула "неожиданную" ошибку - такую ошибку,
|
2014-03-22 14:44:44 +00:00
|
|
|
|
* увидев которую соответствующий метод try* бросил бы исключение. */
|
2014-06-04 13:48:36 +00:00
|
|
|
|
int32_t tryMulti(const Ops & ops, OpResultsPtr * out_results = nullptr);
|
2014-06-30 14:21:39 +00:00
|
|
|
|
/** Использовать только для методов на чтение */
|
2014-07-03 11:22:12 +00:00
|
|
|
|
int32_t tryMultiWithRetries(const Ops & ops, OpResultsPtr * out_results = nullptr, size_t * attempt = nullptr);
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
2014-07-03 17:24:17 +00:00
|
|
|
|
int64_t getClientID();
|
2014-03-22 14:44:44 +00:00
|
|
|
|
|
|
|
|
|
/** Удаляет ноду вместе с поддеревом. Если в это время кто-то добавит иили удалит ноду в поддереве, результат не определен.
|
|
|
|
|
*/
|
|
|
|
|
void removeRecursive(const std::string & path);
|
|
|
|
|
|
2014-07-07 09:51:42 +00:00
|
|
|
|
/** Удаляет ноду вместе с поддеревом. Если в это время кто-то будет тоже удалять какие-нибудь ноды в поддереве, не будет ошибок.
|
|
|
|
|
* Например, можно вызвать одновременно дважды для одной ноды, и результат будет тот же, как если вызвать один раз.
|
|
|
|
|
*/
|
|
|
|
|
void tryRemoveRecursive(const std::string & path);
|
|
|
|
|
|
2014-10-16 01:46:56 +00:00
|
|
|
|
|
2014-10-16 20:05:26 +00:00
|
|
|
|
/** Асинхронный интерфейс (реализовано небольшое подмножество операций).
|
|
|
|
|
*
|
|
|
|
|
* Использование:
|
|
|
|
|
*
|
|
|
|
|
* // Эти вызовы не блокируются.
|
|
|
|
|
* auto future1 = zk.asyncGet("/path1");
|
|
|
|
|
* auto future2 = zk.asyncGet("/path2");
|
|
|
|
|
* ...
|
|
|
|
|
*
|
|
|
|
|
* // Эти вызовы могут заблокироваться до выполнения операции.
|
|
|
|
|
* auto result1 = future1.get();
|
|
|
|
|
* auto result2 = future2.get();
|
|
|
|
|
*
|
|
|
|
|
* future не должна быть уничтожена до получения результата.
|
|
|
|
|
* Результат обязательно необходимо получать.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
template <typename Result, typename... TaskParams>
|
|
|
|
|
class Future
|
|
|
|
|
{
|
|
|
|
|
friend class ZooKeeper;
|
|
|
|
|
private:
|
|
|
|
|
using Task = std::packaged_task<Result (TaskParams...)>;
|
|
|
|
|
using TaskPtr = std::unique_ptr<Task>;
|
2014-12-14 04:38:11 +00:00
|
|
|
|
using TaskPtrPtr = std::unique_ptr<TaskPtr>;
|
|
|
|
|
|
|
|
|
|
/** Всё очень сложно.
|
|
|
|
|
*
|
|
|
|
|
* В асинхронном интерфейсе libzookeeper, функция (например, zoo_aget)
|
|
|
|
|
* принимает указатель на свободную функцию-коллбэк и void* указатель на данные.
|
|
|
|
|
* Указатель на данные потом передаётся в callback.
|
|
|
|
|
* Это значит, что мы должны сами обеспечить, чтобы данные жили во время работы этой функции и до конца работы callback-а,
|
|
|
|
|
* и не можем просто так передать владение данными внутрь функции.
|
|
|
|
|
* Для этого, мы засовываем данные в объект Future, который возвращается пользователю. Данные будут жить, пока живёт объект Future.
|
|
|
|
|
* Данные засунуты в unique_ptr, чтобы при возврате объекта Future из функции, их адрес (который передаётся в libzookeeper) не менялся.
|
|
|
|
|
*
|
|
|
|
|
* Вторая проблема состоит в том, что после того, как std::promise был удовлетворён, и пользователь получил результат из std::future,
|
|
|
|
|
* объект Future может быть уничтожен, при чём раньше, чем завершит работу в другом потоке функция, которая удовлетворяет promise.
|
|
|
|
|
* См. http://stackoverflow.com/questions/10843304/race-condition-in-pthread-once
|
|
|
|
|
* Чтобы этого избежать, используется второй unique_ptr. Внутри callback-а, void* данные преобразуются в unique_ptr, и
|
|
|
|
|
* перемещаются в локальную переменную unique_ptr, чтобы продлить время жизни данных.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TaskPtrPtr task;
|
|
|
|
|
std::future<Result> future;
|
2014-10-16 20:05:26 +00:00
|
|
|
|
|
|
|
|
|
template <typename... Args>
|
2014-12-14 04:38:11 +00:00
|
|
|
|
Future(Args &&... args) : task(new TaskPtr(new Task(std::forward<Args>(args)...))), future((*task)->get_future()) {}
|
2014-10-16 20:05:26 +00:00
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Result get()
|
|
|
|
|
{
|
2014-12-14 04:38:11 +00:00
|
|
|
|
return future.get();
|
2014-10-16 20:05:26 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2014-10-16 01:46:56 +00:00
|
|
|
|
struct ValueAndStat
|
|
|
|
|
{
|
|
|
|
|
std::string value;
|
|
|
|
|
Stat stat;
|
|
|
|
|
};
|
|
|
|
|
|
2014-10-16 20:05:26 +00:00
|
|
|
|
using GetFuture = Future<ValueAndStat, int, const char *, int, const Stat *>;
|
|
|
|
|
GetFuture asyncGet(const std::string & path);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ValueAndStatAndExists
|
|
|
|
|
{
|
|
|
|
|
std::string value;
|
|
|
|
|
Stat stat;
|
|
|
|
|
bool exists;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using TryGetFuture = Future<ValueAndStatAndExists, int, const char *, int, const Stat *>;
|
|
|
|
|
TryGetFuture asyncTryGet(const std::string & path);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct StatAndExists
|
|
|
|
|
{
|
|
|
|
|
Stat stat;
|
|
|
|
|
bool exists;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using ExistsFuture = Future<StatAndExists, int, const Stat *>;
|
|
|
|
|
ExistsFuture asyncExists(const std::string & path);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using GetChildrenFuture = Future<Strings, int, const String_vector *>;
|
|
|
|
|
GetChildrenFuture asyncGetChildren(const std::string & path);
|
2014-10-16 01:46:56 +00:00
|
|
|
|
|
|
|
|
|
|
2014-06-04 13:48:36 +00:00
|
|
|
|
static std::string error2string(int32_t code);
|
|
|
|
|
|
|
|
|
|
/// максимальный размер данных в узле в байтах
|
|
|
|
|
/// В версии 3.4.5. максимальный размер узла 1 Mb
|
|
|
|
|
static const size_t MAX_NODE_SIZE = 1048576;
|
|
|
|
|
|
|
|
|
|
/// Размер прибавляемого ZooKeeper суффикса при создании Sequential ноды
|
|
|
|
|
/// На самом деле размер меньше, но для удобства округлим в верхнюю сторону
|
|
|
|
|
static const size_t SEQUENTIAL_SUFFIX_SIZE = 64;
|
2014-03-07 13:50:58 +00:00
|
|
|
|
private:
|
2014-06-30 11:33:06 +00:00
|
|
|
|
friend struct WatchWithEvent;
|
2014-09-12 00:32:27 +00:00
|
|
|
|
friend class EphemeralNodeHolder;
|
2014-06-30 11:33:06 +00:00
|
|
|
|
|
2014-11-26 18:58:51 +00:00
|
|
|
|
void init(const std::string & hosts, int32_t session_timeout_ms);
|
2014-06-04 13:48:36 +00:00
|
|
|
|
void removeChildrenRecursive(const std::string & path);
|
2014-07-07 09:51:42 +00:00
|
|
|
|
void tryRemoveChildrenRecursive(const std::string & path);
|
2014-06-30 11:33:06 +00:00
|
|
|
|
void * watchForEvent(EventPtr event);
|
|
|
|
|
watcher_fn callbackForEvent(EventPtr event);
|
2014-10-18 17:53:18 +00:00
|
|
|
|
static void processEvent(zhandle_t * zh, int type, int state, const char * path, void * watcherCtx);
|
2014-04-25 13:55:15 +00:00
|
|
|
|
|
2014-06-04 16:48:55 +00:00
|
|
|
|
template <class T>
|
2014-10-16 01:21:03 +00:00
|
|
|
|
int32_t retry(T && operation, size_t * attempt = nullptr)
|
2014-06-04 16:48:55 +00:00
|
|
|
|
{
|
|
|
|
|
int32_t code = operation();
|
2014-07-03 11:22:12 +00:00
|
|
|
|
if (attempt)
|
|
|
|
|
*attempt = 0;
|
2014-07-03 17:24:17 +00:00
|
|
|
|
for (size_t i = 0; (i < retry_num) && (code == ZOPERATIONTIMEOUT || code == ZCONNECTIONLOSS); ++i)
|
2014-06-04 16:48:55 +00:00
|
|
|
|
{
|
2014-07-03 11:22:12 +00:00
|
|
|
|
if (attempt)
|
|
|
|
|
*attempt = i;
|
|
|
|
|
|
2014-07-01 13:40:07 +00:00
|
|
|
|
/// если потеряно соединение подождем timeout/3, авось восстановится
|
2014-11-27 12:25:23 +00:00
|
|
|
|
static const int MAX_SLEEP_TIME = 10;
|
2014-07-01 13:40:07 +00:00
|
|
|
|
if (code == ZCONNECTIONLOSS)
|
2014-11-27 12:25:23 +00:00
|
|
|
|
usleep(std::min(session_timeout_ms * 1000 / 3, MAX_SLEEP_TIME * 1000 * 1000));
|
2014-07-01 13:40:07 +00:00
|
|
|
|
|
2014-07-08 10:13:29 +00:00
|
|
|
|
LOG_WARNING(log, "Error on attempt " << i << ": " << error2string(code) << ". Retry");
|
2014-06-04 16:48:55 +00:00
|
|
|
|
code = operation();
|
|
|
|
|
}
|
2014-07-03 11:22:12 +00:00
|
|
|
|
|
2014-06-04 16:48:55 +00:00
|
|
|
|
return code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// методы не бросают исключений, а возвращают коды ошибок
|
|
|
|
|
int32_t createImpl(const std::string & path, const std::string & data, int32_t mode, std::string & pathCreated);
|
|
|
|
|
int32_t removeImpl(const std::string & path, int32_t version = -1);
|
2014-06-30 11:33:06 +00:00
|
|
|
|
int32_t getImpl(const std::string & path, std::string & res, Stat * stat = nullptr, EventPtr watch = nullptr);
|
2014-06-04 16:48:55 +00:00
|
|
|
|
int32_t setImpl(const std::string & path, const std::string & data,
|
|
|
|
|
int32_t version = -1, Stat * stat = nullptr);
|
|
|
|
|
int32_t getChildrenImpl(const std::string & path, Strings & res,
|
|
|
|
|
Stat * stat = nullptr,
|
2014-06-30 11:33:06 +00:00
|
|
|
|
EventPtr watch = nullptr);
|
2014-06-04 16:48:55 +00:00
|
|
|
|
int32_t multiImpl(const Ops & ops, OpResultsPtr * out_results = nullptr);
|
2014-06-30 11:33:06 +00:00
|
|
|
|
int32_t existsImpl(const std::string & path, Stat * stat_, EventPtr watch = nullptr);
|
2014-06-04 16:48:55 +00:00
|
|
|
|
|
2014-05-13 10:10:26 +00:00
|
|
|
|
std::string hosts;
|
2014-11-26 18:58:51 +00:00
|
|
|
|
int32_t session_timeout_ms;
|
2014-03-21 18:58:24 +00:00
|
|
|
|
|
|
|
|
|
Poco::FastMutex mutex;
|
2014-11-30 07:02:36 +00:00
|
|
|
|
ACLPtr default_acl;
|
2014-06-04 13:48:36 +00:00
|
|
|
|
zhandle_t * impl;
|
2014-05-19 09:21:57 +00:00
|
|
|
|
|
2014-06-30 11:33:06 +00:00
|
|
|
|
std::unordered_set<WatchWithEvent *> watch_store;
|
2014-06-04 16:48:55 +00:00
|
|
|
|
|
2014-06-26 19:08:48 +00:00
|
|
|
|
/// Количество попыток повторить операцию чтения при OperationTimeout, ConnectionLoss
|
2014-06-04 16:48:55 +00:00
|
|
|
|
size_t retry_num = 3;
|
2014-07-01 13:40:07 +00:00
|
|
|
|
Logger * log = nullptr;
|
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);
|
|
|
|
|
}
|
2014-09-12 00:32:27 +00:00
|
|
|
|
catch (const KeeperException & e)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(zookeeper.log, "~EphemeralNodeHolder(): " << e.displayText());
|
|
|
|
|
}
|
2014-03-22 14:44:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::string path;
|
|
|
|
|
ZooKeeper & zookeeper;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef EphemeralNodeHolder::Ptr EphemeralNodeHolderPtr;
|
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
|
}
|