mirror of https://gitee.com/bigwinds/arangodb
Included IN operator in Skiplist. Right now only attribute IN values
This commit is contained in:
parent
cb57f39e06
commit
d381cf2841
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue