mirror of https://gitee.com/bigwinds/arangodb
fixed memleaks
This commit is contained in:
parent
a1de2bfcc1
commit
85eacaa458
|
@ -481,16 +481,23 @@ void IndexBlock::freeCondition () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexBlock::startNextIterator () {
|
void IndexBlock::startNextIterator () {
|
||||||
|
delete _iterator;
|
||||||
|
_iterator = nullptr;
|
||||||
|
|
||||||
++_currentIndex;
|
++_currentIndex;
|
||||||
if (_currentIndex < _indexes.size()) {
|
if (_currentIndex < _indexes.size()) {
|
||||||
auto outVariable = static_cast<IndexNode const*>(getPlanNode())->outVariable();
|
auto outVariable = static_cast<IndexNode const*>(getPlanNode())->outVariable();
|
||||||
auto ast = static_cast<IndexNode const*>(getPlanNode())->_plan->getAst();
|
auto ast = static_cast<IndexNode const*>(getPlanNode())->_plan->getAst();
|
||||||
|
|
||||||
_iterator = _indexes[_currentIndex]->getIterator(_context, ast, _condition->getMember(_currentIndex), outVariable);
|
_iterator = _indexes[_currentIndex]->getIterator(_context, ast, _condition->getMember(_currentIndex), outVariable);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
else {
|
else {
|
||||||
// If all indexes have been exhausted we set _iterator to nullptr;
|
// If all indexes have been exhausted we set _iterator to nullptr;
|
||||||
|
delete _iterator;
|
||||||
_iterator = nullptr;
|
_iterator = nullptr;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is called every time everything in _documents has been passed on
|
// this is called every time everything in _documents has been passed on
|
||||||
|
|
|
@ -2057,19 +2057,15 @@ int triagens::aql::useIndexesRule (Optimizer* opt,
|
||||||
std::cout << "Candidates to replace " << changes.size() << std::endl;
|
std::cout << "Candidates to replace " << changes.size() << std::endl;
|
||||||
|
|
||||||
if (! changes.empty()) {
|
if (! changes.empty()) {
|
||||||
// clone the original plan
|
|
||||||
std::unique_ptr<ExecutionPlan> newPlan(plan->clone());
|
|
||||||
|
|
||||||
for (auto& it : changes) {
|
for (auto& it : changes) {
|
||||||
ExecutionNode* newNode = it.second->clone(newPlan.get(), true, false);
|
plan->registerNode(it.second);
|
||||||
newPlan->registerNode(newNode);
|
plan->replaceNode(plan->getNodeById(it.first), it.second);
|
||||||
newPlan->replaceNode(newPlan->getNodeById(it.first), newNode);
|
|
||||||
|
|
||||||
// prevent double deletion by cleanupChanges()
|
// prevent double deletion by cleanupChanges()
|
||||||
it.second = nullptr;
|
it.second = nullptr;
|
||||||
}
|
}
|
||||||
changes.clear();
|
opt->addPlan(plan, rule, true);
|
||||||
opt->addPlan(newPlan.release(), rule, true);
|
plan->findVarUsage();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
opt->addPlan(plan, rule, false);
|
opt->addPlan(plan, rule, false);
|
||||||
|
|
|
@ -122,23 +122,37 @@ static bool IsEqualKeyElementHash (TRI_hash_index_search_value_t const* left,
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
TRI_doc_mptr_t* HashIndexIterator::next () {
|
TRI_doc_mptr_t* HashIndexIterator::next () {
|
||||||
if (_buffer.empty()) {
|
while (true) {
|
||||||
_index->lookup(_searchValue, _buffer);
|
if (_position >= _keys.size()) {
|
||||||
|
// we're at the end of the lookup values
|
||||||
if (_buffer.empty()) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_posInBuffer < _buffer.size()) {
|
if (_posInBuffer >= _buffer.size()) {
|
||||||
return _buffer[_posInBuffer++];
|
// We have to refill the buffer
|
||||||
}
|
_buffer.clear();
|
||||||
|
|
||||||
return nullptr;
|
_posInBuffer = 0;
|
||||||
|
int res = _index->lookup(_keys[_position++], _buffer);
|
||||||
|
|
||||||
|
if (res != TRI_ERROR_NO_ERROR) {
|
||||||
|
THROW_ARANGO_EXCEPTION(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! _buffer.empty()) {
|
||||||
|
// found something
|
||||||
|
return _buffer.at(_posInBuffer++);
|
||||||
|
}
|
||||||
|
|
||||||
|
// found no result. now go to next lookup value in _keys
|
||||||
|
// ++_position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HashIndexIterator::reset () {
|
void HashIndexIterator::reset () {
|
||||||
_buffer.clear();
|
_buffer.clear();
|
||||||
|
_position = 0;
|
||||||
_posInBuffer = 0;
|
_posInBuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,68 +798,130 @@ IndexIterator* HashIndex::iteratorForCondition (IndexIteratorContext* context,
|
||||||
triagens::aql::AstNode const* node,
|
triagens::aql::AstNode const* node,
|
||||||
triagens::aql::Variable const* reference) const {
|
triagens::aql::Variable const* reference) const {
|
||||||
TRI_ASSERT(node->type == aql::NODE_TYPE_OPERATOR_NARY_AND);
|
TRI_ASSERT(node->type == aql::NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
|
||||||
SimpleAttributeEqualityMatcher matcher(fields());
|
SimpleAttributeEqualityMatcher matcher(fields());
|
||||||
size_t const n = fields().size();
|
size_t const n = fields().size();
|
||||||
triagens::aql::AstNode* allVals = matcher.getAll(ast, this, node, reference);
|
triagens::aql::AstNode* allVals = matcher.getAll(ast, this, node, reference);
|
||||||
TRI_ASSERT(allVals->numMembers() == n);
|
TRI_ASSERT(allVals->numMembers() == n);
|
||||||
|
|
||||||
// setup storage
|
struct PermutationState {
|
||||||
std::unique_ptr<TRI_hash_index_search_value_t> searchValue(new TRI_hash_index_search_value_t);
|
PermutationState (triagens::aql::AstNode const* op, triagens::aql::AstNode const* value, size_t current, size_t n)
|
||||||
searchValue->reserve(n);
|
: op(op),
|
||||||
|
value(value),
|
||||||
if (searchValue->_values == nullptr) {
|
current(current),
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
n(n) {
|
||||||
}
|
|
||||||
auto flds = fields();
|
|
||||||
auto shaper = _collection->getShaper();
|
|
||||||
|
|
||||||
// Convert AstNode -> TRI_hash_index_search_value_t
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
auto comp = allVals->getMember(i);
|
|
||||||
TRI_ASSERT(comp->numMembers() == 2);
|
|
||||||
std::pair<triagens::aql::Variable const*, std::vector<triagens::basics::AttributeName>> paramPair;
|
|
||||||
auto access = comp->getMember(0);
|
|
||||||
auto value = comp->getMember(1);
|
|
||||||
if (! (access->isAttributeAccessForVariable(paramPair) && paramPair.first == reference)) {
|
|
||||||
access = comp->getMember(1);
|
|
||||||
value = comp->getMember(0);
|
|
||||||
if (! (access->isAttributeAccessForVariable(paramPair) && paramPair.first == reference)) {
|
|
||||||
// Both side do not have a correct AttributeAccess, this should not happen and indicates
|
|
||||||
// an error in the optimizer
|
|
||||||
TRI_ASSERT(false);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool filled = false;
|
|
||||||
// value is the value node-side and paramPair.second contains this attributes access.
|
|
||||||
// Now iterator through the paths and fill searchValue
|
|
||||||
for (size_t j = 0; j < n; ++j) {
|
|
||||||
auto f = flds[j];
|
|
||||||
if (f == paramPair.second) {
|
|
||||||
filled = true;
|
|
||||||
auto shaped = TRI_ShapedJsonJson(shaper, value->toJsonValue(TRI_UNKNOWN_MEM_ZONE), false);
|
|
||||||
|
|
||||||
if (shaped == nullptr) {
|
triagens::aql::AstNode const* getValue () const {
|
||||||
TRI_ASSERT(false);
|
if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||||
return nullptr;
|
TRI_ASSERT(current == 0);
|
||||||
}
|
return value;
|
||||||
searchValue->_values[j] = *shaped;
|
|
||||||
TRI_Free(shaper->memoryZone(), shaped);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
else if (op->type == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) {
|
||||||
if (! filled) {
|
TRI_ASSERT(current < n);
|
||||||
// We have an attribute access this index does not cover, should not happen
|
return value->getMember(current);
|
||||||
|
}
|
||||||
|
|
||||||
TRI_ASSERT(false);
|
TRI_ASSERT(false);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
triagens::aql::AstNode const* op;
|
||||||
|
triagens::aql::AstNode const* value;
|
||||||
|
size_t current;
|
||||||
|
size_t const n;
|
||||||
|
};
|
||||||
|
|
||||||
|
// initialize permutations
|
||||||
|
std::vector<PermutationState> permutationStates;
|
||||||
|
permutationStates.reserve(n);
|
||||||
|
size_t maxPermutations = 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
auto comp = allVals->getMemberUnchecked(i);
|
||||||
|
auto attrNode = comp->getMember(0);
|
||||||
|
auto valNode = comp->getMember(1);
|
||||||
|
|
||||||
|
if (attrNode->type != aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
|
// value == a.b -> flip the two sides
|
||||||
|
attrNode = comp->getMember(1);
|
||||||
|
valNode = comp->getMember(0);
|
||||||
|
}
|
||||||
|
TRI_ASSERT(attrNode->type == aql::NODE_TYPE_ATTRIBUTE_ACCESS);
|
||||||
|
|
||||||
|
if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||||
|
permutationStates.emplace_back(PermutationState(comp, valNode, 0, 1));
|
||||||
|
}
|
||||||
|
else if (comp->type == aql::NODE_TYPE_OPERATOR_BINARY_IN) {
|
||||||
|
permutationStates.emplace_back(PermutationState(comp, valNode, 0, valNode->numMembers()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxPermutations *= permutationStates.back().n;
|
||||||
}
|
}
|
||||||
// We have successfully build a searchValue by now.
|
|
||||||
|
std::vector<TRI_hash_index_search_value_t*> searchValues;
|
||||||
|
searchValues.reserve(maxPermutations);
|
||||||
|
|
||||||
|
// create all permutations
|
||||||
|
auto shaper = _collection->getShaper();
|
||||||
|
size_t current = 0;
|
||||||
|
bool done = false;
|
||||||
|
while (! done) {
|
||||||
|
std::unique_ptr<TRI_hash_index_search_value_t> searchValue(new TRI_hash_index_search_value_t);
|
||||||
|
searchValue->reserve(n);
|
||||||
|
|
||||||
|
bool valid = true;
|
||||||
|
for (size_t i = 0; i < n; ++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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shaped = TRI_ShapedJsonJson(shaper, json.get(), false);
|
||||||
|
|
||||||
|
if (shaped == nullptr) {
|
||||||
|
// no such shape exists. this means we won't find this value and can go on with the next permutation
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchValue->_values[i] = *shaped;
|
||||||
|
TRI_Free(shaper->memoryZone(), shaped);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
searchValues.push_back(searchValue.get());
|
||||||
|
searchValue.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(searchValues.size() <= maxPermutations);
|
||||||
|
|
||||||
// Create the iterator
|
// Create the iterator
|
||||||
auto result = new HashIndexIterator(this, searchValue.get());
|
return new HashIndexIterator(this, searchValues);
|
||||||
searchValue.release();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -74,14 +74,18 @@ namespace triagens {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HashIndexIterator (HashIndex const* index,
|
HashIndexIterator (HashIndex const* index,
|
||||||
TRI_hash_index_search_value_t* searchValue)
|
std::vector<TRI_hash_index_search_value_t*>& keys)
|
||||||
: _index(index),
|
: _index(index),
|
||||||
_searchValue(searchValue),
|
_keys(keys),
|
||||||
|
_position(0),
|
||||||
|
_buffer(),
|
||||||
_posInBuffer(0) {
|
_posInBuffer(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~HashIndexIterator() {
|
~HashIndexIterator() {
|
||||||
delete _searchValue;
|
for (auto& it : _keys) {
|
||||||
|
delete it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_doc_mptr_t* next () override;
|
TRI_doc_mptr_t* next () override;
|
||||||
|
@ -90,10 +94,11 @@ namespace triagens {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
HashIndex const* _index;
|
HashIndex const* _index;
|
||||||
TRI_hash_index_search_value_t* _searchValue;
|
std::vector<TRI_hash_index_search_value_t*> _keys;
|
||||||
std::vector<TRI_doc_mptr_t*> _buffer;
|
size_t _position;
|
||||||
size_t _posInBuffer;
|
std::vector<TRI_doc_mptr_t*> _buffer;
|
||||||
|
size_t _posInBuffer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue