1
0
Fork 0

Now the Traverser Node figures out the correct index handle. Next Up: SingleServerTraverser needs to use indexScan for this condition. Traversal Still out of function.

This commit is contained in:
Michael Hackstein 2016-07-15 17:14:03 +02:00
parent 36d579e20e
commit 5b1e1b7496
12 changed files with 222 additions and 79 deletions

View File

@ -568,6 +568,10 @@ struct AstNode {
}
members.erase(members.begin() + i, members.end());
}
inline void clearMembers() {
members.clear();
}
/// @brief set the node's value type
inline void setValueType(AstNodeValueType type) { value.type = type; }

View File

@ -612,7 +612,6 @@ arangodb::OperationCursor* IndexBlock::orderCursor(size_t currentIndex) {
// yet no cursor for index, so create it
IndexNode const* node = static_cast<IndexNode const*>(getPlanNode());
_cursors[currentIndex].reset(_trx->indexScanForCondition(
_collection->getName(),
_indexes[currentIndex],
conditionNode,
node->outVariable(),

View File

@ -410,6 +410,8 @@ size_t TraversalBlock::skipSome(size_t atLeast, size_t atMost) {
/// @brief optimized version of neighbors search, must properly implement this
void TraversalBlock::neighbors(std::string const& startVertex) {
#warning Needs to be rebuild
/*
std::unordered_set<VPackSlice, arangodb::basics::VelocyPackHelper::VPackStringHash, arangodb::basics::VelocyPackHelper::VPackStringEqual> visited;
std::vector<VPackSlice> result;
@ -451,6 +453,7 @@ void TraversalBlock::neighbors(std::string const& startVertex) {
_vertices.emplace_back(AqlValue(mptr.vpack(), AqlValueFromMasterPointer()));
}
*/
}
/// @brief worker for neighbors() function
@ -459,6 +462,7 @@ void TraversalBlock::runNeighbors(std::vector<VPackSlice> const& startVertices,
std::vector<VPackSlice>& distinct,
TRI_edge_direction_e direction,
uint64_t depth) {
/*
std::vector<VPackSlice> nextDepth;
bool initialized = false;
TraversalNode const* node = static_cast<TraversalNode const*>(getPlanNode());
@ -538,4 +542,5 @@ void TraversalBlock::runNeighbors(std::vector<VPackSlice> const& startVertices,
if (!nextDepth.empty()) {
runNeighbors(nextDepth, visited, distinct, direction, depth + 1);
}
*/
}

View File

@ -170,22 +170,10 @@ static void transformCondition(AstNode const* node, Variable const* pvar,
AstNode* result = node->clone(ast);
auto tmpVar = ast->variables()->createTemporaryVariable();
AstNode* varRefNode = tn->getTemporaryRefNode();
size_t const n = result->numMembers();
// replace the path variable access by a variable access to edge/vertex
// (then current to the iteration)
auto varRefNode = new AstNode(NODE_TYPE_REFERENCE);
try {
ast->query()->addNode(varRefNode);
} catch (...) {
// prevent leak
delete varRefNode;
throw;
}
varRefNode->setData(tmpVar);
for (size_t i = 0; i < n; ++i) {
AstNode* baseCondition = result->getMemberUnchecked(i);
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE

View File

@ -27,6 +27,7 @@
#include "Aql/TraversalNode.h"
#include "Aql/ExecutionPlan.h"
#include "Aql/Ast.h"
#include "Aql/SortCondition.h"
#include "Aql/TraversalOptions.h"
#include "Indexes/Index.h"
@ -49,14 +50,17 @@ static uint64_t checkTraversalDepthValue(AstNode const* node) {
return static_cast<uint64_t>(v);
}
TraversalNode::EdgeConditionBuilder::EdgeConditionBuilder(TraversalNode const* tn,
AstNode* modCondition)
TraversalNode::EdgeConditionBuilder::EdgeConditionBuilder(
TraversalNode const* tn)
: _tn(tn), _containsCondition(false) {
_modCondition = _tn->_ast->createNodeNaryOperator(NODE_TYPE_OPERATOR_NARY_AND);
_modCondition->addMember(modCondition);
}
AstNode const* TraversalNode::EdgeConditionBuilder::getOutboundCondition() {
void TraversalNode::EdgeConditionBuilder::addConditionPart(AstNode const* part) {
_modCondition->addMember(part);
}
AstNode* TraversalNode::EdgeConditionBuilder::getOutboundCondition() {
if (_containsCondition) {
_modCondition->changeMember(_modCondition->numMembers() - 1, _tn->_fromCondition);
} else {
@ -69,7 +73,7 @@ AstNode const* TraversalNode::EdgeConditionBuilder::getOutboundCondition() {
return _modCondition;
};
AstNode const* TraversalNode::EdgeConditionBuilder::getInboundCondition() {
AstNode* TraversalNode::EdgeConditionBuilder::getInboundCondition() {
if (_containsCondition) {
_modCondition->changeMember(_modCondition->numMembers() - 1, _tn->_toCondition);
} else {
@ -616,7 +620,101 @@ void TraversalNode::fillTraversalOptions(
arangodb::traverser::TraverserOptions& opts) const {
opts.minDepth = _minDepth;
opts.maxDepth = _maxDepth;
opts.setCollections(_edgeColls, _directions);
// This is required by trx api.
// But we do not use it here.
SortCondition sort;
size_t numEdgeColls = _edgeColls.size();
AstNode* condition = nullptr;
Transaction* trx = _ast->query()->trx();
bool res = false;
EdgeConditionBuilder globalEdgeConditionBuilder(this);
opts._baseIndexHandles.reserve(numEdgeColls);
// Compute Edge Indexes. First default indexes:
for (size_t i = 0; i < numEdgeColls; ++i) {
auto dir = _directions[i];
switch (dir) {
case TRI_EDGE_IN:
condition = globalEdgeConditionBuilder.getInboundCondition();
break;
case TRI_EDGE_OUT:
condition = globalEdgeConditionBuilder.getOutboundCondition();
break;
case TRI_EDGE_ANY:
condition = globalEdgeConditionBuilder.getInboundCondition();
res = trx->getBestIndexHandleForFilterCondition(
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000,
opts._baseIndexHandles);
TRI_ASSERT(res); // Right now we have an enforced edge index which wil
// always fit.
condition = globalEdgeConditionBuilder.getOutboundCondition();
break;
}
#warning hard-coded nrItems.
res = trx->getBestIndexHandleForFilterCondition(
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000,
opts._baseIndexHandles);
TRI_ASSERT(res); // We have an enforced edge index which wil always fit.
}
for (std::pair<size_t, EdgeConditionBuilder> it : _edgeConditions) {
auto ins = opts._depthIndexHandles.emplace(
it.first, std::vector<Transaction::IndexHandle>());
TRI_ASSERT(ins.second);
auto& idxList = ins.first->second;
idxList.reserve(numEdgeColls);
// Compute Edge Indexes. First default indexes:
for (size_t i = 0; i < numEdgeColls; ++i) {
auto dir = _directions[i];
switch (dir) {
case TRI_EDGE_IN:
condition = it.second.getInboundCondition();
break;
case TRI_EDGE_OUT:
condition = it.second.getOutboundCondition();
break;
case TRI_EDGE_ANY:
condition = it.second.getInboundCondition();
res = trx->getBestIndexHandleForFilterCondition(
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList);
TRI_ASSERT(res); // Right now we have an enforced edge index which wil
// always fit.
condition = it.second.getOutboundCondition();
break;
}
#warning hard-coded nrItems.
res = trx->getBestIndexHandleForFilterCondition(
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList);
TRI_ASSERT(res); // We have an enforced edge index which wil always fit.
}
}
VPackBuilder ulf;
ulf.openObject();
ulf.add(VPackValue("base"));
ulf.openArray();
for (auto const& idx : opts._baseIndexHandles) {
ulf.openObject();
idx.toVelocyPack(ulf, false);
ulf.close();
}
ulf.close();
for (auto const& it : opts._depthIndexHandles) {
ulf.add(VPackValue(std::to_string(it.first)));
ulf.openArray();
for (auto const& idx : it.second) {
ulf.openObject();
idx.toVelocyPack(ulf, false);
ulf.close();
}
ulf.close();
}
ulf.close();
LOG(ERR) << ulf.toJson();
opts.useBreadthFirst = _options.useBreadthFirst;
opts.uniqueVertices = _options.uniqueVertices;
opts.uniqueEdges = _options.uniqueEdges;
@ -643,11 +741,17 @@ void TraversalNode::setCondition(arangodb::aql::Condition* condition) {
void TraversalNode::registerCondition(bool isConditionOnEdge,
size_t conditionLevel,
AstNode* condition) {
AstNode const* condition) {
if (isConditionOnEdge) {
TRI_ASSERT(_edgeConditions.find(conditionLevel) == _edgeConditions.end());
_edgeConditions.emplace(conditionLevel, EdgeConditionBuilder(this, condition));
auto const& it = _edgeConditions.find(conditionLevel);
if (it == _edgeConditions.end()) {
EdgeConditionBuilder builder(this);
builder.addConditionPart(condition);
_edgeConditions.emplace(conditionLevel, builder);
} else {
it->second.addConditionPart(condition);
}
} else {
auto const& it = _vertexConditions.find(conditionLevel);
if (it == _vertexConditions.end()) {
@ -664,7 +768,7 @@ void TraversalNode::registerCondition(bool isConditionOnEdge,
}
void TraversalNode::registerGlobalCondition(bool isConditionOnEdge,
AstNode* condition) {
AstNode const* condition) {
std::cout << "Registering global condition for edges: " << isConditionOnEdge << std::endl;
if (isConditionOnEdge) {
_globalEdgeCondition = condition;
@ -674,3 +778,7 @@ void TraversalNode::registerGlobalCondition(bool isConditionOnEdge,
condition->dump(0);
}
AstNode* TraversalNode::getTemporaryRefNode() const {
return _tmpObjVarNode;
}

View File

@ -49,13 +49,15 @@ class TraversalNode : public ExecutionNode {
bool _containsCondition;
public:
EdgeConditionBuilder(TraversalNode const*, AstNode*);
EdgeConditionBuilder(TraversalNode const*);
~EdgeConditionBuilder() {}
AstNode const* getOutboundCondition();
void addConditionPart(AstNode const*);
AstNode const* getInboundCondition();
AstNode* getOutboundCondition();
AstNode* getInboundCondition();
};
@ -211,12 +213,12 @@ class TraversalNode : public ExecutionNode {
/// @brief register a filter condition on a given search depth.
/// If this condition is not fulfilled a traversal will abort.
/// The condition will contain the local variable for it's accesses.
void registerCondition(bool, size_t, AstNode*);
void registerCondition(bool, size_t, AstNode const*);
/// @brief register a filter condition for all search depths
/// If this condition is not fulfilled a traversal will abort.
/// The condition will contain the local variable for it's accesses.
void registerGlobalCondition(bool, AstNode*);
void registerGlobalCondition(bool, AstNode const*);
bool allDirectionsEqual() const;
@ -227,6 +229,8 @@ class TraversalNode : public ExecutionNode {
TraversalOptions const* options() const { return &_options; }
AstNode* getTemporaryRefNode() const;
private:
/// @brief the database
TRI_vocbase_t* _vocbase;
@ -299,10 +303,10 @@ class TraversalNode : public ExecutionNode {
/// @brief The global edge condition. Does not contain
/// _from and _to checks
AstNode* _globalEdgeCondition;
AstNode const* _globalEdgeCondition;
/// @brief The global vertex condition
AstNode* _globalVertexCondition;
AstNode const* _globalVertexCondition;
/// @brief List of all depth specific conditions for edges
std::unordered_map<size_t, EdgeConditionBuilder> _edgeConditions;

View File

@ -101,6 +101,8 @@ void ClusterTraverser::UniqueVertexGetter::reset() {
void ClusterTraverser::ClusterEdgeGetter::getEdge(
std::string const& startVertex, std::vector<std::string>& result,
size_t*& last, size_t& eColIdx) {
#warning This path fetches Edges from DBServer, honoring conditions. Has to be rewritten.
/*
std::string collName;
TRI_edge_direction_e dir;
if (!_traverser->_opts.getCollection(eColIdx, collName, dir)) {
@ -116,8 +118,6 @@ void ClusterTraverser::ClusterEdgeGetter::getEdge(
VPackBuilder resultEdges;
resultEdges.openObject();
#warning This path fetches Edges from DBServer, honoring conditions. Has to be rewritten.
/*
auto found = _traverser->_opts.expressions->find(depth);
if (found != _traverser->_opts.expressions->end()) {
expEdges = found->second;
@ -129,7 +129,6 @@ void ClusterTraverser::ClusterEdgeGetter::getEdge(
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}
*/
resultEdges.close();
VPackSlice resSlice = resultEdges.slice();
VPackSlice edgesSlice = resSlice.get("edges");
@ -225,6 +224,7 @@ void ClusterTraverser::ClusterEdgeGetter::getEdge(
result.push_back(std::move(next));
}
}
*/
}
void ClusterTraverser::ClusterEdgeGetter::getAllEdges(

View File

@ -380,10 +380,9 @@ bool Transaction::sortOrs(arangodb::aql::Ast* ast,
std::pair<bool, bool> Transaction::findIndexHandleForAndNode(
std::vector<std::shared_ptr<Index>> indexes, arangodb::aql::AstNode* node,
arangodb::aql::Variable const* reference,
arangodb::aql::SortCondition const* sortCondition,
size_t itemsInCollection,
arangodb::aql::SortCondition const* sortCondition, size_t itemsInCollection,
std::vector<Transaction::IndexHandle>& usedIndexes,
arangodb::aql::AstNode*& specializedCondition,
bool computeSpecialisation, arangodb::aql::AstNode*& specializedCondition,
bool& isSparse) const {
std::shared_ptr<Index> bestIndex;
double bestCost = 0.0;
@ -461,7 +460,9 @@ std::pair<bool, bool> Transaction::findIndexHandleForAndNode(
return std::make_pair(false, false);
}
specializedCondition = bestIndex->specializeCondition(node, reference);
if (computeSpecialisation) {
specializedCondition = bestIndex->specializeCondition(node, reference);
}
usedIndexes.emplace_back(bestIndex);
isSparse = bestIndex->sparse();
@ -2694,7 +2695,7 @@ std::pair<bool, bool> Transaction::getBestIndexHandlesForFilterCondition(
arangodb::aql::AstNode* specializedCondition = nullptr;
auto canUseIndex = findIndexHandleForAndNode(
indexes, node, reference, sortCondition, itemsInCollection, usedIndexes,
specializedCondition, isSparse);
true, specializedCondition, isSparse);
if (canUseIndex.second && !canUseIndex.first) {
// index can be used for sorting only
@ -2731,6 +2732,41 @@ std::pair<bool, bool> Transaction::getBestIndexHandlesForFilterCondition(
return std::make_pair(canUseForFilter, canUseForSort);
}
/// @brief Gets the best fitting index for one specific condition.
/// Difference to IndexHandles: Condition is only one NARY_AND
/// and the Condition stays unmodified. Also does not care for sorting
/// Returns false if no index could be found.
bool Transaction::getBestIndexHandleForFilterCondition(
std::string const& collectionName,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
arangodb::aql::SortCondition const* sortCondition,
size_t itemsInCollection,
std::vector<IndexHandle>& usedIndexes) {
// We can only start after DNF transformation and only a single AND
TRI_ASSERT(node->type ==
arangodb::aql::AstNodeType::NODE_TYPE_OPERATOR_NARY_AND);
if (node->numMembers() == 0) {
// Well no index can serve no condition.
return false;
}
auto indexes = indexesForCollection(collectionName);
bool isSparse = false;
arangodb::aql::AstNode* specializedCondition = nullptr;
// Const cast is save here. Giving computeSpecialisation == false
// Makes sure node is NOT modified.
auto canUseIndex = findIndexHandleForAndNode(
indexes, const_cast<aql::AstNode*>(node), reference, sortCondition,
itemsInCollection, usedIndexes, false, specializedCondition, isSparse);
return canUseIndex.first;
}
//////////////////////////////////////////////////////////////////////////////
/// @brief Checks if the index supports the filter condition.
/// note: the caller must have read-locked the underlying collection when
@ -2832,7 +2868,7 @@ std::pair<bool, bool> Transaction::getIndexForSortCondition(
//////////////////////////////////////////////////////////////////////////////
OperationCursor* Transaction::indexScanForCondition(
std::string const& collectionName, IndexHandle const& indexId,
IndexHandle const& indexId,
arangodb::aql::AstNode const* condition, arangodb::aql::Variable const* var,
uint64_t limit, uint64_t batchSize, bool reverse) {
if (ServerState::isCoordinator(_serverRole)) {

View File

@ -546,6 +546,17 @@ class Transaction {
arangodb::aql::Variable const*, arangodb::aql::SortCondition const*,
size_t, std::vector<IndexHandle>&, bool&);
/// @brief Gets the best fitting index for one specific condition.
/// Difference to IndexHandles: Condition is only one NARY_AND
/// and the Condition stays unmodified. Also does not care for sorting
/// Returns false if no index could be found.
bool getBestIndexHandleForFilterCondition(std::string const&,
arangodb::aql::AstNode const*,
arangodb::aql::Variable const*,
arangodb::aql::SortCondition const*,
size_t, std::vector<IndexHandle>&);
//////////////////////////////////////////////////////////////////////////////
/// @brief Checks if the index supports the filter condition.
/// note: the caller must have read-locked the underlying collection when
@ -584,10 +595,10 @@ class Transaction {
/// calling this method
//////////////////////////////////////////////////////////////////////////////
OperationCursor* indexScanForCondition(
std::string const& collectionName, IndexHandle const& indexId,
arangodb::aql::AstNode const*, arangodb::aql::Variable const*, uint64_t,
uint64_t, bool);
OperationCursor* indexScanForCondition(IndexHandle const&,
arangodb::aql::AstNode const*,
arangodb::aql::Variable const*,
uint64_t, uint64_t, bool);
//////////////////////////////////////////////////////////////////////////////
/// @brief factory for OperationCursor objects
@ -810,7 +821,7 @@ class Transaction {
arangodb::aql::SortCondition const* sortCondition,
size_t itemsInCollection,
std::vector<Transaction::IndexHandle>& usedIndexes,
arangodb::aql::AstNode*& specializedCondition,
bool computeSpecialisation, arangodb::aql::AstNode*& specializedCondition,
bool& isSparse) const;
//////////////////////////////////////////////////////////////////////////////

View File

@ -294,6 +294,9 @@ aql::AqlValue SingleServerTraverser::pathToAqlValue(VPackBuilder& builder) {
bool SingleServerTraverser::EdgeGetter::nextCursor(std::string const& startVertex,
size_t& eColIdx,
size_t*& last) {
#warning Reimplement
return false;
/*
std::string eColName;
while (true) {
@ -327,6 +330,7 @@ bool SingleServerTraverser::EdgeGetter::nextCursor(std::string const& startVerte
_results.emplace();
return true;
}
*/
}
void SingleServerTraverser::EdgeGetter::nextEdge(
@ -424,6 +428,8 @@ void SingleServerTraverser::EdgeGetter::getAllEdges(
std::string const& startVertex, std::unordered_set<std::string>& edges,
size_t depth) {
#warning reimplement
/*
size_t idxId = 0;
std::string eColName;
arangodb::Transaction::IndexHandle indexHandle;
@ -476,5 +482,6 @@ void SingleServerTraverser::EdgeGetter::getAllEdges(
}
}
}
*/
}

View File

@ -71,34 +71,8 @@ void arangodb::traverser::ShortestPath::vertexToVelocyPack(Transaction* trx, siz
}
}
void arangodb::traverser::TraverserOptions::setCollections(
std::vector<std::string> const& colls, TRI_edge_direction_e dir) {
// We do not allow to reset the collections.
TRI_ASSERT(_collections.empty());
TRI_ASSERT(_directions.empty());
TRI_ASSERT(!colls.empty());
_collections = colls;
_directions.emplace_back(dir);
for (auto const& it : colls) {
_indexHandles.emplace_back(_trx->edgeIndexHandle(it));
}
}
void arangodb::traverser::TraverserOptions::setCollections(
std::vector<std::string> const& colls,
std::vector<TRI_edge_direction_e> const& dirs) {
// We do not allow to reset the collections.
TRI_ASSERT(_collections.empty());
TRI_ASSERT(_directions.empty());
TRI_ASSERT(!colls.empty());
TRI_ASSERT(colls.size() == dirs.size());
_collections = colls;
_directions = dirs;
for (auto const& it : colls) {
_indexHandles.emplace_back(_trx->edgeIndexHandle(it));
}
}
#warning TODO remove
/*
size_t arangodb::traverser::TraverserOptions::collectionCount () const {
return _collections.size();
}
@ -144,6 +118,7 @@ bool arangodb::traverser::TraverserOptions::getCollectionAndSearchValue(
arangodb::EdgeIndex::buildSearchValue(dir, vertexId, builder);
return true;
}
*/
bool arangodb::traverser::TraverserOptions::evaluateEdgeExpression(arangodb::velocypack::Slice edge, size_t depth) const {
#warning This has to be implemented.

View File

@ -39,6 +39,10 @@ namespace velocypack {
class Builder;
class Slice;
}
namespace aql {
class TraversalNode;
}
namespace traverser {
class TraverserExpression {
@ -197,13 +201,17 @@ class TraversalPath {
};
struct TraverserOptions {
friend class arangodb::aql::TraversalNode;
enum UniquenessLevel { NONE, PATH, GLOBAL };
private:
arangodb::Transaction* _trx;
std::vector<std::string> _collections;
std::vector<TRI_edge_direction_e> _directions;
std::vector<arangodb::Transaction::IndexHandle> _indexHandles;
std::vector<arangodb::Transaction::IndexHandle> _baseIndexHandles;
std::unordered_map<size_t, std::vector<arangodb::Transaction::IndexHandle>>
_depthIndexHandles;
public:
uint64_t minDepth;
@ -227,10 +235,7 @@ struct TraverserOptions {
uniqueEdges(UniquenessLevel::PATH) {
}
void setCollections(std::vector<std::string> const&, TRI_edge_direction_e);
void setCollections(std::vector<std::string> const&,
std::vector<TRI_edge_direction_e> const&);
/*
size_t collectionCount() const;
bool getCollection(size_t, std::string&, TRI_edge_direction_e&) const;
@ -238,7 +243,8 @@ struct TraverserOptions {
bool getCollectionAndSearchValue(size_t, std::string const&, std::string&,
arangodb::Transaction::IndexHandle&,
arangodb::velocypack::Builder&) const;
*/
bool evaluateEdgeExpression(arangodb::velocypack::Slice, size_t) const;
bool evaluateVertexExpression(arangodb::velocypack::Slice, size_t) const;