1
0
Fork 0
arangodb/arangod/SkipLists/skiplistIndex.cpp

971 lines
34 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// @brief skiplist index
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 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 triAGENS GmbH, Cologne, Germany
///
/// @author Dr. O
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "skiplistIndex.h"
#include "BasicsC/utf8-helper.h"
#include "ShapedJson/json-shaper.h"
#include "ShapedJson/shaped-json.h"
#include "VocBase/document-collection.h"
#include "VocBase/primary-collection.h"
#include "VocBase/voc-shaper.h"
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Common private methods
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// .............................................................................
// recall for all of the following comparison functions:
//
// left < right return -1
// left > right return 1
// left == right return 0
//
// furthermore:
//
// the following order is currently defined for placing an order on documents
// undef < null < boolean < number < strings < lists < hash arrays
// note: undefined will be treated as NULL pointer not NULL JSON OBJECT
// within each type class we have the following order
// boolean: false < true
// number: natural order
// strings: lexicographical
// lists: lexicographically and within each slot according to these rules.
// ...........................................................................
////////////////////////////////////////////////////////////////////////////////
/// @brief compares a key with an element, version with proper types
////////////////////////////////////////////////////////////////////////////////
static int CompareKeyElement (TRI_shaped_json_t const* left,
TRI_skiplist_index_element_t* right,
size_t rightPosition,
TRI_shaper_t* shaper) {
int result;
assert(NULL != left);
assert(NULL != right);
result = TRI_CompareShapeTypes(NULL,
NULL,
left,
right->_document,
&right->_subObjects[rightPosition],
NULL,
shaper,
shaper);
// ...........................................................................
// In the above function CompareShapeTypes we use strcmp which may
// return an integer greater than 1 or less than -1. From this
// function we only need to know whether we have equality (0), less
// than (-1) or greater than (1)
// ...........................................................................
if (result < 0) {
result = -1;
}
else if (result > 0) {
result = 1;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compares elements, version with proper types
////////////////////////////////////////////////////////////////////////////////
static int CompareElementElement (TRI_skiplist_index_element_t* left,
size_t leftPosition,
TRI_skiplist_index_element_t* right,
size_t rightPosition,
TRI_shaper_t* shaper) {
int result;
assert(NULL != left);
assert(NULL != right);
result = TRI_CompareShapeTypes(left->_document,
&left->_subObjects[leftPosition],
NULL,
right->_document,
&right->_subObjects[rightPosition],
NULL,
shaper,
shaper);
// ...........................................................................
// In the above function CompareShapeTypes we use strcmp which may
// return an integer greater than 1 or less than -1. From this
// function we only need to know whether we have equality (0), less
// than (-1) or greater than (1)
// ...........................................................................
if (result < 0) {
result = -1;
}
else if (result > 0) {
result = 1;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compares two elements in a skip list, this is the generic callback
////////////////////////////////////////////////////////////////////////////////
static int CmpElmElm (void* sli,
void* left,
void* right,
TRI_cmp_type_e cmptype) {
TRI_skiplist_index_element_t* leftElement = static_cast<TRI_skiplist_index_element_t*>(left);
TRI_skiplist_index_element_t* rightElement = static_cast<TRI_skiplist_index_element_t*>(right);
int compareResult;
TRI_shaper_t* shaper;
size_t j;
assert(NULL != left);
assert(NULL != right);
if (leftElement == rightElement) {
return 0;
}
// ..........................................................................
// The document could be the same -- so no further comparison is required.
// ..........................................................................
if (leftElement->_document == rightElement->_document) {
return 0;
}
SkiplistIndex* skiplistindex = static_cast<SkiplistIndex*>(sli);
shaper = skiplistindex->_collection->_shaper;
for (j = 0; j < skiplistindex->_numFields; j++) {
compareResult = CompareElementElement(leftElement,
j,
rightElement,
j,
shaper);
if (compareResult != 0) {
return compareResult;
}
}
// ...........................................................................
// This is where the difference between the preorder and the proper total
// order comes into play. Here if the 'keys' are the same,
// but the doc ptr is different (which it is since we are here), then
// we return 0 if we use the preorder and look at the _key attribute
// otherwise.
// ...........................................................................
if (TRI_CMP_PREORDER == cmptype) {
return 0;
}
// We break this tie in the key comparison by looking at the key:
compareResult = strcmp(leftElement->_document->_key,
rightElement->_document->_key);
if (compareResult < 0) {
return -1;
}
else if (compareResult > 0) {
return 1;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compares a key with an element in a skip list, generic callback
////////////////////////////////////////////////////////////////////////////////
static int CmpKeyElm (void* sli,
void* left,
void* right) {
TRI_skiplist_index_key_t* leftKey = static_cast<TRI_skiplist_index_key_t*>(left);
TRI_skiplist_index_element_t* rightElement = static_cast<TRI_skiplist_index_element_t*>(right);
int compareResult;
TRI_shaper_t* shaper;
size_t j;
assert(NULL != left);
assert(NULL != right);
SkiplistIndex* skiplistindex = static_cast<SkiplistIndex*>(sli);
shaper = skiplistindex->_collection->_shaper;
// Note that the key might contain fewer fields than there are indexed
// attributes, therefore we only run the following loop to
// leftKey->_numFields.
for (j = 0; j < leftKey->_numFields; j++) {
compareResult = CompareKeyElement(&leftKey->_fields[j], rightElement,
j, shaper);
if (compareResult != 0) {
return compareResult;
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief frees an element in the skiplist
////////////////////////////////////////////////////////////////////////////////
static void FreeElm (void* e)
{
TRI_skiplist_index_element_t* element = static_cast<TRI_skiplist_index_element_t*>(e);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, element->_subObjects);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, element);
}
static int CopyElement (SkiplistIndex* skiplistindex,
TRI_skiplist_index_element_t* leftElement,
TRI_skiplist_index_element_t* rightElement) {
assert(NULL != leftElement && NULL != rightElement);
leftElement->_document = rightElement->_document;
leftElement->_subObjects = static_cast<TRI_shaped_sub_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shaped_sub_t) * skiplistindex->_numFields, false));
if (leftElement->_subObjects == NULL) {
return TRI_ERROR_OUT_OF_MEMORY;
}
memcpy(leftElement->_subObjects, rightElement->_subObjects,
sizeof(TRI_shaped_sub_t) * skiplistindex->_numFields);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
// Some static helper functions:
// These are assigned to some callback hooks but do not seem to be used,
// which is good because otherwise the assert(false) statements would
// bite!
////////////////////////////////////////////////////////////////////////////////
static int SkiplistIndex_queryMethodCall (void* theIndex,
TRI_index_operator_t* indexOperator,
TRI_index_challenge_t* challenge,
void* data) {
SkiplistIndex* slIndex = (SkiplistIndex*)(theIndex);
if (slIndex == NULL || indexOperator == NULL) {
return TRI_ERROR_INTERNAL;
}
assert(false);
return TRI_ERROR_NO_ERROR;
}
static TRI_index_iterator_t* SkiplistIndex_resultMethodCall (
void* theIndex,
TRI_index_operator_t* indexOperator,
void* data,
bool (*filter) (TRI_index_iterator_t*)) {
SkiplistIndex* slIndex = (SkiplistIndex*)(theIndex);
if (slIndex == NULL || indexOperator == NULL) {
return NULL;
}
assert(false);
return NULL;
}
static int SkiplistIndex_freeMethodCall (void* theIndex,
void* data) {
SkiplistIndex* slIndex = (SkiplistIndex*)(theIndex);
if (slIndex == NULL) {
return TRI_ERROR_INTERNAL;
}
assert(false);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Attempts to determine if there is a next document within an
/// interval - without advancing the iterator.
////////////////////////////////////////////////////////////////////////////////
static bool SkiplistHasNextIterationCallback(TRI_skiplist_iterator_t* iterator) {
TRI_skiplist_iterator_interval_t* interval;
void* leftNode;
// ...........................................................................
// Some simple checks.
// ...........................................................................
assert(NULL != iterator);
if (NULL == iterator->_cursor) {
return false;
}
// ...........................................................................
// if we have more intervals than the one we are currently working
// on then of course we have a next doc
// ...........................................................................
if (iterator->_intervals._length - 1 > iterator->_currentInterval) {
return true;
}
// ...........................................................................
// Obtain the current interval -- in case we ever use more than one interval
// ...........................................................................
interval = (TRI_skiplist_iterator_interval_t*)
( TRI_AtVector(&(iterator->_intervals), iterator->_currentInterval) );
// ...........................................................................
// Obtain the left end point we are currently at
// ...........................................................................
leftNode = TRI_SkipListNextNode(iterator->_cursor);
// Note that leftNode can be NULL here!
// ...........................................................................
// If the left == right end point AND there are no more intervals then we have
// no next.
// ...........................................................................
if (leftNode == interval->_rightEndPoint) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Jumps forwards by jumpSize and returns the document
////////////////////////////////////////////////////////////////////////////////
static TRI_skiplist_index_element_t* SkiplistIteration(
TRI_skiplist_iterator_t* iterator,
int64_t jumpSize) {
TRI_skiplist_iterator_interval_t* interval;
int64_t j;
// ...........................................................................
// Some simple checks.
// ...........................................................................
assert(NULL != iterator);
if (NULL == iterator->_cursor) {
// In this case the iterator is exhausted or does not even have intervals.
return NULL;
}
assert(jumpSize > 0);
// ...........................................................................
// Obtain the current interval we are at.
// ...........................................................................
interval = (TRI_skiplist_iterator_interval_t*)
( TRI_AtVector(&(iterator->_intervals), iterator->_currentInterval) );
// ...........................................................................
// use the current cursor and move jumpSize forward.
// ...........................................................................
for (j = 0; j < jumpSize; ++j) {
while (true) { // will be left by break
iterator->_cursor = TRI_SkipListNextNode(iterator->_cursor);
if (iterator->_cursor != interval->_rightEndPoint) {
// Note that _cursor can be NULL here!
break; // we found a next one
}
if (iterator->_currentInterval == (iterator->_intervals._length - 1)) {
iterator->_cursor = NULL; // exhausted
return NULL;
}
++iterator->_currentInterval;
interval = (TRI_skiplist_iterator_interval_t*)
( TRI_AtVector(&(iterator->_intervals), iterator->_currentInterval) );
iterator->_cursor = interval->_leftEndPoint;
}
}
return (TRI_skiplist_index_element_t*) (iterator->_cursor->doc);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief default callback for jumping forward by 1
////////////////////////////////////////////////////////////////////////////////
static TRI_skiplist_index_element_t* SkiplistNextIterationCallback(
TRI_skiplist_iterator_t* iterator) {
return SkiplistIteration(iterator,1);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief default callback for jumping forward by jumpSize docs
////////////////////////////////////////////////////////////////////////////////
static TRI_skiplist_index_element_t* SkiplistNextsIterationCallback(
TRI_skiplist_iterator_t* iterator,
int64_t jumpSize) {
return SkiplistIteration(iterator,jumpSize);
}
// -----------------------------------------------------------------------------
// --SECTION-- skiplistIndex common public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup skiplistIndex
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief Assigns a static function call to a function pointer used by
/// the Query Engine, seems not to be used at this stage...
////////////////////////////////////////////////////////////////////////////////
int SkiplistIndex_assignMethod(void* methodHandle,
TRI_index_method_assignment_type_e methodType) {
switch (methodType) {
case TRI_INDEX_METHOD_ASSIGNMENT_FREE : {
TRI_index_query_free_method_call_t* call =
(TRI_index_query_free_method_call_t*)(methodHandle);
*call = SkiplistIndex_freeMethodCall;
break;
}
case TRI_INDEX_METHOD_ASSIGNMENT_QUERY : {
TRI_index_query_method_call_t* call =
(TRI_index_query_method_call_t*)(methodHandle);
*call = SkiplistIndex_queryMethodCall;
break;
}
case TRI_INDEX_METHOD_ASSIGNMENT_RESULT : {
TRI_index_query_result_method_call_t* call =
(TRI_index_query_result_method_call_t*)(methodHandle);
*call = SkiplistIndex_resultMethodCall;
break;
}
default : {
assert(false);
}
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Free a skiplist iterator
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeSkiplistIterator (TRI_skiplist_iterator_t* const iterator) {
assert(NULL != iterator);
TRI_DestroyVector(&iterator->_intervals);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, iterator);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a skip list index , but does not free the pointer
////////////////////////////////////////////////////////////////////////////////
void SkiplistIndex_destroy (SkiplistIndex* slIndex) {
if (slIndex == NULL) {
return;
}
TRI_FreeSkipList(slIndex->skiplist);
slIndex->skiplist = NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a skip list index and frees the pointer
////////////////////////////////////////////////////////////////////////////////
void SkiplistIndex_free (SkiplistIndex* slIndex) {
if (slIndex == NULL) {
return;
}
SkiplistIndex_destroy(slIndex);
TRI_Free(TRI_CORE_MEM_ZONE, slIndex);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Skiplist indices
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Public Methods Skiplist Indices
//------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new skiplist index
////////////////////////////////////////////////////////////////////////////////
SkiplistIndex* SkiplistIndex_new (TRI_primary_collection_t* primary,
size_t numFields, bool unique, bool sparse) {
SkiplistIndex* skiplistIndex = static_cast<SkiplistIndex*>(TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(SkiplistIndex), true));
if (skiplistIndex == NULL) {
return NULL;
}
skiplistIndex->_collection = primary;
skiplistIndex->_numFields = numFields;
skiplistIndex->unique = unique;
skiplistIndex->sparse = sparse;
skiplistIndex->skiplist = TRI_InitSkipList(CmpElmElm,CmpKeyElm,skiplistIndex,
FreeElm,unique);
if (skiplistIndex->skiplist == NULL) {
TRI_Free(TRI_CORE_MEM_ZONE, skiplistIndex);
return NULL;
}
return skiplistIndex;
}
////////////////////////////////////////////////////////////////////////////////
/// @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(
SkiplistIndex* skiplistIndex,
TRI_skiplist_iterator_interval_t* interval) {
int compareResult;
TRI_skiplist_node_t* lNode;
TRI_skiplist_node_t* rNode;
lNode = interval->_leftEndPoint;
if (lNode == NULL) {
return false;
}
// Note that the right end point can be NULL to indicate the end of the index.
rNode = interval->_rightEndPoint;
if (lNode == rNode) {
return false;
}
if (TRI_SkipListNextNode(lNode) == rNode) {
// Interval empty, nothing to do with it.
return false;
}
if (NULL != rNode && TRI_SkipListNextNode(rNode) == lNode) {
// Interval empty, nothing to do with it.
return false;
}
if (TRI_SkipListGetNrUsed(skiplistIndex->skiplist) == 0) {
return false;
}
if ( lNode == TRI_SkipListStartNode(skiplistIndex->skiplist) ||
NULL == 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;
}
compareResult = CmpElmElm( skiplistIndex,
lNode->doc, rNode->doc, TRI_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) {
int compareResult;
TRI_skiplist_node_t* lNode;
TRI_skiplist_node_t* rNode;
lNode = lInterval->_leftEndPoint;
rNode = rInterval->_leftEndPoint;
if (NULL == lNode || NULL == rNode) {
// At least one left boundary is the end, intersection is empty.
return false;
}
// Now find the larger of the two start nodes:
if (lNode == TRI_SkipListStartNode(skiplistIndex->skiplist)) {
// We take rNode, even if it is the start node as well.
compareResult = -1;
}
else if (rNode == TRI_SkipListStartNode(skiplistIndex->skiplist)) {
// We take lNode
compareResult = 1;
}
else {
compareResult = CmpElmElm(skiplistIndex, lNode->doc, rNode->doc,
TRI_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 (NULL == lNode) {
// We take rNode, even is this also the end node.
compareResult = 1;
}
else if (NULL == rNode) {
// We take lNode.
compareResult = -1;
}
else {
compareResult = CmpElmElm(skiplistIndex, lNode->doc, rNode->doc,
TRI_CMP_TOTORDER);
}
if (compareResult < 1) {
interval->_rightEndPoint = lNode;
}
else {
interval->_rightEndPoint = rNode;
}
return skiplistIndex_findHelperIntervalValid(skiplistIndex, interval);
}
static void SkiplistIndex_findHelper (SkiplistIndex* skiplistIndex,
TRI_vector_t* shapeList,
TRI_index_operator_t* indexOperator,
TRI_vector_t* resultIntervalList) {
TRI_skiplist_index_key_t values;
TRI_vector_t leftResult;
TRI_vector_t rightResult;
TRI_relation_index_operator_t* relationOperator;
TRI_logical_index_operator_t* logicalOperator;
TRI_skiplist_iterator_interval_t interval;
TRI_skiplist_iterator_interval_t* tempLeftInterval;
TRI_skiplist_iterator_interval_t* tempRightInterval;
TRI_skiplist_node_t* temp;
size_t i, j;
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));
relationOperator = (TRI_relation_index_operator_t*)(indexOperator);
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;
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_SL_OR_OPERATOR: {
SkiplistIndex_findHelper(skiplistIndex,shapeList,logicalOperator->_left,
&leftResult);
SkiplistIndex_findHelper(skiplistIndex,shapeList,logicalOperator->_right,
&leftResult);
i = 0;
while (i < leftResult._length - 1) {
tempLeftInterval = (TRI_skiplist_iterator_interval_t*)
(TRI_AtVector(&leftResult, i));
tempRightInterval = (TRI_skiplist_iterator_interval_t*)
(TRI_AtVector(&leftResult, i + 1));
// if intervals intersect, optimise and start again
}
assert(0);
}
*/
case TRI_AND_INDEX_OPERATOR: {
SkiplistIndex_findHelper(skiplistIndex,shapeList,
logicalOperator->_left,&leftResult);
SkiplistIndex_findHelper(skiplistIndex,shapeList,
logicalOperator->_right,&rightResult);
for (i = 0; i < leftResult._length; ++i) {
for (j = 0; j < rightResult._length; ++j) {
tempLeftInterval = (TRI_skiplist_iterator_interval_t*)
(TRI_AtVector(&leftResult, i));
tempRightInterval = (TRI_skiplist_iterator_interval_t*)
(TRI_AtVector(&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 = TRI_SkipListLeftKeyLookup(skiplistIndex->skiplist, &values);
if (NULL != temp) {
interval._leftEndPoint = temp;
if (skiplistIndex->unique) {
// At most one hit:
temp = TRI_SkipListNextNode(temp);
if (NULL != temp) {
if (0 == CmpKeyElm(skiplistIndex, &values, temp->doc)) {
interval._rightEndPoint = TRI_SkipListNextNode(temp);
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,
&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
}
}
}
else {
temp = TRI_SkipListRightKeyLookup(skiplistIndex->skiplist, &values);
interval._rightEndPoint = TRI_SkipListNextNode(temp);
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,
&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
}
}
return;
}
case TRI_LE_INDEX_OPERATOR: {
interval._leftEndPoint = TRI_SkipListStartNode(skiplistIndex->skiplist);
temp = TRI_SkipListRightKeyLookup(skiplistIndex->skiplist, &values);
interval._rightEndPoint = TRI_SkipListNextNode(temp);
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
case TRI_LT_INDEX_OPERATOR: {
interval._leftEndPoint = TRI_SkipListStartNode(skiplistIndex->skiplist);
temp = TRI_SkipListLeftKeyLookup(skiplistIndex->skiplist, &values);
interval._rightEndPoint = TRI_SkipListNextNode(temp);
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
case TRI_GE_INDEX_OPERATOR: {
temp = TRI_SkipListLeftKeyLookup(skiplistIndex->skiplist, &values);
interval._leftEndPoint = temp;
interval._rightEndPoint = NULL;
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
case TRI_GT_INDEX_OPERATOR: {
temp = TRI_SkipListRightKeyLookup(skiplistIndex->skiplist, &values);
interval._leftEndPoint = temp;
interval._rightEndPoint = NULL;
if (skiplistIndex_findHelperIntervalValid(skiplistIndex,&interval)) {
TRI_PushBackVector(resultIntervalList, &interval);
}
return;
}
default: {
assert(false);
}
} // end of switch statement
}
TRI_skiplist_iterator_t* SkiplistIndex_find (
SkiplistIndex* skiplistIndex,
TRI_vector_t* shapeList,
TRI_index_operator_t* indexOperator) {
TRI_skiplist_iterator_t* results = static_cast<TRI_skiplist_iterator_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_t), true));
if (results == NULL) {
return NULL; // calling procedure needs to care when the iterator is null
}
results->_index = skiplistIndex;
TRI_InitVector(&(results->_intervals), TRI_UNKNOWN_MEM_ZONE,
sizeof(TRI_skiplist_iterator_interval_t));
results->_currentInterval = 0;
results->_cursor = NULL;
results->_hasNext = SkiplistHasNextIterationCallback;
results->_next = SkiplistNextIterationCallback;
results->_nexts = SkiplistNextsIterationCallback;
SkiplistIndex_findHelper(skiplistIndex, shapeList, indexOperator,
&(results->_intervals));
// Finally initialise _cursor if the result is not empty:
if (0 < TRI_LengthVector(&(results->_intervals))) {
TRI_skiplist_iterator_interval_t* tmp = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AtVector(&(results->_intervals), 0));
results->_cursor = tmp->_leftEndPoint;
}
return results;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief inserts a data element into a unique skip list
////////////////////////////////////////////////////////////////////////////////
int SkiplistIndex_insert (SkiplistIndex* skiplistIndex,
TRI_skiplist_index_element_t* element) {
TRI_skiplist_index_element_t* copy = static_cast<TRI_skiplist_index_element_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_index_element_t), false));
if (NULL == copy) {
return TRI_ERROR_OUT_OF_MEMORY;
}
int res = CopyElement(skiplistIndex, copy, element);
if (res != TRI_ERROR_NO_ERROR) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, copy);
return res;
}
res = TRI_SkipListInsert(skiplistIndex->skiplist, copy);
if (res != TRI_ERROR_NO_ERROR) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, copy->_subObjects);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, copy);
return res;
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an entry from the skip list
////////////////////////////////////////////////////////////////////////////////
int SkiplistIndex_remove (SkiplistIndex* skiplistIndex,
TRI_skiplist_index_element_t* element) {
int result;
result = TRI_SkipListRemove(skiplistIndex->skiplist, element);
if (result == TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
// This is for the case of a rollback in an aborted transaction.
// We silently ignore the fact that the document was not there.
// This could also be useful for the case of a sparse index.
return TRI_ERROR_NO_ERROR;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of elements in the skip list index
////////////////////////////////////////////////////////////////////////////////
uint64_t SkiplistIndex_getNrUsed(SkiplistIndex* skiplistIndex) {
return TRI_SkipListGetNrUsed(skiplistIndex->skiplist);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End: