From 7a25f20e23074ab687ed82c9c8eea12659f297b0 Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Fri, 17 Oct 2014 11:02:37 +0200 Subject: [PATCH 1/7] Fix clone for AqlTransactions. --- arangod/Utils/AqlTransaction.h | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/arangod/Utils/AqlTransaction.h b/arangod/Utils/AqlTransaction.h index 85347cd3d8..3342e6aec0 100644 --- a/arangod/Utils/AqlTransaction.h +++ b/arangod/Utils/AqlTransaction.h @@ -63,9 +63,10 @@ namespace triagens { AqlTransaction (TransactionContext* transactionContext, TRI_vocbase_t* vocbase, - std::map* collections, + std::map const* collections, bool isMainTransaction) - : Transaction(transactionContext, vocbase, 0) { + : Transaction(transactionContext, vocbase, 0), + _collections(*collections) { this->addHint(TRI_TRANSACTION_HINT_LOCK_ENTIRELY, false); if (! isMainTransaction) { @@ -188,20 +189,20 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// triagens::arango::AqlTransaction* clone () const { - auto colls = new std::map(); - try { - auto res = new triagens::arango::AqlTransaction( - new triagens::arango::V8TransactionContext(true), - this->_vocbase, - colls, false); - return res; - } - catch (...) { - delete colls; - throw; - } + return new triagens::arango::AqlTransaction( + new triagens::arango::V8TransactionContext(true), + this->_vocbase, + &_collections, false); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief keep a copy of the collections, this is needed for the clone +/// operation +//////////////////////////////////////////////////////////////////////////////// + + private: + + std::map _collections; }; } From ee614d6ebdbafcdeaa90bc84bc1b0d621b40b17d Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Fri, 17 Oct 2014 15:25:06 +0200 Subject: [PATCH 2/7] v8 context handling --- arangod/Aql/Ast.cpp | 2 + arangod/Aql/ExecutionBlock.cpp | 17 ++++++++ arangod/Aql/Executor.cpp | 76 +++++++++++++++++----------------- arangod/Aql/Expression.cpp | 14 ++++++- arangod/Aql/Expression.h | 9 ++++ arangod/Aql/Query.cpp | 14 +++++++ arangod/Utils/Transaction.h | 20 ++++++++- lib/Basics/ScopeGuard.h | 63 ++++++++++++++++++++++++++++ 8 files changed, 174 insertions(+), 41 deletions(-) create mode 100644 lib/Basics/ScopeGuard.h diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index 939f5114ac..04a6d1497a 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -1079,6 +1079,8 @@ AstNode* Ast::createArithmeticResultNode (double value) { //////////////////////////////////////////////////////////////////////////////// AstNode* Ast::executeConstExpression (AstNode const* node) { + // must enter v8 before we can execute any expression + _query->enterContext(); TRI_json_t* result = _query->executor()->executeExpression(node); if (result == nullptr) { diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 8ebdaa5080..3ba5e78ac6 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -27,6 +27,7 @@ #include "Aql/ExecutionBlock.h" #include "Aql/ExecutionEngine.h" +#include "Basics/ScopeGuard.h" #include "Basics/StringUtils.h" #include "Basics/StringBuffer.h" #include "Basics/json-utilities.h" @@ -906,6 +907,14 @@ bool IndexRangeBlock::readIndex () { newCondition = std::unique_ptr(new IndexOrCondition()); newCondition.get()->push_back(std::vector()); + + // must have a V8 context here to protect Expression::execute() + auto engine = _engine; + triagens::basics::ScopeGuard guard{ + [&engine]() -> void { engine->getQuery()->enterContext(); }, + [&engine]() -> void { engine->getQuery()->exitContext(); } + }; + size_t posInExpressions = 0; for (auto r : en->_ranges.at(0)) { // First create a new RangeInfo containing only the constant @@ -1829,6 +1838,14 @@ void CalculationBlock::doEvaluation (AqlItemBlock* result) { RegisterId nrRegs = result->getNrRegs(); result->setDocumentCollection(_outReg, nullptr); + + // must have a V8 context here to protect Expression::execute() + auto engine = _engine; + triagens::basics::ScopeGuard guard{ + [&engine]() -> void { engine->getQuery()->enterContext(); }, + [&engine]() -> void { engine->getQuery()->exitContext(); } + }; + for (size_t i = 0; i < n; i++) { // need to execute the expression AqlValue a = _expression->execute(_trx, docColls, data, nrRegs * i, _inVars, _inRegs); diff --git a/arangod/Aql/Executor.cpp b/arangod/Aql/Executor.cpp index 286501ae08..1101068802 100644 --- a/arangod/Aql/Executor.cpp +++ b/arangod/Aql/Executor.cpp @@ -406,7 +406,7 @@ void Executor::generateCodeExpression (AstNode const* node) { generateCodeNode(node); // write epilogue - _buffer->appendText("; })"); + _buffer->appendText(";})", 3); } //////////////////////////////////////////////////////////////////////////////// @@ -440,15 +440,15 @@ void Executor::generateCodeList (AstNode const* node) { size_t const n = node->numMembers(); - _buffer->appendText("[ "); + _buffer->appendChar('['); for (size_t i = 0; i < n; ++i) { if (i > 0) { - _buffer->appendText(", "); + _buffer->appendChar(','); } generateCodeNode(node->getMember(i)); } - _buffer->appendText(" ]"); + _buffer->appendChar(']'); } //////////////////////////////////////////////////////////////////////////////// @@ -460,21 +460,21 @@ void Executor::generateCodeArray (AstNode const* node) { size_t const n = node->numMembers(); - _buffer->appendText("{ "); + _buffer->appendChar('{'); for (size_t i = 0; i < n; ++i) { if (i > 0) { - _buffer->appendText(", "); + _buffer->appendChar(','); } auto member = node->getMember(i); if (member != nullptr) { generateCodeString(member->getStringValue()); - _buffer->appendText(" : "); + _buffer->appendChar(':'); generateCodeNode(member->getMember(0)); } } - _buffer->appendText(" }"); + _buffer->appendChar('}'); } //////////////////////////////////////////////////////////////////////////////// @@ -492,12 +492,12 @@ void Executor::generateCodeUnaryOperator (AstNode const* node) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "function not found"); } - _buffer->appendText("aql."); + _buffer->appendText("aql.", 4); _buffer->appendText((*it).second); - _buffer->appendText("("); + _buffer->appendChar('('); generateCodeNode(node->getMember(0)); - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// @@ -518,24 +518,24 @@ void Executor::generateCodeBinaryOperator (AstNode const* node) { bool wrap = (node->type == NODE_TYPE_OPERATOR_BINARY_AND || node->type == NODE_TYPE_OPERATOR_BINARY_OR); - _buffer->appendText("aql."); + _buffer->appendText("aql.", 4); _buffer->appendText((*it).second); - _buffer->appendText("("); + _buffer->appendChar('('); if (wrap) { _buffer->appendText("function () { return "); generateCodeNode(node->getMember(0)); _buffer->appendText("}, function () { return "); generateCodeNode(node->getMember(1)); - _buffer->appendText("}"); + _buffer->appendChar(')'); } else { generateCodeNode(node->getMember(0)); - _buffer->appendText(", "); + _buffer->appendChar(','); generateCodeNode(node->getMember(1)); } - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// @@ -553,9 +553,9 @@ void Executor::generateCodeTernaryOperator (AstNode const* node) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "function not found"); } - _buffer->appendText("aql."); + _buffer->appendText("aql.", 4); _buffer->appendText((*it).second); - _buffer->appendText("("); + _buffer->appendChar('('); generateCodeNode(node->getMember(0)); _buffer->appendText(", function () { return "); @@ -575,9 +575,9 @@ void Executor::generateCodeReference (AstNode const* node) { auto variable = static_cast(node->getData()); - _buffer->appendText("vars["); + _buffer->appendText("vars[", 5); generateCodeString(variable->name.c_str()); - _buffer->appendText("]"); + _buffer->appendChar(']'); } //////////////////////////////////////////////////////////////////////////////// @@ -590,9 +590,9 @@ void Executor::generateCodeVariable (AstNode const* node) { auto variable = static_cast(node->getData()); - _buffer->appendText("vars["); + _buffer->appendText("vars[", 5); generateCodeString(variable->name.c_str()); - _buffer->appendText("]"); + _buffer->appendChar(']'); } //////////////////////////////////////////////////////////////////////////////// @@ -607,7 +607,7 @@ void Executor::generateCodeCollection (AstNode const* node) { _buffer->appendText("aql.GET_DOCUMENTS("); generateCodeString(name); - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// @@ -624,14 +624,14 @@ void Executor::generateCodeFunctionCall (AstNode const* node) { TRI_ASSERT(args != nullptr); TRI_ASSERT(args->type == NODE_TYPE_LIST); - _buffer->appendText("aql."); + _buffer->appendText("aql.", 4); _buffer->appendText(func->internalName); - _buffer->appendText("("); + _buffer->appendChar('('); size_t const n = args->numMembers(); for (size_t i = 0; i < n; ++i) { if (i > 0) { - _buffer->appendText(", "); + _buffer->appendChar(','); } auto member = args->getMember(i); @@ -658,7 +658,7 @@ void Executor::generateCodeFunctionCall (AstNode const* node) { } } - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// @@ -678,17 +678,17 @@ void Executor::generateCodeUserFunctionCall (AstNode const* node) { _buffer->appendText("aql.FCALL_USER("); generateCodeString(name); - _buffer->appendText(", ["); + _buffer->appendText(",[", 2); size_t const n = args->numMembers(); for (size_t i = 0; i < n; ++i) { if (i > 0) { - _buffer->appendText(", "); + _buffer->appendChar(','); } generateCodeNode(args->getMember(i)); } - _buffer->appendText("])"); + _buffer->appendText("])", 2); } //////////////////////////////////////////////////////////////////////////////// @@ -735,9 +735,9 @@ void Executor::generateCodeRange (AstNode const* node) { _buffer->appendText("aql.RANGE("); generateCodeNode(node->getMember(0)); - _buffer->appendText(", "); + _buffer->appendChar(','); generateCodeNode(node->getMember(1)); - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// @@ -750,9 +750,9 @@ void Executor::generateCodeNamedAccess (AstNode const* node) { _buffer->appendText("aql.DOCUMENT_MEMBER("); generateCodeNode(node->getMember(0)); - _buffer->appendText(", "); + _buffer->appendChar(','); generateCodeString(node->getStringValue()); - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// @@ -765,9 +765,9 @@ void Executor::generateCodeBoundAccess (AstNode const* node) { _buffer->appendText("aql.DOCUMENT_MEMBER("); generateCodeNode(node->getMember(0)); - _buffer->appendText(", "); + _buffer->appendChar(','); generateCodeNode(node->getMember(1)); - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// @@ -780,9 +780,9 @@ void Executor::generateCodeIndexedAccess (AstNode const* node) { _buffer->appendText("aql.GET_INDEX("); generateCodeNode(node->getMember(0)); - _buffer->appendText(", "); + _buffer->appendChar(','); generateCodeNode(node->getMember(1)); - _buffer->appendText(")"); + _buffer->appendChar(')'); } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp index 5ce0ccf91f..e0b6a55f7d 100644 --- a/arangod/Aql/Expression.cpp +++ b/arangod/Aql/Expression.cpp @@ -86,6 +86,7 @@ Expression::~Expression () { else if (_type == JSON) { TRI_ASSERT(_data != nullptr); TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _data); + _data = nullptr; // _json is freed automatically by AqlItemBlock } } @@ -160,7 +161,18 @@ void Expression::replaceVariables (std::unordered_mapreplaceVariables(const_cast(_node), replacements); - + + invalidateExpression(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief invalidates an expression +/// this only has an effect for V8-based functions, which need to be created, +/// used and destroyed in the same context. when a V8 function is used across +/// multiple V8 contexts, it must be invalidated in between +//////////////////////////////////////////////////////////////////////////////// + +void Expression::invalidateExpression () { if (_type == V8) { delete _func; _type = UNPROCESSED; diff --git a/arangod/Aql/Expression.h b/arangod/Aql/Expression.h index 1c933c0806..8d7666931c 100644 --- a/arangod/Aql/Expression.h +++ b/arangod/Aql/Expression.h @@ -201,6 +201,15 @@ namespace triagens { void replaceVariables (std::unordered_map const&); +//////////////////////////////////////////////////////////////////////////////// +/// @brief invalidates an expression +/// this only has an effect for V8-based functions, which need to be created, +/// used and destroyed in the same context. when a V8 function is used across +/// multiple V8 contexts, it must be invalidated in between +//////////////////////////////////////////////////////////////////////////////// + + void invalidateExpression (); + // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 14bea4d43a..3e484878a2 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -229,7 +229,11 @@ Query::~Query () { if (_context != nullptr) { TRI_ASSERT(! _contextOwnedByExterior); + + _trx->unregisterInContext(); + _applicationV8->exitContext(_context); + // TODO: unregister transaction and resolver in context _context = nullptr; } @@ -482,6 +486,9 @@ QueryResult Query::prepare (QueryRegistry* registry) { // varsUsedLater and varsValid are unordered_sets and so their orders // are not the same in the serialised and deserialised plans + // return the V8 context + exitContext(); + enterState(EXECUTION); ExecutionEngine* engine(ExecutionEngine::instanciateFromPlan(registry, this, plan.get(), planRegisters)); @@ -805,9 +812,13 @@ void Query::enterContext () { if (! _contextOwnedByExterior) { if (_context == nullptr) { _context = _applicationV8->enterContext("STANDARD", _vocbase, false, false); + if (_context == nullptr) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot enter V8 context"); } + + // register transaction in v8 context + _trx->registerInContext(); } TRI_ASSERT(_context != nullptr); @@ -822,6 +833,9 @@ void Query::exitContext () { if (! _contextOwnedByExterior) { if (_context != nullptr) { if (isRunningInCluster()) { + // unregister transaction in v8 context + _trx->unregisterInContext(); + _applicationV8->exitContext(_context); _context = nullptr; } diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index cdaffb121d..d1ed3b666a 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -136,6 +136,22 @@ namespace triagens { public: +//////////////////////////////////////////////////////////////////////////////// +/// @brief register ourselves in the context +//////////////////////////////////////////////////////////////////////////////// + + int registerInContext () { + return this->_transactionContext->registerTransaction(_trx); + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief register ourselves in the context +//////////////////////////////////////////////////////////////////////////////// + + int unregisterInContext () { + return this->_transactionContext->unregisterTransaction(); + } + //////////////////////////////////////////////////////////////////////////////// /// @brief return database of transaction //////////////////////////////////////////////////////////////////////////////// @@ -1318,7 +1334,7 @@ namespace triagens { } // register the transaction in the context - return this->_transactionContext->registerTransaction(_trx); + return this->registerInContext(); } //////////////////////////////////////////////////////////////////////////////// @@ -1329,7 +1345,7 @@ namespace triagens { TRI_ASSERT(! isEmbeddedTransaction()); if (_trx != nullptr) { - this->_transactionContext->unregisterTransaction(); + this->unregisterInContext(); TRI_FreeTransaction(_trx); _trx = nullptr; diff --git a/lib/Basics/ScopeGuard.h b/lib/Basics/ScopeGuard.h new file mode 100644 index 0000000000..c6c3b9a549 --- /dev/null +++ b/lib/Basics/ScopeGuard.h @@ -0,0 +1,63 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Scope guard class +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2014 ArangoDB GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is ArangoDB GmbH, Cologne, Germany +/// +/// @author Jan Steemann +/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany +/// @author Copyright 2009-2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ARANGODB_BASICS_SCOPE_GUARD_H +#define ARANGODB_BASICS_SCOPE_GUARD_H 1 + +#include "Basics/Common.h" + +namespace triagens { + namespace basics { + class ScopeGuard { + public: + ScopeGuard (std::function onEnter, + std::function onExit) + : _onExit(onExit) { + onEnter(); + } + + ~ScopeGuard () { + _onExit(); + } + + std::function _onExit; + }; + } +} + +#endif + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- + +// Local Variables: +// mode: outline-minor +// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" +// End: From cb75b0b18a144e8b20c805b5c52c14535f296b70 Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Fri, 17 Oct 2014 15:25:46 +0200 Subject: [PATCH 3/7] Sort out transactions in cluster, part I. --- arangod/Aql/ExecutionEngine.cpp | 6 +++--- arangod/Aql/Query.cpp | 6 +++--- arangod/Aql/QueryRegistry.cpp | 35 ++++++++------------------------- arangod/Aql/RestAqlHandler.cpp | 11 ++++++++++- arangod/Utils/AqlTransaction.h | 22 ++------------------- 5 files changed, 26 insertions(+), 54 deletions(-) diff --git a/arangod/Aql/ExecutionEngine.cpp b/arangod/Aql/ExecutionEngine.cpp index c5f4fe8fac..4dc500edc9 100644 --- a/arangod/Aql/ExecutionEngine.cpp +++ b/arangod/Aql/ExecutionEngine.cpp @@ -473,7 +473,7 @@ struct CoordinatorInstanciator : public WalkerWorker { jsonNodesList.set("variables", query->ast()->variables()->toJson(TRI_UNKNOWN_MEM_ZONE)); result.set("plan", jsonNodesList); - result.set("part", Json("main")); // TODO: set correct query type + result.set("part", Json("dependent")); // TODO: set correct query type Json optimizerOptionsRules(Json::List); Json optimizerOptions(Json::Array); @@ -527,12 +527,12 @@ struct CoordinatorInstanciator : public WalkerWorker { triagens::basics::Json response(TRI_UNKNOWN_MEM_ZONE, triagens::basics::JsonHelper::fromString(res->answer->body())); std::string queryId = triagens::basics::JsonHelper::getStringValue(response.json(), "queryId", ""); - // std::cout << "DB SERVER ANSWERED WITHOUT ERROR: " << res->answer->body() << ", SHARDID:" << res->shardID << ", QUERYID: " << queryId << "\n"; + std::cout << "DB SERVER ANSWERED WITHOUT ERROR: " << res->answer->body() << ", SHARDID:" << res->shardID << ", QUERYID: " << queryId << "\n"; queryIds.emplace(std::make_pair(res->shardID, queryId)); } else { - // std::cout << "DB SERVER ANSWERED WITH ERROR: " << res->answer->body() << "\n"; + std::cout << "DB SERVER ANSWERED WITH ERROR: " << res->answer->body() << "\n"; } } delete res; diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 8ecaac1e58..dae2a29bf8 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -39,7 +39,7 @@ #include "Basics/tri-strings.h" #include "Utils/AqlTransaction.h" #include "Utils/Exception.h" -#include "Utils/V8TransactionContext.h" +#include "Utils/StandaloneTransactionContext.h" #include "VocBase/vocbase.h" using namespace triagens::aql; @@ -386,7 +386,7 @@ QueryResult Query::prepare (QueryRegistry* registry) { // std::cout << "AST: " << triagens::basics::JsonHelper::toString(parser->ast()->toJson(TRI_UNKNOWN_MEM_ZONE, false)) << "\n"; } - auto trx = new triagens::arango::AqlTransaction(new triagens::arango::V8TransactionContext(true), _vocbase, _collections.collections(), _part == PART_MAIN); + auto trx = new triagens::arango::AqlTransaction(new triagens::arango::StandaloneTransactionContext(), _vocbase, _collections.collections(), _part == PART_MAIN); _trx = trx; // Save the transaction in our object bool planRegisters; @@ -595,7 +595,7 @@ QueryResult Query::explain () { // std::cout << "AST: " << triagens::basics::JsonHelper::toString(parser.ast()->toJson(TRI_UNKNOWN_MEM_ZONE)) << "\n"; // create the transaction object, but do not start it yet - auto trx = new triagens::arango::AqlTransaction(new triagens::arango::V8TransactionContext(true), _vocbase, _collections.collections(), true); + auto trx = new triagens::arango::AqlTransaction(new triagens::arango::StandaloneTransactionContext(), _vocbase, _collections.collections(), true); _trx = trx; // save the pointer in this // we have an AST diff --git a/arangod/Aql/QueryRegistry.cpp b/arangod/Aql/QueryRegistry.cpp index 4e993c67f4..83e6b3b517 100644 --- a/arangod/Aql/QueryRegistry.cpp +++ b/arangod/Aql/QueryRegistry.cpp @@ -98,13 +98,8 @@ void QueryRegistry::insert (TRI_vocbase_t* vocbase, TRI_ASSERT_EXPENSIVE(_queries.find(vocbase->_name)->second.find(id) != _queries.find(vocbase->_name)->second.end()); - if (query->part() == PART_MAIN) { - // A query that is being shelved must unregister its transaction - // with the current context: - query->trx()->unregisterTransactionWithContext(); - // Also, we need to count down the debugging counters for transactions: - triagens::arango::TransactionBase::increaseNumbers(-1, -1); - } + // Also, we need to count down the debugging counters for transactions: + triagens::arango::TransactionBase::increaseNumbers(-1, -1); } else { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, @@ -136,14 +131,8 @@ Query* QueryRegistry::open (TRI_vocbase_t* vocbase, } qi->_isOpen = true; - // A query that is being opened must register its transaction - // with the current context: - - if (qi->_query->part() == PART_MAIN) { - qi->_query->trx()->registerTransactionWithContext(); - // Also, we need to count up the debugging counters for transactions: - triagens::arango::TransactionBase::increaseNumbers(1, 1); - } + // We need to count up the debugging counters for transactions: + triagens::arango::TransactionBase::increaseNumbers(1, 1); return qi->_query; } @@ -171,13 +160,8 @@ void QueryRegistry::close (TRI_vocbase_t* vocbase, QueryId id, double ttl) { "query with given vocbase and id is not open"); } - // A query that is being closed must unregister its transaction - // with the current context: - if (qi->_query->part() == PART_MAIN) { - qi->_query->trx()->unregisterTransactionWithContext(); - // Also, we need to count down the debugging counters for transactions: - triagens::arango::TransactionBase::increaseNumbers(1, 1); - } + // We need to count down the debugging counters for transactions: + triagens::arango::TransactionBase::increaseNumbers(-1, -1); qi->_isOpen = false; qi->_expires = TRI_microtime() + qi->_timeToLive; @@ -205,11 +189,8 @@ void QueryRegistry::destroy (std::string const& vocbase, QueryId id) { // to register the transaction with the current context and adjust // the debugging counters for transactions: if (! qi->_isOpen) { - if (qi->_query->part() == PART_MAIN) { - qi->_query->trx()->registerTransactionWithContext(); - // Also, we need to count down the debugging counters for transactions: - triagens::arango::TransactionBase::increaseNumbers(1, 1); - } + // We need to count up the debugging counters for transactions: + triagens::arango::TransactionBase::increaseNumbers(1, 1); } // Now we can delete it: diff --git a/arangod/Aql/RestAqlHandler.cpp b/arangod/Aql/RestAqlHandler.cpp index 4c4ce77403..5370df402b 100644 --- a/arangod/Aql/RestAqlHandler.cpp +++ b/arangod/Aql/RestAqlHandler.cpp @@ -113,6 +113,8 @@ void RestAqlHandler::createQueryFromJson () { if (queryJson.isEmpty()) { return; } + + std::cout << "createQueryFromJson" << queryJson.toString() << std::endl; Json plan; Json options; @@ -163,7 +165,7 @@ void RestAqlHandler::createQueryFromJson () { answerBody("queryId", Json(StringUtils::itoa(_qId))) ("ttl", Json(ttl)); - //std::cout << "RESPONSE BODY IS: " << answerBody.toString() << "\n"; + std::cout << "RESPONSE BODY IS: " << answerBody.toString() << "\n"; _response->body().appendText(answerBody.toString()); } @@ -434,6 +436,11 @@ void RestAqlHandler::useQuery (std::string const& operation, _queryRegistry->close(_vocbase, _qId); return; } + std::cout << "useQuery op:" << operation << "," << idString << std::endl + << queryJson.toString() << std::endl; + } + else { + std::cout << "useQuery shutdown" << std::endl; } try { @@ -467,6 +474,8 @@ void RestAqlHandler::useQuery (std::string const& operation, TRI_ERROR_HTTP_SERVER_ERROR, "an unknown exception occurred"); } + std::cout << "Response of useQuery:" << _response->body().c_str() << + std::endl; } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Utils/AqlTransaction.h b/arangod/Utils/AqlTransaction.h index 3342e6aec0..8cb1ba6a6f 100644 --- a/arangod/Utils/AqlTransaction.h +++ b/arangod/Utils/AqlTransaction.h @@ -36,7 +36,7 @@ #include "Cluster/ServerState.h" #include "Utils/CollectionNameResolver.h" #include "Utils/Transaction.h" -#include "Utils/V8TransactionContext.h" +#include "Utils/StandaloneTransactionContext.h" #include "VocBase/transaction.h" #include "VocBase/vocbase.h" #include @@ -165,24 +165,6 @@ namespace triagens { return trxColl->_collection->_collection; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief registerTransaction -//////////////////////////////////////////////////////////////////////////////// - - int registerTransactionWithContext () { - // This calls the method in the V8TransactionContext - return this->_transactionContext->registerTransaction(this->_trx); - } - -//////////////////////////////////////////////////////////////////////////////// -/// @brief unregisterTransaction -//////////////////////////////////////////////////////////////////////////////// - - int unregisterTransactionWithContext () { - // This calls the method in the V8TransactionContext - return this->_transactionContext->unregisterTransaction(); - } - //////////////////////////////////////////////////////////////////////////////// /// @brief clone, used to make daughter transactions for parts of a distributed /// AQL query running on the coordinator @@ -190,7 +172,7 @@ namespace triagens { triagens::arango::AqlTransaction* clone () const { return new triagens::arango::AqlTransaction( - new triagens::arango::V8TransactionContext(true), + new triagens::arango::StandaloneTransactionContext(), this->_vocbase, &_collections, false); } From 3effea896cf80c5c59805daa02363f08d1b67ac4 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Fri, 17 Oct 2014 15:30:55 +0200 Subject: [PATCH 4/7] fixed wrong error code --- arangod/Aql/RestAqlHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arangod/Aql/RestAqlHandler.cpp b/arangod/Aql/RestAqlHandler.cpp index bae7d6f2b3..ba972c4b30 100644 --- a/arangod/Aql/RestAqlHandler.cpp +++ b/arangod/Aql/RestAqlHandler.cpp @@ -819,7 +819,7 @@ void RestAqlHandler::handleUseQuery (std::string const& operation, "initializeCursor lead to an exception"); return; } - answerBody("error", Json(res == TRI_ERROR_NO_ERROR)) + answerBody("error", Json(res != TRI_ERROR_NO_ERROR)) ("code", Json(static_cast(res))); } else if (operation == "shutdown") { From 11ace2de3a3c7ca6b9724ecaeba12f39583609cf Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Fri, 17 Oct 2014 15:33:48 +0200 Subject: [PATCH 5/7] Fix registerTransaction in StandaloneTransactionContext. --- arangod/Utils/StandaloneTransactionContext.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arangod/Utils/StandaloneTransactionContext.cpp b/arangod/Utils/StandaloneTransactionContext.cpp index 0c9f593591..f3238339aa 100644 --- a/arangod/Utils/StandaloneTransactionContext.cpp +++ b/arangod/Utils/StandaloneTransactionContext.cpp @@ -73,8 +73,9 @@ TRI_transaction_t* StandaloneTransactionContext::getParentTransaction () const { //////////////////////////////////////////////////////////////////////////////// int StandaloneTransactionContext::registerTransaction (TRI_transaction_t* trx) { - TRI_ASSERT(_resolver == nullptr); - _resolver = new CollectionNameResolver(trx->_vocbase); + if (_resolver == nullptr) { + _resolver = new CollectionNameResolver(trx->_vocbase); + } return TRI_ERROR_NO_ERROR; } From 026fc2b83ab0d252856e3a4d23d0e27a7010b461 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Fri, 17 Oct 2014 15:47:39 +0200 Subject: [PATCH 6/7] next attempt to fix v8 context handling --- arangod/Aql/Query.cpp | 26 ++++++++++++++++++------ arangod/Utils/Transaction.h | 28 +++++++++----------------- arangod/Utils/V8TransactionContext.cpp | 1 + 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 3230e8dd7d..5d94895331 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -39,8 +39,10 @@ #include "Basics/tri-strings.h" #include "Cluster/ServerState.h" #include "Utils/AqlTransaction.h" +#include "Utils/CollectionNameResolver.h" #include "Utils/Exception.h" #include "Utils/StandaloneTransactionContext.h" +#include "Utils/V8TransactionContext.h" #include "V8Server/ApplicationV8.h" #include "VocBase/vocbase.h" @@ -230,10 +232,14 @@ Query::~Query () { if (_context != nullptr) { TRI_ASSERT(! _contextOwnedByExterior); - _trx->unregisterInContext(); + // unregister transaction and resolver in context + TRI_v8_global_t* v8g = static_cast(v8::Isolate::GetCurrent()->GetData()); + auto ctx = static_cast(v8g->_transactionContext); + if (ctx != nullptr) { + ctx->unregisterTransaction(); + } _applicationV8->exitContext(_context); - // TODO: unregister transaction and resolver in context _context = nullptr; } @@ -817,8 +823,12 @@ void Query::enterContext () { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot enter V8 context"); } - // register transaction in v8 context - _trx->registerInContext(); + // register transaction and resolver in context + TRI_v8_global_t* v8g = static_cast(v8::Isolate::GetCurrent()->GetData()); + auto ctx = static_cast(v8g->_transactionContext); + if (ctx != nullptr) { + ctx->registerTransaction(_trx->getInternals()); + } } TRI_ASSERT(_context != nullptr); @@ -833,8 +843,12 @@ void Query::exitContext () { if (! _contextOwnedByExterior) { if (_context != nullptr) { if (isRunningInCluster()) { - // unregister transaction in v8 context - _trx->unregisterInContext(); + // unregister transaction and resolver in context + TRI_v8_global_t* v8g = static_cast(v8::Isolate::GetCurrent()->GetData()); + auto ctx = static_cast(v8g->_transactionContext); + if (ctx != nullptr) { + ctx->unregisterTransaction(); + } _applicationV8->exitContext(_context); _context = nullptr; diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index d1ed3b666a..5d769702ee 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -136,22 +136,6 @@ namespace triagens { public: -//////////////////////////////////////////////////////////////////////////////// -/// @brief register ourselves in the context -//////////////////////////////////////////////////////////////////////////////// - - int registerInContext () { - return this->_transactionContext->registerTransaction(_trx); - } - -//////////////////////////////////////////////////////////////////////////////// -/// @brief register ourselves in the context -//////////////////////////////////////////////////////////////////////////////// - - int unregisterInContext () { - return this->_transactionContext->unregisterTransaction(); - } - //////////////////////////////////////////////////////////////////////////////// /// @brief return database of transaction //////////////////////////////////////////////////////////////////////////////// @@ -160,6 +144,14 @@ namespace triagens { return _vocbase; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return internals of transaction +//////////////////////////////////////////////////////////////////////////////// + + inline TRI_transaction_t* getInternals () const { + return _trx; + } + //////////////////////////////////////////////////////////////////////////////// /// @brief add a transaction hint //////////////////////////////////////////////////////////////////////////////// @@ -1334,7 +1326,7 @@ namespace triagens { } // register the transaction in the context - return this->registerInContext(); + return this->_transactionContext->registerTransaction(_trx); } //////////////////////////////////////////////////////////////////////////////// @@ -1345,7 +1337,7 @@ namespace triagens { TRI_ASSERT(! isEmbeddedTransaction()); if (_trx != nullptr) { - this->unregisterInContext(); + this->_transactionContext->unregisterTransaction(); TRI_FreeTransaction(_trx); _trx = nullptr; diff --git a/arangod/Utils/V8TransactionContext.cpp b/arangod/Utils/V8TransactionContext.cpp index 7c5ab5a349..451143932f 100644 --- a/arangod/Utils/V8TransactionContext.cpp +++ b/arangod/Utils/V8TransactionContext.cpp @@ -136,6 +136,7 @@ void V8TransactionContext::deleteResolver () { TRI_ASSERT(hasResolver()); delete _resolver; _resolver = nullptr; + _ownResolver = false; } //////////////////////////////////////////////////////////////////////////////// From 42c91307ec742527643f1a6ec1835a5e34624029 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Fri, 17 Oct 2014 15:56:03 +0200 Subject: [PATCH 7/7] handlescope --- arangod/Aql/Ast.cpp | 1 + arangod/Aql/ExecutionBlock.cpp | 4 ++++ arangod/Aql/Query.cpp | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arangod/Aql/Ast.cpp b/arangod/Aql/Ast.cpp index 04a6d1497a..47db2adcf2 100644 --- a/arangod/Aql/Ast.cpp +++ b/arangod/Aql/Ast.cpp @@ -1080,6 +1080,7 @@ AstNode* Ast::createArithmeticResultNode (double value) { AstNode* Ast::executeConstExpression (AstNode const* node) { // must enter v8 before we can execute any expression + v8::HandleScope scope; // do not delete this! _query->enterContext(); TRI_json_t* result = _query->executor()->executeExpression(node); diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index de2fe43d95..996b25c1b1 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -929,6 +929,8 @@ bool IndexRangeBlock::readIndex () { [&engine]() -> void { engine->getQuery()->exitContext(); } }; + v8::HandleScope scope; // do not delete this! + size_t posInExpressions = 0; for (auto r : en->_ranges.at(0)) { // First create a new RangeInfo containing only the constant @@ -1859,6 +1861,8 @@ void CalculationBlock::doEvaluation (AqlItemBlock* result) { [&engine]() -> void { engine->getQuery()->enterContext(); }, [&engine]() -> void { engine->getQuery()->exitContext(); } }; + + v8::HandleScope scope; // do not delete this! for (size_t i = 0; i < n; i++) { // need to execute the expression diff --git a/arangod/Aql/Query.cpp b/arangod/Aql/Query.cpp index 5d94895331..822b226f7d 100644 --- a/arangod/Aql/Query.cpp +++ b/arangod/Aql/Query.cpp @@ -822,7 +822,7 @@ void Query::enterContext () { if (_context == nullptr) { THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "cannot enter V8 context"); } - + // register transaction and resolver in context TRI_v8_global_t* v8g = static_cast(v8::Isolate::GetCurrent()->GetData()); auto ctx = static_cast(v8g->_transactionContext);