mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of https://github.com/triAGENS/ArangoDB into aql2
This commit is contained in:
commit
c3b90a1037
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue