mirror of https://gitee.com/bigwinds/arangodb
Moved some functionality from skiplist-helper into the skiplist and C++ified it. Not yet done
This commit is contained in:
parent
cbd1cd7111
commit
cb9e1b0e98
|
@ -39,6 +39,177 @@ using namespace triagens::arango;
|
|||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief frees an element in the skiplist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void FreeElm (void* e) {
|
||||
auto element = static_cast<TRI_index_element_t*>(e);
|
||||
TRI_index_element_t::free(element);
|
||||
}
|
||||
|
||||
|
||||
// .............................................................................
|
||||
// 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_index_element_t const* right,
|
||||
size_t rightPosition,
|
||||
VocShaper* shaper) {
|
||||
TRI_ASSERT(nullptr != left);
|
||||
TRI_ASSERT(nullptr != right);
|
||||
|
||||
auto rightSubobjects = right->subObjects();
|
||||
|
||||
return TRI_CompareShapeTypes(nullptr,
|
||||
nullptr,
|
||||
left,
|
||||
shaper,
|
||||
right->document()->getShapedJsonPtr(),
|
||||
&rightSubobjects[rightPosition],
|
||||
nullptr,
|
||||
shaper);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares a key with an element in a skip list, generic callback
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CmpKeyElm (void* sli,
|
||||
TRI_skiplist_index_key_t const* leftKey,
|
||||
TRI_index_element_t const* rightElement) {
|
||||
|
||||
TRI_ASSERT(nullptr != left);
|
||||
TRI_ASSERT(nullptr != right);
|
||||
|
||||
triagens::arango::SkiplistIndex2* skiplistindex = static_cast<triagens::arango::SkiplistIndex2*>(sli);
|
||||
auto shaper = skiplistindex->collection()->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
|
||||
// Note that the key might contain fewer fields than there are indexed
|
||||
// attributes, therefore we only run the following loop to
|
||||
// leftKey->_numFields.
|
||||
for (size_t j = 0; j < leftKey->_numFields; j++) {
|
||||
int compareResult = CompareKeyElement(&leftKey->_fields[j], rightElement, j, shaper);
|
||||
|
||||
if (compareResult != 0) {
|
||||
return compareResult;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares elements, version with proper types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CompareElementElement (TRI_index_element_t const* left,
|
||||
size_t leftPosition,
|
||||
TRI_index_element_t const* right,
|
||||
size_t rightPosition,
|
||||
VocShaper* shaper) {
|
||||
TRI_ASSERT(nullptr != left);
|
||||
TRI_ASSERT(nullptr != right);
|
||||
|
||||
auto leftSubobjects = left->subObjects();
|
||||
auto rightSubobjects = right->subObjects();
|
||||
|
||||
return TRI_CompareShapeTypes(left->document()->getShapedJsonPtr(),
|
||||
&leftSubobjects[leftPosition],
|
||||
nullptr,
|
||||
shaper,
|
||||
right->document()->getShapedJsonPtr(),
|
||||
&rightSubobjects[rightPosition],
|
||||
nullptr,
|
||||
shaper);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares two elements in a skip list, this is the generic callback
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CmpElmElm (void* sli,
|
||||
TRI_index_element_t const* leftElement,
|
||||
TRI_index_element_t const* rightElement,
|
||||
triagens::basics::SkipListCmpType cmptype) {
|
||||
|
||||
TRI_ASSERT(nullptr != leftElement);
|
||||
TRI_ASSERT(nullptr != rightElement);
|
||||
|
||||
// ..........................................................................
|
||||
// The document could be the same -- so no further comparison is required.
|
||||
// ..........................................................................
|
||||
|
||||
SkiplistIndex* skiplistindex = static_cast<SkiplistIndex*>(sli);
|
||||
|
||||
if (leftElement == rightElement ||
|
||||
(! skiplistindex->skiplist->isArray() && leftElement->document() == rightElement->document())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto shaper = skiplistindex->_collection->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
for (size_t j = 0; j < skiplistindex->_numFields; j++) {
|
||||
int 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 (triagens::basics::SKIPLIST_CMP_PREORDER == cmptype) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We break this tie in the key comparison by looking at the key:
|
||||
int compareResult = strcmp(TRI_EXTRACT_MARKER_KEY(leftElement->document()), // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
TRI_EXTRACT_MARKER_KEY(rightElement->document())); // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
|
||||
if (compareResult < 0) {
|
||||
return -1;
|
||||
}
|
||||
else if (compareResult > 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FillLookupOperator (TRI_index_operator_t* slOperator,
|
||||
TRI_document_collection_t* document) {
|
||||
if (slOperator == nullptr) {
|
||||
|
@ -117,6 +288,181 @@ static int FillLookupOperator (TRI_index_operator_t* slOperator,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class SkiplistIterator
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
size_t SkiplistIterator::size () {
|
||||
return _intervals.size();
|
||||
}
|
||||
|
||||
void SkiplistIterator::initCursor () {
|
||||
size_t const n = _intervals.size();
|
||||
if (0 < n) {
|
||||
if (_reverse) {
|
||||
// start at last interval, right endpoint
|
||||
_currentInterval = n - 1;
|
||||
_cursor = _intervals[n -1]->_rightEndPoint;
|
||||
}
|
||||
else {
|
||||
// start at first interval, left endpoint
|
||||
_currentInterval = 0;
|
||||
_cursor = _intervals[0]->_leftEndPoint;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cursor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkiplistIterator::hasNext () {
|
||||
if (_reverse) {
|
||||
return hasPrevIteration();
|
||||
}
|
||||
return hasNextIteration();
|
||||
}
|
||||
|
||||
bool SkiplistIterator::next () {
|
||||
if (_reverse) {
|
||||
return prevIteration();
|
||||
}
|
||||
return nextIteration();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Attempts to determine if there is a previous document within an
|
||||
/// interval or before it - without advancing the iterator.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkiplistIterator::hasPrevIteration () {
|
||||
// ...........................................................................
|
||||
// if we have more intervals than the one we are currently working
|
||||
// on then of course we have a previous doc, because intervals are nonempty.
|
||||
// ...........................................................................
|
||||
if (_currentInterval > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Node const* leftNode = _index->prevNode(_cursor);
|
||||
|
||||
// Note that leftNode can be nullptr here!
|
||||
// ...........................................................................
|
||||
// If the leftNode == left end point AND there are no more intervals
|
||||
// then we have no next.
|
||||
// ...........................................................................
|
||||
return leftNode != _intervals[_currentInterval]->_leftEndPoint;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Attempts to determine if there is a next document within an
|
||||
/// interval - without advancing the iterator.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkiplistIterator::hasNextIteration () {
|
||||
if (_cursor == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// if we have more intervals than the one we are currently working
|
||||
// on then of course we have a next doc, since intervals are nonempty.
|
||||
// ...........................................................................
|
||||
if (_intervals.size() - 1 > _currentInterval) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Node const* leftNode = _cursor->nextNode();
|
||||
|
||||
// Note that leftNode can be nullptr here!
|
||||
// ...........................................................................
|
||||
// If the left == right end point AND there are no more intervals then we have
|
||||
// no next.
|
||||
// ...........................................................................
|
||||
return leftNode != _intervals[_currentInterval]->_rightEndPoint;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Jumps backwards by jumpSize and returns the document
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_index_element_t* SkiplistIterator::prevIteration () {
|
||||
static const int64_t jumpSize = 1;
|
||||
|
||||
TRI_skiplist_iterator_interval_t* interval = _intervals[_currentInterval];
|
||||
|
||||
if (interval == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// use the current cursor and move jumpSize backward
|
||||
// ...........................................................................
|
||||
|
||||
Node* result = nullptr;
|
||||
|
||||
result = _index->prevNode(_cursor);
|
||||
|
||||
if (result == interval->_leftEndPoint) {
|
||||
if (_currentInterval == 0) {
|
||||
_cursor = nullptr; // exhausted
|
||||
return nullptr;
|
||||
}
|
||||
--_currentInterval;
|
||||
interval = _intervals[_currentInterval];
|
||||
TRI_ASSERT(interval != nullptr);
|
||||
_cursor = _rightEndPoint;
|
||||
result = _index->prevNode(_cursor);
|
||||
}
|
||||
_cursor = result;
|
||||
|
||||
TRI_ASSERT(result != nullptr);
|
||||
return result->document();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Jumps forwards by jumpSize and returns the document
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_index_element_t* SkiplistIterator::nextIteration () {
|
||||
|
||||
if (_cursor == nullptr) {
|
||||
// In this case the iterator is exhausted or does not even have intervals.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TRI_skiplist_iterator_interval_t* interval = _intervals[_currentInterval];
|
||||
|
||||
if (interval == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (true) { // will be left by break
|
||||
_cursor = _cursor->nextNode();
|
||||
if (_cursor != _rightEndPoint) {
|
||||
// Note that _cursor can be nullptr here!
|
||||
break; // we found a next one
|
||||
}
|
||||
if (_currentInterval == _intervals.size() - 1) {
|
||||
_cursor = nullptr; // exhausted
|
||||
return nullptr;
|
||||
}
|
||||
++_currentInterval;
|
||||
interval = _intervals[_currentInterval];
|
||||
TRI_ASSERT(interval != nullptr);
|
||||
_cursor = interval->_leftEndPoint;
|
||||
}
|
||||
|
||||
return _cursor->document();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class SkiplistIndex
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -137,11 +483,9 @@ SkiplistIndex2::SkiplistIndex2 (TRI_idx_iid_t iid,
|
|||
: PathBasedIndex(iid, collection, fields, unique, sparse),
|
||||
_skiplistIndex(nullptr) {
|
||||
|
||||
_skiplistIndex = SkiplistIndex_new(collection,
|
||||
_paths.size(),
|
||||
unique,
|
||||
_useExpansion);
|
||||
|
||||
_skiplistIndex = new triagens::basics::SkipList(
|
||||
CmpElmElm, CmpKeyElm, skiplistIndex,
|
||||
FreeElm, unique, _useExpansion);
|
||||
if (_skiplistIndex == nullptr) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
@ -153,7 +497,7 @@ SkiplistIndex2::SkiplistIndex2 (TRI_idx_iid_t iid,
|
|||
|
||||
SkiplistIndex2::~SkiplistIndex2 () {
|
||||
if (_skiplistIndex != nullptr) {
|
||||
SkiplistIndex_free(_skiplistIndex);
|
||||
delete _skiplistIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +506,12 @@ SkiplistIndex2::~SkiplistIndex2 () {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
size_t SkiplistIndex2::memory () const {
|
||||
return SkiplistIndex_memoryUsage(_skiplistIndex);
|
||||
return _skiplistIndex->memoryUsage() +
|
||||
static_cast<size_t>(_skiplistIndex->getNrUsed()) * elementSize();
|
||||
}
|
||||
|
||||
size_t SkiplistIndex2::numFields () const {
|
||||
return _fields.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -271,7 +620,7 @@ int SkiplistIndex2::remove (TRI_doc_mptr_t const* doc,
|
|||
/// the TRI_index_operator_t* and the TRI_skiplist_iterator_t* results
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_skiplist_iterator_t* SkiplistIndex2::lookup (TRI_index_operator_t* slOperator,
|
||||
SkiplistIterator* SkiplistIndex2::lookup (TRI_index_operator_t* slOperator,
|
||||
bool reverse) {
|
||||
if (slOperator == nullptr) {
|
||||
return nullptr;
|
||||
|
@ -290,12 +639,31 @@ TRI_skiplist_iterator_t* SkiplistIndex2::lookup (TRI_index_operator_t* slOperato
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<SkiplistIterator> results = new SkiplistIterator(_skiplistIndex, reverse);
|
||||
|
||||
return SkiplistIndex_find(_skiplistIndex,
|
||||
slOperator,
|
||||
reverse);
|
||||
if (!results) {
|
||||
// Check if we could not get an iterator.
|
||||
return nullptr; // calling procedure needs to care when the iterator is null
|
||||
}
|
||||
|
||||
result->findHelper(slOperator, &(results->_intervals));
|
||||
|
||||
results->initCursor();
|
||||
|
||||
// Finally initialise _cursor if the result is not empty:
|
||||
return results;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
size_t SkiplistIndex::elementSize () const {
|
||||
return sizeof(TRI_doc_mptr_t*) + (sizeof(TRI_shaped_sub_t) * numFields());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -42,9 +42,106 @@
|
|||
// --SECTION-- class SkiplistIndex
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
TRI_shaped_json_t* _fields; // list of shaped json objects which the
|
||||
// collection should know about
|
||||
size_t _numFields; // Note that the number of fields coming from
|
||||
// a query can be smaller than the number of
|
||||
// fields indexed
|
||||
}
|
||||
TRI_skiplist_index_key_t;
|
||||
|
||||
namespace triagens {
|
||||
namespace arango {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Iterator structure for skip list. We require a start and stop node
|
||||
///
|
||||
/// Intervals are open in the sense that both end points are not members
|
||||
/// of the interval. This means that one has to use SkipList::nextNode
|
||||
/// on the start node to get the first element and that the stop node
|
||||
/// can be NULL. Note that it is ensured that all intervals in an iterator
|
||||
/// are non-empty.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkiplistIterator {
|
||||
private:
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private structs
|
||||
// -----------------------------------------------------------------------------
|
||||
// Shorthand for the skiplist node
|
||||
typedef triagens::basics::SkipListNode<TRI_skiplist_index_key_t, TRI_index_element_t> Node;
|
||||
|
||||
struct SkiplistIteratorInterval {
|
||||
Node* _leftEndPoint;
|
||||
Node* _rightEndPoint;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
triagens::arango::SkiplistIndex2 const* _index;
|
||||
std::vector<SkiplistIteratorInterval*> _invervals;
|
||||
size_t _currentInterval; // starts with 0, current interval used
|
||||
bool _reverse;
|
||||
Node* _cursor;
|
||||
|
||||
public:
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
SkiplistIterator (
|
||||
triagens::arango::SkiplistIndex2 const* idx,
|
||||
bool reverse
|
||||
) : _index(idx) {
|
||||
_currentInterval = 0;
|
||||
_cursor = nullptr;
|
||||
};
|
||||
|
||||
~SkiplistIterator () {};
|
||||
|
||||
// always holds the last node returned, initially equal to
|
||||
// the _leftEndPoint of the first interval (or the
|
||||
// _rightEndPoint of the last interval in the reverse
|
||||
// case), can be nullptr if there are no intervals
|
||||
// (yet), or, in the reverse case, if the cursor is
|
||||
// at the end of the last interval. Additionally
|
||||
// in the non-reverse case _cursor is set to nullptr
|
||||
// if the cursor is exhausted.
|
||||
// See SkiplistNextIterationCallback and
|
||||
// SkiplistPrevIterationCallback for the exact
|
||||
// condition for the iterator to be exhausted.
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
size_t size ();
|
||||
|
||||
bool hasNext ();
|
||||
|
||||
TRI_index_element_t* next ();
|
||||
|
||||
void initCursor ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
private:
|
||||
bool hasPrevIteration ();
|
||||
TRI_index_element_t* prevIteration ();
|
||||
|
||||
bool hasNextIteration ();
|
||||
TRI_index_element_t* nextIteration ();
|
||||
|
||||
|
||||
};
|
||||
|
||||
class SkiplistIndex2 : public PathBasedIndex {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -86,6 +183,8 @@ namespace triagens {
|
|||
|
||||
int remove (struct TRI_doc_mptr_t const*, bool) override final;
|
||||
|
||||
size_t numFields () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief attempts to locate an entry in the skip list index
|
||||
///
|
||||
|
@ -94,9 +193,16 @@ namespace triagens {
|
|||
/// the TRI_index_operator_t* and the TRI_skiplist_iterator_t* results
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_skiplist_iterator_t* lookup (TRI_index_operator_t*,
|
||||
bool);
|
||||
SkiplistIterator* lookup (TRI_index_operator_t*, bool);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
size_t elementSize () const;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -107,7 +213,7 @@ namespace triagens {
|
|||
/// @brief the actual skiplist index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkiplistIndex* _skiplistIndex;
|
||||
triagens::basics::SkipList<TRI_skiplist_index_key_t, TRI_index_element_t>* _skiplistIndex;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -37,429 +37,15 @@
|
|||
// --SECTION-- private types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
TRI_shaped_json_t* _fields; // list of shaped json objects which the
|
||||
// collection should know about
|
||||
size_t _numFields; // Note that the number of fields coming from
|
||||
// a query can be smaller than the number of
|
||||
// fields indexed
|
||||
}
|
||||
TRI_skiplist_index_key_t;
|
||||
|
||||
typedef struct TRI_skiplist_iterator_interval_s {
|
||||
triagens::basics::SkipListNode* _leftEndPoint;
|
||||
triagens::basics::SkipListNode* _rightEndPoint;
|
||||
}
|
||||
TRI_skiplist_iterator_interval_t;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// .............................................................................
|
||||
// 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_index_element_t const* right,
|
||||
size_t rightPosition,
|
||||
VocShaper* shaper) {
|
||||
TRI_ASSERT(nullptr != left);
|
||||
TRI_ASSERT(nullptr != right);
|
||||
|
||||
auto rightSubobjects = right->subObjects();
|
||||
|
||||
return TRI_CompareShapeTypes(nullptr,
|
||||
nullptr,
|
||||
left,
|
||||
shaper,
|
||||
right->document()->getShapedJsonPtr(),
|
||||
&rightSubobjects[rightPosition],
|
||||
nullptr,
|
||||
shaper);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares elements, version with proper types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CompareElementElement (TRI_index_element_t const* left,
|
||||
size_t leftPosition,
|
||||
TRI_index_element_t const* right,
|
||||
size_t rightPosition,
|
||||
VocShaper* shaper) {
|
||||
TRI_ASSERT(nullptr != left);
|
||||
TRI_ASSERT(nullptr != right);
|
||||
|
||||
auto leftSubobjects = left->subObjects();
|
||||
auto rightSubobjects = right->subObjects();
|
||||
|
||||
return TRI_CompareShapeTypes(left->document()->getShapedJsonPtr(),
|
||||
&leftSubobjects[leftPosition],
|
||||
nullptr,
|
||||
shaper,
|
||||
right->document()->getShapedJsonPtr(),
|
||||
&rightSubobjects[rightPosition],
|
||||
nullptr,
|
||||
shaper);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares two elements in a skip list, this is the generic callback
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CmpElmElm (void* sli,
|
||||
void* left,
|
||||
void* right,
|
||||
triagens::basics::SkipListCmpType cmptype) {
|
||||
|
||||
auto leftElement = static_cast<TRI_index_element_t const*>(left);
|
||||
auto rightElement = static_cast<TRI_index_element_t const*>(right);
|
||||
|
||||
TRI_ASSERT(nullptr != left);
|
||||
TRI_ASSERT(nullptr != right);
|
||||
|
||||
// ..........................................................................
|
||||
// The document could be the same -- so no further comparison is required.
|
||||
// ..........................................................................
|
||||
|
||||
SkiplistIndex* skiplistindex = static_cast<SkiplistIndex*>(sli);
|
||||
|
||||
if (leftElement == rightElement ||
|
||||
(! skiplistindex->skiplist->isArray() && leftElement->document() == rightElement->document())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto shaper = skiplistindex->_collection->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
for (size_t j = 0; j < skiplistindex->_numFields; j++) {
|
||||
int 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 (triagens::basics::SKIPLIST_CMP_PREORDER == cmptype) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We break this tie in the key comparison by looking at the key:
|
||||
int compareResult = strcmp(TRI_EXTRACT_MARKER_KEY(leftElement->document()), // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
TRI_EXTRACT_MARKER_KEY(rightElement->document())); // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
|
||||
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) {
|
||||
auto leftKey = static_cast<TRI_skiplist_index_key_t const*>(left);
|
||||
auto rightElement = static_cast<TRI_index_element_t const*>(right);
|
||||
|
||||
TRI_ASSERT(nullptr != left);
|
||||
TRI_ASSERT(nullptr != right);
|
||||
|
||||
SkiplistIndex* skiplistindex = static_cast<SkiplistIndex*>(sli);
|
||||
auto shaper = skiplistindex->_collection->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
|
||||
|
||||
// Note that the key might contain fewer fields than there are indexed
|
||||
// attributes, therefore we only run the following loop to
|
||||
// leftKey->_numFields.
|
||||
for (size_t j = 0; j < leftKey->_numFields; j++) {
|
||||
int 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) {
|
||||
auto element = static_cast<TRI_index_element_t*>(e);
|
||||
TRI_index_element_t::free(element);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the current interval that the iterator points at
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline TRI_skiplist_iterator_interval_t* GetInterval (TRI_skiplist_iterator_t const* iterator) {
|
||||
return static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AtVector(&iterator->_intervals, iterator->_currentInterval));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Attempts to determine if there is a previous document within an
|
||||
/// interval or before it - without advancing the iterator.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool HasPrevIterationCallback (TRI_skiplist_iterator_t const* iterator) {
|
||||
// Note that iterator->_cursor == nullptr if we are before the largest
|
||||
// document (i.e. the first one in the iterator)!
|
||||
if (iterator == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// if we have more intervals than the one we are currently working
|
||||
// on then of course we have a previous doc, because intervals are nonempty.
|
||||
// ...........................................................................
|
||||
if (iterator->_currentInterval > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void const* leftNode
|
||||
= iterator->_index->skiplist->prevNode(iterator->_cursor);
|
||||
|
||||
// Note that leftNode can be nullptr here!
|
||||
// ...........................................................................
|
||||
// If the leftNode == left end point AND there are no more intervals
|
||||
// then we have no next.
|
||||
// ...........................................................................
|
||||
if (leftNode == GetInterval(iterator)->_leftEndPoint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Attempts to determine if there is a next document within an
|
||||
/// interval - without advancing the iterator.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool HasNextIterationCallback (TRI_skiplist_iterator_t const* iterator) {
|
||||
if (iterator == nullptr ||
|
||||
iterator->_cursor == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// if we have more intervals than the one we are currently working
|
||||
// on then of course we have a next doc, since intervals are nonempty.
|
||||
// ...........................................................................
|
||||
if (TRI_LengthVector(&iterator->_intervals) - 1 > iterator->_currentInterval) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void const* leftNode = iterator->_cursor->nextNode();
|
||||
|
||||
// Note that leftNode can be nullptr here!
|
||||
// ...........................................................................
|
||||
// If the left == right end point AND there are no more intervals then we have
|
||||
// no next.
|
||||
// ...........................................................................
|
||||
if (leftNode == GetInterval(iterator)->_rightEndPoint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Jumps backwards by jumpSize and returns the document
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_index_element_t* PrevIterationCallback (TRI_skiplist_iterator_t* iterator) {
|
||||
static const int64_t jumpSize = 1;
|
||||
|
||||
TRI_ASSERT(jumpSize > 0);
|
||||
|
||||
if (iterator == nullptr) {
|
||||
// In this case the iterator does not even have intervals.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TRI_skiplist_iterator_interval_t* interval = GetInterval(iterator);
|
||||
|
||||
if (interval == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// use the current cursor and move jumpSize backward
|
||||
// ...........................................................................
|
||||
|
||||
triagens::basics::SkipListNode* result = nullptr;
|
||||
|
||||
for (int64_t j = 0; j < jumpSize; ++j) {
|
||||
while (true) { // will be left by break
|
||||
result = iterator->_index->skiplist->prevNode(iterator->_cursor);
|
||||
|
||||
if (result == interval->_leftEndPoint) {
|
||||
if (iterator->_currentInterval == 0) {
|
||||
iterator->_cursor = nullptr; // exhausted
|
||||
return nullptr;
|
||||
}
|
||||
--iterator->_currentInterval;
|
||||
interval = GetInterval(iterator);
|
||||
TRI_ASSERT(interval != nullptr);
|
||||
iterator->_cursor = interval->_rightEndPoint;
|
||||
result = iterator->_index->skiplist->prevNode(iterator->_cursor);
|
||||
}
|
||||
|
||||
iterator->_cursor = result;
|
||||
break; // we found a prev one
|
||||
}
|
||||
}
|
||||
|
||||
TRI_ASSERT(result != nullptr);
|
||||
return static_cast<TRI_index_element_t*>(result->document()); //iterator->_cursor->document());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Jumps forwards by jumpSize and returns the document
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_index_element_t* NextIterationCallback (TRI_skiplist_iterator_t* iterator) {
|
||||
static const int64_t jumpSize = 1;
|
||||
|
||||
TRI_ASSERT(jumpSize > 0);
|
||||
|
||||
if (iterator == nullptr ||
|
||||
iterator->_cursor == nullptr) {
|
||||
// In this case the iterator is exhausted or does not even have intervals.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TRI_skiplist_iterator_interval_t* interval = GetInterval(iterator);
|
||||
|
||||
if (interval == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ...........................................................................
|
||||
// use the current cursor and move jumpSize forward
|
||||
// ...........................................................................
|
||||
|
||||
for (int64_t j = 0; j < jumpSize; ++j) {
|
||||
while (true) { // will be left by break
|
||||
iterator->_cursor = iterator->_cursor->nextNode();
|
||||
if (iterator->_cursor != interval->_rightEndPoint) {
|
||||
// Note that _cursor can be nullptr here!
|
||||
break; // we found a next one
|
||||
}
|
||||
if (iterator->_currentInterval == (TRI_LengthVector(&iterator->_intervals) - 1)) {
|
||||
iterator->_cursor = nullptr; // exhausted
|
||||
return nullptr;
|
||||
}
|
||||
++iterator->_currentInterval;
|
||||
interval = GetInterval(iterator);
|
||||
TRI_ASSERT(interval != nullptr);
|
||||
iterator->_cursor = interval->_leftEndPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<TRI_index_element_t*>(iterator->_cursor->document());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- skiplistIndex common public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Free a skiplist iterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_FreeSkiplistIterator (TRI_skiplist_iterator_t* iterator) {
|
||||
TRI_ASSERT(nullptr != iterator);
|
||||
|
||||
TRI_DestroyVector(&iterator->_intervals);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, iterator);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys a skip list index and frees the pointer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkiplistIndex_free (SkiplistIndex* slIndex) {
|
||||
if (slIndex == nullptr) {
|
||||
return;
|
||||
}
|
||||
delete slIndex->skiplist;
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, slIndex);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Methods Skiplist Indices
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a new skiplist index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkiplistIndex* SkiplistIndex_new (TRI_document_collection_t* document,
|
||||
size_t numFields,
|
||||
bool unique,
|
||||
bool isArray) {
|
||||
SkiplistIndex* skiplistIndex = static_cast<SkiplistIndex*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(SkiplistIndex), true));
|
||||
|
||||
if (skiplistIndex == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
skiplistIndex->_collection = document;
|
||||
skiplistIndex->_numFields = numFields;
|
||||
skiplistIndex->unique = unique;
|
||||
try {
|
||||
skiplistIndex->skiplist = new triagens::basics::SkipList(
|
||||
CmpElmElm, CmpKeyElm, skiplistIndex,
|
||||
FreeElm, unique, isArray);
|
||||
}
|
||||
catch (...) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, skiplistIndex);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return skiplistIndex;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Locates one or more ranges within the skiplist and returns iterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -470,7 +56,7 @@ SkiplistIndex* SkiplistIndex_new (TRI_document_collection_t* document,
|
|||
// Tests whether the LeftEndPoint is > than RightEndPoint (1) [undefined]
|
||||
// .............................................................................
|
||||
|
||||
static bool skiplistIndex_findHelperIntervalValid (SkiplistIndex* skiplistIndex,
|
||||
static bool skiplistIndex_findHelperIntervalValid (triagens::arango::SkiplistIndex2* skiplistIndex,
|
||||
TRI_skiplist_iterator_interval_t const* interval) {
|
||||
triagens::basics::SkipListNode* lNode = interval->_leftEndPoint;
|
||||
|
||||
|
@ -581,7 +167,7 @@ static bool skiplistIndex_findHelperIntervalIntersectionValid (
|
|||
return skiplistIndex_findHelperIntervalValid(skiplistIndex, interval);
|
||||
}
|
||||
|
||||
static void SkiplistIndex_findHelper (SkiplistIndex* skiplistIndex,
|
||||
static void SkiplistIndex_findHelper (triagens::arango::SkiplistIndex2* skiplistIndex,
|
||||
TRI_index_operator_t const* indexOperator,
|
||||
TRI_vector_t* resultIntervalList) {
|
||||
TRI_skiplist_index_key_t values;
|
||||
|
@ -723,63 +309,9 @@ static void SkiplistIndex_findHelper (SkiplistIndex* skiplistIndex,
|
|||
} // end of switch statement
|
||||
}
|
||||
|
||||
TRI_skiplist_iterator_t* SkiplistIndex_find (SkiplistIndex* skiplistIndex,
|
||||
TRI_skiplist_iterator_t* SkiplistIndex_find (triagens::arango::SkiplistIndex2* skiplistIndex,
|
||||
TRI_index_operator_t const* indexOperator,
|
||||
bool reverse) {
|
||||
auto results = static_cast<TRI_skiplist_iterator_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_skiplist_iterator_t), true));
|
||||
|
||||
if (results == nullptr) {
|
||||
return nullptr; // 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 = nullptr;
|
||||
|
||||
if (reverse) {
|
||||
// reverse iteration intentionally assigns the reverse traversal
|
||||
// methods to hasNext() and next() so the interface remains the same
|
||||
// for the caller!
|
||||
results->hasNext = HasPrevIterationCallback;
|
||||
results->next = PrevIterationCallback;
|
||||
}
|
||||
else {
|
||||
results->hasNext = HasNextIterationCallback;
|
||||
results->next = NextIterationCallback;
|
||||
}
|
||||
|
||||
SkiplistIndex_findHelper(skiplistIndex, indexOperator, &(results->_intervals));
|
||||
|
||||
size_t const n = TRI_LengthVector(&results->_intervals);
|
||||
|
||||
// Finally initialise _cursor if the result is not empty:
|
||||
if (0 < n) {
|
||||
if (reverse) {
|
||||
// start at last interval, right endpoint
|
||||
results->_currentInterval = n - 1;
|
||||
auto tmp = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AtVector(&results->_intervals, n - 1));
|
||||
results->_cursor = tmp->_rightEndPoint;
|
||||
}
|
||||
else {
|
||||
// start at first interval, left endpoint
|
||||
auto tmp = static_cast<TRI_skiplist_iterator_interval_t*>(TRI_AtVector(&results->_intervals, 0));
|
||||
results->_cursor = tmp->_leftEndPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the memory used by the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t SkiplistIndex_memoryUsage (SkiplistIndex const* skiplistIndex) {
|
||||
return sizeof(SkiplistIndex) +
|
||||
skiplistIndex->skiplist->memoryUsage() +
|
||||
static_cast<size_t>(skiplistIndex->skiplist->getNrUsed()) * SkiplistIndex_ElementSize(skiplistIndex);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -43,91 +43,22 @@
|
|||
struct TRI_doc_mptr_t;
|
||||
struct TRI_document_collection_t;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- skiplistIndex public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
triagens::basics::SkipList* skiplist;
|
||||
bool unique;
|
||||
struct TRI_document_collection_t* _collection;
|
||||
size_t _numFields;
|
||||
}
|
||||
SkiplistIndex;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Iterator structure for skip list. We require a start and stop node
|
||||
///
|
||||
/// Intervals are open in the sense that both end points are not members
|
||||
/// of the interval. This means that one has to use SkipList::nextNode
|
||||
/// on the start node to get the first element and that the stop node
|
||||
/// can be NULL. Note that it is ensured that all intervals in an iterator
|
||||
/// are non-empty.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct TRI_skiplist_iterator_s {
|
||||
SkiplistIndex* _index;
|
||||
TRI_vector_t _intervals;
|
||||
size_t _currentInterval; // starts with 0, current interval used
|
||||
triagens::basics::SkipListNode* _cursor;
|
||||
// always holds the last node returned, initially equal to
|
||||
// the _leftEndPoint of the first interval (or the
|
||||
// _rightEndPoint of the last interval in the reverse
|
||||
// case), can be nullptr if there are no intervals
|
||||
// (yet), or, in the reverse case, if the cursor is
|
||||
// at the end of the last interval. Additionally
|
||||
// in the non-reverse case _cursor is set to nullptr
|
||||
// if the cursor is exhausted.
|
||||
// See SkiplistNextIterationCallback and
|
||||
// SkiplistPrevIterationCallback for the exact
|
||||
// condition for the iterator to be exhausted.
|
||||
bool (*hasNext) (struct TRI_skiplist_iterator_s const*);
|
||||
TRI_index_element_t* (*next)(struct TRI_skiplist_iterator_s*);
|
||||
}
|
||||
TRI_skiplist_iterator_t;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- skiplistIndex public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Free a skiplist iterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_FreeSkiplistIterator (TRI_skiplist_iterator_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys a skip list index and frees the pointer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkiplistIndex_free (SkiplistIndex*);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
// Skiplist indices, both unique and non-unique
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
SkiplistIndex* SkiplistIndex_new (struct TRI_document_collection_t*,
|
||||
size_t, bool, bool);
|
||||
|
||||
TRI_skiplist_iterator_t* SkiplistIndex_find (SkiplistIndex*,
|
||||
TRI_index_operator_t const*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the memory used by the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t SkiplistIndex_memoryUsage (SkiplistIndex const*);
|
||||
size_t SkiplistIndex_memoryUsage (triagens::arango::SkiplistIndex2 const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the memory size of a skiplist index element
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline size_t SkiplistIndex_ElementSize (SkiplistIndex const* idx) {
|
||||
return sizeof(TRI_doc_mptr_t*) + (sizeof(TRI_shaped_sub_t) * idx->_numFields);
|
||||
}
|
||||
size_t SkiplistIndex_ElementSize (triagens::arango::SkiplistIndex2 const* idx);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue