2014-03-07 13:50:58 +00:00
|
|
|
#include <zkutil/ZooKeeper.h>
|
|
|
|
#include <boost/make_shared.hpp>
|
2014-03-22 14:44:44 +00:00
|
|
|
#include <Yandex/logger_useful.h>
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
#define CHECKED(x) { ReturnCode::type code = x; if (code != ReturnCode::Ok) throw KeeperException(code); }
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
|
|
namespace zkutil
|
|
|
|
{
|
|
|
|
|
|
|
|
typedef std::promise<WatchEventInfo> WatchPromise;
|
|
|
|
|
|
|
|
struct WatchWithPromise : public zk::Watch
|
|
|
|
{
|
|
|
|
WatchPromise promise;
|
2014-04-08 10:13:49 +00:00
|
|
|
bool notified;
|
|
|
|
|
|
|
|
WatchWithPromise() : notified(false) {}
|
2014-03-07 13:50:58 +00:00
|
|
|
|
|
|
|
void process(WatchEvent::type event, SessionState::type state, const std::string & path)
|
|
|
|
{
|
2014-04-08 10:13:49 +00:00
|
|
|
if (notified)
|
|
|
|
{
|
|
|
|
LOG_WARNING(&Logger::get("WatchWithPromise"), "Ignoring event " << WatchEvent::toString(event) << " with state "
|
|
|
|
<< SessionState::toString(state) << " for path " << path);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-07 13:50:58 +00:00
|
|
|
promise.set_value(WatchEventInfo(event, state, path));
|
2014-04-08 10:13:49 +00:00
|
|
|
notified = true;
|
2014-03-07 13:50:58 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef boost::shared_ptr<zk::Watch> WatchPtr;
|
|
|
|
typedef boost::shared_ptr<WatchWithPromise> WatchWithPromisePtr;
|
|
|
|
|
|
|
|
static WatchPtr watchForFuture(WatchFuture * future)
|
|
|
|
{
|
|
|
|
if (!future)
|
|
|
|
return nullptr;
|
|
|
|
WatchWithPromisePtr res = boost::make_shared<WatchWithPromise>();
|
|
|
|
*future = res->promise.get_future();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct StateWatch : public zk::Watch
|
|
|
|
{
|
|
|
|
ZooKeeper * owner;
|
|
|
|
|
|
|
|
StateWatch(ZooKeeper * owner_) : owner(owner_) {}
|
|
|
|
|
|
|
|
void process(WatchEvent::type event, SessionState::type state, const std::string & path)
|
|
|
|
{
|
|
|
|
owner->stateChanged(event, state, path);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-03-13 14:49:17 +00:00
|
|
|
void ZooKeeper::init(const std::string & hosts, int32_t sessionTimeoutMs, WatchFunction * watch_)
|
2014-03-07 13:50:58 +00:00
|
|
|
{
|
2014-03-13 14:49:17 +00:00
|
|
|
state_watch = watch_;
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
CHECKED(impl.init(hosts, sessionTimeoutMs, boost::make_shared<StateWatch>(this)));
|
|
|
|
|
|
|
|
ACL perm;
|
|
|
|
perm.getid().getscheme() = "world";
|
|
|
|
perm.getid().getid() = "anyone";
|
|
|
|
perm.setperms(zk::Permission::All);
|
|
|
|
default_acl.push_back(perm);
|
|
|
|
}
|
|
|
|
|
2014-03-13 14:49:17 +00:00
|
|
|
ZooKeeper::ZooKeeper(const std::string & hosts, int32_t sessionTimeoutMs, WatchFunction * watch_)
|
|
|
|
{
|
|
|
|
init(hosts, sessionTimeoutMs, watch_);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ZooKeeperArgs
|
|
|
|
{
|
|
|
|
ZooKeeperArgs(const Poco::Util::LayeredConfiguration & config, const std::string & config_name)
|
|
|
|
{
|
|
|
|
Poco::Util::AbstractConfiguration::Keys keys;
|
|
|
|
config.keys(config_name, keys);
|
|
|
|
std::string node_key = "node";
|
|
|
|
|
|
|
|
session_timeout_ms = DEFAULT_SESSION_TIMEOUT;
|
|
|
|
for (const auto & key : keys)
|
|
|
|
{
|
|
|
|
if (key == node_key || key.compare(0, node_key.size(), node_key) == 0)
|
|
|
|
{
|
|
|
|
if (hosts.size())
|
2014-03-21 19:49:27 +00:00
|
|
|
hosts += std::string(",");
|
2014-03-13 14:49:17 +00:00
|
|
|
hosts += config.getString(config_name + "." + key + ".host") + ":" + config.getString(config_name + "." + key + ".port");
|
|
|
|
}
|
|
|
|
else if (key == "session_timeout_ms")
|
|
|
|
{
|
|
|
|
session_timeout_ms = config.getInt(config_name + "." + key);
|
|
|
|
}
|
|
|
|
else throw KeeperException(std::string("Unknown key ") + key + " in config file");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string hosts;
|
|
|
|
size_t session_timeout_ms;
|
|
|
|
};
|
|
|
|
|
|
|
|
ZooKeeper::ZooKeeper(const Poco::Util::LayeredConfiguration & config, const std::string & config_name,
|
|
|
|
WatchFunction * watch)
|
|
|
|
{
|
|
|
|
ZooKeeperArgs args(config, config_name);
|
|
|
|
init(args.hosts, args.session_timeout_ms, watch);
|
|
|
|
}
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
void ZooKeeper::stateChanged(WatchEvent::type event, SessionState::type state, const std::string & path)
|
|
|
|
{
|
2014-03-21 18:58:24 +00:00
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
session_state = state;
|
|
|
|
if (state_watch)
|
|
|
|
(*state_watch)(event, state, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ZooKeeper::disconnected()
|
|
|
|
{
|
2014-03-21 18:58:24 +00:00
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
return session_state == SessionState::Expired || session_state == SessionState::AuthFailed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ZooKeeper::setDefaultACL(ACLs & acl)
|
|
|
|
{
|
2014-03-21 18:58:24 +00:00
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
2014-03-07 13:50:58 +00:00
|
|
|
default_acl = acl;
|
|
|
|
}
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
ACLs ZooKeeper::getDefaultACL()
|
|
|
|
{
|
2014-03-21 18:58:24 +00:00
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
return default_acl;
|
|
|
|
}
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
Strings ZooKeeper::getChildren(
|
2014-03-07 13:50:58 +00:00
|
|
|
const std::string & path, Stat * stat, WatchFuture * watch)
|
|
|
|
{
|
|
|
|
Stat s;
|
|
|
|
Strings res;
|
|
|
|
CHECKED(impl.getChildren(path, watchForFuture(watch), res, s));
|
|
|
|
if (stat)
|
|
|
|
*stat = s;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
bool ZooKeeper::tryGetChildren(const std::string & path, Strings & res,
|
|
|
|
Stat * stat, WatchFuture * watch)
|
|
|
|
{
|
|
|
|
Stat s;
|
|
|
|
ReturnCode::type code = impl.getChildren(path, watchForFuture(watch), res, s);
|
|
|
|
if (!( code == ReturnCode::Ok ||
|
|
|
|
code == ReturnCode::NoNode))
|
|
|
|
throw KeeperException(code);
|
|
|
|
if (code == ReturnCode::NoNode)
|
|
|
|
return false;
|
|
|
|
if (stat)
|
|
|
|
*stat = s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
std::string ZooKeeper::create(const std::string & path, const std::string & data, CreateMode::type mode)
|
|
|
|
{
|
2014-03-21 18:58:24 +00:00
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
std::string res;
|
|
|
|
CHECKED(impl.create(path, data, default_acl, mode, res));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnCode::type ZooKeeper::tryCreate(const std::string & path, const std::string & data, CreateMode::type mode, std::string & pathCreated)
|
|
|
|
{
|
2014-03-21 18:58:24 +00:00
|
|
|
Poco::ScopedLock<Poco::FastMutex> lock(mutex);
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
ReturnCode::type code = impl.create(path, data, default_acl, mode, pathCreated);
|
|
|
|
if (!( code == ReturnCode::Ok ||
|
|
|
|
code == ReturnCode::NoNode ||
|
|
|
|
code == ReturnCode::NodeExists ||
|
|
|
|
code == ReturnCode::NoChildrenForEphemerals))
|
2014-03-07 19:18:48 +00:00
|
|
|
throw KeeperException(code);
|
|
|
|
return code;
|
2014-03-07 17:57:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ZooKeeper::remove(const std::string & path, int32_t version)
|
|
|
|
{
|
|
|
|
CHECKED(impl.remove(path, version));
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnCode::type ZooKeeper::tryRemove(const std::string & path, int32_t version)
|
|
|
|
{
|
|
|
|
ReturnCode::type code = impl.remove(path, version);
|
|
|
|
if (!( code == ReturnCode::Ok ||
|
|
|
|
code == ReturnCode::NoNode ||
|
|
|
|
code == ReturnCode::BadVersion ||
|
|
|
|
code == ReturnCode::NotEmpty))
|
2014-03-07 19:18:48 +00:00
|
|
|
throw KeeperException(code);
|
|
|
|
return code;
|
2014-03-07 17:57:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ZooKeeper::exists(const std::string & path, Stat * stat, WatchFuture * watch)
|
|
|
|
{
|
|
|
|
Stat s;
|
|
|
|
ReturnCode::type code = impl.exists(path, watchForFuture(watch), s);
|
2014-03-07 19:18:48 +00:00
|
|
|
if (!( code == ReturnCode::Ok ||
|
|
|
|
code == ReturnCode::NoNode))
|
2014-03-07 17:57:53 +00:00
|
|
|
throw KeeperException(code);
|
2014-03-07 19:18:48 +00:00
|
|
|
if (code == ReturnCode::NoNode)
|
|
|
|
return false;
|
2014-03-07 17:57:53 +00:00
|
|
|
if (stat)
|
|
|
|
*stat = s;
|
2014-03-07 19:18:48 +00:00
|
|
|
return true;
|
2014-03-07 17:57:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string ZooKeeper::get(const std::string & path, Stat * stat, WatchFuture * watch)
|
|
|
|
{
|
|
|
|
std::string res;
|
|
|
|
Stat s;
|
|
|
|
CHECKED(impl.get(path, watchForFuture(watch), res, s));
|
|
|
|
if (stat)
|
|
|
|
*stat = s;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
bool ZooKeeper::tryGet(const std::string & path, std::string & res, Stat * stat, WatchFuture * watch)
|
2014-03-07 17:57:53 +00:00
|
|
|
{
|
|
|
|
Stat s;
|
2014-03-07 19:18:48 +00:00
|
|
|
ReturnCode::type code = impl.get(path, watchForFuture(watch), res, s);
|
|
|
|
if (!( code == ReturnCode::Ok ||
|
|
|
|
code == ReturnCode::NoNode))
|
|
|
|
throw KeeperException(code);
|
2014-03-07 17:57:53 +00:00
|
|
|
if (code == ReturnCode::NoNode)
|
|
|
|
return false;
|
|
|
|
if (stat)
|
|
|
|
*stat = s;
|
|
|
|
return true;
|
2014-03-07 13:50:58 +00:00
|
|
|
}
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
void ZooKeeper::set(const std::string & path, const std::string & data, int32_t version, Stat * stat)
|
|
|
|
{
|
|
|
|
Stat s;
|
|
|
|
CHECKED(impl.set(path, data, version, s));
|
|
|
|
if (stat)
|
|
|
|
*stat = s;
|
|
|
|
}
|
|
|
|
|
2014-03-07 19:18:48 +00:00
|
|
|
ReturnCode::type ZooKeeper::trySet(const std::string & path, const std::string & data,
|
|
|
|
int32_t version, Stat * stat)
|
|
|
|
{
|
|
|
|
Stat s;
|
|
|
|
ReturnCode::type code = impl.set(path, data, version, s);
|
|
|
|
if (!( code == ReturnCode::Ok ||
|
|
|
|
code == ReturnCode::NoNode ||
|
|
|
|
code == ReturnCode::BadVersion))
|
|
|
|
throw KeeperException(code);
|
|
|
|
if (stat)
|
|
|
|
*stat = s;
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
|
|
|
|
OpResultsPtr ZooKeeper::multi(const Ops & ops)
|
|
|
|
{
|
|
|
|
OpResultsPtr res = std::make_shared<OpResults>();
|
|
|
|
CHECKED(impl.multi(ops, *res));
|
|
|
|
for (size_t i = 0; i < res->size(); ++i)
|
|
|
|
{
|
|
|
|
if ((*res)[i].getReturnCode() != ReturnCode::Ok)
|
|
|
|
throw KeeperException((*res)[i].getReturnCode());
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
OpResultsPtr ZooKeeper::tryMulti(const Ops & ops)
|
|
|
|
{
|
|
|
|
OpResultsPtr res = std::make_shared<OpResults>();
|
|
|
|
CHECKED(impl.multi(ops, *res));
|
|
|
|
for (size_t i = 0; i < res->size(); ++i)
|
|
|
|
{
|
|
|
|
ReturnCode::type code = (*res)[i].getReturnCode();
|
|
|
|
|
|
|
|
if (code != ReturnCode::Ok)
|
|
|
|
{
|
|
|
|
bool ok = false;
|
|
|
|
switch (ops[i].getType())
|
|
|
|
{
|
|
|
|
case zk::OpCode::Create:
|
|
|
|
ok |= code == ReturnCode::NoNode;
|
|
|
|
ok |= code == ReturnCode::NodeExists;
|
|
|
|
ok |= code == ReturnCode::NoChildrenForEphemerals;
|
|
|
|
break;
|
|
|
|
case zk::OpCode::Remove:
|
|
|
|
ok |= code == ReturnCode::NoNode;
|
|
|
|
ok |= code == ReturnCode::BadVersion;
|
|
|
|
ok |= code == ReturnCode::NotEmpty;
|
|
|
|
break;
|
|
|
|
case zk::OpCode::SetData:
|
|
|
|
case zk::OpCode::Check:
|
|
|
|
ok |= code == ReturnCode::NoNode;
|
|
|
|
ok |= code == ReturnCode::BadVersion;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw KeeperException("Unexpected op type");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
throw KeeperException(code);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-03-22 14:44:44 +00:00
|
|
|
void ZooKeeper::removeRecursive(const std::string & path)
|
|
|
|
{
|
|
|
|
Strings children = getChildren(path);
|
|
|
|
for (const std::string & child : children)
|
|
|
|
removeRecursive(path + "/" + child);
|
|
|
|
remove(path);
|
|
|
|
}
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
void ZooKeeper::close()
|
|
|
|
{
|
|
|
|
CHECKED(impl.close());
|
|
|
|
}
|
|
|
|
|
2014-03-22 14:44:44 +00:00
|
|
|
ZooKeeper::~ZooKeeper()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
LOG_ERROR(&Logger::get("~ZooKeeper"), "Failed to close ZooKeeper session");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-07 17:57:53 +00:00
|
|
|
}
|