From 479f81f760abc3a36e697324c6a49237fff3cebc Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Fri, 21 Aug 2015 16:05:17 +0200 Subject: [PATCH 1/2] Buckets for hash-array, also C++-ize it. --- arangod/HashIndex/hash-array.cpp | 307 ++++++++++--------------------- arangod/HashIndex/hash-array.h | 183 ++++++++++++++---- arangod/Indexes/HashIndex.cpp | 31 ++-- arangod/Indexes/HashIndex.h | 2 +- arangod/Indexes/Index.h | 9 + 5 files changed, 276 insertions(+), 256 deletions(-) diff --git a/arangod/HashIndex/hash-array.cpp b/arangod/HashIndex/hash-array.cpp index ef39ea1e40..f089cfc01b 100644 --- a/arangod/HashIndex/hash-array.cpp +++ b/arangod/HashIndex/hash-array.cpp @@ -34,7 +34,6 @@ #include "Basics/fasthash.h" #include "Basics/logging.h" #include "Indexes/HashIndex.h" -#include "Indexes/Index.h" #include "VocBase/document-collection.h" #include "VocBase/VocShaper.h" @@ -46,12 +45,11 @@ /// @brief determines if a key corresponds to an element //////////////////////////////////////////////////////////////////////////////// -static bool IsEqualKeyElement (TRI_hash_array_t const* array, - TRI_index_search_value_t const* left, - TRI_index_element_t const* right) { +bool TRI_hash_array_t::isEqualKeyElement (TRI_index_search_value_t const* left, + TRI_index_element_t const* right) const { TRI_ASSERT_EXPENSIVE(right->document() != nullptr); - for (size_t j = 0; j < array->_numFields; ++j) { + for (size_t j = 0; j < _numFields; ++j) { TRI_shaped_json_t* leftJson = &left->_values[j]; TRI_shaped_sub_t* rightSub = &right->subObjects()[j]; @@ -81,11 +79,10 @@ static bool IsEqualKeyElement (TRI_hash_array_t const* array, /// @brief given a key generates a hash integer //////////////////////////////////////////////////////////////////////////////// -static uint64_t HashKey (TRI_hash_array_t const* array, - TRI_index_search_value_t const* key) { +uint64_t TRI_hash_array_t::hashKey (TRI_index_search_value_t const* key) const { uint64_t hash = 0x0123456789abcdef; - for (size_t j = 0; j < array->_numFields; ++j) { + for (size_t j = 0; j < _numFields; ++j) { // ignore the sid for hashing hash = fasthash64(key->_values[j]._data.data, key->_values[j]._data.length, hash); @@ -98,11 +95,10 @@ static uint64_t HashKey (TRI_hash_array_t const* array, /// @brief given an element generates a hash integer //////////////////////////////////////////////////////////////////////////////// -static uint64_t HashElement (TRI_hash_array_t* array, - TRI_index_element_t* element) { +uint64_t TRI_hash_array_t::hashElement (TRI_index_element_t const* element) const { uint64_t hash = 0x0123456789abcdef; - for (size_t j = 0; j < array->_numFields; j++) { + for (size_t j = 0; j < _numFields; j++) { char const* data; size_t length; TRI_InspectShapedSub(&element->subObjects()[j], element->document(), data, length); @@ -119,55 +115,20 @@ static uint64_t HashElement (TRI_hash_array_t* array, // --SECTION-- HASH ARRAY // ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// --SECTION-- private defines -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @brief initial preallocation size of the hash table when the table is -/// first created -/// setting this to a high value will waste memory but reduce the number of -/// reallocations/repositionings necessary when the table grows -//////////////////////////////////////////////////////////////////////////////// - -static inline uint64_t InitialSize () { - return 251; -} - // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief allocate memory for the hash table -//////////////////////////////////////////////////////////////////////////////// - -static int AllocateTable (TRI_hash_array_t* array, - uint64_t numElements) { - size_t const size = static_cast - (sizeof(TRI_index_element_t*) * numElements); - - TRI_index_element_t** table = static_cast(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, size, true)); - - if (table == nullptr) { - return TRI_ERROR_OUT_OF_MEMORY; - } - - array->_table = table; - array->_nrAlloc = numElements; - - return TRI_ERROR_NO_ERROR; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief resizes the array //////////////////////////////////////////////////////////////////////////////// -static int ResizeHashArray (triagens::arango::HashIndex* hashIndex, - TRI_hash_array_t* array, - uint64_t targetSize, - bool allowShrink) { - if (array->_nrAlloc >= targetSize && ! allowShrink) { +int TRI_hash_array_t::resizeInternal (triagens::arango::HashIndex* hashIndex, + Bucket& b, + uint64_t targetSize, + bool allowShrink) { + + if (b._nrAlloc >= targetSize && ! allowShrink) { return TRI_ERROR_NO_ERROR; } @@ -181,45 +142,45 @@ static int ResizeHashArray (triagens::arango::HashIndex* hashIndex, (unsigned long long) targetSize); } - TRI_index_element_t** oldTable = array->_table; - uint64_t oldAlloc = array->_nrAlloc; + TRI_index_element_t** oldTable = b._table; + uint64_t oldAlloc = b._nrAlloc; TRI_ASSERT(targetSize > 0); - int res = AllocateTable(array, targetSize); - - if (res != TRI_ERROR_NO_ERROR) { - return res; + try { + b._table = new TRI_index_element_t* [targetSize]; } + catch (...) { + return TRI_ERROR_OUT_OF_MEMORY; + } + b._nrAlloc = targetSize; - if (array->_nrUsed > 0) { - uint64_t const n = array->_nrAlloc; + if (b._nrUsed > 0) { + uint64_t const n = b._nrAlloc; for (uint64_t j = 0; j < oldAlloc; j++) { TRI_index_element_t* element = oldTable[j]; if (element != nullptr) { uint64_t i, k; - i = k = HashElement(array, element) % n; + i = k = hashElement(element) % n; - for (; i < n && array->_table[i] != nullptr; ++i); + for (; i < n && b._table[i] != nullptr; ++i); if (i == n) { - for (i = 0; i < k && array->_table[i] != nullptr; ++i); + for (i = 0; i < k && b._table[i] != nullptr; ++i); } - TRI_ASSERT_EXPENSIVE(i < n); - // ..................................................................... // add a new element to the associative array // memcpy ok here since are simply moving array items internally // ..................................................................... - array->_table[i] = element; + b._table[i] = element; } } } - TRI_Free(TRI_UNKNOWN_MEM_ZONE, oldTable); + delete [] oldTable; LOG_TIMER((TRI_microtime() - start), "index-resize %s, target size: %llu", @@ -233,10 +194,10 @@ static int ResizeHashArray (triagens::arango::HashIndex* hashIndex, /// @brief triggers a resize if necessary //////////////////////////////////////////////////////////////////////////////// -static bool CheckResize (triagens::arango::HashIndex* hashIndex, - TRI_hash_array_t* array) { - if (array->_nrAlloc < 2 * array->_nrUsed) { - int res = ResizeHashArray(hashIndex, array, 2 * array->_nrAlloc + 1, false); +bool TRI_hash_array_t::checkResize (triagens::arango::HashIndex* hashIndex, + Bucket& b) { + if (2 * b._nrAlloc < 3 * b._nrUsed) { + int res = resizeInternal(hashIndex, b, 2 * b._nrAlloc + 1, false); if (res != TRI_ERROR_NO_ERROR) { return false; @@ -246,59 +207,6 @@ static bool CheckResize (triagens::arango::HashIndex* hashIndex, return true; } -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @brief initialises an array -//////////////////////////////////////////////////////////////////////////////// - -int TRI_InitHashArray (TRI_hash_array_t* array, - size_t numFields) { - - TRI_ASSERT(numFields > 0); - - array->_numFields = numFields; - array->_table = nullptr; - array->_nrUsed = 0; - array->_nrAlloc = 0; - - return AllocateTable(array, InitialSize()); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief destroys an array, but does not free the pointer -//////////////////////////////////////////////////////////////////////////////// - -void TRI_DestroyHashArray (TRI_hash_array_t* array) { - if (array == nullptr) { - return; - } - - // ........................................................................... - // Go through each item in the array and remove any internal allocated memory - // ........................................................................... - - // array->_table might be NULL if array initialisation fails - if (array->_table != nullptr) { - TRI_index_element_t** p; - TRI_index_element_t** e; - - p = array->_table; - e = p + array->_nrAlloc; - - for (; p < e; ++p) { - auto item = *p; - if (item != nullptr) { - TRI_index_element_t::free(item); - } - } - - TRI_Free(TRI_UNKNOWN_MEM_ZONE, array->_table); - } -} - // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- @@ -307,71 +215,57 @@ void TRI_DestroyHashArray (TRI_hash_array_t* array) { /// @brief get the hash array's memory usage //////////////////////////////////////////////////////////////////////////////// -size_t TRI_MemoryUsageHashArray (TRI_hash_array_t const* array) { - if (array == nullptr) { - return 0; +size_t TRI_hash_array_t::memoryUsage () { + size_t sum = 0; + for (auto& b : _buckets) { + sum += (size_t) (b._nrAlloc * sizeof(TRI_index_element_t*)); } - - size_t tableSize = (size_t) (array->_nrAlloc * - sizeof(TRI_index_element_t*)); - size_t memberSize = (size_t) (array->_nrUsed * - (sizeof(TRI_index_element_t) + - array->_numFields * sizeof(TRI_shaped_sub_t))); - - return (size_t) (tableSize + memberSize); + return sum; } //////////////////////////////////////////////////////////////////////////////// /// @brief resizes the hash table //////////////////////////////////////////////////////////////////////////////// -int TRI_ResizeHashArray (triagens::arango::HashIndex* hashIndex, - TRI_hash_array_t* array, - size_t size) { - return ResizeHashArray(hashIndex, array, (uint64_t) (2 * size + 1), false); +int TRI_hash_array_t::resize (triagens::arango::HashIndex* hashIndex, + size_t size) { + int res = TRI_ERROR_NO_ERROR; + for (auto& b : _buckets) { + res = resizeInternal(hashIndex, b, + (uint64_t) (3 * size / 2 + 1) / _buckets.size(), + false); + if (res != TRI_ERROR_NO_ERROR) { + return res; + } + } + return res; } //////////////////////////////////////////////////////////////////////////////// /// @brief finds an element given a key, return NULL if not found //////////////////////////////////////////////////////////////////////////////// -TRI_index_element_t* TRI_LookupByKeyHashArray (TRI_hash_array_t const* array, - TRI_index_search_value_t* key) { - uint64_t const n = array->_nrAlloc; - uint64_t i, k; +TRI_index_element_t* TRI_hash_array_t::findByKey (TRI_index_search_value_t* key) const { + uint64_t i = hashKey(key); + Bucket const& b = _buckets[i & _bucketsMask]; - i = k = HashKey(array, key) % n; + uint64_t const n = b._nrAlloc; + i = i % n; + uint64_t k = i; - for (; i < n && array->_table[i] != nullptr && - ! IsEqualKeyElement(array, key, array->_table[i]); ++i); + for (; i < n && b._table[i] != nullptr && + ! isEqualKeyElement(key, b._table[i]); ++i); if (i == n) { - for (i = 0; i < k && array->_table[i] != nullptr && - ! IsEqualKeyElement(array, key, array->_table[i]); ++i); + for (i = 0; i < k && b._table[i] != nullptr && + ! isEqualKeyElement(key, b._table[i]); ++i); } - TRI_ASSERT_EXPENSIVE(i < n); - // ........................................................................... // return whatever we found, this is nullptr if the thing was not found // and otherwise a valid pointer // ........................................................................... - return array->_table[i]; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief finds an element given a key, return NULL if not found -//////////////////////////////////////////////////////////////////////////////// - -TRI_index_element_t* TRI_FindByKeyHashArray (TRI_hash_array_t const* array, - TRI_index_search_value_t* key) { - TRI_index_element_t* element = TRI_LookupByKeyHashArray(array, key); - - if (element != nullptr && IsEqualKeyElement(array, key, element)) { - return element; - } - - return nullptr; + return b._table[i]; } //////////////////////////////////////////////////////////////////////////////// @@ -381,35 +275,33 @@ TRI_index_element_t* TRI_FindByKeyHashArray (TRI_hash_array_t const* array, /// element. //////////////////////////////////////////////////////////////////////////////// -int TRI_InsertKeyHashArray (triagens::arango::HashIndex* hashIndex, - TRI_hash_array_t* array, - TRI_index_search_value_t const* key, - TRI_index_element_t const* element, - bool isRollback) { - +int TRI_hash_array_t::insert (triagens::arango::HashIndex* hashIndex, + TRI_index_search_value_t const* key, + TRI_index_element_t const* element, + bool isRollback) { // ........................................................................... // we are adding and the table is more than half full, extend it // ........................................................................... - if (! CheckResize(hashIndex, array)) { + uint64_t i = hashKey(key); + Bucket& b = _buckets[i & _bucketsMask]; + + if (! checkResize(hashIndex, b)) { return TRI_ERROR_OUT_OF_MEMORY; } - const uint64_t n = array->_nrAlloc; - uint64_t i, k; + uint64_t const n = b._nrAlloc; + i = i % n; + uint64_t k = i; - i = k = HashKey(array, key) % n; - - for (; i < n && array->_table[i] != nullptr && - ! IsEqualKeyElement(array, key, array->_table[i]); ++i); + for (; i < n && b._table[i] != nullptr && + ! isEqualKeyElement(key, b._table[i]); ++i); if (i == n) { - for (i = 0; i < k && array->_table[i] != nullptr && - ! IsEqualKeyElement(array, key, array->_table[i]); ++i); + for (i = 0; i < k && b._table[i] != nullptr && + ! isEqualKeyElement(key, b._table[i]); ++i); } - TRI_ASSERT_EXPENSIVE(i < n); - - TRI_index_element_t* arrayElement = array->_table[i]; + TRI_index_element_t* arrayElement = b._table[i]; // ........................................................................... // if we found an element, return @@ -419,9 +311,9 @@ int TRI_InsertKeyHashArray (triagens::arango::HashIndex* hashIndex, return TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED; } - array->_table[i] = const_cast(element); - TRI_ASSERT(array->_table[i] != nullptr && array->_table[i]->document() != nullptr); - array->_nrUsed++; + b._table[i] = const_cast(element); + TRI_ASSERT(b._table[i] != nullptr && b._table[i]->document() != nullptr); + b._nrUsed++; return TRI_ERROR_NO_ERROR; } @@ -430,24 +322,23 @@ int TRI_InsertKeyHashArray (triagens::arango::HashIndex* hashIndex, /// @brief removes an element from the array //////////////////////////////////////////////////////////////////////////////// -int TRI_RemoveElementHashArray (triagens::arango::HashIndex* hashIndex, - TRI_hash_array_t* array, - TRI_index_element_t* element) { - uint64_t const n = array->_nrAlloc; - uint64_t i, k; +int TRI_hash_array_t::remove (triagens::arango::HashIndex* hashIndex, + TRI_index_element_t* element) { + uint64_t i = hashElement(element); + Bucket& b = _buckets[i & _bucketsMask]; - i = k = HashElement(array, element) % n; + uint64_t const n = b._nrAlloc; + i = i % n; + uint64_t k = i; - for (; i < n && array->_table[i] != nullptr && - element->document() != array->_table[i]->document(); ++i); + for (; i < n && b._table[i] != nullptr && + element->document() != b._table[i]->document(); ++i); if (i == n) { - for (i = 0; i < k && array->_table[i] != nullptr && - element->document() != array->_table[i]->document(); ++i); + for (i = 0; i < k && b._table[i] != nullptr && + element->document() != b._table[i]->document(); ++i); } - TRI_ASSERT_EXPENSIVE(i < n); - - TRI_index_element_t* arrayElement = array->_table[i]; + TRI_index_element_t* arrayElement = b._table[i]; // ........................................................................... // if we did not find such an item return error code @@ -463,8 +354,8 @@ int TRI_RemoveElementHashArray (triagens::arango::HashIndex* hashIndex, // ........................................................................... TRI_index_element_t::free(arrayElement); - array->_table[i] = nullptr; - array->_nrUsed--; + b._table[i] = nullptr; + b._nrUsed--; // ........................................................................... // and now check the following places for items to move closer together @@ -473,20 +364,20 @@ int TRI_RemoveElementHashArray (triagens::arango::HashIndex* hashIndex, k = TRI_IncModU64(i, n); - while (array->_table[k] != nullptr) { - uint64_t j = HashElement(array, array->_table[k]) % n; + while (b._table[k] != nullptr) { + uint64_t j = hashElement(b._table[k]) % n; if ((i < k && ! (i < j && j <= k)) || (k < i && ! (i < j || j <= k))) { - array->_table[i] = array->_table[k]; - array->_table[k] = nullptr; + b._table[i] = b._table[k]; + b._table[k] = nullptr; i = k; } k = TRI_IncModU64(k, n); } - if (array->_nrUsed == 0) { - ResizeHashArray(hashIndex, array, InitialSize(), true); + if (b._nrUsed == 0) { + resizeInternal (hashIndex, b, initialSize(), true); } return TRI_ERROR_NO_ERROR; diff --git a/arangod/HashIndex/hash-array.h b/arangod/HashIndex/hash-array.h index 4963004eb3..cd808594e2 100644 --- a/arangod/HashIndex/hash-array.h +++ b/arangod/HashIndex/hash-array.h @@ -33,13 +33,12 @@ #include "Basics/Common.h" +#include "Indexes/Index.h" + // ----------------------------------------------------------------------------- // --SECTION-- forward declarations // ----------------------------------------------------------------------------- -struct TRI_index_element_t; -struct TRI_index_search_value_s; - namespace triagens { namespace arango { class HashIndex; @@ -47,43 +46,151 @@ namespace triagens { } // ----------------------------------------------------------------------------- -// --SECTION-- public types +// --SECTION-- TRI_hash_array_t // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief associative array //////////////////////////////////////////////////////////////////////////////// -typedef struct TRI_hash_array_s { - size_t _numFields; // the number of fields indexes +class TRI_hash_array_t { + size_t _numFields; // the number of fields indexes - uint64_t _nrAlloc; // the size of the table - uint64_t _nrUsed; // the number of used entries + struct Bucket { - TRI_index_element_t** _table; // the table itself, aligned to a cache line boundary -} -TRI_hash_array_t; + uint64_t _nrAlloc; // the size of the table + uint64_t _nrUsed; // the number of used entries -// ----------------------------------------------------------------------------- -// --SECTION-- HASH ARRAY -// ----------------------------------------------------------------------------- + TRI_index_element_t** _table; // the table itself, aligned to a cache line boundary + }; + + std::vector _buckets; + size_t _bucketsMask; // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @brief initialises an array +/// @brief constructor //////////////////////////////////////////////////////////////////////////////// -int TRI_InitHashArray (TRI_hash_array_t*, - size_t); + public: + TRI_hash_array_t (size_t numFields, size_t numberBuckets = 1) + : _numFields(numFields) { + + // Make the number of buckets a power of two: + size_t ex = 0; + size_t nr = 1; + numberBuckets >>= 1; + while (numberBuckets > 0) { + ex += 1; + numberBuckets >>= 1; + nr <<= 1; + } + numberBuckets = nr; + _bucketsMask = nr - 1; + + try { + for (size_t j = 0; j < numberBuckets; j++) { + _buckets.emplace_back(); + Bucket& b = _buckets.back(); + b._nrAlloc = initialSize(); + b._table = nullptr; + + // may fail... + b._table = new TRI_index_element_t* [b._nrAlloc]; + + for (uint64_t i = 0; i < b._nrAlloc; i++) { + b._table[i] = nullptr; + } + } + } + catch (...) { + for (auto& b : _buckets) { + delete [] b._table; + b._table = nullptr; + b._nrAlloc = 0; + } + throw; + } + } //////////////////////////////////////////////////////////////////////////////// -/// @brief destroys an array, but does not free the pointer +/// @brief destructor //////////////////////////////////////////////////////////////////////////////// -void TRI_DestroyHashArray (TRI_hash_array_t*); + ~TRI_hash_array_t () { + for (auto& b : _buckets) { + for (size_t i = 0; i < b._nrAlloc; i++) { + TRI_index_element_t* p = b._table[i]; + if (p != nullptr) { + TRI_index_element_t::free(p); + } + } + delete [] b._table; + b._table = nullptr; + b._nrAlloc = 0; + } + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief adhere to the rule of five +//////////////////////////////////////////////////////////////////////////////// + + TRI_hash_array_t (TRI_hash_array_t const&) = delete; // copy constructor + TRI_hash_array_t (TRI_hash_array_t&&) = delete; // move constructor + TRI_hash_array_t& operator= (TRI_hash_array_t const&) = delete; // op = + TRI_hash_array_t& operator= (TRI_hash_array_t&&) = delete; // op = + +//////////////////////////////////////////////////////////////////////////////// +/// @brief initial preallocation size of the hash table when the table is +/// first created +/// setting this to a high value will waste memory but reduce the number of +/// reallocations/repositionings necessary when the table grows +//////////////////////////////////////////////////////////////////////////////// + + private: + + static uint64_t initialSize () { + return 251; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief determines if a key corresponds to an element +//////////////////////////////////////////////////////////////////////////////// + + bool isEqualKeyElement (TRI_index_search_value_t const* left, + TRI_index_element_t const* right) const; + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief given a key generates a hash integer +//////////////////////////////////////////////////////////////////////////////// + + uint64_t hashKey (TRI_index_search_value_t const* key) const; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief given an element generates a hash integer +//////////////////////////////////////////////////////////////////////////////// + + uint64_t hashElement (TRI_index_element_t const* element) const; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief resize the hash array +//////////////////////////////////////////////////////////////////////////////// + + int resizeInternal (triagens::arango::HashIndex* hashIndex, + Bucket& b, + uint64_t targetSize, + bool allowShrink); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a resize of the hash array +//////////////////////////////////////////////////////////////////////////////// + + bool checkResize (triagens::arango::HashIndex* hashIndex, + Bucket& b); // ----------------------------------------------------------------------------- // --SECTION-- public functions @@ -93,40 +200,50 @@ void TRI_DestroyHashArray (TRI_hash_array_t*); /// @brief get the hash array's memory usage //////////////////////////////////////////////////////////////////////////////// -size_t TRI_MemoryUsageHashArray (TRI_hash_array_t const*); + public: + size_t memoryUsage (); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the number of elements in the hash +//////////////////////////////////////////////////////////////////////////////// + + size_t size () { + size_t sum = 0; + for (auto& b : _buckets) { + sum += static_cast(b._nrUsed); + } + return sum; + } //////////////////////////////////////////////////////////////////////////////// /// @brief resizes the hash table //////////////////////////////////////////////////////////////////////////////// -int TRI_ResizeHashArray (triagens::arango::HashIndex*, - TRI_hash_array_t*, - size_t); + int resize (triagens::arango::HashIndex*, size_t); //////////////////////////////////////////////////////////////////////////////// /// @brief finds an element given a key, returns NULL if not found //////////////////////////////////////////////////////////////////////////////// -TRI_index_element_t* TRI_FindByKeyHashArray (TRI_hash_array_t const*, - struct TRI_index_search_value_s* key); + TRI_index_element_t* findByKey (TRI_index_search_value_t* key) const; //////////////////////////////////////////////////////////////////////////////// /// @brief adds an key/element to the array //////////////////////////////////////////////////////////////////////////////// -int TRI_InsertKeyHashArray (triagens::arango::HashIndex*, - TRI_hash_array_t*, - struct TRI_index_search_value_s const* key, - TRI_index_element_t const* element, - bool isRollback); + int insert (triagens::arango::HashIndex*, + TRI_index_search_value_t const* key, + TRI_index_element_t const* element, + bool isRollback); //////////////////////////////////////////////////////////////////////////////// /// @brief removes an element from the array //////////////////////////////////////////////////////////////////////////////// -int TRI_RemoveElementHashArray (triagens::arango::HashIndex*, - TRI_hash_array_t*, - TRI_index_element_t* element); + int remove (triagens::arango::HashIndex*, + TRI_index_element_t* element); + +}; #endif diff --git a/arangod/Indexes/HashIndex.cpp b/arangod/Indexes/HashIndex.cpp index a8dc05b695..a8d98ed8de 100644 --- a/arangod/Indexes/HashIndex.cpp +++ b/arangod/Indexes/HashIndex.cpp @@ -203,7 +203,7 @@ static TRI_vector_pointer_t HashIndex_find (TRI_hash_array_t const* hashArray, // to locate the hash array entry by key. // ............................................................................. - TRI_index_element_t* result = TRI_FindByKeyHashArray(hashArray, key); + TRI_index_element_t* result = hashArray->findByKey(key); if (result != nullptr) { // unique hash index: maximum number is 1 @@ -226,7 +226,7 @@ static int HashIndex_find (TRI_hash_array_t const* hashArray, // to locate the hash array entry by key. // ............................................................................. - TRI_index_element_t* found = TRI_FindByKeyHashArray(hashArray, key); + TRI_index_element_t* found = hashArray->findByKey(key); if (found != nullptr) { // unique hash index: maximum number is 1 @@ -258,9 +258,11 @@ HashIndex::HashIndex (TRI_idx_iid_t iid, TRI_ASSERT(iid != 0); if (unique) { - _hashArray._table = nullptr; - - if (TRI_InitHashArray(&_hashArray, paths.size()) != TRI_ERROR_NO_ERROR) { + _hashArray = nullptr; + try { + _hashArray = new TRI_hash_array_t(paths.size()); + } + catch (...) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); } } @@ -297,7 +299,8 @@ HashIndex::HashIndex (TRI_idx_iid_t iid, HashIndex::~HashIndex () { if (_unique) { - TRI_DestroyHashArray(&_hashArray); + delete _hashArray; + _hashArray = nullptr; } else { delete _multi._hashElement; @@ -326,8 +329,8 @@ double HashIndex::selectivityEstimate () const { size_t HashIndex::memory () const { if (_unique) { - return static_cast(keyEntrySize() * _hashArray._nrUsed + - TRI_MemoryUsageHashArray(&_hashArray)); + return static_cast(keyEntrySize() * _hashArray->size() + + _hashArray->memoryUsage()); } return static_cast(keyEntrySize() * _multi._hashArray->size() + @@ -380,7 +383,7 @@ int HashIndex::sizeHint (size_t size) { } if (_unique) { - return TRI_ResizeHashArray(this, &_hashArray, size); + return _hashArray->resize(this, size); } else { return _multi._hashArray->resize(size); @@ -395,7 +398,7 @@ int HashIndex::sizeHint (size_t size) { // FIXME: use std::vector here as well TRI_vector_pointer_t HashIndex::lookup (TRI_index_search_value_t* searchValue) const { if (_unique) { - return HashIndex_find(&_hashArray, searchValue); + return HashIndex_find(_hashArray, searchValue); } std::vector* results @@ -420,7 +423,7 @@ int HashIndex::lookup (TRI_index_search_value_t* searchValue, std::vector& documents) const { if (_unique) { - return HashIndex_find(&_hashArray, searchValue, documents); + return HashIndex_find(_hashArray, searchValue, documents); } std::vector* results = nullptr; @@ -456,7 +459,7 @@ int HashIndex::lookup (TRI_index_search_value_t* searchValue, if (_unique) { next = nullptr; - return HashIndex_find(&_hashArray, searchValue, documents); + return HashIndex_find(_hashArray, searchValue, documents); } std::vector* results = nullptr; @@ -529,7 +532,7 @@ int HashIndex::insertUnique (TRI_doc_mptr_t const* doc, return res; } - res = TRI_InsertKeyHashArray(this, &_hashArray, &key, element, isRollback); + res = _hashArray->insert(this, &key, element, isRollback); if (key._values != nullptr) { TRI_Free(TRI_UNKNOWN_MEM_ZONE, key._values); @@ -608,7 +611,7 @@ int HashIndex::removeUnique (TRI_doc_mptr_t const* doc, bool isRollback) { return TRI_ERROR_DEBUG; } - int res = TRI_RemoveElementHashArray(this, &_hashArray, element); + int res = _hashArray->remove (this, element); // this might happen when rolling back if (res == TRI_RESULT_ELEMENT_NOT_FOUND) { diff --git a/arangod/Indexes/HashIndex.h b/arangod/Indexes/HashIndex.h index 0dfd995437..28767421b6 100644 --- a/arangod/Indexes/HashIndex.h +++ b/arangod/Indexes/HashIndex.h @@ -267,7 +267,7 @@ namespace triagens { TRI_HashArrayMulti_t; union { - TRI_hash_array_t _hashArray; // the hash array itself, unique values + TRI_hash_array_t* _hashArray; // the hash array itself, unique values struct { TRI_HashArrayMulti_t* _hashArray; // the hash array itself, non-unique values HashElementFunc* _hashElement; // hash function for elements diff --git a/arangod/Indexes/Index.h b/arangod/Indexes/Index.h index febc4a69d2..40dfe47bdc 100644 --- a/arangod/Indexes/Index.h +++ b/arangod/Indexes/Index.h @@ -117,6 +117,15 @@ struct TRI_index_element_t { return new (space) TRI_index_element_t(); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief Memory usage of an index element +//////////////////////////////////////////////////////////////////////////////// + + static size_t memoryUsage (size_t numSubs) { + return sizeof(TRI_doc_mptr_t*) + + (sizeof(TRI_shaped_sub_t) * numSubs); + } + //////////////////////////////////////////////////////////////////////////////// /// @brief Free the index element. //////////////////////////////////////////////////////////////////////////////// From f7126d4974a9f5bcfd76670f3ba1932d95d44f2e Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Fri, 21 Aug 2015 16:21:18 +0200 Subject: [PATCH 2/2] Fix a typo. --- arangod/Indexes/HashIndex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arangod/Indexes/HashIndex.cpp b/arangod/Indexes/HashIndex.cpp index 7782e26434..46b53779d3 100644 --- a/arangod/Indexes/HashIndex.cpp +++ b/arangod/Indexes/HashIndex.cpp @@ -251,7 +251,7 @@ HashIndex::HashIndex (TRI_idx_iid_t iid, if (unique) { _hashArray = nullptr; try { - _hashArray = new TRI_hash_array_t(paths.size()); + _hashArray = new TRI_hash_array_t(_paths.size()); } catch (...) { THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);