translate comments

This commit is contained in:
Alexey Zatelepin 2017-03-17 01:39:52 +03:00 committed by alexey-milovidov
parent faadab3034
commit fccbc82c24
5 changed files with 183 additions and 173 deletions

View File

@ -31,29 +31,37 @@ class ConfigProcessor
public:
using Substitutions = std::vector<std::pair<std::string, std::string> >;
/// log_to_console нужно использовать, если система логгирования еще не инициализирована.
/// Set log_to_console to true if the logging subsystem is not initialized yet.
ConfigProcessor(bool throw_on_bad_incl = false, bool log_to_console = false, const Substitutions & substitutions = Substitutions());
~ConfigProcessor();
/** Выполняет подстановки в конфиге и возвращает XML-документ.
*
* Пусть в качестве path передана "/path/file.xml"
* 1) Объединяем xml-дерево из /path/file.xml со всеми деревьями из файлов /path/{conf,file}.d/ *.{conf,xml}
* Если у элемента есть атрибут replace, заменяем на него подходящий элемент.
* Если у элемента есть атрибут remove, удаляем подходящий элемент.
* Иначе объединяем детей рекурсивно.
* 2) Берем из конфига путь к файлу, из которого будем делать подстановки: <include_from>/path2/metrika.xml</include_from>.
* Если путь не указан, используем /etc/metrika.xml
* 3) Заменяем элементы вида "<foo incl="bar"/>" на "<foo>содержимое элемента yandex.bar из metrika.xml</foo>"
* 4) Заменяет "<layer/>" на "<layer>номер слоя из имени хоста</layer>"
*/
/// Perform config includes and substitutions and return the resulting XML-document.
///
/// Suppose path is "/path/file.xml"
/// 1) Merge XML trees of /path/file.xml with XML trees of all files from /path/{conf,file}.d/*.{conf,xml}
/// * If an element has a "replace" attribute, replace the matching element with it.
/// * If an element has a "remove" attribute, remove the matching element.
/// * Else, recursively merge child elements.
/// 2) Determine the includes file from the config: <include_from>/path2/metrika.xml</include_from>
/// If this path is not configured, use /etc/metrika.xml
/// 3) Replace elements matching the "<foo incl="bar"/>" pattern with
/// "<foo>contents of the yandex/bar element in metrika.xml</foo>"
/// 4) If zk_node_cache is non-NULL, replace elements matching the "<foo from_zk="/bar">" pattern with
/// "<foo>contents of the /bar ZooKeeper node</foo>".
/// If has_zk_includes is non-NULL and there are such elements, set has_zk_includes to true.
/// 5) (Yandex.Metrika-specific) Substitute "<layer/>" with "<layer>layer number from the hostname</layer>".
XMLDocumentPtr processConfig(
const std::string & path,
bool * has_zk_includes = nullptr,
zkutil::ZooKeeperNodeCache * zk_node_cache = nullptr);
/// loadConfig* functions apply processConfig and create Poco::Util::XMLConfiguration.
/// The resulting XML document is saved into a file with the name
/// resulting from adding "-preprocessed" suffix to the path file name.
/// E.g., config.xml -> config-preprocessed.xml
struct LoadedConfig
{
ConfigurationPtr configuration;
@ -62,16 +70,13 @@ public:
bool preprocessed_written;
};
/** Делает processConfig и создает из результата Poco::Util::XMLConfiguration.
* Еще сохраняет результат в файл по пути, полученному из path приписыванием строки "-preprocessed" к имени файла.
*/
/// If allow_zk_includes is true, expects that the configuration xml can contain from_zk nodes.
/// If the xml contains them, set has_zk_includes to true and don't write config-preprocessed.xml,
/// If allow_zk_includes is true, expect that the configuration XML can contain from_zk nodes.
/// If it is the case, set has_zk_includes to true and don't write config-preprocessed.xml,
/// expecting that config would be reloaded with zookeeper later.
LoadedConfig loadConfig(const std::string & path, bool allow_zk_includes = false);
/// If fallback_to_preprocessed is true, then if KeeperException is thrown during config
/// processing, load the configuration from the preprocessed file.
LoadedConfig loadConfigWithZooKeeperIncludes(
const std::string & path,
zkutil::ZooKeeperNodeCache & zk_node_cache,

View File

@ -20,7 +20,7 @@ static bool endsWith(const std::string & s, const std::string & suffix)
return s.size() >= suffix.size() && s.substr(s.size() - suffix.size()) == suffix;
}
/// Извлекает из строки первое попавшееся число, состоящее из хотя бы двух цифр.
/// Extracts from a string the first encountered number consisting of at least two digits.
static std::string numberFromHost(const std::string & s)
{
for (size_t i = 0; i < s.size(); ++i)
@ -66,13 +66,14 @@ ConfigProcessor::~ConfigProcessor()
}
/// Вектор из имени элемента и отсортированного списка имен и значений атрибутов (кроме атрибутов replace и remove).
/// Взаимно однозначно задает имя элемента и список его атрибутов. Нужен, чтобы сравнивать элементы.
/// Vector containing the name of the element and a sorted list of attribute names and values
/// (except "remove" and "replace" attributes).
/// Serves as a unique identifier of the element contents for comparison.
using ElementIdentifier = std::vector<std::string>;
using NamedNodeMapPtr = Poco::AutoPtr<Poco::XML::NamedNodeMap>;
/// NOTE Можно избавиться от использования Node.childNodes() и итерации по полученному списку, потому что
/// доступ к i-му элементу этого списка работает за O(i).
/// NOTE getting rid of iterating over the result of Node.childNodes() call is a good idea
/// because accessing the i-th element of this list takes O(i) time.
using NodeListPtr = Poco::AutoPtr<Poco::XML::NodeList>;
static ElementIdentifier getElementIdentifier(Node * element)
@ -107,7 +108,8 @@ static Node * getRootNode(Document * document)
for (size_t i = 0; i < children->length(); ++i)
{
Node * child = children->item(i);
/// Кроме корневого элемента на верхнем уровне могут быть комментарии. Пропустим их.
/// Besides the root element there can be comment nodes on the top level.
/// Skip them.
if (child->nodeType() == Node::ELEMENT_NODE)
return child;
}
@ -135,7 +137,7 @@ void ConfigProcessor::mergeRecursive(XMLDocumentPtr config, Node * config_root,
for (Node * node = config_root->firstChild(); node;)
{
Node * next_node = node->nextSibling();
/// Уберем исходный текст из объединяемой части.
/// Remove text from the original config node.
if (node->nodeType() == Node::TEXT_NODE && !allWhitespace(node->getNodeValue()))
{
config_root->removeChild(node);
@ -241,7 +243,8 @@ void ConfigProcessor::doIncludesRecursive(
if (node->nodeType() != Node::ELEMENT_NODE)
return;
/// Будем заменять <layer> на число из имени хоста, только если во входном файле есть тег <layer>, и он пустой, и у него нет атрибутов
/// Substitute <layer> for the number extracted from the hostname only if there is an
/// empty <layer> tag without attributes in the original file.
if ( node->nodeName() == "layer" &&
!node->hasAttributes() &&
!node->hasChildNodes() &&
@ -259,7 +262,7 @@ void ConfigProcessor::doIncludesRecursive(
if (incl_attribute && from_zk_attribute)
throw Poco::Exception("both incl and from_zk attributes set for element <" + node->nodeName() + ">");
/// Заменять имеющееся значение, а не добавлять к нему.
/// Replace the original contents, not add to it.
bool replace = attributes->getNamedItem("replace");
auto process_include = [&](const Node * include_attr, const std::function<Node * (const std::string &)> & get_node, const char * error_msg)

View File

@ -126,6 +126,9 @@ using EventPtr = std::shared_ptr<Poco::Event>;
class ZooKeeper;
/// Callback to call when the watch fires.
/// Because callbacks are called in the single "completion" thread internal to libzookeeper,
/// they must execute as quickly as possible (preferably just set some notification).
/// Parameters:
/// zookeeper - zookeeper session to which the fired watch belongs
/// type - event type, one of the *_EVENT constants from zookeeper.h
/// state - session connection state, one of the *_STATE constants from zookeeper.h

View File

@ -34,21 +34,26 @@ const UInt32 BIG_SESSION_TIMEOUT = 600000;
struct WatchContext;
/** Сессия в ZooKeeper. Интерфейс существенно отличается от обычного API ZooKeeper.
* Вместо callback-ов для watch-ей используются Poco::Event. Для указанного события вызывается set() только при первом вызове watch.
* Методы на чтение при восстанавливаемых ошибках OperationTimeout, ConnectionLoss пытаются еще retry_num раз.
* Методы на запись не пытаются повторить при восстанавливаемых ошибках, т.к. это приводит к проблеммам типа удаления дважды одного и того же.
*
* Методы с названиями, не начинающимися с try, бросают исключение при любой ошибке.
*/
class ZooKeeper
/// ZooKeeper session. The interface is substantially different from the usual libzookeeper API.
///
/// Poco::Event objects are used for watches. The event is set only once on the first
/// watch notification.
/// Callback-based watch interface is also provided.
///
/// Read-only methods retry retry_num times if recoverable errors like OperationTimeout
/// or ConnectionLoss are encountered.
///
/// Modifying methods do not retry, because it leads to problems of the double-delete type.
///
/// Methods with names not starting at try- raise KeeperException on any error.
class ZooKeeper
{
public:
using Ptr = std::shared_ptr<ZooKeeper>;
ZooKeeper(const std::string & hosts, int32_t session_timeout_ms = DEFAULT_SESSION_TIMEOUT);
/** конфиг вида
/** Config of the form:
<zookeeper>
<node>
<host>example1</host>
@ -65,73 +70,68 @@ public:
~ZooKeeper();
/** Создает новую сессию с теми же параметрами. Можно использовать для переподключения, если сессия истекла.
* Новой сессии соответствует только возвращенный экземпляр ZooKeeper, этот экземпляр не изменяется.
*/
/// Creates a new session with the same parameters. This method can be used for reconnecting
/// after the session has expired.
/// This object remains unchanged, and the new session is returned.
Ptr startNewSession() const;
/** Возвращает true, если сессия навсегда завершена.
* Это возможно только если соединение было установлено, потом разорвалось, потом снова восстановилось, но слишком поздно.
* С другой стороны, если, например, указан неправильный сервер или порт, попытки соединения будут продолжаться бесконечно,
* expired() будет возвращать false, и все вызовы будут выбрасывать исключение ConnectionLoss.
* Также возвращает true, если выставлен флаг is_dirty - просьба побыстрее завершить сессию.
*/
/// Returns true, if the session has expired forever.
/// This is possible only if the connection has been established, then lost and re-established
/// again, but too late.
/// In contrast, if, for instance, the server name or port is misconfigured, connection
/// attempts will continue indefinitely, expired() will return false and all method calls
/// will raise ConnectionLoss exception.
/// Also returns true if is_dirty flag is set - a request to close the session ASAP.
bool expired();
ACLPtr getDefaultACL();
void setDefaultACL(ACLPtr new_acl);
/** Создать znode. Используется ACL, выставленный вызовом setDefaultACL (по умолчанию, всем полный доступ).
* Если что-то пошло не так, бросить исключение.
*/
/// Create a znode. ACL set by setDefaultACL is used (full access to everybody by default).
/// Throw an exception if something went wrong.
std::string create(const std::string & path, const std::string & data, int32_t mode);
/** Не бросает исключение при следующих ошибках:
* - Нет родителя создаваемой ноды.
* - Родитель эфемерный.
* - Такая нода уже есть.
* При остальных ошибках бросает исключение.
*/
/// Doesn not throw in the following cases:
/// * The parent for the created node does not exist
/// * The parent is ephemeral.
/// * The node already exists.
/// In case of other errors throws an exception.
int32_t tryCreate(const std::string & path, const std::string & data, int32_t mode, std::string & path_created);
int32_t tryCreate(const std::string & path, const std::string & data, int32_t mode);
int32_t tryCreateWithRetries(const std::string & path, const std::string & data, int32_t mode,
std::string & path_created, size_t * attempt = nullptr);
/** создает Persistent ноду.
* Игнорирует, если нода уже создана.
* Пытается сделать retry при ConnectionLoss или OperationTimeout
*/
/// Create a Persistent node.
/// Does nothing if the node already exists.
/// Retries on ConnectionLoss or OperationTimeout.
void createIfNotExists(const std::string & path, const std::string & data);
/** Создает всех еще не существующих предков ноды, с пустыми данными. Саму указанную ноду не создает.
*/
/// Creates all non-existent ancestors of the given path with empty contents.
/// Does not create the node itself.
void createAncestors(const std::string & path);
/** Удалить ноду, если ее версия равна version (если -1, подойдет любая версия).
*/
/// Remove the node if the version matches. (if version == -1, remove any version).
void remove(const std::string & path, int32_t version = -1);
/** Удаляет ноду. В случае сетевых ошибок пробует удалять повторно.
* Ошибка ZNONODE для второй и последующих попыток игнорируется
*/
/// Removes the node. In case of network errors tries to remove again.
/// ZNONODE error for the second and the following tries is ignored.
void removeWithRetries(const std::string & path, int32_t version = -1);
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет.
* - У ноды другая версия.
* - У ноды есть дети.
*/
/// Doesn't throw in the following cases:
/// * The node doesn't exist
/// * Versions don't match
/// * The node has children.
int32_t tryRemove(const std::string & path, int32_t version = -1);
/// Если есть проблемы с сетью может сам удалить ноду и вернуть ZNONODE
/// Retries in case of network errors, returns ZNONODE if the node is already removed.
int32_t tryRemoveWithRetries(const std::string & path, int32_t version = -1, size_t * attempt = nullptr);
/** То же самое, но также выставляет флаг is_dirty, если все попытки удалить были неуспешными.
* Это делается, потому что сессия может ещё жить после всех попыток, даже если прошло больше session_timeout времени.
* Поэтому не стоит рассчитывать, что эфемерная нода действительно будет удалена.
* Но флаг is_dirty позволит побыстрее завершить сессию.
Ridiculously Long Delay to Expire
/// The same, but sets is_dirty flag if all removal attempts were unsuccessful.
/// This is needed because the session might still exist after all retries,
/// even if more time than session_timeout has passed.
/// So we do not rely on the ephemeral node being deleted and set is_dirty to
/// try and close the session ASAP.
/** Ridiculously Long Delay to Expire
When disconnects do happen, the common case should be a very* quick
reconnect to another server, but an extended network outage may
introduce a long delay before a client can reconnect to the ZooKeep
@ -156,9 +156,8 @@ public:
std::string get(const std::string & path, Stat * stat = nullptr, const EventPtr & watch = nullptr);
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет. В таком случае возвращает false.
*/
/// Doesn't not throw in the following cases:
/// * The node doesn't exist. Returns false in this case.
bool tryGet(const std::string & path, std::string & res, Stat * stat = nullptr, const EventPtr & watch = nullptr, int * code = nullptr);
bool tryGetWatch(const std::string & path, std::string & res, Stat * stat, const WatchCallback & watch_callback, int * code = nullptr);
@ -166,13 +165,12 @@ public:
void set(const std::string & path, const std::string & data,
int32_t version = -1, Stat * stat = nullptr);
/** Создает ноду, если ее не существует. Иначе обновляет */
/// Creates the node if it doesn't exist. Updates its contents otherwise.
void createOrUpdate(const std::string & path, const std::string & data, int32_t mode);
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет.
* - У ноды другая версия.
*/
/// Doesn't not throw in the following cases:
/// * The node doesn't exist.
/// * Versions do not match.
int32_t trySet(const std::string & path, const std::string & data,
int32_t version = -1, Stat * stat = nullptr);
@ -180,54 +178,51 @@ public:
Stat * stat = nullptr,
const EventPtr & watch = nullptr);
/** Не бросает исключение при следующих ошибках:
* - Такой ноды нет.
*/
/// Doesn't not throw in the following cases:
/// * The node doesn't exist.
int32_t tryGetChildren(const std::string & path, Strings & res,
Stat * stat = nullptr,
const EventPtr & watch = nullptr);
/** Транзакционно выполняет несколько операций. При любой ошибке бросает исключение.
*/
/// Performs several operations in a transaction.
/// Throws on every error.
OpResultsPtr multi(const Ops & ops);
/** Бросает исключение только если какая-нибудь операция вернула "неожиданную" ошибку - такую ошибку,
* увидев которую соответствующий метод try* бросил бы исключение. */
/// Throws only if some operation has returned an "unexpected" error
/// - an error that would cause the corresponding try- method to throw.
int32_t tryMulti(const Ops & ops, OpResultsPtr * out_results = nullptr);
/** Использовать только для методов на чтение */
/// Use only with read-only operations.
int32_t tryMultiWithRetries(const Ops & ops, OpResultsPtr * out_results = nullptr, size_t * attempt = nullptr);
Int64 getClientID();
/** Удаляет ноду вместе с поддеревом. Если в это время кто-то добавит иили удалит ноду в поддереве, результат не определен.
*/
/// Remove the node with the subtree. If someone concurrently adds or removes a node
/// in the subtree, the result is undefined.
void removeRecursive(const std::string & path);
/** Удаляет ноду вместе с поддеревом. Если в это время кто-то будет тоже удалять какие-нибудь ноды в поддереве, не будет ошибок.
* Например, можно вызвать одновременно дважды для одной ноды, и результат будет тот же, как если вызвать один раз.
*/
/// Remove the node with the subtree. If someone concurrently removes a node in the subtree,
/// this will not cause errors.
/// For instance, you can call this method twice concurrently for the same node and the end
/// result would be the same as for the single call.
void tryRemoveRecursive(const std::string & path);
/** Подождать, пока нода перестанет существовать или вернуть сразу, если нода не существует.
*/
/// Wait for the node to disappear or return immediately if it doesn't exist.
void waitForDisappear(const std::string & path);
/** Асинхронный интерфейс (реализовано небольшое подмножество операций).
*
* Использование:
*
* // Эти вызовы не блокируются.
* auto future1 = zk.asyncGet("/path1");
* auto future2 = zk.asyncGet("/path2");
* ...
*
* // Эти вызовы могут заблокироваться до выполнения операции.
* auto result1 = future1.get();
* auto result2 = future2.get();
*
* future не должна быть уничтожена до получения результата.
* Результат обязательно необходимо получать.
*/
/// Async interface (a small subset of operations is implemented).
///
/// Usage:
///
/// // Non-blocking calls:
/// auto future1 = zk.asyncGet("/path1");
/// auto future2 = zk.asyncGet("/path2");
/// ...
///
/// // These calls can block until the operations are completed:
/// auto result1 = future1.get();
/// auto result2 = future2.get();
///
/// Future should not be destroyed before the result is gotten.
template <typename Result, typename... TaskParams>
class Future
@ -238,22 +233,26 @@ public:
using TaskPtr = std::unique_ptr<Task>;
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, чтобы продлить время жизни данных.
*/
/// Everything is complicated.
///
/// In libzookeeper async interface a function (e.g. zoo_aget)
/// accepts a pointer to a standalone callback function and void* pointer to the context
/// which is then passed to the callback.
/// The caller is responsible for ensuring that the context lives until the callback
/// is finished and we can't simply pass ownership of the context into function object.
/// Instead, we save the context in a Future object and return it to the caller.
/// The cantext will live until the Future lives.
/// Context data is wrapped in an unique_ptr so that its address (which is passed to
/// libzookeeper) remains unchanged after the Future is returned from the function.
///
/// The second problem is that after std::promise has been fulfilled, and the user
/// has gotten the result from std::future, the Future object can be destroyed
/// before the std::promise::set_value() call that fulfils the promise completes in another
/// thread.
/// See http://stackoverflow.com/questions/10843304/race-condition-in-pthread-once
/// To combat this we use the second unique_ptr. Inside the callback, the void* context
/// is cast to unique_ptr and moved into the local unique_ptr to prolong the lifetime of
/// the context data.
TaskPtrPtr task;
std::future<Result> future;
@ -272,9 +271,8 @@ public:
~Future()
{
/** Если никто не дождался результата, то мы должны его дождаться перед уничтожением объекта,
* так как данные этого объекта могут всё ещё использоваться в колбэке.
*/
/// If nobody has waited for the result, we must wait for it before the object is
/// destroyed, because the object contents can still be used in the callback.
if (future.valid())
future.wait();
}
@ -322,12 +320,12 @@ public:
static std::string error2string(int32_t code);
/// максимальный размер данных в узле в байтах
/// В версии 3.4.5. максимальный размер узла 1 Mb
/// Max size of node contents in bytes.
/// In 3.4.5 max node size is 1Mb.
static const size_t MAX_NODE_SIZE = 1048576;
/// Размер прибавляемого ZooKeeper суффикса при создании Sequential ноды
/// На самом деле размер меньше, но для удобства округлим в верхнюю сторону
/// Length of the suffix that ZooKeeper adds to sequential nodes.
/// In fact it is smaller, but round it up for convenience.
static const size_t SEQUENTIAL_SUFFIX_SIZE = 64;
@ -357,7 +355,7 @@ private:
if (attempt)
*attempt = i;
/// если потеряно соединение подождем timeout/3, авось восстановится
/// If the connection has been lost, wait timeout/3 hoping for connection re-establishment.
static const int MAX_SLEEP_TIME = 10;
if (code == ZCONNECTIONLOSS)
usleep(std::min(session_timeout_ms * 1000 / 3, MAX_SLEEP_TIME * 1000 * 1000));
@ -369,7 +367,7 @@ private:
return code;
}
/// методы не бросают исключений, а возвращают коды ошибок
/// The following methods don't throw exceptions but return error codes.
int32_t createImpl(const std::string & path, const std::string & data, int32_t mode, std::string & path_created);
int32_t removeImpl(const std::string & path, int32_t version = -1);
int32_t getImpl(const std::string & path, std::string & res, Stat * stat, WatchCallback watch_callback);
@ -387,22 +385,20 @@ private:
std::unordered_set<WatchContext *> watch_context_store;
/// Количество попыток повторить операцию чтения при OperationTimeout, ConnectionLoss
/// Retries number in case of OperationTimeout or ConnectionLoss errors.
static constexpr size_t retry_num = 3;
Logger * log = nullptr;
/** При работе с сессией были неудачные попытки удалить эфемерные ноды,
* после которых лучше завершить сессию (чтобы эфемерные ноды всё-таки удалились)
* вместо того, чтобы продолжить пользоваться восстановившейся сессией.
*/
/// If true, there were unsuccessfull attempts to remove ephemeral nodes.
/// It is better to close the session to remove ephemeral nodes with certainty
/// instead of continuing to use re-established session.
bool is_dirty = false;
};
using ZooKeeperPtr = ZooKeeper::Ptr;
/** В конструкторе создает эфемерную ноду, в деструкторе - удаляет.
*/
/// Creates an ephemeral node in the constructor, removes it in the destructor.
class EphemeralNodeHolder
{
public:
@ -439,10 +435,10 @@ public:
{
try
{
/** Важно, что в случае недоступности ZooKeeper, делаются повторные попытки удалить ноду.
* Иначе возможна ситуация, когда объект EphemeralNodeHolder уничтожен,
* но сессия восстановится в течние session timeout, и эфемерная нода в ZooKeeper останется ещё надолго.
*/
/// Important: if the ZooKeeper is temporarily unavailable, repeated attempts to
/// delete the node are made.
/// Otherwise it is possible that EphemeralNodeHolder is destroyed,
/// but the session has recovered and the node in ZooKeeper remains for the long time.
zookeeper.tryRemoveEphemeralNodeWithRetries(path);
}
catch (const KeeperException & e)

View File

@ -45,7 +45,7 @@ void check(int32_t code, const std::string path = "")
struct WatchContext
{
/// существует все время существования WatchContext
/// ZooKeeper instance exists for the entire WatchContext lifetime.
ZooKeeper & zk;
WatchCallback callback;
CurrentMetrics::Increment metric_increment{CurrentMetrics::ZooKeeperWatch};
@ -64,7 +64,8 @@ void ZooKeeper::processCallback(zhandle_t * zh, int type, int state, const char
WatchContext * context = static_cast<WatchContext *>(watcher_ctx);
context->process(type, state, path);
/// Гарантируется, что не-ZOO_SESSION_EVENT событие придет ровно один раз (https://issues.apache.org/jira/browse/ZOOKEEPER-890).
/// It is guaranteed that non-ZOO_SESSION_EVENT notification will be delivered only once
/// (https://issues.apache.org/jira/browse/ZOOKEEPER-890)
if (type != ZOO_SESSION_EVENT)
destroyContext(context);
}
@ -114,7 +115,7 @@ struct ZooKeeperArgs
else throw KeeperException(std::string("Unknown key ") + key + " in config file");
}
/// перемешиваем порядок хостов, чтобы сделать нагрузку на zookeeper более равномерной
/// Shuffle the hosts to distribute the load among ZooKeeper nodes.
std::random_shuffle(hosts_strings.begin(), hosts_strings.end());
for (auto & host : hosts_strings)
@ -234,7 +235,7 @@ int32_t ZooKeeper::tryGetChildren(const std::string & path, Strings & res,
int32_t ZooKeeper::createImpl(const std::string & path, const std::string & data, int32_t mode, std::string & path_created)
{
int code;
/// имя ноды может быть больше переданного пути, если создается sequential нода.
/// The name of the created node can be longer than path if the sequential node is created.
size_t name_buffer_size = path.size() + SEQUENTIAL_SUFFIX_SIZE;
char * name_buffer = new char[name_buffer_size];
@ -363,8 +364,8 @@ int32_t ZooKeeper::tryRemoveEphemeralNodeWithRetries(const std::string & path, i
}
catch (const KeeperException &)
{
// Установим флажок, который говорит о том, что сессию лучше воспринимать так же как истёкшую,
/// чтобы кто-нибудь её пересоздал, и, в случае эфемерной ноды, нода всё-таки была удалена.
/// Set the flag indicating that the session is better treated as expired so that someone
/// recreates it and the ephemeral nodes are indeed deleted.
is_dirty = true;
throw;
@ -437,7 +438,7 @@ int32_t ZooKeeper::getImpl(const std::string & path, std::string & res, Stat * s
if (stat_)
*stat_ = stat;
if (buffer_len < 0) /// Такое бывает, если в ноде в ZK лежит NULL. Не будем отличать его от пустой строки.
if (buffer_len < 0) /// This can happen if the node contains NULL. Do not distinguish it from the empty string.
res.clear();
else
res.assign(buffer, buffer_len);
@ -537,17 +538,19 @@ int32_t ZooKeeper::multiImpl(const Ops & ops_, OpResultsPtr * out_results_)
if (ops_.empty())
return ZOK;
/// Workaround ошибки в сишном клиенте ZooKeeper. Если сессия истекла, zoo_multi иногда падает с segfault.
/// Наверно, здесь есть race condition, и возможен segfault, если сессия истечет между этой проверкой и zoo_multi.
/// TODO: Посмотреть, не исправлено ли это в последней версии клиента, и исправить.
/// Workaround of the libzookeeper bug. If the session is expired, zoo_multi sometimes
/// segfaults.
/// Possibly, there is a race condition and a segfault is still possible if the session
/// expires between this check and zoo_multi call.
/// TODO: check if the bug is fixed in the latest version of libzookeeper.
if (expired())
return ZINVALIDSTATE;
size_t count = ops_.size();
OpResultsPtr out_results(new OpResults(count));
/// копируем структуру, содержащую указатели, дефолтным конструктором копирования
/// это безопасно, т.к. у нее нет деструктора
/// Copy the struct containing pointers with default copy-constructor.
/// It is safe because it hasn't got a destructor.
std::vector<zoo_op_t> ops;
for (const auto & op : ops_)
ops.push_back(*(op->data));
@ -631,9 +634,9 @@ void ZooKeeper::tryRemoveChildrenRecursive(const std::string & path)
ops.emplace_back(std::make_unique<Op::Remove>(batch.back(), -1));
}
/** Сначала пытаемся удалить детей более быстрым способом - сразу пачкой. Если не получилось,
* значит кто-то кроме нас удаляет этих детей, и придется удалять их по одному.
*/
/// Try to remove the children with a faster method - in bulk. If this fails,
/// this means someone is concurrently removing these children and we will have
/// to remove them one by one.
if (tryMulti(ops) != ZOK)
{
for (const std::string & child : batch)
@ -664,7 +667,7 @@ void ZooKeeper::waitForDisappear(const std::string & path)
zkutil::EventPtr event = std::make_shared<Poco::Event>();
std::string unused;
/// get вместо exists, чтобы не утек watch, если ноды уже нет.
/// Use get instead of exists to prevent watch leak if the node has already disappeared.
if (!tryGet(path, unused, nullptr, event))
break;
@ -684,7 +687,7 @@ ZooKeeper::~ZooKeeper()
LOG_INFO(&Logger::get("~ZooKeeper"), "Removing " << watch_context_store.size() << " watches");
/// удаляем WatchContext которые уже никогда не будут обработаны
/// Destroy WatchContexts that will never be used.
for (WatchContext * context : watch_context_store)
delete context;
@ -739,7 +742,7 @@ ZooKeeper::GetFuture ZooKeeper::asyncGet(const std::string & path)
throw KeeperException(rc, path);
std::string value_str;
if (value_len > 0) /// Может быть не так, если в ZK лежит NULL. Мы не отличаем его от пустой строки.
if (value_len > 0) /// May be otherwise of the node contains NULL. We don't distinguish it from the empty string.
value_str = { value, size_t(value_len) };
return ValueAndStat{ value_str, stat ? *stat : Stat() };
@ -772,7 +775,7 @@ ZooKeeper::TryGetFuture ZooKeeper::asyncTryGet(const std::string & path)
throw KeeperException(rc, path);
std::string value_str;
if (value_len > 0) /// Может быть не так, если в ZK лежит NULL. Мы не отличаем его от пустой строки.
if (value_len > 0) /// May be otherwise of the node contains NULL. We don't distinguish it from the empty string.
value_str = { value, size_t(value_len) };
return ValueAndStatAndExists{ value_str, stat ? *stat : Stat(), rc != ZNONODE };