1
0
Fork 0

The CPP shortest path can now live with non existent vertices and even with non existent vertex collections (dropped after edge creation but before path computation)

This commit is contained in:
Michael Hackstein 2015-05-12 15:39:04 -07:00
parent c785388366
commit 3b3a28e16a
4 changed files with 129 additions and 96 deletions

View File

@ -66,7 +66,6 @@ namespace triagens {
bool embed)
: Transaction(new V8TransactionContext(embed), vocbase, 0) {
// std::cout << TRI_CurrentThreadId() << ", EXPLICITTRANSACTION " << this << " CTOR\r\n";
this->addHint(TRI_TRANSACTION_HINT_LOCK_ENTIRELY, false);
if (lockTimeout >= 0.0) {
@ -86,12 +85,43 @@ namespace triagens {
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create the transaction with cids
////////////////////////////////////////////////////////////////////////////////
ExplicitTransaction (struct TRI_vocbase_s* vocbase,
std::vector<TRI_voc_cid_t> const& readCollections,
std::vector<TRI_voc_cid_t> const& writeCollections,
double lockTimeout,
bool waitForSync,
bool embed)
: Transaction(new V8TransactionContext(embed), vocbase, 0) {
this->addHint(TRI_TRANSACTION_HINT_LOCK_ENTIRELY, false);
if (lockTimeout >= 0.0) {
this->setTimeout(lockTimeout);
}
if (waitForSync) {
this->setWaitForSync();
}
for (auto it = readCollections.begin(); it != readCollections.end(); ++it) {
this->addCollection((*it), TRI_TRANSACTION_READ);
}
for (auto it = writeCollections.begin(); it != writeCollections.end(); ++it) {
this->addCollection((*it), TRI_TRANSACTION_WRITE);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief end the transaction
////////////////////////////////////////////////////////////////////////////////
~ExplicitTransaction () {
// std::cout << TRI_CurrentThreadId() << ", EXPLICITTRANSACTION " << this << " DTOR\r\n";
}
};

View File

@ -200,7 +200,7 @@ class AttributeWeightCalculator {
/// to explicitly allow move semantics.
////////////////////////////////////////////////////////////////////////////////
static inline VertexId extractFromId(TRI_doc_mptr_copy_t& ptr) {
static VertexId extractFromId(TRI_doc_mptr_copy_t& ptr) {
return VertexId(TRI_EXTRACT_MARKER_FROM_CID(&ptr),
TRI_EXTRACT_MARKER_FROM_KEY(&ptr));
};
@ -210,7 +210,7 @@ static inline VertexId extractFromId(TRI_doc_mptr_copy_t& ptr) {
/// to explicitly allow move semantics.
////////////////////////////////////////////////////////////////////////////////
static inline VertexId extractToId(TRI_doc_mptr_copy_t& ptr) {
static VertexId extractToId(TRI_doc_mptr_copy_t& ptr) {
return VertexId(TRI_EXTRACT_MARKER_TO_CID(&ptr),
TRI_EXTRACT_MARKER_TO_KEY(&ptr));
};

View File

@ -1495,7 +1495,7 @@ static void JS_QueryIsKilledAql (const v8::FunctionCallbackInfo<v8::Value>& args
/// @brief Transforms VertexId to v8String
////////////////////////////////////////////////////////////////////////////////
static inline v8::Local<v8::String> vertexIdToString (
static v8::Local<v8::String> vertexIdToString (
v8::Isolate* isolate,
CollectionNameResolver const* resolver,
VertexId const& id
@ -1506,7 +1506,7 @@ static inline v8::Local<v8::String> vertexIdToString (
/// @brief Transforms EdgeId to v8String
////////////////////////////////////////////////////////////////////////////////
static inline v8::Local<v8::String> edgeIdToString (
static v8::Local<v8::String> edgeIdToString (
v8::Isolate* isolate,
CollectionNameResolver const* resolver,
EdgeId const& id
@ -1518,7 +1518,7 @@ static inline v8::Local<v8::String> edgeIdToString (
/// @brief Transforms VertexId to v8 json
////////////////////////////////////////////////////////////////////////////////
static inline v8::Handle<v8::Value> vertexIdToData(
static v8::Handle<v8::Value> vertexIdToData(
v8::Isolate* isolate,
CollectionNameResolver const* resolver,
ExplicitTransaction* trx,
@ -1526,10 +1526,17 @@ static inline v8::Handle<v8::Value> vertexIdToData(
VertexId const& vertexId
) {
auto i = barriers.find(vertexId.cid);
TRI_ASSERT(i != barriers.end());
if (i == barriers.end()) {
v8::EscapableHandleScope scope(isolate);
return scope.Escape<v8::Value>(v8::Null(isolate));
}
TRI_doc_mptr_copy_t document;
trx->readSingle(i->second.col, &document, vertexId.key);
int res = trx->readSingle(i->second.col, &document, vertexId.key);
if (res != TRI_ERROR_NO_ERROR) {
v8::EscapableHandleScope scope(isolate);
return scope.Escape<v8::Value>(v8::Null(isolate));
}
return TRI_WrapShapedJson(isolate, resolver, i->second.barrier,
vertexId.cid, i->second.col->_collection->_collection, document.getDataPtr());
};
@ -1538,7 +1545,7 @@ static inline v8::Handle<v8::Value> vertexIdToData(
/// @brief Transforms EdgeId to v8 json
////////////////////////////////////////////////////////////////////////////////
static inline v8::Handle<v8::Value> edgeIdToData(
static v8::Handle<v8::Value> edgeIdToData(
v8::Isolate* isolate,
CollectionNameResolver const* resolver,
ExplicitTransaction* trx,
@ -1554,54 +1561,52 @@ static inline v8::Handle<v8::Value> edgeIdToData(
/// @brief Extracts all touched collections from ArangoDBPathFinder::Path
////////////////////////////////////////////////////////////////////////////////
static inline vector<string> extractCidsFromPath(ArangoDBPathFinder::Path& p,
CollectionNameResolver const* resolver) {
static void extractCidsFromPath(TRI_vocbase_t* vocbase,
ArangoDBPathFinder::Path& p,
vector<TRI_voc_cid_t>& result) {
unordered_set<TRI_voc_cid_t> found;
vector<string> result;
uint32_t const vn = static_cast<uint32_t>(p.vertices.size());
uint32_t const en = static_cast<uint32_t>(p.edges.size());
for (uint32_t j = 0; j < vn; ++j) {
TRI_voc_cid_t cid = p.vertices[j].cid;
auto it = found.find(cid);
if (it == found.end()) {
// Not yet found. Insert it
result.push_back(resolver->getCollectionName(cid));
found.emplace(cid);
// Not yet found. Insert it if it exists
if (TRI_LookupCollectionByIdVocBase(vocbase, cid) != nullptr) {
result.push_back(cid);
found.insert(cid);
}
}
}
for (uint32_t j = 0; j < en; ++j) {
TRI_voc_cid_t cid = p.edges[j].cid;
auto it = found.find(cid);
if (it == found.end()) {
// Not yet found. Insert it
result.push_back(resolver->getCollectionName(cid));
found.emplace(cid);
// Not yet found. Insert it if it exists
if (TRI_LookupCollectionByIdVocBase(vocbase, cid) != nullptr) {
result.push_back(cid);
found.insert(cid);
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Request a barrier for the given collection
////////////////////////////////////////////////////////////////////////////////
static inline void addBarrier(
static void addBarrier(
ExplicitTransaction* trx,
CollectionNameResolver const* resolver,
string const& collectionName,
TRI_voc_cid_t const& cid,
unordered_map<TRI_voc_cid_t, CollectionBarrierInfo>& 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));
TRI_barrier_t* barrier = trx->orderBarrier(trx->trxCollection(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));
= trx->trxCollection(cid);
barriers.emplace(cid, CollectionBarrierInfo(barrier, dcol));
}
////////////////////////////////////////////////////////////////////////////////
@ -1611,10 +1616,10 @@ static inline void addBarrier(
/// If this function throws the transaction is non-existent.
////////////////////////////////////////////////////////////////////////////////
static inline ExplicitTransaction* beginTransaction(
static ExplicitTransaction* beginTransaction(
TRI_vocbase_t* vocbase,
vector<string>& readCollections,
vector<string>& writeCollections,
vector<TRI_voc_cid_t>& readCollections,
vector<TRI_voc_cid_t>& writeCollections,
CollectionNameResolver const* resolver,
unordered_map<TRI_voc_cid_t, CollectionBarrierInfo>& barriers
) {
@ -1645,10 +1650,10 @@ static inline ExplicitTransaction* beginTransaction(
try {
// Get all barriers at once
for (auto it : readCollections) {
addBarrier(trx, resolver, it, barriers);
addBarrier(trx, it, barriers);
}
for (auto it : writeCollections) {
addBarrier(trx, resolver, it, barriers);
addBarrier(trx, it, barriers);
}
} catch (int e) {
// Could not get a barrier.
@ -1657,7 +1662,6 @@ static inline ExplicitTransaction* beginTransaction(
delete trx;
throw e;
}
return trx;
}
@ -1665,12 +1669,12 @@ static inline ExplicitTransaction* beginTransaction(
/// @brief Transforms an ArangoDBPathFinder::Path to v8 json values
////////////////////////////////////////////////////////////////////////////////
static inline v8::Handle<v8::Value> pathIdsToV8(v8::Isolate* isolate,
static v8::Handle<v8::Value> pathIdsToV8(v8::Isolate* isolate,
TRI_vocbase_t* vocbase,
CollectionNameResolver const* resolver,
ArangoDBPathFinder::Path& p,
unordered_map<TRI_voc_cid_t, CollectionBarrierInfo>& barriers,
bool includeData = false) {
bool& includeData) {
v8::EscapableHandleScope scope(isolate);
v8::Handle<v8::Object> result = v8::Object::New(isolate);
@ -1680,10 +1684,10 @@ static inline v8::Handle<v8::Value> pathIdsToV8(v8::Isolate* isolate,
uint32_t const en = static_cast<uint32_t>(p.edges.size());
v8::Handle<v8::Array> edges = v8::Array::New(isolate, static_cast<int>(en));
if (includeData) {
vector<string> readCollections = extractCidsFromPath(p, resolver);
vector<string> writeCollections;
vector<TRI_voc_cid_t> readCollections;
extractCidsFromPath(vocbase, p, readCollections);
vector<TRI_voc_cid_t> writeCollections;
unordered_map<TRI_voc_cid_t, CollectionBarrierInfo> barriers;
ExplicitTransaction* trx = beginTransaction(vocbase, readCollections,
writeCollections, resolver, barriers);
@ -1715,7 +1719,7 @@ static inline v8::Handle<v8::Value> pathIdsToV8(v8::Isolate* isolate,
/// @brief Extract collection names from v8 array.
////////////////////////////////////////////////////////////////////////////////
static inline unordered_set<string> v8ArrayToStrings (const v8::Handle<v8::Value>& parameter) {
static unordered_set<string> v8ArrayToStrings (const v8::Handle<v8::Value>& parameter) {
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(parameter);
uint32_t const n = array->Length();
unordered_set<string> result;
@ -1737,25 +1741,19 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo<v8::Value>& arg
v8::Isolate* isolate = args.GetIsolate();
v8::HandleScope scope(isolate);
if (args.Length() < 4 || args.Length() > 5) {
TRI_V8_THROW_EXCEPTION_USAGE("CPP_SHORTEST_PATH(<vertexcollections[]>, <edgecollections[]>, <start>, <end>, <options>)");
if (args.Length() < 3 || args.Length() > 4) {
TRI_V8_THROW_EXCEPTION_USAGE("CPP_SHORTEST_PATH(<edgecollections[]>, <start>, <end>, <options>)");
}
TRI_vocbase_t* vocbase;
vocbase = GetContextVocBase(isolate);
// get the vertex collection
if (! args[0]->IsArray()) {
TRI_V8_THROW_TYPE_ERROR("expecting array for <vertexcollections[]>");
}
unordered_set<string> vertexCollectionNames = v8ArrayToStrings(args[0]);
// get the edge collection
if (! args[1]->IsString()) {
if (! args[0]->IsString()) {
TRI_V8_THROW_TYPE_ERROR("expecting array for <edgecollections[]>");
}
string const edgeCollectionName = TRI_ObjectToString(args[1]);
string const edgeCollectionName = TRI_ObjectToString(args[0]);
vocbase = GetContextVocBase(isolate);
@ -1763,26 +1761,26 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo<v8::Value>& arg
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
if (! args[2]->IsString()) {
TRI_V8_THROW_TYPE_ERROR("expecting string for <startVertex>");
if (! args[1]->IsString()) {
TRI_V8_THROW_TYPE_ERROR("expecting id for <startVertex>");
}
string const startVertex = TRI_ObjectToString(args[2]);
string const startVertex = TRI_ObjectToString(args[1]);
if (! args[3]->IsString()) {
TRI_V8_THROW_TYPE_ERROR("expecting string for <targetVertex>");
if (! args[2]->IsString()) {
TRI_V8_THROW_TYPE_ERROR("expecting id for <targetVertex>");
}
string const targetVertex = TRI_ObjectToString(args[3]);
string const targetVertex = TRI_ObjectToString(args[2]);
traverser::ShortestPathOptions opts;
if (args.Length() == 5) {
if (! args[4]->IsObject()) {
bool includeData = false;
if (args.Length() == 4) {
if (! args[3]->IsObject()) {
TRI_V8_THROW_TYPE_ERROR("expecting json for <options>");
}
v8::Handle<v8::Object> options = args[4]->ToObject();
v8::Handle<v8::Object> options = args[3]->ToObject();
v8::Local<v8::String> keyDirection = TRI_V8_ASCII_STRING("direction");
v8::Local<v8::String> keyWeight= TRI_V8_ASCII_STRING("distance");
v8::Local<v8::String> keyDefaultWeight= TRI_V8_ASCII_STRING("defaultDistance");
if (options->Has(keyDirection) ) {
opts.direction = TRI_ObjectToString(options->Get(keyDirection));
@ -1793,28 +1791,35 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo<v8::Value>& arg
TRI_V8_THROW_TYPE_ERROR("expecting direction to be 'outbound', 'inbound' or 'any'");
}
}
v8::Local<v8::String> keyWeight= TRI_V8_ASCII_STRING("distance");
v8::Local<v8::String> keyDefaultWeight= TRI_V8_ASCII_STRING("defaultDistance");
if (options->Has(keyWeight) && options->Has(keyDefaultWeight) ) {
opts.useWeight = true;
opts.weightAttribute = TRI_ObjectToString(options->Get(keyWeight));
opts.defaultWeight = TRI_ObjectToDouble(options->Get(keyDefaultWeight));
}
v8::Local<v8::String> keyIncludeData = TRI_V8_ASCII_STRING("includeData");
if (options->Has(keyIncludeData)) {
includeData = TRI_ObjectToBoolean(options->Get(keyIncludeData));
}
v8::Local<v8::String> keyBidirectional = TRI_V8_ASCII_STRING("bidirectional");
if (options->Has(keyBidirectional)) {
opts.bidirectional = TRI_ObjectToBoolean(options->Get(keyBidirectional));
}
v8::Local<v8::String> keyMultiThreaded = TRI_V8_ASCII_STRING("multiThreaded");
if (options->Has(keyMultiThreaded)) {
opts.multiThreaded = TRI_ObjectToBoolean(options->Get(keyMultiThreaded));
}
}
vector<string> readCollections;
vector<string> writeCollections;
for (auto it : vertexCollectionNames) {
readCollections.push_back(it);
}
readCollections.push_back(edgeCollectionName);
vector<TRI_voc_cid_t> readCollections;
vector<TRI_voc_cid_t> writeCollections;
V8ResolverGuard resolverGuard(vocbase);
@ -1822,6 +1827,8 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo<v8::Value>& arg
int res = 0;
CollectionNameResolver const* resolver = resolverGuard.getResolver();
readCollections.push_back(resolver->getCollectionId(edgeCollectionName));
// Start the transaction and
// Order Barriers
unordered_map<TRI_voc_cid_t, CollectionBarrierInfo> barriers;
@ -1865,7 +1872,7 @@ static void JS_QueryShortestPath (const v8::FunctionCallbackInfo<v8::Value>& arg
// Adding additional locks on vertex collections at this point to the transaction
// would cause dead-locks.
// Will be fixed automatically with new MVCC version.
auto result = pathIdsToV8(isolate, vocbase, resolver, *path, barriers, true);
auto result = pathIdsToV8(isolate, vocbase, resolver, *path, barriers, includeData);
TRI_V8_RETURN(result);
}
@ -1990,17 +1997,19 @@ static void JS_QueryNeighbors (const v8::FunctionCallbackInfo<v8::Value>& args)
}
}
vector<string> readCollections;
vector<string> writeCollections;
readCollections.push_back(vertexCollectionName);
readCollections.push_back(edgeCollectionName);
// TODO: Replace with cids instead of names
vector<TRI_voc_cid_t> readCollections;
vector<TRI_voc_cid_t> writeCollections;
V8ResolverGuard resolverGuard(vocbase);
CollectionNameResolver const* resolver = resolverGuard.getResolver();
readCollections.push_back(resolver->getCollectionId(vertexCollectionName));
readCollections.push_back(resolver->getCollectionId(edgeCollectionName));
ExplicitTransaction* trx = nullptr;
int res = 0;
CollectionNameResolver const* resolver = resolverGuard.getResolver();
unordered_map<TRI_voc_cid_t, CollectionBarrierInfo> barriers;
// Start the transaction

View File

@ -5597,26 +5597,20 @@ function AQL_SHORTEST_PATH (vertexCollection,
direction,
params) {
'use strict';
if (typeof startVertex === "string" && typeof endVertex === "string") {
var opts = {
direction: direction
};
if (params.hasOwnProperty("distance") && params.hasOwnProperty("defaultDistance")) {
opts.distance = params.distance;
opts.defaultDistance = params.defaultDistance;
}
return CPP_SHORTEST_PATH([vertexCollection], edgeCollection, startVertex, endVertex, opts);
var opts = {
direction: direction
};
if (params.hasOwnProperty("distance") && params.hasOwnProperty("defaultDistance")) {
opts.distance = params.distance;
opts.defaultDistance = params.defaultDistance;
}
params = SHORTEST_PATH_PARAMS(params);
return TRAVERSAL_FUNC("SHORTEST_PATH",
TRAVERSAL.collectionDatasourceFactory(COLLECTION(edgeCollection)),
TO_ID(startVertex, vertexCollection),
TO_ID(endVertex, vertexCollection),
direction,
params);
if (params.hasOwnProperty("includeData") {
opts.includeData = params.includeData;
}
return CPP_SHORTEST_PATH(edgeCollection,
TO_ID(startVertex, vertexCollection),
TO_ID(endVertex, vertexCollection),
opts);
}
////////////////////////////////////////////////////////////////////////////////