mirror of https://gitee.com/bigwinds/arangodb
Cleanup of unused queues in ClusterComm
This commit is contained in:
parent
31ab3c7c09
commit
3e02a726ee
|
@ -251,10 +251,7 @@ ClusterComm::ClusterComm(bool ignored)
|
||||||
/// @brief ClusterComm destructor
|
/// @brief ClusterComm destructor
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ClusterComm::~ClusterComm() {
|
ClusterComm::~ClusterComm() { stopBackgroundThreads(); }
|
||||||
stopBackgroundThreads();
|
|
||||||
cleanupAllQueues();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief getter for our singleton instance
|
/// @brief getter for our singleton instance
|
||||||
|
@ -449,7 +446,12 @@ OperationID ClusterComm::asyncRequest(
|
||||||
initTimeout](int errorCode, std::unique_ptr<GeneralResponse> response) {
|
initTimeout](int errorCode, std::unique_ptr<GeneralResponse> response) {
|
||||||
{
|
{
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
CONDITION_LOCKER(locker, somethingReceived);
|
||||||
responses.erase(result->operationID);
|
size_t numErased = responses.erase(result->operationID);
|
||||||
|
if (numErased == 0) {
|
||||||
|
// Request has been dropped, noone cares for it anymore.
|
||||||
|
// So do not call the callback (might be gone anyways)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result->fromError(errorCode, std::move(response));
|
result->fromError(errorCode, std::move(response));
|
||||||
if (result->status == CL_COMM_BACKEND_UNAVAILABLE) {
|
if (result->status == CL_COMM_BACKEND_UNAVAILABLE) {
|
||||||
|
@ -461,7 +463,12 @@ OperationID ClusterComm::asyncRequest(
|
||||||
callbacks._onSuccess = [callback, result, this](std::unique_ptr<GeneralResponse> response) {
|
callbacks._onSuccess = [callback, result, this](std::unique_ptr<GeneralResponse> response) {
|
||||||
{
|
{
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
CONDITION_LOCKER(locker, somethingReceived);
|
||||||
responses.erase(result->operationID);
|
size_t numErased = responses.erase(result->operationID);
|
||||||
|
if (numErased == 0) {
|
||||||
|
// Request has been dropped, noone cares for it anymore.
|
||||||
|
// So do not call the callback (might be gone anyways)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TRI_ASSERT(response.get() != nullptr);
|
TRI_ASSERT(response.get() != nullptr);
|
||||||
result->fromResponse(std::move(response));
|
result->fromResponse(std::move(response));
|
||||||
|
@ -471,6 +478,8 @@ OperationID ClusterComm::asyncRequest(
|
||||||
} else {
|
} else {
|
||||||
callbacks._onError = [result, doLogConnectionErrors, this,
|
callbacks._onError = [result, doLogConnectionErrors, this,
|
||||||
initTimeout](int errorCode, std::unique_ptr<GeneralResponse> response) {
|
initTimeout](int errorCode, std::unique_ptr<GeneralResponse> response) {
|
||||||
|
// If the result has been removed from responses we are the last ones
|
||||||
|
// having a shared_ptr So it will be gone after this callback
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
CONDITION_LOCKER(locker, somethingReceived);
|
||||||
result->fromError(errorCode, std::move(response));
|
result->fromError(errorCode, std::move(response));
|
||||||
if (result->status == CL_COMM_BACKEND_UNAVAILABLE) {
|
if (result->status == CL_COMM_BACKEND_UNAVAILABLE) {
|
||||||
|
@ -479,6 +488,8 @@ OperationID ClusterComm::asyncRequest(
|
||||||
somethingReceived.broadcast();
|
somethingReceived.broadcast();
|
||||||
};
|
};
|
||||||
callbacks._onSuccess = [result, this](std::unique_ptr<GeneralResponse> response) {
|
callbacks._onSuccess = [result, this](std::unique_ptr<GeneralResponse> response) {
|
||||||
|
// If the result has been removed from responses we are the last ones
|
||||||
|
// having a shared_ptr So it will be gone after this callback
|
||||||
TRI_ASSERT(response.get() != nullptr);
|
TRI_ASSERT(response.get() != nullptr);
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
CONDITION_LOCKER(locker, somethingReceived);
|
||||||
result->fromResponse(std::move(response));
|
result->fromResponse(std::move(response));
|
||||||
|
@ -488,12 +499,15 @@ OperationID ClusterComm::asyncRequest(
|
||||||
|
|
||||||
TRI_ASSERT(request != nullptr);
|
TRI_ASSERT(request != nullptr);
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
CONDITION_LOCKER(locker, somethingReceived);
|
||||||
|
// Call a random communicator
|
||||||
|
auto communicatorPtr = communicator();
|
||||||
auto ticketId =
|
auto ticketId =
|
||||||
communicator()->addRequest(createCommunicatorDestination(result->endpoint, path),
|
communicatorPtr->addRequest(createCommunicatorDestination(result->endpoint, path),
|
||||||
std::move(request), callbacks, opt);
|
std::move(request), callbacks, opt);
|
||||||
|
|
||||||
result->operationID = ticketId;
|
result->operationID = ticketId;
|
||||||
responses.emplace(ticketId, AsyncResponse{TRI_microtime(), result});
|
responses.emplace(ticketId, AsyncResponse{TRI_microtime(), result,
|
||||||
|
std::move(communicatorPtr)});
|
||||||
return ticketId;
|
return ticketId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,123 +751,25 @@ ClusterCommResult const ClusterComm::wait(ClientTransactionID const& clientTrans
|
||||||
void ClusterComm::drop(ClientTransactionID const& clientTransactionID,
|
void ClusterComm::drop(ClientTransactionID const& clientTransactionID,
|
||||||
CoordTransactionID const coordTransactionID,
|
CoordTransactionID const coordTransactionID,
|
||||||
OperationID const operationID, ShardID const& shardID) {
|
OperationID const operationID, ShardID const& shardID) {
|
||||||
QueueIterator q;
|
// Loop through the responses queue
|
||||||
QueueIterator nextq;
|
|
||||||
IndexIterator i;
|
|
||||||
|
|
||||||
// First look through the send queue:
|
|
||||||
{
|
{
|
||||||
CONDITION_LOCKER(sendLocker, somethingToSend);
|
// Lock out the communicators to write responses in this very moment.
|
||||||
|
CONDITION_LOCKER(guard, somethingReceived);
|
||||||
for (q = toSend.begin(); q != toSend.end();) {
|
ResponseIterator q = responses.begin();
|
||||||
ClusterCommOperation* op = *q;
|
while (q != responses.end()) {
|
||||||
if ((0 != operationID && operationID == op->result.operationID) ||
|
ClusterCommResult* result = q->second.result.get();
|
||||||
match(clientTransactionID, coordTransactionID, shardID, &op->result)) {
|
// The result is not allowed to be deleted
|
||||||
if (op->result.status == CL_COMM_SENDING) {
|
TRI_ASSERT(result != nullptr);
|
||||||
op->result.dropped = true;
|
if ((0 != operationID && result->operationID == operationID) ||
|
||||||
q++;
|
match(clientTransactionID, coordTransactionID, shardID, result)) {
|
||||||
} else {
|
// Abort on communicator does not trigger a function that requires responses list.
|
||||||
nextq = q;
|
q->second.communicator->abortRequest(q->first);
|
||||||
nextq++;
|
q = responses.erase(q);
|
||||||
i = toSendByOpID.find(op->result.operationID); // cannot fail
|
|
||||||
TRI_ASSERT(i != toSendByOpID.end());
|
|
||||||
TRI_ASSERT(q == i->second);
|
|
||||||
toSendByOpID.erase(i);
|
|
||||||
toSend.erase(q);
|
|
||||||
q = nextq;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Now look through the receive queue:
|
|
||||||
{
|
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
|
||||||
|
|
||||||
for (q = received.begin(); q != received.end();) {
|
|
||||||
ClusterCommOperation* op = *q;
|
|
||||||
if ((0 != operationID && operationID == op->result.operationID) ||
|
|
||||||
match(clientTransactionID, coordTransactionID, shardID, &op->result)) {
|
|
||||||
nextq = q;
|
|
||||||
nextq++;
|
|
||||||
i = receivedByOpID.find(op->result.operationID); // cannot fail
|
|
||||||
if (i != receivedByOpID.end() && q == i->second) {
|
|
||||||
receivedByOpID.erase(i);
|
|
||||||
}
|
|
||||||
received.erase(q);
|
|
||||||
delete op;
|
|
||||||
q = nextq;
|
|
||||||
} else {
|
|
||||||
q++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief move an operation from the send to the receive queue
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool ClusterComm::moveFromSendToReceived(OperationID operationID) {
|
|
||||||
TRI_ASSERT(false);
|
|
||||||
LOG_TOPIC(DEBUG, Logger::CLUSTER) << "In moveFromSendToReceived " << operationID;
|
|
||||||
|
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
|
||||||
CONDITION_LOCKER(sendLocker, somethingToSend);
|
|
||||||
|
|
||||||
IndexIterator i = toSendByOpID.find(operationID); // cannot fail
|
|
||||||
// TRI_ASSERT(i != toSendByOpID.end());
|
|
||||||
// KV: Except the operation has been dropped in the meantime
|
|
||||||
|
|
||||||
QueueIterator q = i->second;
|
|
||||||
ClusterCommOperation* op = *q;
|
|
||||||
TRI_ASSERT(op->result.operationID == operationID);
|
|
||||||
toSendByOpID.erase(i);
|
|
||||||
toSend.erase(q);
|
|
||||||
std::unique_ptr<ClusterCommOperation> opPtr(op);
|
|
||||||
if (op->result.dropped) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (op->result.status == CL_COMM_SENDING) {
|
|
||||||
// Note that in the meantime the status could have changed to
|
|
||||||
// CL_COMM_ERROR, CL_COMM_TIMEOUT or indeed to CL_COMM_RECEIVED in
|
|
||||||
// these cases, we do not want to overwrite this result
|
|
||||||
op->result.status = CL_COMM_SENT;
|
|
||||||
}
|
|
||||||
received.push_back(op);
|
|
||||||
opPtr.release();
|
|
||||||
q = received.end();
|
|
||||||
q--;
|
|
||||||
receivedByOpID[operationID] = q;
|
|
||||||
somethingReceived.broadcast();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief cleanup all queues
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void ClusterComm::cleanupAllQueues() {
|
|
||||||
{
|
|
||||||
CONDITION_LOCKER(locker, somethingToSend);
|
|
||||||
|
|
||||||
for (auto& it : toSend) {
|
|
||||||
delete it;
|
|
||||||
}
|
|
||||||
toSendByOpID.clear();
|
|
||||||
toSend.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
|
||||||
|
|
||||||
for (auto& it : received) {
|
|
||||||
delete it;
|
|
||||||
}
|
|
||||||
receivedByOpID.clear();
|
|
||||||
received.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1243,9 +1159,6 @@ void ClusterCommThread::beginShutdown() {
|
||||||
// different thread than the ClusterCommThread. Therefore we can still
|
// different thread than the ClusterCommThread. Therefore we can still
|
||||||
// use the condition variable to wake up the ClusterCommThread.
|
// use the condition variable to wake up the ClusterCommThread.
|
||||||
Thread::beginShutdown();
|
Thread::beginShutdown();
|
||||||
|
|
||||||
CONDITION_LOCKER(guard, _cc->somethingToSend);
|
|
||||||
guard.signal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -636,14 +636,6 @@ class ClusterComm {
|
||||||
|
|
||||||
static OperationID getOperationID();
|
static OperationID getOperationID();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief send queue with lock and index
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::list<ClusterCommOperation*> toSend;
|
|
||||||
std::map<OperationID, std::list<ClusterCommOperation*>::iterator> toSendByOpID;
|
|
||||||
arangodb::basics::ConditionVariable somethingToSend;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief received queue with lock and index
|
/// @brief received queue with lock and index
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -651,33 +643,24 @@ class ClusterComm {
|
||||||
struct AsyncResponse {
|
struct AsyncResponse {
|
||||||
double timestamp;
|
double timestamp;
|
||||||
std::shared_ptr<ClusterCommResult> result;
|
std::shared_ptr<ClusterCommResult> result;
|
||||||
|
std::shared_ptr<communicator::Communicator> communicator;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unordered_map<communicator::Ticket, AsyncResponse>::iterator ResponseIterator;
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief Map of requests that are in flight or not yet read.
|
||||||
|
/// The communicator will write into the response whenever
|
||||||
|
/// communication is resolved. Needs to be modified under the
|
||||||
|
/// somethingReceived lock.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
std::unordered_map<communicator::Ticket, AsyncResponse> responses;
|
std::unordered_map<communicator::Ticket, AsyncResponse> responses;
|
||||||
|
typedef decltype(ClusterComm::responses)::iterator ResponseIterator;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief condition variable to protect the responses map
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Receiving answers:
|
|
||||||
std::list<ClusterCommOperation*> received;
|
|
||||||
std::map<OperationID, std::list<ClusterCommOperation*>::iterator> receivedByOpID;
|
|
||||||
arangodb::basics::ConditionVariable somethingReceived;
|
arangodb::basics::ConditionVariable somethingReceived;
|
||||||
|
|
||||||
// Note: If you really have to lock both `somethingToSend`
|
|
||||||
// and `somethingReceived` at the same time (usually you should
|
|
||||||
// not have to!), then: first lock `somethingToReceive`, then
|
|
||||||
// lock `somethingtoSend` in this order!
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief iterator type which is frequently used
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
typedef std::list<ClusterCommOperation*>::iterator QueueIterator;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief iterator type which is frequently used
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
typedef std::map<OperationID, QueueIterator>::iterator IndexIterator;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief internal function to match an operation:
|
/// @brief internal function to match an operation:
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -686,18 +669,6 @@ class ClusterComm {
|
||||||
CoordTransactionID const coordTransactionID,
|
CoordTransactionID const coordTransactionID,
|
||||||
ShardID const& shardID, ClusterCommResult* res);
|
ShardID const& shardID, ClusterCommResult* res);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief move an operation from the send to the receive queue
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool moveFromSendToReceived(OperationID operationID);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief cleanup all queues
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void cleanupAllQueues();
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief activeServerTickets for a list of servers
|
/// @brief activeServerTickets for a list of servers
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
/// @author Copyright 2017, ArangoDB GmbH, Cologne, Germany
|
/// @author Copyright 2017, ArangoDB GmbH, Cologne, Germany
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "catch.hpp"
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include "catch.hpp"
|
||||||
|
|
||||||
#include "Basics/ConditionLocker.h"
|
#include "Basics/ConditionLocker.h"
|
||||||
#include "Cluster/ClusterComm.h"
|
#include "Cluster/ClusterComm.h"
|
||||||
|
@ -39,7 +39,7 @@ using namespace arangodb;
|
||||||
using namespace arangodb::rest;
|
using namespace arangodb::rest;
|
||||||
|
|
||||||
class ClusterCommTester : public ClusterComm {
|
class ClusterCommTester : public ClusterComm {
|
||||||
public:
|
public:
|
||||||
ClusterCommTester()
|
ClusterCommTester()
|
||||||
: ClusterComm(false),
|
: ClusterComm(false),
|
||||||
_oldSched(nullptr), _testerSched(1, 2, 3, 4)
|
_oldSched(nullptr), _testerSched(1, 2, 3, 4)
|
||||||
|
@ -62,30 +62,29 @@ public:
|
||||||
result->coordTransactionID = transId;
|
result->coordTransactionID = transId;
|
||||||
result->status = status;
|
result->status = status;
|
||||||
|
|
||||||
responses.emplace(id, AsyncResponse{TRI_microtime(), result});
|
responses.emplace(id, AsyncResponse{TRI_microtime(), result,
|
||||||
|
nullptr /* communicator, we do not care for it*/});
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
} // addSimpleRequest
|
} // addSimpleRequest
|
||||||
|
|
||||||
AsyncResponse & getResponse(size_t index) {
|
AsyncResponse& getResponse(size_t index) {
|
||||||
auto it = responses.begin();
|
auto it = responses.begin();
|
||||||
for (; 0<index; ++it, --index);
|
for (; 0 < index; ++it, --index)
|
||||||
|
;
|
||||||
return it->second;
|
return it->second;
|
||||||
} // getResponse
|
} // getResponse
|
||||||
|
|
||||||
void signalResponse() {
|
void signalResponse() {
|
||||||
CONDITION_LOCKER(locker, somethingReceived);
|
CONDITION_LOCKER(locker, somethingReceived);
|
||||||
somethingReceived.broadcast();
|
somethingReceived.broadcast();
|
||||||
} // signalResponse
|
} // signalResponse
|
||||||
|
|
||||||
Scheduler * _oldSched;
|
Scheduler* _oldSched;
|
||||||
Scheduler _testerSched;
|
Scheduler _testerSched;
|
||||||
|
}; // class ClusterCommTester
|
||||||
};// class ClusterCommTester
|
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
|
|
||||||
SECTION("no matching responses") {
|
SECTION("no matching responses") {
|
||||||
ClusterCommTester testme;
|
ClusterCommTester testme;
|
||||||
ClusterCommResult result;
|
ClusterCommResult result;
|
||||||
|
@ -95,8 +94,7 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
REQUIRE(CL_COMM_DROPPED == result.status);
|
REQUIRE(CL_COMM_DROPPED == result.status);
|
||||||
REQUIRE(42 == result.operationID);
|
REQUIRE(42 == result.operationID);
|
||||||
|
|
||||||
} // no matching responses
|
} // no matching responses
|
||||||
|
|
||||||
|
|
||||||
SECTION("single response") {
|
SECTION("single response") {
|
||||||
ClusterCommTester testme;
|
ClusterCommTester testme;
|
||||||
|
@ -106,7 +104,7 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
|
|
||||||
// find by transId
|
// find by transId
|
||||||
transId = TRI_NewTickServer();
|
transId = TRI_NewTickServer();
|
||||||
id=testme.addSimpleRequest(transId, CL_COMM_RECEIVED);
|
id = testme.addSimpleRequest(transId, CL_COMM_RECEIVED);
|
||||||
|
|
||||||
result = testme.wait("", transId, 0, "", 0.1);
|
result = testme.wait("", transId, 0, "", 0.1);
|
||||||
REQUIRE(CL_COMM_RECEIVED == result.status);
|
REQUIRE(CL_COMM_RECEIVED == result.status);
|
||||||
|
@ -114,13 +112,13 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
|
|
||||||
// find by ticketId
|
// find by ticketId
|
||||||
transId = TRI_NewTickServer();
|
transId = TRI_NewTickServer();
|
||||||
id=testme.addSimpleRequest(transId, CL_COMM_RECEIVED);
|
id = testme.addSimpleRequest(transId, CL_COMM_RECEIVED);
|
||||||
|
|
||||||
result = testme.wait("", 0, id, "", 0.1);
|
result = testme.wait("", 0, id, "", 0.1);
|
||||||
REQUIRE(CL_COMM_RECEIVED == result.status);
|
REQUIRE(CL_COMM_RECEIVED == result.status);
|
||||||
REQUIRE(id == result.operationID);
|
REQUIRE(id == result.operationID);
|
||||||
|
|
||||||
} // single response
|
} // single response
|
||||||
|
|
||||||
SECTION("out of order response") {
|
SECTION("out of order response") {
|
||||||
ClusterCommTester testme;
|
ClusterCommTester testme;
|
||||||
|
@ -145,7 +143,7 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
REQUIRE(id_other == result.operationID);
|
REQUIRE(id_other == result.operationID);
|
||||||
REQUIRE(id_first != result.operationID);
|
REQUIRE(id_first != result.operationID);
|
||||||
|
|
||||||
} // out of order response
|
} // out of order response
|
||||||
|
|
||||||
SECTION("simple function time out") {
|
SECTION("simple function time out") {
|
||||||
ClusterCommTester testme;
|
ClusterCommTester testme;
|
||||||
|
@ -160,7 +158,7 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
result = testme.wait("", transId, 0, "", 0.005);
|
result = testme.wait("", transId, 0, "", 0.005);
|
||||||
endTime = TRI_microtime();
|
endTime = TRI_microtime();
|
||||||
diff = endTime - startTime;
|
diff = endTime - startTime;
|
||||||
REQUIRE(0.0049 < diff); // must write range test in two parts for REQUIRE
|
REQUIRE(0.0049 < diff); // must write range test in two parts for REQUIRE
|
||||||
REQUIRE(CL_COMM_TIMEOUT == result.status);
|
REQUIRE(CL_COMM_TIMEOUT == result.status);
|
||||||
REQUIRE(0 == result.operationID);
|
REQUIRE(0 == result.operationID);
|
||||||
|
|
||||||
|
@ -169,10 +167,10 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
result = testme.wait("", transId, 0, "", 0.1);
|
result = testme.wait("", transId, 0, "", 0.1);
|
||||||
endTime = TRI_microtime();
|
endTime = TRI_microtime();
|
||||||
diff = endTime - startTime;
|
diff = endTime - startTime;
|
||||||
REQUIRE(0.09 <= diff); // must write range test in two parts for REQUIRE
|
REQUIRE(0.09 <= diff); // must write range test in two parts for REQUIRE
|
||||||
REQUIRE(CL_COMM_TIMEOUT == result.status);
|
REQUIRE(CL_COMM_TIMEOUT == result.status);
|
||||||
REQUIRE(0 == result.operationID);
|
REQUIRE(0 == result.operationID);
|
||||||
} // simple function time out
|
} // simple function time out
|
||||||
|
|
||||||
SECTION("time delayed, out of order response") {
|
SECTION("time delayed, out of order response") {
|
||||||
ClusterCommTester testme;
|
ClusterCommTester testme;
|
||||||
|
@ -193,36 +191,40 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
id_other = testme.getResponse(1).result->operationID;
|
id_other = testme.getResponse(1).result->operationID;
|
||||||
|
|
||||||
startTime = TRI_microtime();
|
startTime = TRI_microtime();
|
||||||
std::future<void> f1(std::async(std::launch::async, [&]{
|
std::future<void> f1(std::async(std::launch::async,
|
||||||
timespec ts={0,15000000};
|
[&] {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(ts.tv_nsec / 1000L));
|
timespec ts = {0, 15000000};
|
||||||
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
std::this_thread::sleep_for(
|
||||||
testme.signalResponse();
|
std::chrono::microseconds(ts.tv_nsec / 1000L));
|
||||||
} // lambda
|
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
||||||
));
|
testme.signalResponse();
|
||||||
|
} // lambda
|
||||||
|
));
|
||||||
|
|
||||||
result = testme.wait("", transId, 0, "", 0.1);
|
result = testme.wait("", transId, 0, "", 0.1);
|
||||||
endTime = TRI_microtime();
|
endTime = TRI_microtime();
|
||||||
diff = endTime - startTime;
|
diff = endTime - startTime;
|
||||||
REQUIRE(0.014 <= diff); // must write range test in two parts for REQUIRE
|
REQUIRE(0.014 <= diff); // must write range test in two parts for REQUIRE
|
||||||
REQUIRE(CL_COMM_RECEIVED == result.status);
|
REQUIRE(CL_COMM_RECEIVED == result.status);
|
||||||
REQUIRE(id_first == result.operationID);
|
REQUIRE(id_first == result.operationID);
|
||||||
f1.get();
|
f1.get();
|
||||||
|
|
||||||
// do second time to get other response
|
// do second time to get other response
|
||||||
startTime = TRI_microtime();
|
startTime = TRI_microtime();
|
||||||
std::future<void> f2(std::async(std::launch::async, [&]{
|
std::future<void> f2(std::async(std::launch::async,
|
||||||
timespec ts={0, 30000000};
|
[&] {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(ts.tv_nsec / 1000L));
|
timespec ts = {0, 30000000};
|
||||||
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
std::this_thread::sleep_for(
|
||||||
testme.signalResponse();
|
std::chrono::microseconds(ts.tv_nsec / 1000L));
|
||||||
} // lambda
|
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
||||||
));
|
testme.signalResponse();
|
||||||
|
} // lambda
|
||||||
|
));
|
||||||
|
|
||||||
result = testme.wait("", transId, 0, "", 0.1);
|
result = testme.wait("", transId, 0, "", 0.1);
|
||||||
endTime = TRI_microtime();
|
endTime = TRI_microtime();
|
||||||
diff = endTime - startTime;
|
diff = endTime - startTime;
|
||||||
REQUIRE(0.029 <= diff); // must write range test in two parts for REQUIRE
|
REQUIRE(0.029 <= diff); // must write range test in two parts for REQUIRE
|
||||||
REQUIRE(CL_COMM_RECEIVED == result.status);
|
REQUIRE(CL_COMM_RECEIVED == result.status);
|
||||||
REQUIRE(id_other == result.operationID);
|
REQUIRE(id_other == result.operationID);
|
||||||
f2.get();
|
f2.get();
|
||||||
|
@ -242,36 +244,40 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
id_other = testme.getResponse(1).result->operationID;
|
id_other = testme.getResponse(1).result->operationID;
|
||||||
|
|
||||||
startTime = TRI_microtime();
|
startTime = TRI_microtime();
|
||||||
std::future<void> f3(std::async(std::launch::async, [&]{
|
std::future<void> f3(std::async(std::launch::async,
|
||||||
timespec ts={0,15000000};
|
[&] {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(ts.tv_nsec / 1000L));
|
timespec ts = {0, 15000000};
|
||||||
testme.getResponse(1).result->status = CL_COMM_RECEIVED;
|
std::this_thread::sleep_for(
|
||||||
testme.signalResponse();
|
std::chrono::microseconds(ts.tv_nsec / 1000L));
|
||||||
} // lambda
|
testme.getResponse(1).result->status = CL_COMM_RECEIVED;
|
||||||
));
|
testme.signalResponse();
|
||||||
|
} // lambda
|
||||||
|
));
|
||||||
|
|
||||||
result = testme.wait("", transId, 0, "", 0.1);
|
result = testme.wait("", transId, 0, "", 0.1);
|
||||||
endTime = TRI_microtime();
|
endTime = TRI_microtime();
|
||||||
diff = endTime - startTime;
|
diff = endTime - startTime;
|
||||||
REQUIRE(0.014 <= diff); // must write range test in two parts for REQUIRE
|
REQUIRE(0.014 <= diff); // must write range test in two parts for REQUIRE
|
||||||
REQUIRE(CL_COMM_RECEIVED == result.status);
|
REQUIRE(CL_COMM_RECEIVED == result.status);
|
||||||
REQUIRE(id_other == result.operationID);
|
REQUIRE(id_other == result.operationID);
|
||||||
f3.get();
|
f3.get();
|
||||||
|
|
||||||
// do second time to get other response
|
// do second time to get other response
|
||||||
startTime = TRI_microtime();
|
startTime = TRI_microtime();
|
||||||
std::future<void> f4(std::async(std::launch::async, [&]{
|
std::future<void> f4(std::async(std::launch::async,
|
||||||
timespec ts={0, 30000000};
|
[&] {
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(ts.tv_nsec / 1000L));
|
timespec ts = {0, 30000000};
|
||||||
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
std::this_thread::sleep_for(
|
||||||
testme.signalResponse();
|
std::chrono::microseconds(ts.tv_nsec / 1000L));
|
||||||
} // lambda
|
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
||||||
));
|
testme.signalResponse();
|
||||||
|
} // lambda
|
||||||
|
));
|
||||||
|
|
||||||
result = testme.wait("", transId, 0, "", 0.1);
|
result = testme.wait("", transId, 0, "", 0.1);
|
||||||
endTime = TRI_microtime();
|
endTime = TRI_microtime();
|
||||||
diff = endTime - startTime;
|
diff = endTime - startTime;
|
||||||
REQUIRE(0.029 <= diff); // must write range test in two parts for REQUIRE
|
REQUIRE(0.029 <= diff); // must write range test in two parts for REQUIRE
|
||||||
REQUIRE(CL_COMM_RECEIVED == result.status);
|
REQUIRE(CL_COMM_RECEIVED == result.status);
|
||||||
REQUIRE(id_first == result.operationID);
|
REQUIRE(id_first == result.operationID);
|
||||||
f4.get();
|
f4.get();
|
||||||
|
@ -279,22 +285,23 @@ TEST_CASE("ClusterComm::wait", "[cluster][mev]") {
|
||||||
// infinite wait
|
// infinite wait
|
||||||
id_first = testme.addSimpleRequest(transId, CL_COMM_SUBMITTED);
|
id_first = testme.addSimpleRequest(transId, CL_COMM_SUBMITTED);
|
||||||
startTime = TRI_microtime();
|
startTime = TRI_microtime();
|
||||||
std::future<void> f5(std::async(std::launch::async, [&]{
|
std::future<void> f5(
|
||||||
timespec ts={0, 500000000}; //0.5 seconds
|
std::async(std::launch::async,
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(ts.tv_nsec / 1000L));
|
[&] {
|
||||||
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
timespec ts = {0, 500000000}; // 0.5 seconds
|
||||||
testme.signalResponse();
|
std::this_thread::sleep_for(std::chrono::microseconds(ts.tv_nsec / 1000L));
|
||||||
} // lambda
|
testme.getResponse(0).result->status = CL_COMM_RECEIVED;
|
||||||
));
|
testme.signalResponse();
|
||||||
|
} // lambda
|
||||||
|
));
|
||||||
|
|
||||||
result = testme.wait("", transId, 0, "", 0.0);
|
result = testme.wait("", transId, 0, "", 0.0);
|
||||||
endTime = TRI_microtime();
|
endTime = TRI_microtime();
|
||||||
diff = endTime - startTime;
|
diff = endTime - startTime;
|
||||||
REQUIRE(0.499 <= diff); // must write range test in two parts for REQUIRE
|
REQUIRE(0.499 <= diff); // must write range test in two parts for REQUIRE
|
||||||
REQUIRE(CL_COMM_RECEIVED == result.status);
|
REQUIRE(CL_COMM_RECEIVED == result.status);
|
||||||
REQUIRE(id_first == result.operationID);
|
REQUIRE(id_first == result.operationID);
|
||||||
f5.get();
|
f5.get();
|
||||||
|
|
||||||
} // out of order response
|
} // out of order response
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue