mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:arangodb/arangodb into devel
This commit is contained in:
commit
b6f3d506d9
|
@ -25,14 +25,6 @@
|
|||
|
||||
using namespace arangodb::traverser;
|
||||
|
||||
void SingleServerTraversalPath::getDocumentByIdentifier(arangodb::Transaction* trx,
|
||||
std::string const& identifier,
|
||||
VPackBuilder& result) {
|
||||
std::shared_ptr<VPackBuffer<uint8_t>> vertex =
|
||||
_traverser->fetchVertexData(_path.vertices.back());
|
||||
result.add(VPackSlice(vertex->data()));
|
||||
}
|
||||
|
||||
void SingleServerTraversalPath::pathToVelocyPack(arangodb::Transaction* trx,
|
||||
VPackBuilder& result) {
|
||||
result.openObject();
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace traverser {
|
|||
|
||||
class SingleServerTraversalPath : public TraversalPath {
|
||||
public:
|
||||
explicit SingleServerTraversalPath(
|
||||
SingleServerTraversalPath(
|
||||
arangodb::basics::EnumeratedPath<std::string, std::string> const& path,
|
||||
SingleServerTraverser* traverser)
|
||||
: _traverser(traverser), _path(path) {}
|
||||
|
@ -50,15 +50,9 @@ class SingleServerTraversalPath : public TraversalPath {
|
|||
|
||||
private:
|
||||
|
||||
void getDocumentByIdentifier(Transaction*, std::string const&,
|
||||
arangodb::velocypack::Builder&);
|
||||
|
||||
SingleServerTraverser* _traverser;
|
||||
|
||||
arangodb::basics::EnumeratedPath<std::string, std::string> _path;
|
||||
|
||||
arangodb::velocypack::Builder _searchBuilder;
|
||||
|
||||
};
|
||||
|
||||
} // namespace traverser
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
|
||||
#include "SingleServerTraverser.h"
|
||||
#include "Utils/OperationCursor.h"
|
||||
#include "Utils/Transaction.h"
|
||||
#include "VocBase/MasterPointer.h"
|
||||
#include "VocBase/SingleServerTraversalPath.h"
|
||||
|
||||
using namespace arangodb;
|
||||
using namespace arangodb::traverser;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -37,7 +39,6 @@ using namespace arangodb::traverser;
|
|||
|
||||
static int FetchDocumentById(arangodb::Transaction* trx,
|
||||
std::string const& id,
|
||||
VPackBuilder& builder,
|
||||
VPackBuilder& result) {
|
||||
size_t pos = id.find('/');
|
||||
if (pos == std::string::npos) {
|
||||
|
@ -49,12 +50,10 @@ static int FetchDocumentById(arangodb::Transaction* trx,
|
|||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
std::string col = id.substr(0, pos);
|
||||
trx->addCollectionAtRuntime(col);
|
||||
builder.clear();
|
||||
builder.add(VPackValue(id.substr(pos + 1)));
|
||||
TransactionBuilderLeaser builder(trx);
|
||||
builder->add(VPackValue(id.substr(pos + 1)));
|
||||
|
||||
int res = trx->documentFastPath(col, builder.slice(), result);
|
||||
int res = trx->documentFastPath(id.substr(0, pos), builder->slice(), result);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR && res != TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
|
||||
THROW_ARANGO_EXCEPTION(res);
|
||||
|
@ -125,7 +124,7 @@ std::shared_ptr<VPackBuffer<uint8_t>> SingleServerTraverser::fetchVertexData(
|
|||
auto it = _vertices.find(id);
|
||||
if (it == _vertices.end()) {
|
||||
VPackBuilder tmp;
|
||||
int res = FetchDocumentById(_trx, id, _builder, tmp);
|
||||
int res = FetchDocumentById(_trx, id, tmp);
|
||||
++_readDocuments;
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_ASSERT(res == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND);
|
||||
|
@ -143,7 +142,7 @@ bool SingleServerTraverser::VertexGetter::getVertex(std::string const& edge,
|
|||
std::string const& vertex,
|
||||
size_t depth,
|
||||
std::string& result) {
|
||||
auto const& it = _traverser->_edges.find(edge);
|
||||
auto it = _traverser->_edges.find(edge);
|
||||
TRI_ASSERT(it != _traverser->_edges.end());
|
||||
VPackSlice v(it->second->data());
|
||||
// NOTE: We assume that we only have valid edges.
|
||||
|
@ -165,7 +164,7 @@ void SingleServerTraverser::VertexGetter::reset(std::string const&) {
|
|||
bool SingleServerTraverser::UniqueVertexGetter::getVertex(
|
||||
std::string const& edge, std::string const& vertex, size_t depth,
|
||||
std::string& result) {
|
||||
auto const& it = _traverser->_edges.find(edge);
|
||||
auto it = _traverser->_edges.find(edge);
|
||||
TRI_ASSERT(it != _traverser->_edges.end());
|
||||
VPackSlice v(it->second->data());
|
||||
// NOTE: We assume that we only have valid edges.
|
||||
|
@ -209,7 +208,7 @@ void SingleServerTraverser::setStartVertex(std::string const& v) {
|
|||
if (fetchVertex) {
|
||||
fetchVertex = false;
|
||||
VPackBuilder tmp;
|
||||
int result = FetchDocumentById(_trx, v, _builder, tmp);
|
||||
int result = FetchDocumentById(_trx, v, tmp);
|
||||
++_readDocuments;
|
||||
if (result != TRI_ERROR_NO_ERROR) {
|
||||
// Vertex does not exist
|
||||
|
@ -290,11 +289,11 @@ TraversalPath* SingleServerTraverser::next() {
|
|||
}
|
||||
}
|
||||
|
||||
auto p = std::make_unique<SingleServerTraversalPath>(path, this);
|
||||
if (countEdges < _opts.minDepth) {
|
||||
return next();
|
||||
}
|
||||
return p.release();
|
||||
|
||||
return new SingleServerTraversalPath(path, this);
|
||||
}
|
||||
|
||||
bool SingleServerTraverser::EdgeGetter::nextCursor(std::string const& startVertex,
|
||||
|
|
|
@ -80,8 +80,8 @@ class SingleServerTraverser : public Traverser {
|
|||
arangodb::velocypack::ValueLength> {
|
||||
public:
|
||||
EdgeGetter(SingleServerTraverser* traverser,
|
||||
TraverserOptions const& opts,
|
||||
Transaction* trx)
|
||||
TraverserOptions const& opts,
|
||||
Transaction* trx)
|
||||
: _traverser(traverser), _opts(opts), _trx(trx) {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -33,30 +33,6 @@
|
|||
|
||||
using TraverserExpression = arangodb::traverser::TraverserExpression;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Helper to transform a vertex _id string to VertexId struct.
|
||||
/// NOTE: Make sure the given string is not freed as long as the resulting
|
||||
/// VertexId is in use
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::traverser::VertexId arangodb::traverser::IdStringToVertexId(
|
||||
CollectionNameResolver const* resolver, std::string const& vertex) {
|
||||
size_t split;
|
||||
char const* str = vertex.c_str();
|
||||
|
||||
if (!TRI_ValidateDocumentIdKeyGenerator(str, vertex.size(), &split)) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
|
||||
}
|
||||
|
||||
std::string const collectionName = vertex.substr(0, split);
|
||||
auto cid = resolver->getCollectionIdCluster(collectionName);
|
||||
|
||||
if (cid == 0) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
|
||||
}
|
||||
return VertexId(cid, const_cast<char*>(str + split + 1));
|
||||
}
|
||||
|
||||
/// @brief Class Shortest Path
|
||||
|
||||
|
||||
|
@ -83,11 +59,12 @@ void arangodb::traverser::ShortestPath::vertexToVelocyPack(Transaction* trx, siz
|
|||
std::string collection = v.copyString();
|
||||
size_t p = collection.find("/");
|
||||
TRI_ASSERT(p != std::string::npos);
|
||||
_searchBuilder.clear();
|
||||
_searchBuilder.add(VPackValue(collection.substr(p + 1)));
|
||||
|
||||
TransactionBuilderLeaser searchBuilder(trx);
|
||||
searchBuilder->add(VPackValue(collection.substr(p + 1)));
|
||||
collection = collection.substr(0, p);
|
||||
|
||||
int res = trx->documentFastPath(collection, _searchBuilder.slice(), builder);
|
||||
int res = trx->documentFastPath(collection, searchBuilder->slice(), builder);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
builder.clear(); // Just in case...
|
||||
builder.add(basics::VelocyPackHelper::NullValue());
|
||||
|
|
|
@ -41,43 +41,6 @@ class Slice;
|
|||
}
|
||||
namespace traverser {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Template for a vertex id. Is simply a pair of cid and key
|
||||
/// NOTE: This struct will never free the value asigned to char const* key
|
||||
/// The environment has to make sure that the string it points to is
|
||||
/// not freed as long as this struct is in use!
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct VertexId {
|
||||
TRI_voc_cid_t cid;
|
||||
char const* key;
|
||||
|
||||
VertexId() : cid(0), key("") {}
|
||||
|
||||
VertexId(TRI_voc_cid_t cid, char const* key) : cid(cid), key(key) {}
|
||||
|
||||
bool operator==(VertexId const& other) const {
|
||||
if (cid == other.cid) {
|
||||
return strcmp(key, other.key) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string toString(arangodb::CollectionNameResolver const* resolver) const {
|
||||
return resolver->getCollectionNameCluster(cid) + "/" + std::string(key);
|
||||
}
|
||||
};
|
||||
|
||||
// EdgeId and VertexId are similar here. both have a key and a cid
|
||||
typedef VertexId EdgeId;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Helper function to convert an _id string into a VertexId
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VertexId IdStringToVertexId(arangodb::CollectionNameResolver const* resolver,
|
||||
std::string const& vertex);
|
||||
|
||||
class TraverserExpression {
|
||||
public:
|
||||
bool isEdgeAccess;
|
||||
|
@ -171,9 +134,6 @@ class ShortestPath {
|
|||
size_t length() { return _vertices.size(); };
|
||||
|
||||
private:
|
||||
/// @brief Local builder to create a search value
|
||||
arangodb::velocypack::Builder _searchBuilder;
|
||||
|
||||
/// @brief Count how many documents have been read
|
||||
size_t _readDocuments;
|
||||
|
||||
|
@ -417,37 +377,4 @@ class Traverser {
|
|||
} // traverser
|
||||
} // arangodb
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<arangodb::traverser::VertexId> {
|
||||
public:
|
||||
size_t operator()(arangodb::traverser::VertexId const& s) const {
|
||||
size_t h1 = std::hash<TRI_voc_cid_t>()(s.cid);
|
||||
size_t h2 = static_cast<size_t>(TRI_FnvHashString(s.key));
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct equal_to<arangodb::traverser::VertexId> {
|
||||
public:
|
||||
bool operator()(arangodb::traverser::VertexId const& s,
|
||||
arangodb::traverser::VertexId const& t) const {
|
||||
return s.cid == t.cid && strcmp(s.key, t.key) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct less<arangodb::traverser::VertexId> {
|
||||
public:
|
||||
bool operator()(arangodb::traverser::VertexId const& lhs,
|
||||
arangodb::traverser::VertexId const& rhs) {
|
||||
if (lhs.cid != rhs.cid) {
|
||||
return lhs.cid < rhs.cid;
|
||||
}
|
||||
return strcmp(lhs.key, rhs.key) < 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -128,6 +128,12 @@ var registerCompatibilityFunctions = function() {
|
|||
}, false);
|
||||
};
|
||||
|
||||
var fixWeight = function (options) {
|
||||
if (!options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("weight")) {
|
||||
options.weightAttribute = options.weight;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief transform a string into an array.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1490,14 +1496,15 @@ Graph.prototype._shortestPath = function(startVertexExample, endVertexExample, o
|
|||
query += "ANY ";
|
||||
}
|
||||
query += `SHORTEST_PATH start TO target GRAPH @graphName `;
|
||||
if (options.hasOwnProperty("weight") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weight: @attribute, defaultWeight: @default}
|
||||
fixWeight(options);
|
||||
if (options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weightAttribute: @attribute, defaultWeight: @default}
|
||||
RETURN {
|
||||
v: v,
|
||||
e: e,
|
||||
d: IS_NULL(e) ? 0 : (IS_NUMBER(e[@attribute]) ? e[@attribute] : @default)
|
||||
}) `;
|
||||
bindVars.attribute = options.weight;
|
||||
bindVars.attribute = options.weightAttribute;
|
||||
bindVars.default = options.defaultWeight;
|
||||
} else {
|
||||
query += "RETURN {v: v, e: e, d: IS_NULL(e) ? 0 : 1}) ";
|
||||
|
@ -1534,10 +1541,11 @@ Graph.prototype._distanceTo = function(startVertexExample, endVertexExample, opt
|
|||
query += "ANY ";
|
||||
}
|
||||
query += `SHORTEST_PATH start TO target GRAPH @graphName `;
|
||||
if (options.hasOwnProperty("weight") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weight: @attribute, defaultWeight: @default}
|
||||
fixWeight(options);
|
||||
if (options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weightAttribute: @attribute, defaultWeight: @default}
|
||||
FILTER e != null RETURN IS_NUMBER(e[@attribute]) ? e[@attribute] : @default) `;
|
||||
bindVars.attribute = options.weight;
|
||||
bindVars.attribute = options.weightAttribute;
|
||||
bindVars.default = options.defaultWeight;
|
||||
} else {
|
||||
query += "FILTER e != null RETURN 1) ";
|
||||
|
@ -1575,10 +1583,11 @@ Graph.prototype._absoluteEccentricity = function(vertexExample, options) {
|
|||
query += "ANY ";
|
||||
}
|
||||
query += "SHORTEST_PATH start TO target GRAPH @graphName ";
|
||||
if (options.hasOwnProperty("weight") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weight: @attribute, defaultWeight: @default}
|
||||
fixWeight(options);
|
||||
if (options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weightAttribute: @attribute, defaultWeight: @default}
|
||||
FILTER e != null RETURN IS_NUMBER(e[@attribute]) ? e[@attribute] : @default) `;
|
||||
bindVars.attribute = options.weight;
|
||||
bindVars.attribute = options.weightAttribute;
|
||||
bindVars.default = options.defaultWeight;
|
||||
} else {
|
||||
query += "FILTER e != null RETURN 1) ";
|
||||
|
@ -1617,10 +1626,11 @@ Graph.prototype._farness = Graph.prototype._absoluteCloseness = function(vertexE
|
|||
query += "ANY ";
|
||||
}
|
||||
query += "SHORTEST_PATH start TO target GRAPH @graphName ";
|
||||
if (options.hasOwnProperty("weight") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weight: @attribute, defaultWeight: @default}
|
||||
fixWeight(options);
|
||||
if (options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weightAttribute: @attribute, defaultWeight: @default}
|
||||
FILTER e != null RETURN IS_NUMBER(e[@attribute]) ? e[@attribute] : @default) `;
|
||||
bindVars.attribute = options.weight;
|
||||
bindVars.attribute = options.weightAttribute;
|
||||
bindVars.default = options.defaultWeight;
|
||||
} else {
|
||||
query += "FILTER e != null RETURN 1) ";
|
||||
|
@ -1704,9 +1714,10 @@ Graph.prototype._absoluteBetweenness = function(example, options) {
|
|||
query += "ANY ";
|
||||
}
|
||||
query += "SHORTEST_PATH start TO target GRAPH @graphName ";
|
||||
if (options.hasOwnProperty("weight") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weight: @attribute, defaultWeight: @default} `;
|
||||
bindVars.attribute = options.weight;
|
||||
fixWeight(options);
|
||||
if (options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weightAttribute: @attribute, defaultWeight: @default} `;
|
||||
bindVars.attribute = options.weightAttribute;
|
||||
bindVars.default = options.defaultWeight;
|
||||
}
|
||||
query += `
|
||||
|
@ -1784,10 +1795,11 @@ Graph.prototype._radius = function(options) {
|
|||
query += "ANY ";
|
||||
}
|
||||
query += "SHORTEST_PATH s TO t GRAPH @graphName ";
|
||||
if (options.hasOwnProperty("weight") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weight: @attribute, defaultWeight: @default}
|
||||
fixWeight(options);
|
||||
if (options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weightAttribute: @attribute, defaultWeight: @default}
|
||||
FILTER e != null RETURN IS_NUMBER(e[@attribute]) ? e[@attribute] : @default) `;
|
||||
bindVars.attribute = options.weight;
|
||||
bindVars.attribute = options.weightAttribute;
|
||||
bindVars.default = options.defaultWeight;
|
||||
} else {
|
||||
query += "FILTER e != null RETURN 1) ";
|
||||
|
@ -1828,10 +1840,11 @@ Graph.prototype._diameter = function(options) {
|
|||
"graphName": this.__name
|
||||
};
|
||||
query += "SHORTEST_PATH s TO t GRAPH @graphName ";
|
||||
if (options.hasOwnProperty("weight") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weight: @attribute, defaultWeight: @default}
|
||||
fixWeight(options);
|
||||
if (options.hasOwnProperty("weightAttribute") && options.hasOwnProperty("defaultWeight")) {
|
||||
query += `OPTIONS {weightAttribute: @attribute, defaultWeight: @default}
|
||||
FILTER e != null RETURN IS_NUMBER(e[@attribute]) ? e[@attribute] : @default)) `;
|
||||
bindVars.attribute = options.weight;
|
||||
bindVars.attribute = options.weightAttribute;
|
||||
bindVars.default = options.defaultWeight;
|
||||
} else {
|
||||
query += "RETURN 1)) - 1 ";
|
||||
|
|
|
@ -243,7 +243,7 @@ class BreadthFirstEnumerator : public PathEnumerator<edgeIdentifier, vertexIdent
|
|||
PathStep() {}
|
||||
|
||||
public:
|
||||
PathStep(vertexIdentifier const& vertex) : sourceIdx(0), vertex(vertex) {}
|
||||
explicit PathStep(vertexIdentifier const& vertex) : sourceIdx(0), vertex(vertex) {}
|
||||
|
||||
PathStep(size_t sourceIdx, edgeIdentifier const& edge,
|
||||
vertexIdentifier const& vertex)
|
||||
|
@ -453,6 +453,15 @@ class BreadthFirstEnumerator : public PathEnumerator<edgeIdentifier, vertexIdent
|
|||
|
||||
private:
|
||||
|
||||
inline size_t getDepth(size_t index) const {
|
||||
size_t depth = 0;
|
||||
while (index != 0) {
|
||||
++depth;
|
||||
index = _schreier[index]->sourceIdx;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Build the enumerated path for the given index in the schreier
|
||||
/// vector.
|
||||
|
@ -460,23 +469,27 @@ class BreadthFirstEnumerator : public PathEnumerator<edgeIdentifier, vertexIdent
|
|||
|
||||
void computeEnumeratedPath(size_t index) {
|
||||
TRI_ASSERT(index < _schreier.size());
|
||||
std::vector<edgeIdentifier> edges;
|
||||
std::vector<vertexIdentifier> vertices;
|
||||
PathStep* current = nullptr;
|
||||
while (index != 0) {
|
||||
current = _schreier[index];
|
||||
vertices.push_back(current->vertex);
|
||||
edges.push_back(current->edge);
|
||||
index = current->sourceIdx;
|
||||
}
|
||||
current = _schreier[0];
|
||||
vertices.push_back(current->vertex);
|
||||
|
||||
// Computed path. Insert it into the path enumerator.
|
||||
size_t depth = getDepth(index);
|
||||
this->_enumeratedPath.edges.clear();
|
||||
this->_enumeratedPath.vertices.clear();
|
||||
std::copy(vertices.rbegin(), vertices.rend(), std::back_inserter(this->_enumeratedPath.vertices));
|
||||
std::copy(edges.rbegin(), edges.rend(), std::back_inserter(this->_enumeratedPath.edges));
|
||||
this->_enumeratedPath.edges.resize(depth);
|
||||
this->_enumeratedPath.vertices.resize(depth + 1);
|
||||
|
||||
// Computed path. Insert it into the path enumerator.
|
||||
PathStep* current = nullptr;
|
||||
while (index != 0) {
|
||||
TRI_ASSERT(depth > 0);
|
||||
current = _schreier[index];
|
||||
this->_enumeratedPath.vertices[depth] = current->vertex;
|
||||
this->_enumeratedPath.edges[depth - 1] = current->edge;
|
||||
|
||||
index = current->sourceIdx;
|
||||
--depth;
|
||||
}
|
||||
|
||||
current = _schreier[0];
|
||||
this->_enumeratedPath.vertices[0] = current->vertex;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue