#pragma once #include #include #include #include namespace Poco { class Logger; } namespace zkutil { /** Caveats: usage of locks in ZooKeeper is incorrect in 99% of cases, * and highlights your poor understanding of distributed systems. * * It's only correct if all the operations that are performed under lock * are atomically checking that the lock still holds * or if we ensure that these operations will be undone if lock is lost * (due to ZooKeeper session loss) that's very difficult to achieve. * * It's Ok if every operation that we perform under lock is actually operation in ZooKeeper. * * In 1% of cases when you can correctly use Lock, the logic is complex enough, so you don't need this class. * * TLDR: Don't use this code if you are not sure. We only have a few cases of it's usage. */ class ZooKeeperLock { public: /// lock_prefix - path where the ephemeral lock node will be created /// lock_name - the name of the ephemeral lock node ZooKeeperLock( const ZooKeeperPtr & zookeeper_, const std::string & lock_prefix_, const std::string & lock_name_, const std::string & lock_message_ = "", bool throw_if_lost_ = true); ~ZooKeeperLock(); void unlock(); bool tryLock(); bool isLocked() const; const std::string & getLockPath() const; private: zkutil::ZooKeeperPtr zookeeper; std::string lock_path; std::string lock_message; bool throw_if_lost{true}; LoggerPtr log; bool locked = false; }; std::unique_ptr createSimpleZooKeeperLock( const ZooKeeperPtr & zookeeper, const String & lock_prefix, const String & lock_name, const String & lock_message, bool throw_if_lost = true); }