diff --git a/arangod/V8Server/V8Traverser.cpp b/arangod/V8Server/V8Traverser.cpp index 44fb666030..75d1375614 100644 --- a/arangod/V8Server/V8Traverser.cpp +++ b/arangod/V8Server/V8Traverser.cpp @@ -352,71 +352,14 @@ class SimpleEdgeExpander { //////////////////////////////////////////////////////////////////////////////// unique_ptr TRI_RunShortestPathSearch ( - v8::Isolate* isolate, - TRI_vocbase_t* vocbase, string const& vertexCollectionName, string const& edgeCollectionName, string const& startVertex, string const& targetVertex, + CollectionNameResolver const* resolver, + TRI_document_collection_t* ecol, ShortestPathOptions& opts) { - vector readCollections; - vector writeCollections; - - readCollections.push_back(vertexCollectionName); - readCollections.push_back(edgeCollectionName); - - - // IHHF isCoordinator - double lockTimeout = (double) (TRI_TRANSACTION_DEFAULT_LOCK_TIMEOUT / 1000000ULL); - bool embed = true; - bool waitForSync = false; - - V8ResolverGuard resolver(vocbase); - - // Start Transaction to collect all parts of the path - ExplicitTransaction trx( - vocbase, - readCollections, - writeCollections, - lockTimeout, - waitForSync, - embed - ); - - int res = trx.begin(); - - if (res != TRI_ERROR_NO_ERROR) { - trx.finish(res); - throw res; - } - - TRI_vocbase_col_t const* col = resolver.getResolver()->getCollectionStruct(vertexCollectionName); - if (col == nullptr) { - trx.finish(res); - throw TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; - } - - if (trx.orderBarrier(trx.trxCollection(col->_cid)) == nullptr) { - trx.finish(res); - throw TRI_ERROR_OUT_OF_MEMORY; - } - - col = resolver.getResolver()->getCollectionStruct(edgeCollectionName); - if (col == nullptr) { - trx.finish(res); - throw TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; - } - - if (trx.orderBarrier(trx.trxCollection(col->_cid)) == nullptr) { - trx.finish(res); - throw TRI_ERROR_OUT_OF_MEMORY; - } - - TRI_document_collection_t* ecol - = trx.trxCollection(col->_cid)->_collection->_collection; - CollectionNameResolver resolver1(vocbase); - CollectionNameResolver resolver2(vocbase); TRI_edge_direction_e forward; TRI_edge_direction_e backward; if (opts.direction == "outbound") { @@ -450,16 +393,12 @@ unique_ptr TRI_RunShortestPathSearch ( size_t split; char const* str = startVertex.c_str(); if (!TRI_ValidateDocumentIdKeyGenerator(str, &split)) { - // TODO Error Handling - trx.finish(res); return nullptr; } string collectionName = startVertex.substr(0, split); - auto coli = resolver1.getCollectionStruct(collectionName); + auto coli = resolver->getCollectionStruct(collectionName); if (coli == nullptr) { - // collection not found - trx.finish(res); throw TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; } @@ -467,16 +406,12 @@ unique_ptr TRI_RunShortestPathSearch ( str = targetVertex.c_str(); if (!TRI_ValidateDocumentIdKeyGenerator(str, &split)) { - // TODO Error Handling - trx.finish(res); return nullptr; } collectionName = targetVertex.substr(0, split); - coli = resolver2.getCollectionStruct(collectionName); + coli = resolver->getCollectionStruct(collectionName); if (coli == nullptr) { - // collection not found - trx.finish(res); throw TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; } VertexId tv(coli->_cid, str + split + 1); @@ -491,7 +426,6 @@ unique_ptr TRI_RunShortestPathSearch ( else { path.reset(pathFinder.shortestPath(sv, tv)); } - res = trx.finish(res); return path; } diff --git a/arangod/V8Server/V8Traverser.h b/arangod/V8Server/V8Traverser.h index 850cade391..20605fd251 100644 --- a/arangod/V8Server/V8Traverser.h +++ b/arangod/V8Server/V8Traverser.h @@ -94,12 +94,12 @@ typedef triagens::basics::PathFinder /// @brief Wrapper for the shortest path computation //////////////////////////////////////////////////////////////////////////////// std::unique_ptr TRI_RunShortestPathSearch ( - v8::Isolate* isolate, - TRI_vocbase_t* vocbase, std::string const& vertexCollectionName, std::string const& edgeCollectionName, std::string const& startVertex, std::string const& targetVertex, + triagens::arango::CollectionNameResolver const* resolver, + TRI_document_collection_t* ecol, triagens::basics::traverser::ShortestPathOptions& opts ); diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index a65767c404..491ac1d99e 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -104,6 +104,20 @@ int32_t const WRP_VOCBASE_TYPE = 1; int32_t const WRP_VOCBASE_COL_TYPE = 2; +// ----------------------------------------------------------------------------- +// --SECTION-- private constants +// ----------------------------------------------------------------------------- + +struct CollectionBarrierInfo { + TRI_barrier_t* barrier; + TRI_transaction_collection_t* col; + + CollectionBarrierInfo( + TRI_barrier_t* barrier, + TRI_transaction_collection_t* col + ) : barrier(barrier), col(col) {} +}; + // ----------------------------------------------------------------------------- // --SECTION-- HELPER FUNCTIONS // ----------------------------------------------------------------------------- @@ -1489,21 +1503,50 @@ static inline v8::Local vertexIdToString ( return TRI_V8_STD_STRING((resolver->getCollectionName(id.cid) + "/" + string(id.key))); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief Transforms VertexId to v8 json +//////////////////////////////////////////////////////////////////////////////// + +static inline v8::Handle vertexIdToData( + v8::Isolate* isolate, + CollectionNameResolver const* resolver, + ExplicitTransaction* trx, + unordered_map& barriers, + VertexId& vertexId + ) { + auto i = barriers.find(vertexId.cid); + TRI_ASSERT(i != barriers.end()); + TRI_doc_mptr_copy_t document; + + trx->readSingle(i->second.col, &document, vertexId.key); + return TRI_WrapShapedJson(isolate, resolver, i->second.barrier, + vertexId.cid, i->second.col->_collection->_collection, document.getDataPtr()); +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief Transforms an ArangoDBPathFinder Path to v8 json values //////////////////////////////////////////////////////////////////////////////// static inline v8::Handle pathIdsToV8(v8::Isolate* isolate, + ExplicitTransaction* trx, CollectionNameResolver const* resolver, - ArangoDBPathFinder::Path& p) { + ArangoDBPathFinder::Path& p, + unordered_map& barriers, + bool includeData = false) { v8::EscapableHandleScope scope(isolate); v8::Handle result = v8::Object::New(isolate); uint32_t const vn = static_cast(p.vertices.size()); v8::Handle vertices = v8::Array::New(isolate, static_cast(vn)); - for (uint32_t j = 0; j < vn; ++j) { - vertices->Set(j, vertexIdToString(isolate, resolver, p.vertices[j])); + if (includeData) { + for (uint32_t j = 0; j < vn; ++j) { + vertices->Set(j, vertexIdToData(isolate, resolver, trx, barriers, p.vertices[j])); + } + } else { + for (uint32_t j = 0; j < vn; ++j) { + vertices->Set(j, vertexIdToString(isolate, resolver, p.vertices[j])); + } } result->Set(TRI_V8_STRING("vertices"), vertices); @@ -1517,7 +1560,61 @@ static inline v8::Handle pathIdsToV8(v8::Isolate* isolate, result->Set(TRI_V8_STRING("distance"), v8::Number::New(isolate, p.weight)); return scope.Escape(result); -}; +} + + +static inline ExplicitTransaction* beginTransaction( + TRI_vocbase_t* vocbase, + vector readCollections, + vector writeCollections + ) { + + // IHHF isCoordinator + double lockTimeout = (double) (TRI_TRANSACTION_DEFAULT_LOCK_TIMEOUT / 1000000ULL); + bool embed = true; + bool waitForSync = false; + + // Start Transaction to collect all parts of the path + ExplicitTransaction* trx = new ExplicitTransaction( + vocbase, + readCollections, + writeCollections, + lockTimeout, + waitForSync, + embed + ); + + int res = trx->begin(); + + if (res != TRI_ERROR_NO_ERROR) { + trx->finish(res); + throw res; + } + return trx; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Request a barrier for the given collection +//////////////////////////////////////////////////////////////////////////////// + +static inline void addBarrier( + ExplicitTransaction* trx, + CollectionNameResolver const* resolver, + string const& collectionName, + unordered_map& barriers + ) { + TRI_vocbase_col_t const* col = resolver->getCollectionStruct(collectionName); + if (col == nullptr) { + throw TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; + } + TRI_barrier_t* barrier = trx->orderBarrier(trx->trxCollection(col->_cid)); + if (barrier == nullptr) { + throw TRI_ERROR_OUT_OF_MEMORY; + } + TRI_transaction_collection_t* dcol + = trx->trxCollection(col->_cid); + barriers.emplace(col->_cid, CollectionBarrierInfo(barrier, dcol)); +} //////////////////////////////////////////////////////////////////////////////// /// @brief Executes a shortest Path Traversal @@ -1597,24 +1694,69 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo& arg opts.multiThreaded = TRI_ObjectToBoolean(options->Get(keyMultiThreaded)); } } - unique_ptr path = TRI_RunShortestPathSearch( - isolate, - vocbase, - vertexCollectionName, - edgeCollectionName, - startVertex, - targetVertex, - opts - ); + vector readCollections; + vector writeCollections; + + readCollections.push_back(vertexCollectionName); + readCollections.push_back(edgeCollectionName); + + V8ResolverGuard resolverGuard(vocbase); + + ExplicitTransaction* trx = nullptr; + int res = 0; + CollectionNameResolver const* resolver = resolverGuard.getResolver(); + + // Start the transaction + try { + trx = beginTransaction(vocbase, readCollections, writeCollections); + } catch (int e) { + TRI_V8_THROW_EXCEPTION(e); + } + + // Order Barriers + unordered_map barriers; + try { + addBarrier(trx, resolver, vertexCollectionName, barriers); + addBarrier(trx, resolver, edgeCollectionName, barriers); + } catch (int e) { + trx->finish(e); + // Free all the pointers + delete trx; + TRI_V8_THROW_EXCEPTION(e); + } + + // Compute the path + unique_ptr path; + TRI_voc_cid_t edgeCid = resolver->getCollectionId(edgeCollectionName); + + TRI_ASSERT(barriers.find(edgeCid) != barriers.end()); + try { + path = TRI_RunShortestPathSearch( + vertexCollectionName, + edgeCollectionName, + startVertex, + targetVertex, + resolver, + barriers.find(edgeCid)->second.col->_collection->_collection, + opts + ); + } catch (int e) { + trx->finish(e); + delete trx; + TRI_V8_THROW_EXCEPTION(e); + } + + // Lift the result to v8 if (path.get() == nullptr) { v8::EscapableHandleScope scope(isolate); + trx->finish(res); + delete trx; TRI_V8_RETURN(scope.Escape(v8::Object::New(isolate))); } - V8ResolverGuard resolverGuard(vocbase); - CollectionNameResolver const* resolver = resolverGuard.getResolver(); - auto result = pathIdsToV8(isolate, resolver, *path); - + auto result = pathIdsToV8(isolate, trx, resolver, *path, barriers, true); + trx->finish(res); + delete trx; TRI_V8_RETURN(result); }