1
0
Fork 0

Included IN operator in Skiplist. Right now only attribute IN values

This commit is contained in:
Michael Hackstein 2015-10-07 17:27:35 +02:00
parent cb57f39e06
commit d381cf2841
2 changed files with 123 additions and 65 deletions

View File

@ -627,18 +627,26 @@ TRI_index_element_t* SkiplistIterator::nextIteration () {
TRI_doc_mptr_t* SkiplistIndexIterator::next () { TRI_doc_mptr_t* SkiplistIndexIterator::next () {
if (_iterator == nullptr) { if (_iterator == nullptr) {
// We restart the lookup // We restart the lookup
_iterator = _index->lookup(_operator, _reverse); _iterator = _index->lookup(_operators[_currentOperator], _reverse);
} }
TRI_index_element_t* res = _iterator->next(); TRI_index_element_t* res = _iterator->next();
if (res != nullptr) { while (res == nullptr) {
return res->document(); // Try the next iterator
} _currentOperator++;
if (_currentOperator == _operators.size()) {
// We are done
return nullptr; return nullptr;
}
_iterator = _index->lookup(_operators[_currentOperator], _reverse);
res = _iterator->next();
}
return res->document();
} }
void SkiplistIndexIterator::reset () { void SkiplistIndexIterator::reset () {
delete _iterator; delete _iterator;
_iterator = nullptr; _iterator = nullptr;
_currentOperator = 0;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -1108,10 +1116,15 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
return false; return false;
}; };
size_t i = 0; // initialize permutations
for (; i < _fields.size(); ++i) { std::vector<PermutationState> permutationStates;
permutationStates.reserve(_fields.size());
size_t maxPermutations = 1;
size_t usedFields = 0;
for (; usedFields < _fields.size(); ++usedFields) {
// We are in the equality range, we only allow one == or IN node per attribute // We are in the equality range, we only allow one == or IN node per attribute
auto it = found.find(i); auto it = found.find(usedFields);
if (it == found.end() || if (it == found.end() ||
it->second.size() != 1) { it->second.size() != 1) {
// We are either done, // We are either done,
@ -1119,7 +1132,7 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
// Continue with more complicated loop // Continue with more complicated loop
break; break;
} }
auto comp = found.find(i)->second[0]; auto comp = found.find(usedFields)->second[0];
TRI_ASSERT(comp->numMembers() == 2); TRI_ASSERT(comp->numMembers() == 2);
triagens::aql::AstNode const* access = nullptr; triagens::aql::AstNode const* access = nullptr;
triagens::aql::AstNode const* value = nullptr; triagens::aql::AstNode const* value = nullptr;
@ -1127,13 +1140,16 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
// We found an access for this field // We found an access for this field
if (comp->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { if (comp->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
// This is an equalityCheck, we can continue with the next field // This is an equalityCheck, we can continue with the next field
equalityValues.emplace_back(value->toJsonValue(TRI_UNKNOWN_MEM_ZONE)); permutationStates.emplace_back(PermutationState(comp, value, 0, 1));
}
else if (comp->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) {
permutationStates.emplace_back(PermutationState(comp, value, 0, value->numMembers()));
} }
// TODO support IN
else { else {
// This is a one-sided range // This is a one-sided range
break; break;
} }
maxPermutations *= permutationStates.back().n;
} }
// Now handle the next element, which might be a range // Now handle the next element, which might be a range
@ -1141,8 +1157,8 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
bool includeUpper = false; bool includeUpper = false;
TRI_json_t* lower = nullptr; TRI_json_t* lower = nullptr;
TRI_json_t* upper = nullptr; TRI_json_t* upper = nullptr;
if (i < _fields.size()) { if (usedFields < _fields.size()) {
auto it = found.find(i); auto it = found.find(usedFields);
if (it != found.end()) { if (it != found.end()) {
auto rangeConditions = it->second; auto rangeConditions = it->second;
TRI_ASSERT(rangeConditions.size() <= 2); TRI_ASSERT(rangeConditions.size() <= 2);
@ -1169,11 +1185,6 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
}; };
// This is not an equalityCheck, set lower or upper // This is not an equalityCheck, set lower or upper
switch (comp->type) { switch (comp->type) {
case triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ:
case triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN:
// TODO
TRI_ASSERT(false);
break;
case triagens::aql::NODE_TYPE_OPERATOR_BINARY_LT: case triagens::aql::NODE_TYPE_OPERATOR_BINARY_LT:
setBorder(true, false); setBorder(true, false);
break; break;
@ -1195,7 +1206,12 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
} }
} }
std::unique_ptr<TRI_index_operator_t> op(nullptr); std::vector<TRI_index_operator_t*> searchValues;
searchValues.reserve(maxPermutations);
std::unique_ptr<TRI_index_operator_t> rangeOperator(nullptr);
if (lower != nullptr) { if (lower != nullptr) {
TRI_index_operator_type_e type; TRI_index_operator_type_e type;
if (includeLower) { if (includeLower) {
@ -1210,7 +1226,7 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
return nullptr; return nullptr;
} }
TRI_PushBack3ArrayJson(TRI_UNKNOWN_MEM_ZONE, parameter, lower); TRI_PushBack3ArrayJson(TRI_UNKNOWN_MEM_ZONE, parameter, lower);
op.reset(TRI_CreateIndexOperator(type, rangeOperator.reset(TRI_CreateIndexOperator(type,
nullptr, nullptr,
nullptr, nullptr,
parameter, parameter,
@ -1238,12 +1254,12 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
parameter, parameter,
_shaper, _shaper,
1)); 1));
if (op != nullptr) { if (rangeOperator == nullptr) {
op.reset(tmpOp.release()); rangeOperator.reset(tmpOp.release());
} }
else { else {
op.reset(TRI_CreateIndexOperator(TRI_AND_INDEX_OPERATOR, rangeOperator.reset(TRI_CreateIndexOperator(TRI_AND_INDEX_OPERATOR,
op.release(), rangeOperator.release(),
tmpOp.release(), tmpOp.release(),
parameter, parameter,
_shaper, _shaper,
@ -1251,35 +1267,73 @@ IndexIterator* SkiplistIndex::iteratorForCondition (IndexIteratorContext* contex
} }
} }
if (! equalityValues.empty() ) { if (usedFields == 0) {
size_t size = equalityValues.size(); // We have a range query based on the first _field
TRI_json_t* parameter = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE, size); searchValues.emplace_back(rangeOperator.release());
if (parameter == nullptr) {
return nullptr;
} }
for (size_t i = 0; i < size; ++i) { else {
TRI_PushBack3ArrayJson(TRI_UNKNOWN_MEM_ZONE, parameter, equalityValues[i]); bool done = false;
// create all permutations
while (! done) {
std::unique_ptr<TRI_json_t> parameter(TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE, usedFields));
bool valid = true;
for (size_t i = 0; i < usedFields; ++i) {
auto state = permutationStates[i];
std::unique_ptr<TRI_json_t> json(state.getValue()->toJsonValue(TRI_UNKNOWN_MEM_ZONE));
if (json == nullptr) {
valid = false;
break;
} }
TRI_PushBack3ArrayJson(TRI_UNKNOWN_MEM_ZONE, parameter.get(), json.get());
}
if (valid) {
std::unique_ptr<TRI_index_operator_t> tmpOp(TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR, std::unique_ptr<TRI_index_operator_t> tmpOp(TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR,
nullptr, nullptr,
nullptr, nullptr,
parameter, parameter,
_shaper, _shaper,
size)); usedFields));
if (op != nullptr) { if (rangeOperator != nullptr) {
op.reset(tmpOp.release()); // NOTE: We might have to clone the rangeOperator here!
} std::unique_ptr<TRI_index_operator_t> combinedOp(TRI_CreateIndexOperator(TRI_AND_INDEX_OPERATOR,
else { rangeOperator.get(),
op.reset(TRI_CreateIndexOperator(TRI_AND_INDEX_OPERATOR, tmpOp.get(),
op.release(),
tmpOp.release(),
parameter, parameter,
_shaper, _shaper,
2)); 2));
tmpOp.release();
searchValues.push_back(combinedOp.get());
combinedOp.release();
}
else {
searchValues.push_back(tmpOp.get());
tmpOp.release();
} }
} }
return new SkiplistIndexIterator(this, op.release()); // now permute
while (true) {
if (++permutationStates[current].current < permutationStates[current].n) {
current = 0;
// abort inner iteration
break;
}
permutationStates[current].current = 0;
if (++current >= n) {
done = true;
break;
}
// next inner iteration
}
}
}
return new SkiplistIndexIterator(this, searchValues);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -178,15 +178,18 @@ namespace triagens {
public: public:
SkiplistIndexIterator (SkiplistIndex const* index, SkiplistIndexIterator (SkiplistIndex const* index,
TRI_index_operator_t* op) std::vector<TRI_index_operator_t*> op)
: _index(index), : _index(index),
_operator(op), _operators(op),
_reverse(false), _reverse(false),
_currentOperator(0),
_iterator(nullptr) { _iterator(nullptr) {
} }
~SkiplistIndexIterator () { ~SkiplistIndexIterator () {
delete _operator; for (auto& op : _operators) {
delete op;
}
delete _iterator; delete _iterator;
} }
@ -198,8 +201,9 @@ namespace triagens {
private: private:
SkiplistIndex const* _index; SkiplistIndex const* _index;
TRI_index_operator_t* _operator; std::vector<TRI_index_operator_t*> _operators;
bool _reverse; bool _reverse;
size_t _currentOperator;
SkiplistIterator* _iterator; SkiplistIterator* _iterator;
}; };