mirror of https://gitee.com/bigwinds/arangodb
a bit of index cleanup
This commit is contained in:
parent
cae493f060
commit
2fdf65c3a4
|
@ -48,10 +48,7 @@ static std::vector<std::vector<arangodb::basics::AttributeName>> const IndexAttr
|
|||
{{arangodb::basics::AttributeName("_from", false)},
|
||||
{arangodb::basics::AttributeName("_to", false)}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief hashes an edge key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static uint64_t HashElementKey(void*, VPackSlice const* key) {
|
||||
TRI_ASSERT(key != nullptr);
|
||||
// we can get away with the fast hash function here, as edge
|
||||
|
@ -59,10 +56,7 @@ static uint64_t HashElementKey(void*, VPackSlice const* key) {
|
|||
return SimpleIndexElement::hash(*key);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief hashes an edge
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static uint64_t HashElementEdge(void*, SimpleIndexElement const& element, bool byKey) {
|
||||
if (byKey) {
|
||||
return element.hash();
|
||||
|
@ -72,10 +66,7 @@ static uint64_t HashElementEdge(void*, SimpleIndexElement const& element, bool b
|
|||
return fasthash64(&revisionId, sizeof(revisionId), 0x56781234);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks if key and element match
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualKeyEdge(void* userData, VPackSlice const* left, SimpleIndexElement const& right) {
|
||||
TRI_ASSERT(left != nullptr);
|
||||
IndexLookupContext* context = static_cast<IndexLookupContext*>(userData);
|
||||
|
@ -90,18 +81,12 @@ static bool IsEqualKeyEdge(void* userData, VPackSlice const* left, SimpleIndexEl
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks for elements are equal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualElementEdge(void*, SimpleIndexElement const& left, SimpleIndexElement const& right) {
|
||||
return left.revisionId() == right.revisionId();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks for elements are equal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualElementEdgeByKey(void* userData, SimpleIndexElement const& left, SimpleIndexElement const& right) {
|
||||
IndexLookupContext* context = static_cast<IndexLookupContext*>(userData);
|
||||
try {
|
||||
|
@ -429,10 +414,7 @@ void EdgeIndex::buildSearchValueFromArray(TRI_edge_direction_e dir,
|
|||
builder.close();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a selectivity estimate for the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double EdgeIndex::selectivityEstimate() const {
|
||||
if (_edgesFrom == nullptr ||
|
||||
_edgesTo == nullptr ||
|
||||
|
@ -448,20 +430,14 @@ double EdgeIndex::selectivityEstimate() const {
|
|||
return estimate;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the memory usage for the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t EdgeIndex::memory() const {
|
||||
TRI_ASSERT(_edgesFrom != nullptr);
|
||||
TRI_ASSERT(_edgesTo != nullptr);
|
||||
return _edgesFrom->memoryUsage() + _edgesTo->memoryUsage();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EdgeIndex::toVelocyPack(VPackBuilder& builder, bool withFigures) const {
|
||||
Index::toVelocyPack(builder, withFigures);
|
||||
|
||||
|
@ -470,10 +446,7 @@ void EdgeIndex::toVelocyPack(VPackBuilder& builder, bool withFigures) const {
|
|||
builder.add("sparse", VPackValue(false));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index figures
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EdgeIndex::toVelocyPackFigures(VPackBuilder& builder) const {
|
||||
Index::toVelocyPackFigures(builder);
|
||||
builder.add("buckets", VPackValue(_numBuckets));
|
||||
|
@ -576,10 +549,7 @@ int EdgeIndex::unload() {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief provides a size hint for the edge index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int EdgeIndex::sizeHint(arangodb::Transaction* trx, size_t size) {
|
||||
// we assume this is called when setting up the index and the index
|
||||
// is still empty
|
||||
|
@ -604,10 +574,7 @@ int EdgeIndex::sizeHint(arangodb::Transaction* trx, size_t size) {
|
|||
return _edgesTo->resize(&context, size + 2049);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks whether the index supports the condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool EdgeIndex::supportsFilterCondition(
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
|
@ -618,10 +585,7 @@ bool EdgeIndex::supportsFilterCondition(
|
|||
estimatedCost);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given Condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* EdgeIndex::iteratorForCondition(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -662,10 +626,7 @@ IndexIterator* EdgeIndex::iteratorForCondition(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specializes the condition for use with the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* EdgeIndex::specializeCondition(
|
||||
arangodb::aql::AstNode* node,
|
||||
arangodb::aql::Variable const* reference) const {
|
||||
|
@ -674,12 +635,9 @@ arangodb::aql::AstNode* EdgeIndex::specializeCondition(
|
|||
return matcher.specializeOne(this, node, reference);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Transform the list of search slices to search values.
|
||||
/// This will multiply all IN entries and simply return all other
|
||||
/// entries.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EdgeIndex::expandInSearchValues(VPackSlice const slice,
|
||||
VPackBuilder& builder) const {
|
||||
TRI_ASSERT(slice.isArray());
|
||||
|
@ -711,7 +669,6 @@ void EdgeIndex::expandInSearchValues(VPackSlice const slice,
|
|||
}
|
||||
builder.close();
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given VelocyPackSlices.
|
||||
/// The searchValue is a an Array with exactly two Entries.
|
||||
/// If the first is set it means we are searching for _from (OUTBOUND),
|
||||
|
@ -726,8 +683,6 @@ void EdgeIndex::expandInSearchValues(VPackSlice const slice,
|
|||
/// Reverse is not supported, hence ignored
|
||||
/// NOTE: The iterator is only valid as long as the slice points to
|
||||
/// a valid memory region.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* EdgeIndex::iteratorForSlice(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -771,10 +726,7 @@ IndexIterator* EdgeIndex::iteratorForSlice(
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the iterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* EdgeIndex::createEqIterator(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -798,10 +750,7 @@ IndexIterator* EdgeIndex::createEqIterator(
|
|||
return new EdgeIndexIterator(_collection, trx, mmdr, this, isFrom ? _edgesFrom : _edgesTo, keys);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the iterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* EdgeIndex::createInIterator(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -832,10 +781,7 @@ IndexIterator* EdgeIndex::createInIterator(
|
|||
return new EdgeIndexIterator(_collection, trx, mmdr, this, isFrom ? _edgesFrom : _edgesTo, keys);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a single value node to the iterator's keys
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EdgeIndex::handleValNode(VPackBuilder* keys,
|
||||
arangodb::aql::AstNode const* valNode) const {
|
||||
if (!valNode->isStringValue() || valNode->getStringLength() == 0) {
|
||||
|
|
|
@ -118,10 +118,7 @@ class EdgeIndex final : public Index {
|
|||
arangodb::velocypack::Builder&);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief typedef for hash tables
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public:
|
||||
IndexType type() const override {
|
||||
return Index::TRI_IDX_TYPE_EDGE_INDEX;
|
||||
|
@ -172,16 +169,12 @@ class EdgeIndex final : public Index {
|
|||
arangodb::aql::AstNode* specializeCondition(
|
||||
arangodb::aql::AstNode*, arangodb::aql::Variable const*) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Transform the list of search slices to search values.
|
||||
/// This will multiply all IN entries and simply return all other
|
||||
/// entries.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void expandInSearchValues(arangodb::velocypack::Slice const,
|
||||
arangodb::velocypack::Builder&) const override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given VelocyPackSlices.
|
||||
/// The searchValue is a an Array with exactly two Entries, one of them
|
||||
/// has to be NONE.
|
||||
|
@ -195,8 +188,6 @@ class EdgeIndex final : public Index {
|
|||
/// Reverse is not supported, hence ignored
|
||||
/// NOTE: The iterator is only valid as long as the slice points to
|
||||
/// a valid memory region.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* iteratorForSlice(arangodb::Transaction*,
|
||||
ManagedDocumentResult*,
|
||||
arangodb::velocypack::Slice const,
|
||||
|
|
|
@ -34,11 +34,8 @@
|
|||
|
||||
using namespace arangodb;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief walk over the attribute. Also Extract sub-attributes and elements in
|
||||
/// list.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ExtractWords(std::vector<std::string>& words,
|
||||
VPackSlice const value,
|
||||
size_t minWordLength,
|
||||
|
@ -116,10 +113,7 @@ size_t FulltextIndex::memory() const {
|
|||
return TRI_MemoryFulltextIndex(_fulltextIndex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FulltextIndex::toVelocyPack(VPackBuilder& builder,
|
||||
bool withFigures) const {
|
||||
Index::toVelocyPack(builder, withFigures);
|
||||
|
@ -250,11 +244,8 @@ int FulltextIndex::cleanup() {
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief callback function called by the fulltext index to determine the
|
||||
/// words to index for a specific document
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> FulltextIndex::wordlist(VPackSlice const& doc) {
|
||||
std::vector<std::string> words;
|
||||
try {
|
||||
|
|
|
@ -95,22 +95,13 @@ class FulltextIndex final : public Index {
|
|||
std::vector<std::string> wordlist(arangodb::velocypack::Slice const&);
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the indexed attribute (path)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> _attr;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the fulltext index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_fts_index_t* _fulltextIndex;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief minimum word length
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _minWordLength;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -82,10 +82,7 @@ GeoIndex::~GeoIndex() {
|
|||
|
||||
size_t GeoIndex::memory() const { return GeoIndex_MemoryUsage(_geoIndex); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a JSON representation of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GeoIndex::toVelocyPack(VPackBuilder& builder, bool withFigures) const {
|
||||
// Basic index
|
||||
Index::toVelocyPack(builder, withFigures);
|
||||
|
@ -326,10 +323,7 @@ GeoCoordinates* GeoIndex::withinQuery(arangodb::Transaction* trx, double lat,
|
|||
return GeoIndex_PointsWithinRadius(_geoIndex, &gc, radius);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief looks up the nearest points
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeoCoordinates* GeoIndex::nearQuery(arangodb::Transaction* trx, double lat,
|
||||
double lon, size_t count) const {
|
||||
GeoCoordinate gc;
|
||||
|
|
|
@ -48,10 +48,7 @@ class GeoIndex final : public Index {
|
|||
~GeoIndex();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief geo index variants
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum IndexVariant {
|
||||
INDEX_GEO_NONE = 0,
|
||||
INDEX_GEO_INDIVIDUAL_LAT_LON,
|
||||
|
@ -90,17 +87,11 @@ class GeoIndex final : public Index {
|
|||
|
||||
int unload() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief looks up all points within a given radius
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeoCoordinates* withinQuery(arangodb::Transaction*, double, double,
|
||||
double) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief looks up the nearest points
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeoCoordinates* nearQuery(arangodb::Transaction*, double, double,
|
||||
size_t) const;
|
||||
|
||||
|
@ -124,31 +115,19 @@ class GeoIndex final : public Index {
|
|||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief attribute paths
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> _location;
|
||||
std::vector<std::string> _latitude;
|
||||
std::vector<std::string> _longitude;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the geo index variant (geo1 or geo2)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexVariant _variant;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether the index is a geoJson index (latitude / longitude
|
||||
/// reversed)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _geoJson;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the actual geo index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeoIdx* _geoIndex;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -203,10 +203,7 @@ void LookupBuilder::buildNextSearchValue() {
|
|||
_builder->close(); // End of search Array
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if two elements are equal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualElementElementUnique(void*,
|
||||
HashIndexElement const* left,
|
||||
HashIndexElement const* right) {
|
||||
|
@ -214,10 +211,7 @@ static bool IsEqualElementElementUnique(void*,
|
|||
return left->revisionId() == right->revisionId();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if two elements are equal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualElementElementMulti(void* userData,
|
||||
HashIndexElement const* left,
|
||||
HashIndexElement const* right) {
|
||||
|
@ -247,18 +241,12 @@ static bool IsEqualElementElementMulti(void* userData,
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief given a key generates a hash integer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static uint64_t HashKey(void*, VPackSlice const* key) {
|
||||
return HashIndexElement::hash(*key);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if a key corresponds to an element
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualKeyElementMulti(void* userData,
|
||||
VPackSlice const* left,
|
||||
HashIndexElement const* right) {
|
||||
|
@ -283,10 +271,7 @@ static bool IsEqualKeyElementMulti(void* userData,
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if a key corresponds to an element
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualKeyElementUnique(void* userData, VPackSlice const* left,
|
||||
uint64_t, HashIndexElement const* right) {
|
||||
return IsEqualKeyElementMulti(userData, left, right);
|
||||
|
@ -429,10 +414,7 @@ void HashIndexIteratorVPack::reset() {
|
|||
_iterator.reset();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the unique array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HashIndex::UniqueArray::UniqueArray(
|
||||
size_t numPaths,
|
||||
TRI_HashArray_t* hashArray, HashElementFunc* hashElement,
|
||||
|
@ -446,10 +428,7 @@ HashIndex::UniqueArray::UniqueArray(
|
|||
TRI_ASSERT(_isEqualElElByKey != nullptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy the unique array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HashIndex::UniqueArray::~UniqueArray() {
|
||||
if (_hashArray != nullptr) {
|
||||
auto cb = [this](HashIndexElement* element) -> bool {
|
||||
|
@ -463,10 +442,7 @@ HashIndex::UniqueArray::~UniqueArray() {
|
|||
delete _isEqualElElByKey;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the multi array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HashIndex::MultiArray::MultiArray(size_t numPaths,
|
||||
TRI_HashArrayMulti_t* hashArray,
|
||||
HashElementFunc* hashElement,
|
||||
|
@ -480,10 +456,7 @@ HashIndex::MultiArray::MultiArray(size_t numPaths,
|
|||
TRI_ASSERT(_isEqualElElByKey != nullptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy the multi array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HashIndex::MultiArray::~MultiArray() {
|
||||
if (_hashArray != nullptr) {
|
||||
auto cb = [this](HashIndexElement* element) -> bool {
|
||||
|
@ -536,10 +509,7 @@ HashIndex::HashIndex(TRI_idx_iid_t iid, LogicalCollection* collection,
|
|||
func.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HashIndex::~HashIndex() {
|
||||
if (_unique) {
|
||||
delete _uniqueArray;
|
||||
|
@ -548,10 +518,7 @@ HashIndex::~HashIndex() {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a selectivity estimate for the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double HashIndex::selectivityEstimate() const {
|
||||
if (_unique) {
|
||||
return 1.0;
|
||||
|
@ -568,10 +535,7 @@ double HashIndex::selectivityEstimate() const {
|
|||
return estimate;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the index memory usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t HashIndex::memory() const {
|
||||
size_t elementSize = HashIndexElement::baseMemoryUsage(_paths.size());
|
||||
|
||||
|
@ -584,20 +548,14 @@ size_t HashIndex::memory() const {
|
|||
_multiArray->_hashArray->memoryUsage());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a velocypack representation of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HashIndex::toVelocyPack(VPackBuilder& builder, bool withFigures) const {
|
||||
Index::toVelocyPack(builder, withFigures);
|
||||
builder.add("unique", VPackValue(_unique));
|
||||
builder.add("sparse", VPackValue(_sparse));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a velocypack representation of the index figures
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void HashIndex::toVelocyPackFigures(VPackBuilder& builder) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
builder.add("memory", VPackValue(memory()));
|
||||
|
@ -682,10 +640,7 @@ int HashIndex::insert(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
|||
return insertMulti(trx, revisionId, doc, isRollback);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes an entry from the hash array part of the hash index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int HashIndex::remove(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
||||
VPackSlice const& doc, bool isRollback) {
|
||||
std::vector<HashIndexElement*> elements;
|
||||
|
@ -736,10 +691,7 @@ int HashIndex::unload() {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief provides a size hint for the hash index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int HashIndex::sizeHint(arangodb::Transaction* trx, size_t size) {
|
||||
if (_sparse) {
|
||||
// for sparse indexes, we assume that we will have less index entries
|
||||
|
@ -757,10 +709,7 @@ int HashIndex::sizeHint(arangodb::Transaction* trx, size_t size) {
|
|||
return _multiArray->_hashArray->resize(&context, size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief locates entries in the hash index given VelocyPack slices
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int HashIndex::lookup(arangodb::Transaction* trx,
|
||||
VPackSlice key,
|
||||
std::vector<HashIndexElement*>& documents) const {
|
||||
|
@ -1017,10 +966,7 @@ int HashIndex::removeMultiElement(arangodb::Transaction* trx,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks whether the index supports the condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HashIndex::supportsFilterCondition(
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
|
@ -1031,10 +977,7 @@ bool HashIndex::supportsFilterCondition(
|
|||
estimatedCost);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given Condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* HashIndex::iteratorForCondition(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -1046,10 +989,7 @@ IndexIterator* HashIndex::iteratorForCondition(
|
|||
return new HashIndexIterator(_collection, trx, mmdr, this, node, reference);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given VelocyPackSlices
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* HashIndex::iteratorForSlice(arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
VPackSlice const searchValues,
|
||||
|
@ -1065,10 +1005,7 @@ IndexIterator* HashIndex::iteratorForSlice(arangodb::Transaction* trx,
|
|||
return new HashIndexIteratorVPack(_collection, trx, mmdr, this, keys);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specializes the condition for use with the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* HashIndex::specializeCondition(
|
||||
arangodb::aql::AstNode* node,
|
||||
arangodb::aql::Variable const* reference) const {
|
||||
|
|
|
@ -39,18 +39,12 @@
|
|||
#include <velocypack/Slice.h>
|
||||
#include <velocypack/velocypack-aliases.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief hash index query parameter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
class HashIndex;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Class to build Slice lookups out of AST Conditions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class LookupBuilder {
|
||||
private:
|
||||
TransactionBuilderLeaser _builder;
|
||||
|
@ -84,10 +78,7 @@ class LookupBuilder {
|
|||
class HashIndexIterator final : public IndexIterator {
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Construct an HashIndexIterator based on Ast Conditions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HashIndexIterator(LogicalCollection* collection, arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
HashIndex const* index,
|
||||
|
@ -114,10 +105,7 @@ class HashIndexIterator final : public IndexIterator {
|
|||
class HashIndexIteratorVPack final : public IndexIterator {
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Construct an HashIndexIterator based on VelocyPack
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HashIndexIteratorVPack(LogicalCollection* collection,
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -196,14 +184,11 @@ class HashIndex final : public PathBasedIndex {
|
|||
arangodb::aql::Variable const*,
|
||||
bool) const override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given VelocyPackSlices
|
||||
/// Each slice represents the field at the same position. (order matters)
|
||||
/// And each slice has to be an object of one of the following types:
|
||||
/// 1) {"eq": <compareValue>} // The value in index is exactly this
|
||||
/// 2) {"in": <compareValues>} // The value in index os one of them
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* iteratorForSlice(arangodb::Transaction*,
|
||||
ManagedDocumentResult*,
|
||||
arangodb::velocypack::Slice const,
|
||||
|
@ -237,10 +222,7 @@ class HashIndex final : public PathBasedIndex {
|
|||
arangodb::aql::Variable const* reference,
|
||||
std::unordered_set<size_t>& found) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief given an element generates a hash integer
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
class HashElementFunc {
|
||||
public:
|
||||
|
@ -259,10 +241,7 @@ class HashIndex final : public PathBasedIndex {
|
|||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if a key corresponds to an element
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class IsEqualElementElementByKey {
|
||||
size_t _numFields;
|
||||
|
||||
|
@ -296,10 +275,7 @@ class HashIndex final : public PathBasedIndex {
|
|||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the actual hash index (unique type)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef arangodb::basics::AssocUnique<arangodb::velocypack::Slice,
|
||||
HashIndexElement*> TRI_HashArray_t;
|
||||
|
||||
|
@ -316,10 +292,7 @@ class HashIndex final : public PathBasedIndex {
|
|||
size_t _numPaths;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the actual hash index (multi type)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef arangodb::basics::AssocMulti<arangodb::velocypack::Slice,
|
||||
HashIndexElement*, uint32_t,
|
||||
false> TRI_HashArrayMulti_t;
|
||||
|
|
|
@ -66,11 +66,8 @@ Index::Index(TRI_idx_iid_t iid, arangodb::LogicalCollection* collection,
|
|||
setFields(fields, Index::allowExpansion(Index::type(slice.get("type").copyString())));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an index stub with a hard-coded selectivity estimate
|
||||
/// this is used in the cluster coordinator case
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Index::Index(VPackSlice const& slice)
|
||||
: _iid(arangodb::basics::StringUtils::uint64(
|
||||
arangodb::basics::VelocyPackHelper::checkAndGetStringValue(slice,
|
||||
|
@ -166,10 +163,7 @@ Index::IndexType Index::type(std::string const& type) {
|
|||
return Index::type(type.c_str());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the name of an index type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char const* Index::typeName(Index::IndexType type) {
|
||||
switch (type) {
|
||||
case TRI_IDX_TYPE_PRIMARY_INDEX:
|
||||
|
@ -195,10 +189,7 @@ char const* Index::typeName(Index::IndexType type) {
|
|||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate an index id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Index::validateId(char const* key) {
|
||||
char const* p = key;
|
||||
|
||||
|
@ -217,10 +208,7 @@ bool Index::validateId(char const* key) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate an index handle (collection name + / + index id)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Index::validateHandle(char const* key, size_t* split) {
|
||||
char const* p = key;
|
||||
char c = *p;
|
||||
|
@ -261,17 +249,11 @@ bool Index::validateHandle(char const* key, size_t* split) {
|
|||
return validateId(p);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate a new index id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_idx_iid_t Index::generateId() { return TRI_NewTickServer(); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief index comparator, used by the coordinator to detect if two index
|
||||
/// contents are the same
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Index::Compare(VPackSlice const& lhs, VPackSlice const& rhs) {
|
||||
VPackSlice lhsType = lhs.get("type");
|
||||
TRI_ASSERT(lhsType.isString());
|
||||
|
@ -363,10 +345,7 @@ bool Index::Compare(VPackSlice const& lhs, VPackSlice const& rhs) {
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a contextual string for logging
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string Index::context() const {
|
||||
std::ostringstream result;
|
||||
|
||||
|
@ -386,11 +365,8 @@ std::string Index::context() const {
|
|||
return result.str();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a VelocyPack representation of the index
|
||||
/// base functionality (called from derived classes)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::shared_ptr<VPackBuilder> Index::toVelocyPack(bool withFigures) const {
|
||||
auto builder = std::make_shared<VPackBuilder>();
|
||||
builder->openObject();
|
||||
|
@ -399,12 +375,9 @@ std::shared_ptr<VPackBuilder> Index::toVelocyPack(bool withFigures) const {
|
|||
return builder;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a VelocyPack representation of the index
|
||||
/// base functionality (called from derived classes)
|
||||
/// note: needs an already-opened object as its input!
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Index::toVelocyPack(VPackBuilder& builder, bool withFigures) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
builder.add("id", VPackValue(std::to_string(_iid)));
|
||||
|
@ -430,11 +403,8 @@ void Index::toVelocyPack(VPackBuilder& builder, bool withFigures) const {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a VelocyPack representation of the index figures
|
||||
/// base functionality (called from derived classes)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::shared_ptr<VPackBuilder> Index::toVelocyPackFigures() const {
|
||||
auto builder = std::make_shared<VPackBuilder>();
|
||||
builder->openObject();
|
||||
|
@ -443,11 +413,8 @@ std::shared_ptr<VPackBuilder> Index::toVelocyPackFigures() const {
|
|||
return builder;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a VelocyPack representation of the index figures
|
||||
/// base functionality (called from derived classes)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Index::toVelocyPackFigures(VPackBuilder& builder) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
builder.add("memory", VPackValue(memory()));
|
||||
|
@ -514,6 +481,13 @@ double Index::selectivityEstimate() const {
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/// @brief default implementation for implicitlyUnique
|
||||
bool Index::implicitlyUnique() const {
|
||||
// simply return whether the index actually is unique
|
||||
// in this base class, we cannot do anything else
|
||||
return _unique;
|
||||
}
|
||||
|
||||
/// @brief default implementation for selectivityEstimate
|
||||
int Index::batchInsert(arangodb::Transaction*, std::vector<std::pair<TRI_voc_rid_t, VPackSlice>> const&, size_t) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
|
||||
|
@ -567,10 +541,7 @@ bool Index::supportsSortCondition(arangodb::aql::SortCondition const*,
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default iterator factory method. does not create an iterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* Index::iteratorForCondition(arangodb::Transaction*,
|
||||
ManagedDocumentResult*,
|
||||
arangodb::aql::AstNode const*,
|
||||
|
@ -581,19 +552,13 @@ IndexIterator* Index::iteratorForCondition(arangodb::Transaction*,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specializes the condition for use with the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* Index::specializeCondition(
|
||||
arangodb::aql::AstNode* node, arangodb::aql::Variable const*) const {
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief perform some base checks for an index condition part
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Index::canUseConditionPart(arangodb::aql::AstNode const* access,
|
||||
arangodb::aql::AstNode const* other,
|
||||
arangodb::aql::AstNode const* op,
|
||||
|
@ -716,7 +681,6 @@ bool Index::canUseConditionPart(arangodb::aql::AstNode const* access,
|
|||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Transform the list of search slices to search values.
|
||||
/// Always expects a list of lists as input.
|
||||
/// Outer list represents the single lookups, inner list represents the
|
||||
|
@ -726,8 +690,6 @@ bool Index::canUseConditionPart(arangodb::aql::AstNode const* access,
|
|||
/// Example: Index on (a, b)
|
||||
/// Input: [ [{=: 1}, {in: 2,3}], [{=:2}, {=:3}]
|
||||
/// Result: [ [{=: 1}, {=: 2}],[{=:1}, {=:3}], [{=:2}, {=:3}]]
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Index::expandInSearchValues(VPackSlice const base,
|
||||
VPackBuilder& result) const {
|
||||
TRI_ASSERT(base.isArray());
|
||||
|
@ -819,19 +781,13 @@ void Index::expandInSearchValues(VPackSlice const base,
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief append the index description to an output stream
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, arangodb::Index const* index) {
|
||||
stream << index->context();
|
||||
return stream;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief append the index description to an output stream
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, arangodb::Index const& index) {
|
||||
stream << index.context();
|
||||
return stream;
|
||||
|
|
|
@ -72,10 +72,7 @@ class Index {
|
|||
virtual ~Index();
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief index types
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum IndexType {
|
||||
TRI_IDX_TYPE_UNKNOWN = 0,
|
||||
TRI_IDX_TYPE_PRIMARY_INDEX,
|
||||
|
@ -98,10 +95,7 @@ class Index {
|
|||
return _fields;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the index fields names
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::vector<std::vector<std::string>> fieldNames() const {
|
||||
std::vector<std::vector<std::string>> result;
|
||||
|
||||
|
@ -115,10 +109,7 @@ class Index {
|
|||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the ith attribute is expanded (somewhere)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool isAttributeExpanded(size_t i) const {
|
||||
if (i >= _fields.size()) {
|
||||
return false;
|
||||
|
@ -126,10 +117,7 @@ class Index {
|
|||
return TRI_AttributeNamesHaveExpansion(_fields[i]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not any attribute is expanded
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool isAttributeExpanded(
|
||||
std::vector<arangodb::basics::AttributeName> const& attribute) const {
|
||||
for (auto const& it : _fields) {
|
||||
|
@ -222,14 +210,21 @@ class Index {
|
|||
|
||||
virtual bool matchesDefinition(arangodb::velocypack::Slice const&) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the index is sorted
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual bool isSorted() const = 0;
|
||||
|
||||
/// @brief whether or not the index has a selectivity estimate
|
||||
virtual bool hasSelectivityEstimate() const = 0;
|
||||
|
||||
/// @brief return the selectivity estimate of the index
|
||||
/// must only be called if hasSelectivityEstimate() returns true
|
||||
virtual double selectivityEstimate() const;
|
||||
|
||||
/// @brief whether or not the index is implicitly unique
|
||||
/// this can be the case if the index is not declared as unique, but contains a
|
||||
/// unique attribute such as _key
|
||||
virtual bool implicitlyUnique() const;
|
||||
|
||||
virtual size_t memory() const = 0;
|
||||
|
||||
virtual void toVelocyPack(arangodb::velocypack::Builder&, bool) const;
|
||||
|
@ -286,12 +281,9 @@ class Index {
|
|||
std::unordered_set<std::string>& nonNullAttributes,
|
||||
bool) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Transform the list of search slices to search values.
|
||||
/// This will multiply all IN entries and simply return all other
|
||||
/// entries.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void expandInSearchValues(arangodb::velocypack::Slice const,
|
||||
arangodb::velocypack::Builder&) const;
|
||||
|
||||
|
|
|
@ -43,26 +43,17 @@ IndexIterator::IndexIterator(LogicalCollection* collection,
|
|||
TRI_ASSERT(_mmdr != nullptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default destructor. Does not free anything
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator::~IndexIterator() {
|
||||
if (_responsible) {
|
||||
delete _mmdr;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default implementation for next
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult IndexIterator::next() { return IndexLookupResult(); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default implementation for nextBabies
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IndexIterator::nextBabies(std::vector<IndexLookupResult>& result, size_t batchSize) {
|
||||
result.clear();
|
||||
|
||||
|
@ -81,16 +72,10 @@ void IndexIterator::nextBabies(std::vector<IndexLookupResult>& result, size_t ba
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default implementation for reset
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IndexIterator::reset() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief default implementation for skip
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IndexIterator::skip(uint64_t count, uint64_t& skipped) {
|
||||
// Skip the first count-many entries
|
||||
// TODO: Can be improved
|
||||
|
@ -100,12 +85,9 @@ void IndexIterator::skip(uint64_t count, uint64_t& skipped) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element
|
||||
/// If one iterator is exhausted, the next one is used.
|
||||
/// A nullptr indicates that all iterators are exhausted
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult MultiIndexIterator::next() {
|
||||
if (_current == nullptr) {
|
||||
return IndexLookupResult();
|
||||
|
@ -123,12 +105,9 @@ IndexLookupResult MultiIndexIterator::next() {
|
|||
return next;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next limit many elements
|
||||
/// If one iterator is exhausted, the next one will be used.
|
||||
/// An empty result vector indicates that all iterators are exhausted
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MultiIndexIterator::nextBabies(std::vector<IndexLookupResult>& result, size_t limit) {
|
||||
result.clear();
|
||||
|
||||
|
@ -147,11 +126,8 @@ void MultiIndexIterator::nextBabies(std::vector<IndexLookupResult>& result, size
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
/// This will reset ALL internal iterators and start all over again
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MultiIndexIterator::reset() {
|
||||
_current = _iterators.at(0);
|
||||
_currentIdx = 0;
|
||||
|
|
|
@ -36,11 +36,8 @@ class Index;
|
|||
class LogicalCollection;
|
||||
class Transaction;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a base class to iterate over the index. An iterator is requested
|
||||
/// at the index itself
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class IndexIterator {
|
||||
public:
|
||||
IndexIterator(IndexIterator const&) = delete;
|
||||
|
@ -72,10 +69,7 @@ class IndexIterator {
|
|||
bool _responsible;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Special iterator if the condition cannot have any result
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EmptyIndexIterator final : public IndexIterator {
|
||||
public:
|
||||
EmptyIndexIterator(LogicalCollection* collection, arangodb::Transaction* trx, ManagedDocumentResult* mmdr, arangodb::Index const* index)
|
||||
|
@ -96,14 +90,11 @@ class EmptyIndexIterator final : public IndexIterator {
|
|||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a wrapper class to iterate over several IndexIterators.
|
||||
/// Each iterator is requested at the index itself.
|
||||
/// This iterator does NOT check for uniqueness.
|
||||
/// Will always start with the first iterator in the vector. Reverse them
|
||||
/// Outside if necessary.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class MultiIndexIterator final : public IndexIterator {
|
||||
|
||||
public:
|
||||
|
@ -126,27 +117,18 @@ class MultiIndexIterator final : public IndexIterator {
|
|||
|
||||
char const* typeName() const override { return "multi-index-iterator"; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element
|
||||
/// If one iterator is exhausted, the next one is used.
|
||||
/// A nullptr indicates that all iterators are exhausted
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult next() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get at most the next limit many elements
|
||||
/// If one iterator is exhausted, the next one will be used.
|
||||
/// An empty result vector indicates that all iterators are exhausted
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void nextBabies(std::vector<IndexLookupResult>&, size_t) override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
/// This will reset ALL internal iterators and start all over again
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void reset() override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -31,6 +31,10 @@
|
|||
|
||||
using namespace arangodb;
|
||||
|
||||
/// @brief the _key attribute, which, when used in an index, will implictly make it unique
|
||||
static std::vector<arangodb::basics::AttributeName> const KeyAttribute
|
||||
{arangodb::basics::AttributeName("_key", false)};
|
||||
|
||||
arangodb::aql::AstNode const* PathBasedIndex::PermutationState::getValue()
|
||||
const {
|
||||
if (type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||
|
@ -46,10 +50,7 @@ arangodb::aql::AstNode const* PathBasedIndex::PermutationState::getValue()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PathBasedIndex::PathBasedIndex(TRI_idx_iid_t iid,
|
||||
arangodb::LogicalCollection* collection,
|
||||
VPackSlice const& info, bool allowPartialIndex)
|
||||
|
@ -70,16 +71,36 @@ PathBasedIndex::PathBasedIndex(TRI_idx_iid_t iid,
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PathBasedIndex::~PathBasedIndex() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper function to insert a document into any index type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the index is implicitly unique
|
||||
/// this can be the case if the index is not declared as unique, but contains a
|
||||
/// unique attribute such as _key
|
||||
bool PathBasedIndex::implicitlyUnique() const {
|
||||
if (_unique) {
|
||||
// a unique index is always unique
|
||||
return true;
|
||||
}
|
||||
if (_useExpansion) {
|
||||
// when an expansion such as a[*] is used, the index may not be unique, even
|
||||
// if it contains attributes that are guaranteed to be unique
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto const& it : _fields) {
|
||||
// if _key is contained in the index fields definition, then the index is
|
||||
// implicitly unique
|
||||
if (it == KeyAttribute) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// _key not contained
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief helper function to insert a document into any index type
|
||||
template<typename T>
|
||||
int PathBasedIndex::fillElement(std::vector<T*>& elements,
|
||||
TRI_voc_rid_t revisionId,
|
||||
|
@ -162,10 +183,7 @@ int PathBasedIndex::fillElement(std::vector<T*>& elements,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper function to create the sole index value insert
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<VPackSlice, uint32_t>> PathBasedIndex::buildIndexValue(
|
||||
VPackSlice const documentSlice) {
|
||||
size_t const n = _paths.size();
|
||||
|
@ -192,10 +210,7 @@ std::vector<std::pair<VPackSlice, uint32_t>> PathBasedIndex::buildIndexValue(
|
|||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper function to create a set of index combinations to insert
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathBasedIndex::buildIndexValues(
|
||||
VPackSlice const document, size_t level,
|
||||
std::vector<std::vector<std::pair<VPackSlice, uint32_t>>>& toInsert,
|
||||
|
@ -311,10 +326,7 @@ void PathBasedIndex::buildIndexValues(
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper function to transform AttributeNames into strings.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathBasedIndex::fillPaths(std::vector<std::vector<std::string>>& paths,
|
||||
std::vector<int>& expanding) {
|
||||
paths.clear();
|
||||
|
|
|
@ -73,15 +73,14 @@ class PathBasedIndex : public Index {
|
|||
return _paths;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the attribute paths, a -1 entry means none is expanding,
|
||||
/// otherwise the non-negative number is the index of the expanding one.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<int> const& expanding() const {
|
||||
return _expanding;
|
||||
}
|
||||
|
||||
bool implicitlyUnique() const override;
|
||||
|
||||
protected:
|
||||
/// @brief helper function to insert a document into any index type
|
||||
template<typename T>
|
||||
|
@ -97,43 +96,25 @@ class PathBasedIndex : public Index {
|
|||
void fillPaths(std::vector<std::vector<std::string>>& paths,
|
||||
std::vector<int>& expanding);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper function to create a set of index combinations to insert
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::pair<VPackSlice, uint32_t>> buildIndexValue(VPackSlice const documentSlice);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper function to create a set of index combinations to insert
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void buildIndexValues(VPackSlice const document, size_t level,
|
||||
std::vector<std::vector<std::pair<VPackSlice, uint32_t>>>& toInsert,
|
||||
std::vector<std::pair<VPackSlice, uint32_t>>& sliceStack);
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the attribute paths
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::vector<std::string>> _paths;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ... and which of them expands
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<int> _expanding;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not at least one attribute is expanded
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _useExpansion;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not partial indexing is allowed
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool _allowPartialIndex;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -56,10 +56,7 @@ static inline uint64_t HashElement(void*, SimpleIndexElement const& element) {
|
|||
return element.hash();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if a key corresponds to an element
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualKeyElement(void* userData, uint8_t const* key,
|
||||
uint64_t hash,
|
||||
SimpleIndexElement const& right) {
|
||||
|
@ -75,10 +72,7 @@ static bool IsEqualKeyElement(void* userData, uint8_t const* key,
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if two elements are equal
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualElementElement(void* userData, SimpleIndexElement const& left,
|
||||
SimpleIndexElement const& right) {
|
||||
IndexLookupContext* context = static_cast<IndexLookupContext*>(userData);
|
||||
|
@ -216,24 +210,15 @@ PrimaryIndex::~PrimaryIndex() {
|
|||
delete _primaryIndex;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the number of documents from the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t PrimaryIndex::size() const { return _primaryIndex->size(); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the memory usage of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t PrimaryIndex::memory() const {
|
||||
return _primaryIndex->memoryUsage();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PrimaryIndex::toVelocyPack(VPackBuilder& builder, bool withFigures) const {
|
||||
Index::toVelocyPack(builder, withFigures);
|
||||
// hard-coded
|
||||
|
@ -312,14 +297,11 @@ SimpleIndexElement* PrimaryIndex::lookupKeyRef(arangodb::Transaction* trx,
|
|||
return element;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a method to iterate over all elements in the index in
|
||||
/// a sequential order.
|
||||
/// Returns nullptr if all documents have been returned.
|
||||
/// Convention: position === 0 indicates a new start.
|
||||
/// DEPRECATED
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SimpleIndexElement PrimaryIndex::lookupSequential(
|
||||
arangodb::Transaction* trx, arangodb::basics::BucketPosition& position,
|
||||
uint64_t& total) {
|
||||
|
@ -328,36 +310,27 @@ SimpleIndexElement PrimaryIndex::lookupSequential(
|
|||
return _primaryIndex->findSequential(&context, position, total);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request an iterator over all elements in the index in
|
||||
/// a sequential order.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* PrimaryIndex::allIterator(arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
bool reverse) const {
|
||||
return new AllIndexIterator(_collection, trx, mmdr, this, _primaryIndex, reverse);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request an iterator over all elements in the index in
|
||||
/// a random order. It is guaranteed that each element is found
|
||||
/// exactly once unless the collection is modified.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* PrimaryIndex::anyIterator(arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr) const {
|
||||
return new AnyIndexIterator(_collection, trx, mmdr, this, _primaryIndex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a method to iterate over all elements in the index in
|
||||
/// reversed sequential order.
|
||||
/// Returns nullptr if all documents have been returned.
|
||||
/// Convention: position === UINT64_MAX indicates a new start.
|
||||
/// DEPRECATED
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SimpleIndexElement PrimaryIndex::lookupSequentialReverse(
|
||||
arangodb::Transaction* trx, arangodb::basics::BucketPosition& position) {
|
||||
ManagedDocumentResult result(trx);
|
||||
|
@ -365,11 +338,8 @@ SimpleIndexElement PrimaryIndex::lookupSequentialReverse(
|
|||
return _primaryIndex->findSequentialReverse(&context, position);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds a key/element to the index
|
||||
/// returns a status code, and *found will contain a found element (if any)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int PrimaryIndex::insertKey(arangodb::Transaction* trx, TRI_voc_rid_t revisionId, VPackSlice const& doc) {
|
||||
ManagedDocumentResult result(trx);
|
||||
IndexLookupContext context(trx, _collection, &result, 1);
|
||||
|
@ -385,10 +355,7 @@ int PrimaryIndex::insertKey(arangodb::Transaction* trx, TRI_voc_rid_t revisionId
|
|||
return _primaryIndex->insert(&context, element);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes an key/element from the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int PrimaryIndex::removeKey(arangodb::Transaction* trx,
|
||||
TRI_voc_rid_t revisionId, VPackSlice const& doc) {
|
||||
ManagedDocumentResult result(trx);
|
||||
|
@ -418,10 +385,7 @@ int PrimaryIndex::removeKey(arangodb::Transaction* trx,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief resizes the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int PrimaryIndex::resize(arangodb::Transaction* trx, size_t targetSize) {
|
||||
ManagedDocumentResult result(trx);
|
||||
IndexLookupContext context(trx, _collection, &result, 1);
|
||||
|
@ -438,10 +402,7 @@ void PrimaryIndex::invokeOnAllElementsForRemoval(
|
|||
_primaryIndex->invokeOnAllElementsForRemoval(work);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks whether the index supports the condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PrimaryIndex::supportsFilterCondition(
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
|
@ -452,10 +413,7 @@ bool PrimaryIndex::supportsFilterCondition(
|
|||
estimatedCost);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given Condition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* PrimaryIndex::iteratorForCondition(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -494,10 +452,7 @@ IndexIterator* PrimaryIndex::iteratorForCondition(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates an IndexIterator for the given slice
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* PrimaryIndex::iteratorForSlice(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -513,10 +468,7 @@ IndexIterator* PrimaryIndex::iteratorForSlice(
|
|||
return new PrimaryIndexIterator(_collection, trx, mmdr, this, keys);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specializes the condition for use with the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* PrimaryIndex::specializeCondition(
|
||||
arangodb::aql::AstNode* node,
|
||||
arangodb::aql::Variable const* reference) const {
|
||||
|
@ -525,10 +477,7 @@ arangodb::aql::AstNode* PrimaryIndex::specializeCondition(
|
|||
return matcher.specializeOne(this, node, reference);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the iterator, for a single attribute, IN operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* PrimaryIndex::createInIterator(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -561,10 +510,7 @@ IndexIterator* PrimaryIndex::createInIterator(
|
|||
return new PrimaryIndexIterator(_collection, trx, mmdr, this, keys);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the iterator, for a single attribute, EQ operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* PrimaryIndex::createEqIterator(
|
||||
arangodb::Transaction* trx,
|
||||
ManagedDocumentResult* mmdr,
|
||||
|
@ -588,10 +534,7 @@ IndexIterator* PrimaryIndex::createEqIterator(
|
|||
return new PrimaryIndexIterator(_collection, trx, mmdr, this, keys);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a single value node to the iterator's keys
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PrimaryIndex::handleValNode(arangodb::Transaction* trx,
|
||||
VPackBuilder* keys,
|
||||
arangodb::aql::AstNode const* valNode,
|
||||
|
|
|
@ -156,41 +156,29 @@ class PrimaryIndex final : public Index {
|
|||
SimpleIndexElement* lookupKeyRef(arangodb::Transaction*, VPackSlice const&) const;
|
||||
SimpleIndexElement* lookupKeyRef(arangodb::Transaction*, VPackSlice const&, ManagedDocumentResult&) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a method to iterate over all elements in the index in
|
||||
/// a sequential order.
|
||||
/// Returns nullptr if all documents have been returned.
|
||||
/// Convention: position === 0 indicates a new start.
|
||||
/// DEPRECATED
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SimpleIndexElement lookupSequential(arangodb::Transaction*,
|
||||
arangodb::basics::BucketPosition& position,
|
||||
uint64_t& total);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request an iterator over all elements in the index in
|
||||
/// a sequential order.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* allIterator(arangodb::Transaction*, ManagedDocumentResult*, bool reverse) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request an iterator over all elements in the index in
|
||||
/// a random order. It is guaranteed that each element is found
|
||||
/// exactly once unless the collection is modified.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* anyIterator(arangodb::Transaction*, ManagedDocumentResult*) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief a method to iterate over all elements in the index in
|
||||
/// reversed sequential order.
|
||||
/// Returns nullptr if all documents have been returned.
|
||||
/// Convention: position === UINT64_MAX indicates a new start.
|
||||
/// DEPRECATED
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SimpleIndexElement lookupSequentialReverse(
|
||||
arangodb::Transaction*, arangodb::basics::BucketPosition& position);
|
||||
|
||||
|
@ -225,30 +213,21 @@ class PrimaryIndex final : public Index {
|
|||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the iterator, for a single attribute, IN operator
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* createInIterator(
|
||||
arangodb::Transaction*,
|
||||
ManagedDocumentResult*,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::AstNode const*) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the iterator, for a single attribute, EQ operator
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexIterator* createEqIterator(
|
||||
arangodb::Transaction*,
|
||||
ManagedDocumentResult*,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::AstNode const*) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a single value node to the iterator's keys
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void handleValNode(arangodb::Transaction* trx,
|
||||
VPackBuilder* keys,
|
||||
arangodb::aql::AstNode const* valNode,
|
||||
|
|
|
@ -122,10 +122,7 @@ RocksDBIterator::RocksDBIterator(LogicalCollection* collection,
|
|||
reset();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RocksDBIterator::reset() {
|
||||
if (_reverse) {
|
||||
_probe = true;
|
||||
|
@ -138,10 +135,7 @@ void RocksDBIterator::reset() {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element in the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult RocksDBIterator::next() {
|
||||
auto comparator = RocksDBFeature::instance()->comparator();
|
||||
|
||||
|
@ -208,30 +202,21 @@ IndexLookupResult RocksDBIterator::next() {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RocksDBIndex::RocksDBIndex(TRI_idx_iid_t iid,
|
||||
arangodb::LogicalCollection* collection,
|
||||
arangodb::velocypack::Slice const& info)
|
||||
: PathBasedIndex(iid, collection, info, true),
|
||||
_db(RocksDBFeature::instance()->db()) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RocksDBIndex::~RocksDBIndex() {}
|
||||
|
||||
size_t RocksDBIndex::memory() const {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RocksDBIndex::toVelocyPack(VPackBuilder& builder,
|
||||
bool withFigures) const {
|
||||
Index::toVelocyPack(builder, withFigures);
|
||||
|
@ -239,19 +224,13 @@ void RocksDBIndex::toVelocyPack(VPackBuilder& builder,
|
|||
builder.add("sparse", VPackValue(_sparse));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index figures
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RocksDBIndex::toVelocyPackFigures(VPackBuilder& builder) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
builder.add("memory", VPackValue(memory()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inserts a document into the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int RocksDBIndex::insert(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
||||
VPackSlice const& doc, bool isRollback) {
|
||||
auto comparator = RocksDBFeature::instance()->comparator();
|
||||
|
@ -408,10 +387,7 @@ int RocksDBIndex::insert(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes a document from the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int RocksDBIndex::remove(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
||||
VPackSlice const& doc, bool isRollback) {
|
||||
std::vector<SkiplistIndexElement*> elements;
|
||||
|
@ -1070,10 +1046,7 @@ IndexIterator* RocksDBIndex::iteratorForCondition(
|
|||
return lookup(trx, mmdr, searchSlice, reverse);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specializes the condition for use with the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* RocksDBIndex::specializeCondition(
|
||||
arangodb::aql::AstNode* node,
|
||||
arangodb::aql::Variable const* reference) const {
|
||||
|
|
|
@ -53,10 +53,7 @@ class PrimaryIndex;
|
|||
class RocksDBIndex;
|
||||
class Transaction;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Iterator structure for RocksDB. We require a start and stop node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RocksDBIterator final : public IndexIterator {
|
||||
private:
|
||||
friend class RocksDBIndex;
|
||||
|
@ -77,16 +74,10 @@ class RocksDBIterator final : public IndexIterator {
|
|||
|
||||
char const* typeName() const override { return "rocksdb-index-iterator"; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element in the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult next() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void reset() override;
|
||||
|
||||
private:
|
||||
|
@ -167,13 +158,10 @@ class RocksDBIndex final : public PathBasedIndex {
|
|||
|
||||
int drop() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief attempts to locate an entry in the index
|
||||
///
|
||||
/// Warning: who ever calls this function is responsible for destroying
|
||||
/// the velocypack::Slice and the RocksDBIterator* results
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RocksDBIterator* lookup(arangodb::Transaction*,
|
||||
ManagedDocumentResult* mmdr,
|
||||
arangodb::velocypack::Slice const,
|
||||
|
@ -216,10 +204,7 @@ class RocksDBIndex final : public PathBasedIndex {
|
|||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the RocksDB instance
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
rocksdb::OptimisticTransactionDB* _db;
|
||||
|
||||
};
|
||||
|
|
|
@ -34,11 +34,8 @@ SimpleAttributeEqualityMatcher::SimpleAttributeEqualityMatcher(
|
|||
std::vector<std::vector<arangodb::basics::AttributeName>> const& attributes)
|
||||
: _attributes(attributes), _found() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief match a single of the attributes
|
||||
/// this is used for the primary index and the edge index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SimpleAttributeEqualityMatcher::matchOne(
|
||||
arangodb::Index const* index, arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
|
@ -66,7 +63,7 @@ bool SimpleAttributeEqualityMatcher::matchOne(
|
|||
if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op,
|
||||
reference, nonNullAttributes, false)) {
|
||||
// we can use the index
|
||||
// use slightly different cost calculation for IN that for EQ
|
||||
// use slightly different cost calculation for IN than for EQ
|
||||
calculateIndexCosts(index, itemsInIndex, estimatedItems, estimatedCost);
|
||||
estimatedItems *= op->getMember(1)->numMembers();
|
||||
estimatedCost *= op->getMember(1)->numMembers();
|
||||
|
@ -81,11 +78,8 @@ bool SimpleAttributeEqualityMatcher::matchOne(
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief match all of the attributes, in any order
|
||||
/// this is used for the hash index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SimpleAttributeEqualityMatcher::matchAll(
|
||||
arangodb::Index const* index, arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
|
@ -146,12 +140,9 @@ bool SimpleAttributeEqualityMatcher::matchAll(
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specialize the condition for the index
|
||||
/// this is used for the primary index and the edge index
|
||||
/// requires that a previous matchOne() returned true
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* SimpleAttributeEqualityMatcher::specializeOne(
|
||||
arangodb::Index const* index, arangodb::aql::AstNode* node,
|
||||
arangodb::aql::Variable const* reference) {
|
||||
|
@ -201,12 +192,9 @@ arangodb::aql::AstNode* SimpleAttributeEqualityMatcher::specializeOne(
|
|||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specialize the condition for the index
|
||||
/// this is used for the hash index
|
||||
/// requires that a previous matchAll() returned true
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* SimpleAttributeEqualityMatcher::specializeAll(
|
||||
arangodb::Index const* index, arangodb::aql::AstNode* node,
|
||||
arangodb::aql::Variable const* reference) {
|
||||
|
@ -271,23 +259,20 @@ arangodb::aql::AstNode* SimpleAttributeEqualityMatcher::specializeAll(
|
|||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determine the costs of using this index and the number of items
|
||||
/// that will return in average
|
||||
/// cost values have no special meaning, except that multiple cost values are
|
||||
/// comparable, and lower values mean lower costs
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SimpleAttributeEqualityMatcher::calculateIndexCosts(
|
||||
arangodb::Index const* index, size_t itemsInIndex, size_t& estimatedItems,
|
||||
double& estimatedCost) const {
|
||||
double equalityReductionFactor = 20.0;
|
||||
|
||||
if (index->unique()) {
|
||||
if (index->unique() || index->implicitlyUnique()) {
|
||||
// index is unique, and the condition covers all attributes
|
||||
// now use a low value for the costs
|
||||
estimatedItems = 1;
|
||||
estimatedCost = 0.95;
|
||||
estimatedCost = 0.95 - 0.02 * (index->fields().size() - 1);
|
||||
} else if (index->hasSelectivityEstimate()) {
|
||||
// use index selectivity estimate
|
||||
double estimate = index->selectivityEstimate();
|
||||
|
@ -320,10 +305,7 @@ void SimpleAttributeEqualityMatcher::calculateIndexCosts(
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the access fits
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SimpleAttributeEqualityMatcher::accessFitsIndex(
|
||||
arangodb::Index const* index, arangodb::aql::AstNode const* access,
|
||||
arangodb::aql::AstNode const* other, arangodb::aql::AstNode const* op,
|
||||
|
|
|
@ -42,68 +42,47 @@ class SimpleAttributeEqualityMatcher {
|
|||
std::vector<std::vector<arangodb::basics::AttributeName>> const&);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief match a single of the attributes
|
||||
/// this is used for the primary index and the edge index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool matchOne(arangodb::Index const*, arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&, double&);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief match all of the attributes, in any order
|
||||
/// this is used for the hash index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool matchAll(arangodb::Index const*, arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&, double&);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the condition parts that the index is responsible for
|
||||
/// this is used for the primary index and the edge index
|
||||
/// requires that a previous matchOne() returned true
|
||||
/// the caller must not free the returned AstNode*, as it belongs to the ast
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* getOne(arangodb::aql::Ast*, arangodb::Index const*,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specialize the condition for the index
|
||||
/// this is used for the primary index and the edge index
|
||||
/// requires that a previous matchOne() returned true
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* specializeOne(arangodb::Index const*,
|
||||
arangodb::aql::AstNode*,
|
||||
arangodb::aql::Variable const*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specialize the condition for the index
|
||||
/// this is used for the hash index
|
||||
/// requires that a previous matchAll() returned true
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* specializeAll(arangodb::Index const*,
|
||||
arangodb::aql::AstNode*,
|
||||
arangodb::aql::Variable const*);
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determine the costs of using this index and the number of items
|
||||
/// that will return in average
|
||||
/// cost values have no special meaning, except that multiple cost values are
|
||||
/// comparable, and lower values mean lower costs
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void calculateIndexCosts(arangodb::Index const*, size_t, size_t&,
|
||||
double&) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not the access fits
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool accessFitsIndex(arangodb::Index const*, arangodb::aql::AstNode const*,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::AstNode const*,
|
||||
|
@ -112,17 +91,11 @@ class SimpleAttributeEqualityMatcher {
|
|||
bool);
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief array of attributes used for comparisons
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::vector<arangodb::basics::AttributeName>> const& _attributes;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief an internal map to mark which condition parts were useful and
|
||||
/// covered by the index. Also contains the matching Node
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<size_t, arangodb::aql::AstNode const*> _found;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -74,10 +74,7 @@ static size_t sortWeight(arangodb::aql::AstNode const* node) {
|
|||
// lists: lexicographically and within each slot according to these rules.
|
||||
// ...........................................................................
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares a key with an element, version with proper types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CompareKeyElement(void* userData,
|
||||
VPackSlice const* left,
|
||||
SkiplistIndexElement const* right,
|
||||
|
@ -89,10 +86,7 @@ static int CompareKeyElement(void* userData,
|
|||
*left, right->slice(context, rightPosition), true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares elements, version with proper types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int CompareElementElement(void* userData,
|
||||
SkiplistIndexElement const* left,
|
||||
size_t leftPosition,
|
||||
|
@ -515,10 +509,7 @@ SkiplistIterator::SkiplistIterator(LogicalCollection* collection, arangodb::Tran
|
|||
reset(); // Initializes the cursor
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkiplistIterator::reset() {
|
||||
if (_reverse) {
|
||||
_cursor = _rightEndPoint;
|
||||
|
@ -527,10 +518,7 @@ void SkiplistIterator::reset() {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element in the skiplist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult SkiplistIterator::next() {
|
||||
if (_cursor == nullptr) {
|
||||
// We are exhausted already, sorry
|
||||
|
@ -576,11 +564,8 @@ SkiplistIterator2::SkiplistIterator2(LogicalCollection* collection, arangodb::Tr
|
|||
(!_intervals.empty() && _cursor != nullptr));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Checks if the interval is valid. It is declared invalid if
|
||||
/// one border is nullptr or the right is lower than left.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkiplistIterator2::intervalValid(void* userData, Node* left, Node* right) const {
|
||||
if (left == nullptr) {
|
||||
return false;
|
||||
|
@ -599,10 +584,7 @@ bool SkiplistIterator2::intervalValid(void* userData, Node* left, Node* right) c
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkiplistIterator2::reset() {
|
||||
// If _intervals is empty at this point
|
||||
// the cursor does not contain any
|
||||
|
@ -618,10 +600,7 @@ void SkiplistIterator2::reset() {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element in the skiplist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult SkiplistIterator2::next() {
|
||||
if (_cursor == nullptr) {
|
||||
// We are exhausted already, sorry
|
||||
|
@ -744,10 +723,7 @@ SkiplistIndex::SkiplistIndex(TRI_idx_iid_t iid,
|
|||
new TRI_Skiplist(CmpElmElm, CmpKeyElm, [this](SkiplistIndexElement* element) { element->free(); }, _unique, _useExpansion);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroy the skiplist index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkiplistIndex::~SkiplistIndex() { delete _skiplistIndex; }
|
||||
|
||||
size_t SkiplistIndex::memory() const {
|
||||
|
@ -755,10 +731,7 @@ size_t SkiplistIndex::memory() const {
|
|||
static_cast<size_t>(_skiplistIndex->getNrUsed()) * SkiplistIndexElement::baseMemoryUsage(_paths.size());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkiplistIndex::toVelocyPack(VPackBuilder& builder,
|
||||
bool withFigures) const {
|
||||
Index::toVelocyPack(builder, withFigures);
|
||||
|
@ -766,20 +739,14 @@ void SkiplistIndex::toVelocyPack(VPackBuilder& builder,
|
|||
builder.add("sparse", VPackValue(_sparse));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return a VelocyPack representation of the index figures
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkiplistIndex::toVelocyPackFigures(VPackBuilder& builder) const {
|
||||
TRI_ASSERT(builder.isOpenObject());
|
||||
builder.add("memory", VPackValue(memory()));
|
||||
_skiplistIndex->appendToVelocyPack(builder);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inserts a document into a skiplist index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SkiplistIndex::insert(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
||||
VPackSlice const& doc, bool isRollback) {
|
||||
std::vector<SkiplistIndexElement*> elements;
|
||||
|
@ -830,10 +797,7 @@ int SkiplistIndex::insert(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes a document from a skiplist index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SkiplistIndex::remove(arangodb::Transaction* trx, TRI_voc_rid_t revisionId,
|
||||
VPackSlice const& doc, bool isRollback) {
|
||||
std::vector<SkiplistIndexElement*> elements;
|
||||
|
@ -880,11 +844,8 @@ int SkiplistIndex::unload() {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Checks if the interval is valid. It is declared invalid if
|
||||
/// one border is nullptr or the right is lower than left.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkiplistIndex::intervalValid(void* userData, Node* left, Node* right) const {
|
||||
if (left == nullptr) {
|
||||
return false;
|
||||
|
@ -903,10 +864,7 @@ bool SkiplistIndex::intervalValid(void* userData, Node* left, Node* right) const
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares a key with an element in a skip list, generic callback
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SkiplistIndex::KeyElementComparator::operator()(void* userData,
|
||||
VPackSlice const* leftKey, SkiplistIndexElement const* rightElement) const {
|
||||
TRI_ASSERT(nullptr != leftKey);
|
||||
|
@ -928,10 +886,7 @@ int SkiplistIndex::KeyElementComparator::operator()(void* userData,
|
|||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief compares two elements in a skip list, this is the generic callback
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SkiplistIndex::ElementElementComparator::operator()(
|
||||
void* userData,
|
||||
SkiplistIndexElement const* leftElement,
|
||||
|
@ -1399,7 +1354,8 @@ bool SkiplistIndex::supportsFilterCondition(
|
|||
values = 1;
|
||||
}
|
||||
|
||||
if (attributesCoveredByEquality == _fields.size() && unique()) {
|
||||
if (attributesCoveredByEquality == _fields.size() &&
|
||||
(unique() || implicitlyUnique())) {
|
||||
// index is unique and condition covers all attributes by equality
|
||||
if (estimatedItems >= values) {
|
||||
// reduce costs due to uniqueness
|
||||
|
@ -1464,10 +1420,7 @@ bool SkiplistIndex::supportsSortCondition(
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief specializes the condition for use with the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
arangodb::aql::AstNode* SkiplistIndex::specializeCondition(
|
||||
arangodb::aql::AstNode* node,
|
||||
arangodb::aql::Variable const* reference) const {
|
||||
|
|
|
@ -158,7 +158,6 @@ class SkiplistInLookupBuilder : public BaseSkiplistLookupBuilder {
|
|||
void buildSearchValues();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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
|
||||
|
@ -166,8 +165,6 @@ class SkiplistInLookupBuilder : public BaseSkiplistLookupBuilder {
|
|||
/// 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 final : public IndexIterator {
|
||||
private:
|
||||
friend class SkiplistIndex;
|
||||
|
@ -198,20 +195,13 @@ class SkiplistIterator final : public IndexIterator {
|
|||
public:
|
||||
char const* typeName() const override { return "skiplist-index-iterator"; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element in the skiplist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult next() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void reset() override;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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
|
||||
|
@ -219,8 +209,6 @@ class SkiplistIterator final : public IndexIterator {
|
|||
/// 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 SkiplistIterator2 final : public IndexIterator {
|
||||
private:
|
||||
// Shorthand for the skiplist node
|
||||
|
@ -270,42 +258,27 @@ class SkiplistIterator2 final : public IndexIterator {
|
|||
|
||||
char const* typeName() const override { return "skiplist-index-iterator2"; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Get the next element in the skiplist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IndexLookupResult next() override;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Reset the cursor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void reset() override;
|
||||
|
||||
size_t numPaths() const { return _numPaths; }
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Initialize left and right endpoints with current lookup
|
||||
/// value. Also points the _cursor to the border of this interval.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initNextInterval();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Forward the cursor to the next interval. If there was no
|
||||
/// interval the next one is computed. If the _cursor has
|
||||
/// nullptr after this call the iterator is exhausted.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void forwardCursor();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Checks if the interval is valid. It is declared invalid if
|
||||
/// one border is nullptr or the right is lower than left.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool intervalValid(void*, Node*, Node*) const;
|
||||
};
|
||||
|
||||
|
@ -416,11 +389,8 @@ class SkiplistIndex final : public PathBasedIndex {
|
|||
arangodb::aql::AstNode const*, arangodb::aql::Variable const*,
|
||||
std::vector<std::vector<arangodb::aql::AstNode const*>>&, bool&) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Checks if the interval is valid. It is declared invalid if
|
||||
/// one border is nullptr or the right is lower than left.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Shorthand for the skiplist node
|
||||
typedef arangodb::basics::SkipListNode<VPackSlice,
|
||||
SkiplistIndexElement> Node;
|
||||
|
@ -433,10 +403,7 @@ class SkiplistIndex final : public PathBasedIndex {
|
|||
|
||||
KeyElementComparator CmpKeyElm;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the actual skiplist index
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_Skiplist* _skiplistIndex;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue