mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'sharding' of ssh://github.com/triAGENS/ArangoDB into sharding
This commit is contained in:
commit
d50d4d019f
|
@ -351,9 +351,60 @@ std::list<AgencyEndpoint*> AgencyComm::_globalEndpoints;
|
||||||
AgencyConnectionOptions AgencyComm::_globalConnectionOptions = {
|
AgencyConnectionOptions AgencyComm::_globalConnectionOptions = {
|
||||||
15.0, // connectTimeout
|
15.0, // connectTimeout
|
||||||
3.0, // requestTimeout
|
3.0, // requestTimeout
|
||||||
|
5.0, // lockTimeout
|
||||||
3 // numRetries
|
3 // numRetries
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- AgencyCommLocker
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors and destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructs an agency comm locker
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AgencyCommLocker::AgencyCommLocker (std::string const& key,
|
||||||
|
std::string const& type,
|
||||||
|
double ttl)
|
||||||
|
: _key(key),
|
||||||
|
_type(type),
|
||||||
|
_isLocked(false) {
|
||||||
|
|
||||||
|
AgencyComm comm;
|
||||||
|
if (comm.lock(key, ttl, 0.0, type)) {
|
||||||
|
_isLocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief destroys an agency comm locker
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AgencyCommLocker::~AgencyCommLocker () {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief unlocks the lock
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void AgencyCommLocker::unlock () {
|
||||||
|
if (_isLocked) {
|
||||||
|
AgencyComm comm;
|
||||||
|
if (comm.unlock(_key, _type, 0.0)) {
|
||||||
|
_isLocked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- AgencyComm
|
// --SECTION-- AgencyComm
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -574,59 +625,6 @@ bool AgencyComm::hasEndpoint (std::string const& endpointSpecification) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief sets the global prefix for all operations
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void AgencyComm::setPrefix (std::string const& prefix) {
|
|
||||||
// agency prefix must not be changed
|
|
||||||
if (! _globalPrefix.empty() && prefix != _globalPrefix) {
|
|
||||||
LOG_ERROR("agency-prefix cannot be changed at runtime");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_globalPrefix = prefix;
|
|
||||||
|
|
||||||
// make sure prefix starts with a forward slash
|
|
||||||
if (prefix[0] != '/') {
|
|
||||||
_globalPrefix = '/' + _globalPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure prefix ends with a forward slash
|
|
||||||
if (_globalPrefix.size() > 0) {
|
|
||||||
if (_globalPrefix[_globalPrefix.size() - 1] != '/') {
|
|
||||||
_globalPrefix += '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_TRACE("setting agency-prefix to '%s'", prefix.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief gets the global prefix for all operations
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::string AgencyComm::prefix () {
|
|
||||||
return _globalPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief generate a timestamp
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::string AgencyComm::generateStamp () {
|
|
||||||
time_t tt = time(0);
|
|
||||||
struct tm tb;
|
|
||||||
char buffer[21];
|
|
||||||
|
|
||||||
// TODO: optimise this
|
|
||||||
TRI_gmtime(tt, &tb);
|
|
||||||
|
|
||||||
size_t len = ::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &tb);
|
|
||||||
|
|
||||||
return std::string(buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get a stringified version of the endpoints
|
/// @brief get a stringified version of the endpoints
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -683,6 +681,76 @@ const std::string AgencyComm::getEndpointsString () {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief sets the global prefix for all operations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void AgencyComm::setPrefix (std::string const& prefix) {
|
||||||
|
// agency prefix must not be changed
|
||||||
|
if (! _globalPrefix.empty() && prefix != _globalPrefix) {
|
||||||
|
LOG_ERROR("agency-prefix cannot be changed at runtime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_globalPrefix = prefix;
|
||||||
|
|
||||||
|
// make sure prefix starts with a forward slash
|
||||||
|
if (prefix[0] != '/') {
|
||||||
|
_globalPrefix = '/' + _globalPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure prefix ends with a forward slash
|
||||||
|
if (_globalPrefix.size() > 0) {
|
||||||
|
if (_globalPrefix[_globalPrefix.size() - 1] != '/') {
|
||||||
|
_globalPrefix += '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_TRACE("setting agency-prefix to '%s'", prefix.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief gets the global prefix for all operations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string AgencyComm::prefix () {
|
||||||
|
return _globalPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief generate a timestamp
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string AgencyComm::generateStamp () {
|
||||||
|
time_t tt = time(0);
|
||||||
|
struct tm tb;
|
||||||
|
char buffer[21];
|
||||||
|
|
||||||
|
// TODO: optimise this
|
||||||
|
TRI_gmtime(tt, &tb);
|
||||||
|
|
||||||
|
size_t len = ::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &tb);
|
||||||
|
|
||||||
|
return std::string(buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief validates the lock type
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool AgencyComm::checkLockType (std::string const& key,
|
||||||
|
std::string const& value) {
|
||||||
|
if (key != "Plan" && key != "Current" && key != "Target") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != "READ" && value != "WRITE") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private static methods
|
// --SECTION-- private static methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -728,7 +796,7 @@ bool AgencyComm::sendServerState () {
|
||||||
":" +
|
":" +
|
||||||
AgencyComm::generateStamp();
|
AgencyComm::generateStamp();
|
||||||
|
|
||||||
AgencyCommResult result(setValue("Sync/ServerStates/" + ServerState::instance()->getId(), value));
|
AgencyCommResult result(setValue("Sync/ServerStates/" + ServerState::instance()->getId(), value, 0.0));
|
||||||
return result.successful();
|
return result.successful();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,13 +843,14 @@ AgencyCommResult AgencyComm::createDirectory (std::string const& key) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AgencyCommResult AgencyComm::setValue (std::string const& key,
|
AgencyCommResult AgencyComm::setValue (std::string const& key,
|
||||||
std::string const& value) {
|
std::string const& value,
|
||||||
|
double ttl) {
|
||||||
AgencyCommResult result;
|
AgencyCommResult result;
|
||||||
|
|
||||||
sendWithFailover(triagens::rest::HttpRequest::HTTP_REQUEST_PUT,
|
sendWithFailover(triagens::rest::HttpRequest::HTTP_REQUEST_PUT,
|
||||||
_globalConnectionOptions._requestTimeout,
|
_globalConnectionOptions._requestTimeout,
|
||||||
result,
|
result,
|
||||||
buildUrl(key),
|
buildUrl(key) + ttlParam(ttl, true),
|
||||||
"value=" + triagens::basics::StringUtils::urlEncode(value),
|
"value=" + triagens::basics::StringUtils::urlEncode(value),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
@ -842,13 +911,14 @@ AgencyCommResult AgencyComm::removeValues (std::string const& key,
|
||||||
AgencyCommResult AgencyComm::casValue (std::string const& key,
|
AgencyCommResult AgencyComm::casValue (std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
bool prevExists,
|
bool prevExists,
|
||||||
|
double ttl,
|
||||||
double timeout) {
|
double timeout) {
|
||||||
AgencyCommResult result;
|
AgencyCommResult result;
|
||||||
|
|
||||||
sendWithFailover(triagens::rest::HttpRequest::HTTP_REQUEST_PUT,
|
sendWithFailover(triagens::rest::HttpRequest::HTTP_REQUEST_PUT,
|
||||||
timeout == 0.0 ? _globalConnectionOptions._requestTimeout : timeout,
|
timeout == 0.0 ? _globalConnectionOptions._requestTimeout : timeout,
|
||||||
result,
|
result,
|
||||||
buildUrl(key) + "?prevExists=" + (prevExists ? "true" : "false"),
|
buildUrl(key) + "?prevExists=" + (prevExists ? "true" : "false") + ttlParam(ttl, false),
|
||||||
"value=" + triagens::basics::StringUtils::urlEncode(value),
|
"value=" + triagens::basics::StringUtils::urlEncode(value),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
@ -864,13 +934,14 @@ AgencyCommResult AgencyComm::casValue (std::string const& key,
|
||||||
AgencyCommResult AgencyComm::casValue (std::string const& key,
|
AgencyCommResult AgencyComm::casValue (std::string const& key,
|
||||||
std::string const& oldValue,
|
std::string const& oldValue,
|
||||||
std::string const& newValue,
|
std::string const& newValue,
|
||||||
|
double ttl,
|
||||||
double timeout) {
|
double timeout) {
|
||||||
AgencyCommResult result;
|
AgencyCommResult result;
|
||||||
|
|
||||||
sendWithFailover(triagens::rest::HttpRequest::HTTP_REQUEST_PUT,
|
sendWithFailover(triagens::rest::HttpRequest::HTTP_REQUEST_PUT,
|
||||||
timeout == 0.0 ? _globalConnectionOptions._requestTimeout : timeout,
|
timeout == 0.0 ? _globalConnectionOptions._requestTimeout : timeout,
|
||||||
result,
|
result,
|
||||||
buildUrl(key) + "?prevValue=" + triagens::basics::StringUtils::urlEncode(oldValue),
|
buildUrl(key) + "?prevValue=" + triagens::basics::StringUtils::urlEncode(oldValue) + ttlParam(ttl, false),
|
||||||
"value=" + triagens::basics::StringUtils::urlEncode(newValue),
|
"value=" + triagens::basics::StringUtils::urlEncode(newValue),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
@ -951,7 +1022,8 @@ bool AgencyComm::unlockWrite (std::string const& key,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AgencyCommResult AgencyComm::uniqid (std::string const& key,
|
AgencyCommResult AgencyComm::uniqid (std::string const& key,
|
||||||
uint64_t count) {
|
uint64_t count,
|
||||||
|
double timeout) {
|
||||||
static const int maxTries = 10;
|
static const int maxTries = 10;
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
|
|
||||||
|
@ -978,7 +1050,7 @@ AgencyCommResult AgencyComm::uniqid (std::string const& key,
|
||||||
|
|
||||||
uint64_t newValue = triagens::basics::StringUtils::int64(oldValue) + count;
|
uint64_t newValue = triagens::basics::StringUtils::int64(oldValue) + count;
|
||||||
|
|
||||||
result = casValue(key, oldValue, triagens::basics::StringUtils::itoa(newValue), 0.0);
|
result = casValue(key, oldValue, triagens::basics::StringUtils::itoa(newValue), 0.0, timeout);
|
||||||
|
|
||||||
if (result.successful()) {
|
if (result.successful()) {
|
||||||
result._index = triagens::basics::StringUtils::int64(oldValue) + 1;
|
result._index = triagens::basics::StringUtils::int64(oldValue) + 1;
|
||||||
|
@ -993,6 +1065,19 @@ AgencyCommResult AgencyComm::uniqid (std::string const& key,
|
||||||
// --SECTION-- private methods
|
// --SECTION-- private methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief creates a ttl URL parameter
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string AgencyComm::ttlParam (double ttl,
|
||||||
|
bool isFirst) {
|
||||||
|
if (ttl <= 0.0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return (isFirst ? "?ttl=" : "&ttl=") + triagens::basics::StringUtils::itoa((int) ttl);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief acquires a lock
|
/// @brief acquires a lock
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1001,13 +1086,32 @@ bool AgencyComm::lock (std::string const& key,
|
||||||
double ttl,
|
double ttl,
|
||||||
double timeout,
|
double timeout,
|
||||||
std::string const& value) {
|
std::string const& value) {
|
||||||
|
if (! checkLockType(key, value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout == 0.0) {
|
||||||
|
timeout = _globalConnectionOptions._lockTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
assert(value == "READ" || value == "WRITE");
|
|
||||||
const double end = TRI_microtime() + timeout;
|
const double end = TRI_microtime() + timeout;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
AgencyCommResult result = casValue(key, "UNLOCKED", value, timeout);
|
AgencyCommResult result = casValue(key + "/Lock",
|
||||||
|
"UNLOCKED",
|
||||||
|
value,
|
||||||
|
ttl,
|
||||||
|
timeout);
|
||||||
|
|
||||||
|
if (! result.successful() && result.httpCode() == 404) {
|
||||||
|
// key does not yet exist. create it now
|
||||||
|
result = casValue(key + "/Lock",
|
||||||
|
value,
|
||||||
|
false,
|
||||||
|
ttl,
|
||||||
|
timeout);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.successful()) {
|
if (result.successful()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1032,13 +1136,23 @@ bool AgencyComm::lock (std::string const& key,
|
||||||
bool AgencyComm::unlock (std::string const& key,
|
bool AgencyComm::unlock (std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
double timeout) {
|
double timeout) {
|
||||||
|
if (! checkLockType(key, value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout == 0.0) {
|
||||||
|
timeout = _globalConnectionOptions._lockTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
assert(value == "READ" || value == "WRITE");
|
|
||||||
const double end = TRI_microtime() + timeout;
|
const double end = TRI_microtime() + timeout;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
AgencyCommResult result = casValue(key, value, "UNLOCKED", timeout);
|
AgencyCommResult result = casValue(key + "/Lock",
|
||||||
|
value,
|
||||||
|
std::string("UNLOCKED"),
|
||||||
|
0.0,
|
||||||
|
timeout);
|
||||||
|
|
||||||
if (result.successful()) {
|
if (result.successful()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1056,10 +1170,6 @@ bool AgencyComm::unlock (std::string const& key,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief releases a lock
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief pop an endpoint from the queue
|
/// @brief pop an endpoint from the queue
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -103,6 +103,7 @@ namespace triagens {
|
||||||
struct AgencyConnectionOptions {
|
struct AgencyConnectionOptions {
|
||||||
double _connectTimeout;
|
double _connectTimeout;
|
||||||
double _requestTimeout;
|
double _requestTimeout;
|
||||||
|
double _lockTimeout;
|
||||||
size_t _connectRetries;
|
size_t _connectRetries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -180,6 +181,14 @@ namespace triagens {
|
||||||
return _location;
|
return _location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return the body (might be empty)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const std::string body () const {
|
||||||
|
return _body;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief recursively flatten the JSON response into a map
|
/// @brief recursively flatten the JSON response into a map
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -211,12 +220,64 @@ namespace triagens {
|
||||||
bool _connected;
|
bool _connected;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- AgencyCommLocker
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class AgencyCommLocker {
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors / destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructs an agency comm locker
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AgencyCommLocker (std::string const&,
|
||||||
|
std::string const&,
|
||||||
|
double);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief destroys an agency comm locker
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
~AgencyCommLocker ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief unlocks the lock
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void unlock ();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- private variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const std::string _key;
|
||||||
|
const std::string _type;
|
||||||
|
bool _isLocked;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- AgencyComm
|
// --SECTION-- AgencyComm
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class AgencyComm {
|
class AgencyComm {
|
||||||
friend struct AgencyCommResult;
|
friend struct AgencyCommResult;
|
||||||
|
friend class AgencyCommLocker;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- constructors / destructors
|
// --SECTION-- constructors / destructors
|
||||||
|
@ -307,6 +368,13 @@ namespace triagens {
|
||||||
|
|
||||||
static std::string generateStamp ();
|
static std::string generateStamp ();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief validates the lock type
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static bool checkLockType (std::string const&,
|
||||||
|
std::string const&);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private static methods
|
// --SECTION-- private static methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -344,7 +412,8 @@ namespace triagens {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AgencyCommResult setValue (std::string const&,
|
AgencyCommResult setValue (std::string const&,
|
||||||
std::string const&);
|
std::string const&,
|
||||||
|
double);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief gets one or multiple values from the back end
|
/// @brief gets one or multiple values from the back end
|
||||||
|
@ -368,6 +437,7 @@ namespace triagens {
|
||||||
AgencyCommResult casValue (std::string const&,
|
AgencyCommResult casValue (std::string const&,
|
||||||
std::string const&,
|
std::string const&,
|
||||||
bool,
|
bool,
|
||||||
|
double,
|
||||||
double);
|
double);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -379,6 +449,7 @@ namespace triagens {
|
||||||
AgencyCommResult casValue (std::string const&,
|
AgencyCommResult casValue (std::string const&,
|
||||||
std::string const&,
|
std::string const&,
|
||||||
std::string const&,
|
std::string const&,
|
||||||
|
double,
|
||||||
double);
|
double);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -386,7 +457,8 @@ namespace triagens {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
AgencyCommResult uniqid (std::string const&,
|
AgencyCommResult uniqid (std::string const&,
|
||||||
uint64_t);
|
uint64_t,
|
||||||
|
double);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief blocks on a change of a single value in the back end
|
/// @brief blocks on a change of a single value in the back end
|
||||||
|
@ -433,6 +505,13 @@ namespace triagens {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief create a URL parameter for a TTL value
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string ttlParam (double,
|
||||||
|
bool);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief acquire a lock
|
/// @brief acquire a lock
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -263,33 +263,41 @@ bool ApplicationCluster::open () {
|
||||||
ServerState::RoleEnum role = ServerState::instance()->getRole();
|
ServerState::RoleEnum role = ServerState::instance()->getRole();
|
||||||
|
|
||||||
// tell the agency that we are ready
|
// tell the agency that we are ready
|
||||||
AgencyComm comm;
|
{
|
||||||
AgencyCommResult result = comm.setValue("Current/ServersRegistered/" + _myId, _myAddress);
|
AgencyCommLocker locker("Current", "WRITE", 0.0);
|
||||||
|
|
||||||
|
AgencyComm comm;
|
||||||
|
AgencyCommResult result = comm.setValue("Current/ServersRegistered/" + _myId, _myAddress, 0.0);
|
||||||
|
|
||||||
if (! result.successful()) {
|
if (! result.successful()) {
|
||||||
LOG_FATAL_AND_EXIT("unable to register server in agency");
|
locker.unlock();
|
||||||
}
|
LOG_FATAL_AND_EXIT("unable to register server in agency");
|
||||||
|
}
|
||||||
|
|
||||||
if (role == ServerState::ROLE_COORDINATOR) {
|
if (role == ServerState::ROLE_COORDINATOR) {
|
||||||
ServerState::instance()->setState(ServerState::STATE_SERVING);
|
ServerState::instance()->setState(ServerState::STATE_SERVING);
|
||||||
|
|
||||||
// register coordinator
|
// register coordinator
|
||||||
AgencyCommResult result = comm.setValue("Current/Coordinators/" + _myId, "none");
|
AgencyCommResult result = comm.setValue("Current/Coordinators/" + _myId, "none", 0.0);
|
||||||
if (! result.successful()) {
|
if (! result.successful()) {
|
||||||
LOG_FATAL_AND_EXIT("unable to register coordinator in agency");
|
locker.unlock();
|
||||||
|
LOG_FATAL_AND_EXIT("unable to register coordinator in agency");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (role == ServerState::ROLE_PRIMARY) {
|
||||||
else if (role == ServerState::ROLE_PRIMARY) {
|
ServerState::instance()->setState(ServerState::STATE_SERVINGASYNC);
|
||||||
ServerState::instance()->setState(ServerState::STATE_SERVINGASYNC);
|
|
||||||
|
|
||||||
// register server
|
// register server
|
||||||
AgencyCommResult result = comm.setValue("Current/DBServers/" + _myId, "none");
|
AgencyCommResult result = comm.setValue("Current/DBServers/" + _myId, "none", 0.0);
|
||||||
if (! result.successful()) {
|
if (! result.successful()) {
|
||||||
LOG_FATAL_AND_EXIT("unable to register db server in agency");
|
locker.unlock();
|
||||||
|
LOG_FATAL_AND_EXIT("unable to register db server in agency");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (role == ServerState::ROLE_SECONDARY) {
|
||||||
|
locker.unlock();
|
||||||
|
LOG_FATAL_AND_EXIT("secondary server tasks are currently not implemented");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (role == ServerState::ROLE_SECONDARY) {
|
|
||||||
LOG_FATAL_AND_EXIT("secondary server tasks are currently not implemented");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -329,9 +337,13 @@ void ApplicationCluster::stop () {
|
||||||
comm.sendServerState();
|
comm.sendServerState();
|
||||||
|
|
||||||
_heartbeat->stop();
|
_heartbeat->stop();
|
||||||
|
|
||||||
// unregister ourselves
|
{
|
||||||
comm.removeValues("Current/ServersRegistered/" + _myId, false);
|
AgencyCommLocker locker("Current", "WRITE", 0.0);
|
||||||
|
|
||||||
|
// unregister ourselves
|
||||||
|
comm.removeValues("Current/ServersRegistered/" + _myId, false);
|
||||||
|
}
|
||||||
|
|
||||||
ClusterComm::cleanup();
|
ClusterComm::cleanup();
|
||||||
ClusterInfo::cleanup();
|
ClusterInfo::cleanup();
|
||||||
|
@ -380,11 +392,17 @@ std::string ApplicationCluster::getEndpointForId () const {
|
||||||
|
|
||||||
ServerState::RoleEnum ApplicationCluster::checkCoordinatorsList () const {
|
ServerState::RoleEnum ApplicationCluster::checkCoordinatorsList () const {
|
||||||
// fetch value at Plan/Coordinators
|
// fetch value at Plan/Coordinators
|
||||||
// we need this to determine the server's role
|
// we need to do this to determine the server's role
|
||||||
|
|
||||||
|
AgencyCommLocker locker("Plan", "READ", 0.0);
|
||||||
|
|
||||||
const std::string key = "Plan/Coordinators";
|
const std::string key = "Plan/Coordinators";
|
||||||
|
|
||||||
AgencyComm comm;
|
AgencyComm comm;
|
||||||
AgencyCommResult result = comm.getValues(key, true);
|
AgencyCommResult result = comm.getValues(key, true);
|
||||||
|
|
||||||
|
// do this here because we might abort the program below
|
||||||
|
locker.unlock();
|
||||||
|
|
||||||
if (! result.successful()) {
|
if (! result.successful()) {
|
||||||
const std::string endpoints = AgencyComm::getEndpointsString();
|
const std::string endpoints = AgencyComm::getEndpointsString();
|
||||||
|
@ -419,11 +437,17 @@ ServerState::RoleEnum ApplicationCluster::checkCoordinatorsList () const {
|
||||||
|
|
||||||
ServerState::RoleEnum ApplicationCluster::checkServersList () const {
|
ServerState::RoleEnum ApplicationCluster::checkServersList () const {
|
||||||
// fetch value at Plan/DBServers
|
// fetch value at Plan/DBServers
|
||||||
// we need this to determine the server's role
|
// we need to do this to determine the server's role
|
||||||
|
|
||||||
|
AgencyCommLocker locker("Plan", "READ", 0.0);
|
||||||
|
|
||||||
const std::string key = "Plan/DBServers";
|
const std::string key = "Plan/DBServers";
|
||||||
|
|
||||||
AgencyComm comm;
|
AgencyComm comm;
|
||||||
AgencyCommResult result = comm.getValues(key, true);
|
AgencyCommResult result = comm.getValues(key, true);
|
||||||
|
|
||||||
|
// do this here because we might abort the program below
|
||||||
|
locker.unlock();
|
||||||
|
|
||||||
if (! result.successful()) {
|
if (! result.successful()) {
|
||||||
const std::string endpoints = AgencyComm::getEndpointsString();
|
const std::string endpoints = AgencyComm::getEndpointsString();
|
||||||
|
|
|
@ -164,7 +164,7 @@ uint64_t ServerState::uniqid () {
|
||||||
|
|
||||||
if (_uniqid._currentValue >= _uniqid._upperValue) {
|
if (_uniqid._currentValue >= _uniqid._upperValue) {
|
||||||
AgencyComm comm;
|
AgencyComm comm;
|
||||||
AgencyCommResult result = comm.uniqid("Sync/LatestID", ValuesPerBatch);
|
AgencyCommResult result = comm.uniqid("Sync/LatestID", ValuesPerBatch, 0.0);
|
||||||
|
|
||||||
if (! result.successful() || result._index == 0) {
|
if (! result.successful() || result._index == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -77,25 +77,30 @@ static v8::Handle<v8::Value> JS_CasAgency (v8::Arguments const& argv) {
|
||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
|
|
||||||
if (argv.Length() < 3) {
|
if (argv.Length() < 3) {
|
||||||
TRI_V8_EXCEPTION_USAGE(scope, "cas(<key>, <oldValue>, <newValue>, <timeout>, <throw>)");
|
TRI_V8_EXCEPTION_USAGE(scope, "cas(<key>, <oldValue>, <newValue>, <ttl>, <timeout>, <throw>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string key = TRI_ObjectToString(argv[0]);
|
const std::string key = TRI_ObjectToString(argv[0]);
|
||||||
const std::string oldValue = TRI_ObjectToString(argv[1]);
|
const std::string oldValue = TRI_ObjectToString(argv[1]);
|
||||||
const std::string newValue = TRI_ObjectToString(argv[2]);
|
const std::string newValue = TRI_ObjectToString(argv[2]);
|
||||||
|
|
||||||
double timeout = 1.0;
|
double ttl = 0.0;
|
||||||
if (argv.Length() > 3) {
|
if (argv.Length() > 3) {
|
||||||
timeout = TRI_ObjectToDouble(argv[3]);
|
ttl = TRI_ObjectToDouble(argv[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeout = 1.0;
|
||||||
|
if (argv.Length() > 4) {
|
||||||
|
timeout = TRI_ObjectToDouble(argv[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldThrow = false;
|
bool shouldThrow = false;
|
||||||
if (argv.Length() > 4) {
|
if (argv.Length() > 5) {
|
||||||
shouldThrow = TRI_ObjectToBoolean(argv[4]);
|
shouldThrow = TRI_ObjectToBoolean(argv[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
AgencyComm comm;
|
AgencyComm comm;
|
||||||
AgencyCommResult result = comm.casValue(key, oldValue, newValue, timeout);
|
AgencyCommResult result = comm.casValue(key, oldValue, newValue, ttl, timeout);
|
||||||
|
|
||||||
if (! result.successful()) {
|
if (! result.successful()) {
|
||||||
if (! shouldThrow) {
|
if (! shouldThrow) {
|
||||||
|
@ -226,6 +231,120 @@ static v8::Handle<v8::Value> JS_GetAgency (v8::Arguments const& argv) {
|
||||||
return scope.Close(l);
|
return scope.Close(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief acquires a read-lock in the agency
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static v8::Handle<v8::Value> JS_LockReadAgency (v8::Arguments const& argv) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
|
||||||
|
if (argv.Length() < 1) {
|
||||||
|
TRI_V8_EXCEPTION_USAGE(scope, "lockRead(<part>, <ttl>, <timeout>)");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string part = TRI_ObjectToString(argv[0]);
|
||||||
|
|
||||||
|
double ttl = 0.0;
|
||||||
|
if (argv.Length() > 1) {
|
||||||
|
ttl = TRI_ObjectToDouble(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeout = 0.0;
|
||||||
|
if (argv.Length() > 2) {
|
||||||
|
timeout = TRI_ObjectToDouble(argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
AgencyComm comm;
|
||||||
|
if (! comm.lockRead(part, ttl, timeout)) {
|
||||||
|
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_INTERNAL, "unable to acquire lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.Close(v8::True());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief acquires a write-lock in the agency
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static v8::Handle<v8::Value> JS_LockWriteAgency (v8::Arguments const& argv) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
|
||||||
|
if (argv.Length() < 1) {
|
||||||
|
TRI_V8_EXCEPTION_USAGE(scope, "lockWrite(<part>, <ttl>, <timeout>)");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string part = TRI_ObjectToString(argv[0]);
|
||||||
|
|
||||||
|
double ttl = 0.0;
|
||||||
|
if (argv.Length() > 1) {
|
||||||
|
ttl = TRI_ObjectToDouble(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeout = 0.0;
|
||||||
|
if (argv.Length() > 2) {
|
||||||
|
timeout = TRI_ObjectToDouble(argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
AgencyComm comm;
|
||||||
|
if (! comm.lockWrite(part, ttl, timeout)) {
|
||||||
|
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_INTERNAL, "unable to acquire lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.Close(v8::True());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief releases a read-lock in the agency
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static v8::Handle<v8::Value> JS_UnlockReadAgency (v8::Arguments const& argv) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
|
||||||
|
if (argv.Length() > 2) {
|
||||||
|
TRI_V8_EXCEPTION_USAGE(scope, "unlockRead(<part>, <timeout>)");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string part = TRI_ObjectToString(argv[0]);
|
||||||
|
|
||||||
|
double timeout = 0.0;
|
||||||
|
if (argv.Length() > 1) {
|
||||||
|
timeout = TRI_ObjectToDouble(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
AgencyComm comm;
|
||||||
|
if (! comm.unlockRead(part, timeout)) {
|
||||||
|
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_INTERNAL, "unable to release lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.Close(v8::True());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief releases a write-lock in the agency
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static v8::Handle<v8::Value> JS_UnlockWriteAgency (v8::Arguments const& argv) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
|
||||||
|
if (argv.Length() > 2) {
|
||||||
|
TRI_V8_EXCEPTION_USAGE(scope, "unlockWrite(<part>, <timeout>)");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string part = TRI_ObjectToString(argv[0]);
|
||||||
|
|
||||||
|
double timeout = 0.0;
|
||||||
|
if (argv.Length() > 1) {
|
||||||
|
timeout = TRI_ObjectToDouble(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
AgencyComm comm;
|
||||||
|
if (! comm.unlockWrite(part, timeout)) {
|
||||||
|
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_INTERNAL, "unable to release lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.Close(v8::True());
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief removes a value from the agency
|
/// @brief removes a value from the agency
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -262,14 +381,19 @@ static v8::Handle<v8::Value> JS_SetAgency (v8::Arguments const& argv) {
|
||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
|
|
||||||
if (argv.Length() < 2) {
|
if (argv.Length() < 2) {
|
||||||
TRI_V8_EXCEPTION_USAGE(scope, "set(<key>, <value>)");
|
TRI_V8_EXCEPTION_USAGE(scope, "set(<key>, <value>, <ttl>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string key = TRI_ObjectToString(argv[0]);
|
const std::string key = TRI_ObjectToString(argv[0]);
|
||||||
const std::string value = TRI_ObjectToString(argv[1]);
|
const std::string value = TRI_ObjectToString(argv[1]);
|
||||||
|
|
||||||
|
double ttl = 0.0;
|
||||||
|
if (argv.Length() > 2) {
|
||||||
|
ttl = TRI_ObjectToDouble(argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
AgencyComm comm;
|
AgencyComm comm;
|
||||||
AgencyCommResult result = comm.setValue(key, value);
|
AgencyCommResult result = comm.setValue(key, value, ttl);
|
||||||
|
|
||||||
if (! result.successful()) {
|
if (! result.successful()) {
|
||||||
return scope.Close(v8::ThrowException(CreateAgencyException(result)));
|
return scope.Close(v8::ThrowException(CreateAgencyException(result)));
|
||||||
|
@ -380,23 +504,28 @@ static v8::Handle<v8::Value> JS_PrefixAgency (v8::Arguments const& argv) {
|
||||||
static v8::Handle<v8::Value> JS_UniqidAgency (v8::Arguments const& argv) {
|
static v8::Handle<v8::Value> JS_UniqidAgency (v8::Arguments const& argv) {
|
||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
|
|
||||||
if (argv.Length() > 2) {
|
if (argv.Length() > 3) {
|
||||||
TRI_V8_EXCEPTION_USAGE(scope, "uniqid(<key>, <count>)");
|
TRI_V8_EXCEPTION_USAGE(scope, "uniqid(<key>, <count>, <timeout>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string key = TRI_ObjectToString(argv[0]);
|
const std::string key = TRI_ObjectToString(argv[0]);
|
||||||
|
|
||||||
uint64_t count = 1;
|
uint64_t count = 1;
|
||||||
if (argv.Length() == 2) {
|
if (argv.Length() > 1) {
|
||||||
count = TRI_ObjectToUInt64(argv[1], true);
|
count = TRI_ObjectToUInt64(argv[1], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count < 1 || count > 10000000) {
|
if (count < 1 || count > 10000000) {
|
||||||
TRI_V8_EXCEPTION_PARAMETER(scope, "<count> is invalid");
|
TRI_V8_EXCEPTION_PARAMETER(scope, "<count> is invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double timeout = 0.0;
|
||||||
|
if (argv.Length() > 2) {
|
||||||
|
timeout = TRI_ObjectToDouble(argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
AgencyComm comm;
|
AgencyComm comm;
|
||||||
AgencyCommResult result = comm.uniqid(key, count);
|
AgencyCommResult result = comm.uniqid(key, count, timeout);
|
||||||
|
|
||||||
if (! result.successful() || result._index == 0) {
|
if (! result.successful() || result._index == 0) {
|
||||||
return scope.Close(v8::ThrowException(CreateAgencyException(result)));
|
return scope.Close(v8::ThrowException(CreateAgencyException(result)));
|
||||||
|
@ -529,12 +658,16 @@ void TRI_InitV8Cluster (v8::Handle<v8::Context> context) {
|
||||||
TRI_AddMethodVocbase(rt, "createDirectory", JS_CreateDirectoryAgency);
|
TRI_AddMethodVocbase(rt, "createDirectory", JS_CreateDirectoryAgency);
|
||||||
TRI_AddMethodVocbase(rt, "get", JS_GetAgency);
|
TRI_AddMethodVocbase(rt, "get", JS_GetAgency);
|
||||||
TRI_AddMethodVocbase(rt, "isEnabled", JS_IsEnabledAgency);
|
TRI_AddMethodVocbase(rt, "isEnabled", JS_IsEnabledAgency);
|
||||||
|
TRI_AddMethodVocbase(rt, "lockRead", JS_LockReadAgency);
|
||||||
|
TRI_AddMethodVocbase(rt, "lockWrite", JS_LockWriteAgency);
|
||||||
TRI_AddMethodVocbase(rt, "remove", JS_RemoveAgency);
|
TRI_AddMethodVocbase(rt, "remove", JS_RemoveAgency);
|
||||||
TRI_AddMethodVocbase(rt, "set", JS_SetAgency);
|
TRI_AddMethodVocbase(rt, "set", JS_SetAgency);
|
||||||
TRI_AddMethodVocbase(rt, "watch", JS_WatchAgency);
|
TRI_AddMethodVocbase(rt, "watch", JS_WatchAgency);
|
||||||
TRI_AddMethodVocbase(rt, "endpoints", JS_EndpointsAgency);
|
TRI_AddMethodVocbase(rt, "endpoints", JS_EndpointsAgency);
|
||||||
TRI_AddMethodVocbase(rt, "prefix", JS_PrefixAgency);
|
TRI_AddMethodVocbase(rt, "prefix", JS_PrefixAgency);
|
||||||
TRI_AddMethodVocbase(rt, "uniqid", JS_UniqidAgency);
|
TRI_AddMethodVocbase(rt, "uniqid", JS_UniqidAgency);
|
||||||
|
TRI_AddMethodVocbase(rt, "unlockRead", JS_UnlockReadAgency);
|
||||||
|
TRI_AddMethodVocbase(rt, "unlockWrite", JS_UnlockWriteAgency);
|
||||||
TRI_AddMethodVocbase(rt, "version", JS_VersionAgency);
|
TRI_AddMethodVocbase(rt, "version", JS_VersionAgency);
|
||||||
|
|
||||||
v8g->AgencyTempl = v8::Persistent<v8::ObjectTemplate>::New(isolate, rt);
|
v8g->AgencyTempl = v8::Persistent<v8::ObjectTemplate>::New(isolate, rt);
|
||||||
|
|
|
@ -39,6 +39,12 @@ var internal = require("internal");
|
||||||
function AgencySuite () {
|
function AgencySuite () {
|
||||||
var agency;
|
var agency;
|
||||||
|
|
||||||
|
var cleanupLocks = function () {
|
||||||
|
agency.set("Target/Lock", "UNLOCKED");
|
||||||
|
agency.set("Plan/Lock", "UNLOCKED");
|
||||||
|
agency.set("Current/Lock", "UNLOCKED");
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
setUp : function () {
|
setUp : function () {
|
||||||
|
@ -62,6 +68,219 @@ function AgencySuite () {
|
||||||
assertMatch(/^etcd/, agency.version());
|
assertMatch(/^etcd/, agency.version());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockRead
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockReadInvalid : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
var invalidKeys = [ "foo", "bar", "baz", "plans", "PLAN" ];
|
||||||
|
|
||||||
|
invalidKeys.forEach (function (key) {
|
||||||
|
try {
|
||||||
|
agency.lockRead(key);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockRead
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockRead : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Target"));
|
||||||
|
assertTrue(agency.unlockRead("Target"));
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Plan"));
|
||||||
|
assertTrue(agency.unlockRead("Plan"));
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Current"));
|
||||||
|
assertTrue(agency.unlockRead("Current"));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockRead
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockReadNotExisting : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
assertTrue(agency.remove("Target/Lock"));
|
||||||
|
assertTrue(agency.remove("Plan/Lock"));
|
||||||
|
assertTrue(agency.remove("Current/Lock"));
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Target"));
|
||||||
|
assertTrue(agency.unlockRead("Target"));
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Plan"));
|
||||||
|
assertTrue(agency.unlockRead("Plan"));
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Current"));
|
||||||
|
assertTrue(agency.unlockRead("Current"));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockRead
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockReadDouble : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Target", 5));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// this will fail because of a duplicate lock
|
||||||
|
assertTrue(agency.lockRead("Target", 1, 1));
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(agency.unlockRead("Target"));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockRead
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockReadWrongType : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Target", 5));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// unlock of a wrong type
|
||||||
|
agency.unlockWrite("Target", 1);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(agency.unlockRead("Target"));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockWrite
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockWriteInvalid : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
var invalidKeys = [ "foo", "bar", "baz", "plans", "PLAN" ];
|
||||||
|
|
||||||
|
invalidKeys.forEach (function (key) {
|
||||||
|
try {
|
||||||
|
agency.lockWrite(key);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockWrite
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockWrite : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
assertTrue(agency.lockWrite("Target"));
|
||||||
|
assertTrue(agency.unlockWrite("Target"));
|
||||||
|
|
||||||
|
assertTrue(agency.lockWrite("Plan"));
|
||||||
|
assertTrue(agency.unlockWrite("Plan"));
|
||||||
|
|
||||||
|
assertTrue(agency.lockWrite("Current"));
|
||||||
|
assertTrue(agency.unlockWrite("Current"));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test lockWrite
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockWriteDouble : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
assertTrue(agency.lockWrite("Target", 5));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// this will fail because of a duplicate lock
|
||||||
|
assertTrue(agency.lockWrite("Target", 1, 1));
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(agency.unlockWrite("Target"));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test re-lock
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testLockRelock : function () {
|
||||||
|
cleanupLocks();
|
||||||
|
|
||||||
|
assertTrue(agency.lockRead("Target", 5));
|
||||||
|
|
||||||
|
var start = require("internal").time();
|
||||||
|
assertTrue(agency.lockWrite("Target", 5, 10));
|
||||||
|
var end = require("internal").time();
|
||||||
|
|
||||||
|
assertTrue(Math.round(end - start) >= 3);
|
||||||
|
assertTrue(agency.unlockWrite("Target"));
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test set
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testSet : function () {
|
||||||
|
// insert
|
||||||
|
agency.set("UnitTestsAgency/foo", "test1");
|
||||||
|
var values = agency.get("UnitTestsAgency/foo");
|
||||||
|
assertTrue(values.hasOwnProperty("UnitTestsAgency/foo"));
|
||||||
|
assertEqual(values["UnitTestsAgency/foo"], "test1");
|
||||||
|
|
||||||
|
// overwrite
|
||||||
|
agency.set("UnitTestsAgency/foo", "test2", 2);
|
||||||
|
var values = agency.get("UnitTestsAgency/foo");
|
||||||
|
assertTrue(values.hasOwnProperty("UnitTestsAgency/foo"));
|
||||||
|
assertEqual(values["UnitTestsAgency/foo"], "test2");
|
||||||
|
|
||||||
|
assertTrue(agency.remove("UnitTestsAgency/foo"));
|
||||||
|
|
||||||
|
// re-insert
|
||||||
|
agency.set("UnitTestsAgency/foo", "test3");
|
||||||
|
var values = agency.get("UnitTestsAgency/foo");
|
||||||
|
assertTrue(values.hasOwnProperty("UnitTestsAgency/foo"));
|
||||||
|
assertEqual(values["UnitTestsAgency/foo"], "test3");
|
||||||
|
|
||||||
|
// update with ttl
|
||||||
|
agency.set("UnitTestsAgency/foo", "test4", 2);
|
||||||
|
var values = agency.get("UnitTestsAgency/foo");
|
||||||
|
assertTrue(values.hasOwnProperty("UnitTestsAgency/foo"));
|
||||||
|
assertEqual(values["UnitTestsAgency/foo"], "test4");
|
||||||
|
|
||||||
|
require("internal").wait(3);
|
||||||
|
|
||||||
|
try {
|
||||||
|
values = agency.get("UnitTestsAgency/foo");
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
assertEqual(404, e.code);
|
||||||
|
assertEqual(100, e.errorNum); // not found
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief test watch
|
/// @brief test watch
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -147,6 +366,7 @@ function AgencySuite () {
|
||||||
assertTrue(agency.cas("UnitTestsAgency/foo", "bar", "baz"));
|
assertTrue(agency.cas("UnitTestsAgency/foo", "bar", "baz"));
|
||||||
assertTrue(agency.cas("UnitTestsAgency/foo", "baz", "bart"));
|
assertTrue(agency.cas("UnitTestsAgency/foo", "baz", "bart"));
|
||||||
assertFalse(agency.cas("UnitTestsAgency/foo", "foo", "bar"));
|
assertFalse(agency.cas("UnitTestsAgency/foo", "foo", "bar"));
|
||||||
|
assertFalse(agency.cas("UnitTestsAgency/boo", "foo", "bar"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
agency.cas("UnitTestsAgency/foo", "foo", "bar", 1, true);
|
agency.cas("UnitTestsAgency/foo", "foo", "bar", 1, true);
|
||||||
|
@ -155,7 +375,7 @@ function AgencySuite () {
|
||||||
catch (err) {
|
catch (err) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(agency.cas("UnitTestsAgency/foo", "bart", "baz", 1, true));
|
assertTrue(agency.cas("UnitTestsAgency/foo", "bart", "baz", 0, 1, true));
|
||||||
},
|
},
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue