1
0
Fork 0

Merge branch 'aql2' of https://github.com/triAGENS/ArangoDB into aql2

This commit is contained in:
Jan Steemann 2014-09-11 17:02:03 +02:00
commit c3b90a1037
4 changed files with 125 additions and 47 deletions

View File

@ -846,23 +846,73 @@ IndexRangeBlock::~IndexRangeBlock () {
bool IndexRangeBlock::readIndex () { bool IndexRangeBlock::readIndex () {
// TODO: adjust to make callable multiple times with proper cleanup // This is either called from initialize if all bounds are constant,
// TODO: in variable case, evaluate all expressions, work actual values // in this case it is never called again. If there is at least one
// into constant bound and finally use these // variable bound, then readIndex is called once for every item coming
// in from our dependency. In that case, it is guaranteed that
// _buffer is not empty, in particular _buffer.front() is defined
// _pos points to a position in _buffer.front()
// Therefore, we can use the register values in _buffer.front() in row
// _pos to evaluate the variable bounds.
if (_documents.empty()) { if (_documents.empty()) {
_documents.reserve(DefaultBatchSize); _documents.reserve(DefaultBatchSize);
} }
else {
_documents.clear(); _documents.clear();
}
auto en = static_cast<IndexRangeNode const*>(getPlanNode()); auto en = static_cast<IndexRangeNode const*>(getPlanNode());
IndexOrCondition const* condition = &en->_ranges;
// Find out about the actual values for the bounds in the variable bound case:
if (! _allBoundsConstant) {
#if 0
auto newCondition = new IndexOrCondition();
try {
newCondition->push_back(std::vector<RangeInfo>());
size_t posInExpressions = 0;
for (auto r : en->_ranges.at(0)) {
// First create a new RangeInfo containing only the constant
// low and high bound of r:
RangeInfo actualRange(r._var, r._attr, r._lowConst, r._highConst,
r.equality);
// Now work the actual values of the variable lows and highs into
// this constant range:
Expression* e;
for (auto l : r._lows) {
e = &(_allVariableBoundExpressions[posInExpressions++]);
//AqlValue a = e.execute(...);
if (a._type == AqlValue::JSON) {
//RangeInfoBound b(
//actualRange.andCombineLowerBounds(
}
else {
}
}
for (auto h : r._highs) {
e = &(_allVariableBoundExpressions[posInExpressions++]);
//...
}
newCondition->at(0).push_back(actualRange);
}
}
catch (...) {
delete newCondition;
throw;
}
condition = newCondition;
#endif
}
if (en->_index->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) { if (en->_index->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) {
readSkiplistIndex(); readSkiplistIndex(*condition);
} }
else if (en->_index->_type == TRI_IDX_TYPE_HASH_INDEX) { else if (en->_index->_type == TRI_IDX_TYPE_HASH_INDEX) {
readHashIndex(); readHashIndex(*condition);
} }
else { else {
TRI_ASSERT(false); TRI_ASSERT(false);
@ -879,8 +929,9 @@ int IndexRangeBlock::initialize () {
} }
} }
// TODO: if all constant, then do it here, otherwise not if (_allBoundsConstant) {
readIndex(); readIndex();
}
return res; return res;
} }
@ -915,10 +966,16 @@ AqlItemBlock* IndexRangeBlock::getSome (size_t atLeast,
return nullptr; return nullptr;
} }
_pos = 0; // this is in the first block _pos = 0; // this is in the first block
// This is a new item, so let's read the index if bounds are variable:
if (! _allBoundsConstant) {
readIndex();
}
_posInDocs = 0; // position in _documents . . . _posInDocs = 0; // position in _documents . . .
} }
// If we get here, we do have _buffer.front() // If we get here, we do have _buffer.front() and _pos points into it
AqlItemBlock* cur = _buffer.front(); AqlItemBlock* cur = _buffer.front();
size_t const curRegs = cur->getNrRegs(); size_t const curRegs = cur->getNrRegs();
@ -956,8 +1013,7 @@ AqlItemBlock* IndexRangeBlock::getSome (size_t atLeast,
// Advance read position: // Advance read position:
if (_posInDocs >= _documents.size()) { if (_posInDocs >= _documents.size()) {
// we have exhausted our local documents buffer // we have exhausted our local documents buffer,
_posInDocs = 0;
if (++_pos >= cur->size()) { if (++_pos >= cur->size()) {
_buffer.pop_front(); // does not throw _buffer.pop_front(); // does not throw
@ -965,8 +1021,14 @@ AqlItemBlock* IndexRangeBlock::getSome (size_t atLeast,
_pos = 0; _pos = 0;
} }
// TODO: if bounds are variable, then repeat readIndex here // let's read the index if bounds are variable:
if (! _buffer.empty() && ! _allBoundsConstant) {
readIndex();
}
_posInDocs = 0;
// If _buffer is empty, then we will fetch a new block in the next call
// and then read the index.
} }
// Clear out registers no longer needed later: // Clear out registers no longer needed later:
@ -991,31 +1053,47 @@ size_t IndexRangeBlock::skipSome (size_t atLeast,
if (_buffer.empty()) { if (_buffer.empty()) {
if (! ExecutionBlock::getBlock(DefaultBatchSize, DefaultBatchSize)) { if (! ExecutionBlock::getBlock(DefaultBatchSize, DefaultBatchSize)) {
_done = true; _done = true;
return 0; return skipped;
} }
_pos = 0; // this is in the first block _pos = 0; // this is in the first block
// This is a new item, so let's read the index if bounds are variable:
if (! _allBoundsConstant) {
readIndex();
} }
// If we get here, we do have _buffer.front() _posInDocs = 0; // position in _documents . . .
}
// If we get here, we do have _buffer.front() and _pos points into it
AqlItemBlock* cur = _buffer.front(); AqlItemBlock* cur = _buffer.front();
_posInDocs += std::min(atMost, _documents.size() - _posInDocs); size_t available = _documents.size() - _posInDocs;
size_t toSkip = std::min(atMost - skipped, available);
_posInDocs += toSkip;
skipped += toSkip;
if (atMost < _documents.size() - _posInDocs){ // Advance read position:
// eat just enough of _documents . . . if (_posInDocs >= _documents.size()) {
_posInDocs += atMost; // we have exhausted our local documents buffer,
skipped = atMost;
} if (++_pos >= cur->size()) {
else { _buffer.pop_front(); // does not throw
// eat the whole of the current inVariable and proceed . . .
skipped += (_documents.size() - _posInDocs);
_posInDocs = 0;
delete cur; delete cur;
_buffer.pop_front();
_pos = 0; _pos = 0;
} }
// let's read the index if bounds are variable:
if (! _buffer.empty() && ! _allBoundsConstant) {
readIndex();
}
_posInDocs = 0;
// If _buffer is empty, then we will fetch a new block in the next round
// and then read the index.
}
} }
return skipped; return skipped;
@ -1053,13 +1131,11 @@ size_t IndexRangeBlock::skipSome (size_t atLeast,
// (i.e. the 1 in x.c >= 1) cannot be lists or arrays. // (i.e. the 1 in x.c >= 1) cannot be lists or arrays.
// //
void IndexRangeBlock::readSkiplistIndex () { void IndexRangeBlock::readSkiplistIndex (IndexOrCondition const& ranges) {
auto en = static_cast<IndexRangeNode const*>(getPlanNode()); auto en = static_cast<IndexRangeNode const*>(getPlanNode());
TRI_index_t* idx = en->_index; TRI_index_t* idx = en->_index;
TRI_ASSERT(idx != nullptr); TRI_ASSERT(idx != nullptr);
std::vector<std::vector<RangeInfo>> const& ranges = en->_ranges;
TRI_shaper_t* shaper = _collection->documentCollection()->getShaper(); TRI_shaper_t* shaper = _collection->documentCollection()->getShaper();
TRI_ASSERT(shaper != nullptr); TRI_ASSERT(shaper != nullptr);
@ -1069,8 +1145,10 @@ void IndexRangeBlock::readSkiplistIndex () {
size_t i = 0; size_t i = 0;
for (;i < ranges.at(0).size(); i++) { for (;i < ranges.at(0).size(); i++) {
// ranges.at(0) corresponds to a prefix of idx->_fields . . . // ranges.at(0) corresponds to a prefix of idx->_fields . . .
// TODO only doing 1 dim case at the moment . . . // TODO only doing case with a single OR (i.e. ranges.size()==1 at the
// moment ...
auto range = ranges.at(0).at(i); auto range = ranges.at(0).at(i);
TRI_ASSERT(range.isConstant());
if (range.is1ValueRangeInfo()) { // it's an equality . . . if (range.is1ValueRangeInfo()) { // it's an equality . . .
parameters(range._lowConst.bound().copy()); parameters(range._lowConst.bound().copy());
} }
@ -1140,7 +1218,7 @@ void IndexRangeBlock::readSkiplistIndex () {
TRI_FreeSkiplistIterator(skiplistIterator); TRI_FreeSkiplistIterator(skiplistIterator);
} }
void IndexRangeBlock::readHashIndex () { void IndexRangeBlock::readHashIndex (IndexOrCondition const& ranges) {
auto en = static_cast<IndexRangeNode const*>(getPlanNode()); auto en = static_cast<IndexRangeNode const*>(getPlanNode());
TRI_index_t* idx = en->_index; TRI_index_t* idx = en->_index;
TRI_ASSERT(idx != nullptr); TRI_ASSERT(idx != nullptr);
@ -1179,7 +1257,7 @@ void IndexRangeBlock::readHashIndex () {
char const* name = TRI_AttributeNameShapePid(shaper, pid); char const* name = TRI_AttributeNameShapePid(shaper, pid);
for (auto x: en->_ranges.at(0)) { for (auto x: ranges.at(0)) {
if (x._attr == std::string(name)){ //found attribute if (x._attr == std::string(name)){ //found attribute
auto shaped = TRI_ShapedJsonJson(shaper, x._lowConst.bound().json(), false); auto shaped = TRI_ShapedJsonJson(shaper, x._lowConst.bound().json(), false);
// here x->_low->_bound = x->_high->_bound // here x->_low->_bound = x->_high->_bound

View File

@ -652,13 +652,13 @@ public:
/// @brief read using a skiplist index /// @brief read using a skiplist index
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void readSkiplistIndex (); void readSkiplistIndex (IndexOrCondition const&);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief read using a hash index /// @brief read using a hash index
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void readHashIndex (); void readHashIndex (IndexOrCondition const&);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private variables // --SECTION-- private variables

View File

@ -806,7 +806,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
class SortAnalysis { class SortAnalysis {
using ECN = triagens::aql::EnumerateCollectionNode; using ECN = triagens::aql::EnumerateCollectionNode;
typedef std::pair<ECN::IndexMatchVec, RangeInfoVec> Range_IndexPair; typedef std::pair<ECN::IndexMatchVec, IndexOrCondition> Range_IndexPair;
struct sortNodeData { struct sortNodeData {
bool ASC; bool ASC;
@ -902,7 +902,7 @@ public:
Range_IndexPair getAttrsForVariableName (std::string &variableName) { Range_IndexPair getAttrsForVariableName (std::string &variableName) {
ECN::IndexMatchVec v; ECN::IndexMatchVec v;
RangeInfoVec rangeInfo; IndexOrCondition rangeInfo;
for (size_t j = 0; j < _sortNodeData.size(); j ++) { for (size_t j = 0; j < _sortNodeData.size(); j ++) {
if (_sortNodeData[j]->variableName != variableName) { if (_sortNodeData[j]->variableName != variableName) {

View File

@ -590,15 +590,15 @@ namespace triagens {
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief RangeInfoVec, type for vector of vector of RangeInfo. The meaning /// @brief IndexOrCondition, type for vector of vector of RangeInfo. The meaning
/// is: the outer vector means an implicit "OR" between the entries. Each /// is: the outer vector means an implicit "OR" between the entries. Each
/// entry is a vector which means an implicit "AND" between the individual /// entry is a vector whose entries correspond to the attributes of the
/// RangeInfo objects. This is actually the disjunctive normal form of /// index. They are a RangeInfo specifying the condition for that attribute.
/// all conditions, therefore, every boolean expression of ANDs and ORs /// Note that in the variable range bound case one RangeInfo can contain
/// can be expressed in this form. /// multiple conditions which are implicitly "AND"ed.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typedef std::vector<std::vector<RangeInfo>> RangeInfoVec; typedef std::vector<std::vector<RangeInfo>> IndexOrCondition;
} }
} }