mirror of https://gitee.com/bigwinds/arangodb
325 lines
12 KiB
C++
325 lines
12 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief skiplist index helper
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
|
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Dr. Oreste Costa-Panaia
|
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
|
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "skiplist-helper.h"
|
|
#include "Basics/Utf8Helper.h"
|
|
#include "VocBase/document-collection.h"
|
|
#include "VocBase/shaped-json.h"
|
|
#include "VocBase/VocShaper.h"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private types
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- skiplistIndex common public methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Methods Skiplist Indices
|
|
//------------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Locates one or more ranges within the skiplist and returns iterator
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// .............................................................................
|
|
// Tests whether the LeftEndPoint is < than RightEndPoint (-1)
|
|
// Tests whether the LeftEndPoint is == to RightEndPoint (0) [empty]
|
|
// Tests whether the LeftEndPoint is > than RightEndPoint (1) [undefined]
|
|
// .............................................................................
|
|
|
|
static bool skiplistIndex_findHelperIntervalValid (triagens::arango::SkiplistIndex2* skiplistIndex,
|
|
TRI_skiplist_iterator_interval_t const* interval) {
|
|
triagens::basics::SkipListNode* lNode = interval->_leftEndPoint;
|
|
|
|
if (lNode == nullptr) {
|
|
return false;
|
|
}
|
|
// Note that the right end point can be nullptr to indicate the end of
|
|
// the index.
|
|
|
|
triagens::basics::SkipListNode* rNode = interval->_rightEndPoint;
|
|
|
|
if (lNode == rNode) {
|
|
return false;
|
|
}
|
|
|
|
if (lNode->nextNode() == rNode) {
|
|
// Interval empty, nothing to do with it.
|
|
return false;
|
|
}
|
|
|
|
if (nullptr != rNode && rNode->nextNode() == lNode) {
|
|
// Interval empty, nothing to do with it.
|
|
return false;
|
|
}
|
|
|
|
if (skiplistIndex->skiplist->getNrUsed() == 0) {
|
|
return false;
|
|
}
|
|
|
|
if ( lNode == skiplistIndex->skiplist->startNode() ||
|
|
nullptr == rNode ) {
|
|
// The index is not empty, the nodes are not neighbours, one of them
|
|
// is at the boundary, so the interval is valid and not empty.
|
|
return true;
|
|
}
|
|
|
|
int compareResult = CmpElmElm( skiplistIndex,
|
|
lNode->document(),
|
|
rNode->document(),
|
|
triagens::basics::SKIPLIST_CMP_TOTORDER);
|
|
return (compareResult == -1);
|
|
// Since we know that the nodes are not neighbours, we can guarantee
|
|
// at least one document in the interval.
|
|
}
|
|
|
|
static bool skiplistIndex_findHelperIntervalIntersectionValid (
|
|
SkiplistIndex* skiplistIndex,
|
|
TRI_skiplist_iterator_interval_t* lInterval,
|
|
TRI_skiplist_iterator_interval_t* rInterval,
|
|
TRI_skiplist_iterator_interval_t* interval) {
|
|
|
|
triagens::basics::SkipListNode* lNode = lInterval->_leftEndPoint;
|
|
triagens::basics::SkipListNode* rNode = rInterval->_leftEndPoint;
|
|
|
|
if (nullptr == lNode || nullptr == rNode) {
|
|
// At least one left boundary is the end, intersection is empty.
|
|
return false;
|
|
}
|
|
|
|
int compareResult;
|
|
// Now find the larger of the two start nodes:
|
|
if (lNode == skiplistIndex->skiplist->startNode()) {
|
|
// We take rNode, even if it is the start node as well.
|
|
compareResult = -1;
|
|
}
|
|
else if (rNode == skiplistIndex->skiplist->startNode()) {
|
|
// We take lNode
|
|
compareResult = 1;
|
|
}
|
|
else {
|
|
compareResult = CmpElmElm(skiplistIndex, lNode->document(),
|
|
rNode->document(),
|
|
triagens::basics::SKIPLIST_CMP_TOTORDER);
|
|
}
|
|
|
|
if (compareResult < 1) {
|
|
interval->_leftEndPoint = rNode;
|
|
}
|
|
else {
|
|
interval->_leftEndPoint = lNode;
|
|
}
|
|
|
|
lNode = lInterval->_rightEndPoint;
|
|
rNode = rInterval->_rightEndPoint;
|
|
|
|
// Now find the smaller of the two end nodes:
|
|
if (nullptr == lNode) {
|
|
// We take rNode, even is this also the end node.
|
|
compareResult = 1;
|
|
}
|
|
else if (nullptr == rNode) {
|
|
// We take lNode.
|
|
compareResult = -1;
|
|
}
|
|
else {
|
|
compareResult = CmpElmElm(skiplistIndex, lNode->document(),
|
|
rNode->document(),
|
|
triagens::basics::SKIPLIST_CMP_TOTORDER);
|
|
}
|
|
|
|
if (compareResult < 1) {
|
|
interval->_rightEndPoint = lNode;
|
|
}
|
|
else {
|
|
interval->_rightEndPoint = rNode;
|
|
}
|
|
|
|
return skiplistIndex_findHelperIntervalValid(skiplistIndex, interval);
|
|
}
|
|
|
|
static void SkiplistIndex_findHelper (triagens::arango::SkiplistIndex2* skiplistIndex,
|
|
TRI_index_operator_t const* indexOperator,
|
|
TRI_vector_t* resultIntervalList) {
|
|
TRI_skiplist_index_key_t values;
|
|
TRI_vector_t leftResult;
|
|
TRI_vector_t rightResult;
|
|
TRI_skiplist_iterator_interval_t interval;
|
|
triagens::basics::SkipListNode* temp;
|
|
|
|
TRI_InitVector(&(leftResult), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_interval_t));
|
|
TRI_InitVector(&(rightResult), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_interval_t));
|
|
|
|
TRI_relation_index_operator_t* relationOperator = (TRI_relation_index_operator_t*) indexOperator;
|
|
TRI_logical_index_operator_t* logicalOperator = (TRI_logical_index_operator_t*) indexOperator;
|
|
|
|
switch (indexOperator->_type) {
|
|
case TRI_EQ_INDEX_OPERATOR:
|
|
case TRI_LE_INDEX_OPERATOR:
|
|
case TRI_LT_INDEX_OPERATOR:
|
|
case TRI_GE_INDEX_OPERATOR:
|
|
case TRI_GT_INDEX_OPERATOR:
|
|
|
|
values._fields = relationOperator->_fields;
|
|
values._numFields = relationOperator->_numFields;
|
|
break; // this is to silence a compiler warning
|
|
|
|
default: {
|
|
// must not access relationOperator->xxx if the operator is not a
|
|
// relational one otherwise we'll get invalid reads and the prog
|
|
// might crash
|
|
}
|
|
}
|
|
|
|
switch (indexOperator->_type) {
|
|
case TRI_AND_INDEX_OPERATOR: {
|
|
SkiplistIndex_findHelper(skiplistIndex, logicalOperator->_left, &leftResult);
|
|
SkiplistIndex_findHelper(skiplistIndex, logicalOperator->_right, &rightResult);
|
|
|
|
size_t nl = TRI_LengthVector(&leftResult);
|
|
size_t nr = TRI_LengthVector(&rightResult);
|
|
for (size_t i = 0; i < nl; ++i) {
|
|
for (size_t j = 0; j < nr; ++j) {
|
|
auto tempLeftInterval = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AddressVector(&leftResult, i));
|
|
auto tempRightInterval = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AddressVector(&rightResult, j));
|
|
|
|
if (skiplistIndex_findHelperIntervalIntersectionValid(
|
|
skiplistIndex,
|
|
tempLeftInterval,
|
|
tempRightInterval,
|
|
&interval)) {
|
|
TRI_PushBackVector(resultIntervalList, &interval);
|
|
}
|
|
}
|
|
}
|
|
TRI_DestroyVector(&leftResult);
|
|
TRI_DestroyVector(&rightResult);
|
|
return;
|
|
}
|
|
|
|
|
|
case TRI_EQ_INDEX_OPERATOR: {
|
|
temp = skiplistIndex->skiplist->leftKeyLookup(&values);
|
|
TRI_ASSERT(nullptr != temp);
|
|
interval._leftEndPoint = temp;
|
|
|
|
bool const allAttributesCoveredByCondition = (values._numFields == skiplistIndex->_numFields);
|
|
|
|
if (skiplistIndex->unique && allAttributesCoveredByCondition) {
|
|
// At most one hit:
|
|
temp = temp->nextNode();
|
|
if (nullptr != temp) {
|
|
if (0 == CmpKeyElm(skiplistIndex, &values, temp->document())) {
|
|
interval._rightEndPoint = temp->nextNode();
|
|
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,
|
|
&interval)) {
|
|
TRI_PushBackVector(resultIntervalList, &interval);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
temp = skiplistIndex->skiplist->rightKeyLookup(&values);
|
|
interval._rightEndPoint = temp->nextNode();
|
|
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,
|
|
&interval)) {
|
|
TRI_PushBackVector(resultIntervalList, &interval);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
case TRI_LE_INDEX_OPERATOR: {
|
|
interval._leftEndPoint = skiplistIndex->skiplist->startNode();
|
|
temp = skiplistIndex->skiplist->rightKeyLookup(&values);
|
|
interval._rightEndPoint = temp->nextNode();
|
|
|
|
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
|
|
TRI_PushBackVector(resultIntervalList, &interval);
|
|
}
|
|
return;
|
|
}
|
|
|
|
case TRI_LT_INDEX_OPERATOR: {
|
|
interval._leftEndPoint = skiplistIndex->skiplist->startNode();
|
|
temp = skiplistIndex->skiplist->leftKeyLookup(&values);
|
|
interval._rightEndPoint = temp->nextNode();
|
|
|
|
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
|
|
TRI_PushBackVector(resultIntervalList, &interval);
|
|
}
|
|
return;
|
|
}
|
|
|
|
case TRI_GE_INDEX_OPERATOR: {
|
|
temp = skiplistIndex->skiplist->leftKeyLookup(&values);
|
|
interval._leftEndPoint = temp;
|
|
interval._rightEndPoint = skiplistIndex->skiplist->endNode();
|
|
|
|
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
|
|
TRI_PushBackVector(resultIntervalList, &interval);
|
|
}
|
|
return;
|
|
}
|
|
|
|
case TRI_GT_INDEX_OPERATOR: {
|
|
temp = skiplistIndex->skiplist->rightKeyLookup(&values);
|
|
interval._leftEndPoint = temp;
|
|
interval._rightEndPoint = skiplistIndex->skiplist->endNode();
|
|
|
|
if (skiplistIndex_findHelperIntervalValid(skiplistIndex, &interval)) {
|
|
TRI_PushBackVector(resultIntervalList, &interval);
|
|
}
|
|
return;
|
|
}
|
|
|
|
default: {
|
|
TRI_ASSERT(false);
|
|
}
|
|
|
|
} // end of switch statement
|
|
}
|
|
|
|
TRI_skiplist_iterator_t* SkiplistIndex_find (triagens::arango::SkiplistIndex2* skiplistIndex,
|
|
TRI_index_operator_t const* indexOperator,
|
|
bool reverse) {
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- END-OF-FILE
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
|
// End:
|