mirror of https://gitee.com/bigwinds/arangodb
Started templatefying hash-array to AssocUnique
This commit is contained in:
parent
2dd0f7cf7f
commit
80e1f6decc
|
@ -32,7 +32,6 @@
|
||||||
#include "hash-array.h"
|
#include "hash-array.h"
|
||||||
|
|
||||||
#include "Basics/fasthash.h"
|
#include "Basics/fasthash.h"
|
||||||
#include "Basics/logging.h"
|
|
||||||
#include "Indexes/HashIndex.h"
|
#include "Indexes/HashIndex.h"
|
||||||
#include "VocBase/document-collection.h"
|
#include "VocBase/document-collection.h"
|
||||||
#include "VocBase/VocShaper.h"
|
#include "VocBase/VocShaper.h"
|
||||||
|
@ -111,277 +110,6 @@ uint64_t TRI_hash_array_t::hashElement (TRI_index_element_t const* element) cons
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- HASH ARRAY
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- private functions
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief resizes the array
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only log performance infos for indexes with more than this number of entries
|
|
||||||
static uint64_t const NotificationSizeThreshold = 131072;
|
|
||||||
|
|
||||||
double start = TRI_microtime();
|
|
||||||
if (targetSize > NotificationSizeThreshold) {
|
|
||||||
LOG_ACTION("index-resize %s, target size: %llu",
|
|
||||||
hashIndex->context().c_str(),
|
|
||||||
(unsigned long long) targetSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_index_element_t** oldTable = b._table;
|
|
||||||
uint64_t oldAlloc = b._nrAlloc;
|
|
||||||
|
|
||||||
TRI_ASSERT(targetSize > 0);
|
|
||||||
|
|
||||||
try {
|
|
||||||
b._table = new TRI_index_element_t* [targetSize];
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < targetSize; i++) {
|
|
||||||
b._table[i] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
return TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
b._nrAlloc = targetSize;
|
|
||||||
|
|
||||||
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(element) % n;
|
|
||||||
|
|
||||||
for (; i < n && b._table[i] != nullptr; ++i);
|
|
||||||
if (i == n) {
|
|
||||||
for (i = 0; i < k && b._table[i] != nullptr; ++i);
|
|
||||||
}
|
|
||||||
|
|
||||||
b._table[i] = element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete [] oldTable;
|
|
||||||
|
|
||||||
LOG_TIMER((TRI_microtime() - start),
|
|
||||||
"index-resize %s, target size: %llu",
|
|
||||||
hashIndex->context().c_str(),
|
|
||||||
(unsigned long long) targetSize);
|
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief triggers a resize if necessary
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- public functions
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief get the hash array's memory usage
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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*));
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief resizes the hash table
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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_hash_array_t::findByKey (TRI_index_search_value_t* key) const {
|
|
||||||
uint64_t i = hashKey(key);
|
|
||||||
Bucket const& b = _buckets[i & _bucketsMask];
|
|
||||||
|
|
||||||
uint64_t const n = b._nrAlloc;
|
|
||||||
i = i % n;
|
|
||||||
uint64_t k = i;
|
|
||||||
|
|
||||||
for (; i < n && b._table[i] != nullptr &&
|
|
||||||
! isEqualKeyElement(key, b._table[i]); ++i);
|
|
||||||
if (i == n) {
|
|
||||||
for (i = 0; i < k && b._table[i] != nullptr &&
|
|
||||||
! isEqualKeyElement(key, b._table[i]); ++i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// return whatever we found, this is nullptr if the thing was not found
|
|
||||||
// and otherwise a valid pointer
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
return b._table[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief adds an key/element to the array
|
|
||||||
///
|
|
||||||
/// This function claims the owenship of the sub-objects in the inserted
|
|
||||||
/// element.
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
uint64_t i = hashKey(key);
|
|
||||||
Bucket& b = _buckets[i & _bucketsMask];
|
|
||||||
|
|
||||||
if (! checkResize(hashIndex, b)) {
|
|
||||||
return TRI_ERROR_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t const n = b._nrAlloc;
|
|
||||||
i = i % n;
|
|
||||||
uint64_t k = i;
|
|
||||||
|
|
||||||
for (; i < n && b._table[i] != nullptr &&
|
|
||||||
! isEqualKeyElement(key, b._table[i]); ++i);
|
|
||||||
if (i == n) {
|
|
||||||
for (i = 0; i < k && b._table[i] != nullptr &&
|
|
||||||
! isEqualKeyElement(key, b._table[i]); ++i);
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_index_element_t* arrayElement = b._table[i];
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// if we found an element, return
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
if (arrayElement != nullptr) {
|
|
||||||
return TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED;
|
|
||||||
}
|
|
||||||
|
|
||||||
b._table[i] = const_cast<TRI_index_element_t*>(element);
|
|
||||||
TRI_ASSERT(b._table[i] != nullptr && b._table[i]->document() != nullptr);
|
|
||||||
b._nrUsed++;
|
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief removes an element from the array
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
TRI_index_element_t* TRI_hash_array_t::remove (
|
|
||||||
triagens::arango::HashIndex* hashIndex,
|
|
||||||
TRI_index_element_t* element) {
|
|
||||||
uint64_t i = hashElement(element);
|
|
||||||
Bucket& b = _buckets[i & _bucketsMask];
|
|
||||||
|
|
||||||
uint64_t const n = b._nrAlloc;
|
|
||||||
i = i % n;
|
|
||||||
uint64_t k = i;
|
|
||||||
|
|
||||||
for (; i < n && b._table[i] != nullptr &&
|
|
||||||
element->document() != b._table[i]->document(); ++i);
|
|
||||||
if (i == n) {
|
|
||||||
for (i = 0; i < k && b._table[i] != nullptr &&
|
|
||||||
element->document() != b._table[i]->document(); ++i);
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_index_element_t* old = b._table[i];
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// if we did not find such an item return error code
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
if (old == nullptr) {
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// remove item - destroy any internal memory associated with the
|
|
||||||
// element structure
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
b._table[i] = nullptr;
|
|
||||||
b._nrUsed--;
|
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// and now check the following places for items to move closer together
|
|
||||||
// so that there are no gaps in the array
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
k = TRI_IncModU64(i, 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))) {
|
|
||||||
b._table[i] = b._table[k];
|
|
||||||
b._table[k] = nullptr;
|
|
||||||
i = k;
|
|
||||||
}
|
|
||||||
|
|
||||||
k = TRI_IncModU64(k, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b._nrUsed == 0) {
|
|
||||||
resizeInternal (hashIndex, b, initialSize(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- END-OF-FILE
|
// --SECTION-- END-OF-FILE
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -32,28 +32,30 @@
|
||||||
#define ARANGODB_HASH_INDEX_HASH__ARRAY_H 1
|
#define ARANGODB_HASH_INDEX_HASH__ARRAY_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
#include "Basics/logging.h"
|
||||||
#include "Indexes/Index.h"
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- forward declarations
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace triagens {
|
namespace triagens {
|
||||||
namespace arango {
|
namespace basics {
|
||||||
class HashIndex;
|
// -----------------------------------------------------------------------------
|
||||||
}
|
// --SECTION-- UNIQUE ASSOCIATIVE POINTERS
|
||||||
}
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// --SECTION-- TRI_hash_array_t
|
/// @brief associative array
|
||||||
// -----------------------------------------------------------------------------
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template <class Key, class Element>
|
||||||
/// @brief associative array
|
class AssocUnique {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class TRI_hash_array_t {
|
public:
|
||||||
|
|
||||||
|
typedef std::function<uint64_t(Key const*)> HashKeyFuncType;
|
||||||
|
typedef std::function<uint64_t(Element const*, bool)> HashElementFuncType;
|
||||||
|
typedef std::function<bool(Key const*, Element const*)>
|
||||||
|
IsEqualKeyElementFuncType;
|
||||||
|
typedef std::function<void(Element*)> CallbackElementFuncType;
|
||||||
|
|
||||||
|
private:
|
||||||
size_t _numFields; // the number of fields indexes
|
size_t _numFields; // the number of fields indexes
|
||||||
|
|
||||||
struct Bucket {
|
struct Bucket {
|
||||||
|
@ -61,23 +63,38 @@ class TRI_hash_array_t {
|
||||||
uint64_t _nrAlloc; // the size of the table
|
uint64_t _nrAlloc; // the size of the table
|
||||||
uint64_t _nrUsed; // the number of used entries
|
uint64_t _nrUsed; // the number of used entries
|
||||||
|
|
||||||
TRI_index_element_t** _table; // the table itself, aligned to a cache line boundary
|
Element** _table; // the table itself, aligned to a cache line boundary
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Bucket> _buckets;
|
std::vector<Bucket> _buckets;
|
||||||
size_t _bucketsMask;
|
size_t _bucketsMask;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
HashKeyFuncType const _hashKey;
|
||||||
// --SECTION-- constructors and destructors
|
HashElementFuncType const _hashElement;
|
||||||
// -----------------------------------------------------------------------------
|
IsEqualKeyElementFuncType const _isEqualKeyElement;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
std::function<std::string()> _contextCallback;
|
||||||
/// @brief constructor
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- constructors and destructors
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TRI_hash_array_t (size_t numFields, size_t numberBuckets = 1)
|
AssocUnique (HashKeyFuncType hashKey,
|
||||||
: _numFields(numFields) {
|
HashElementFuncType hashElement,
|
||||||
|
IsEqualKeyElementFuncType isEqualKeyElement,
|
||||||
|
size_t numFields,
|
||||||
|
size_t numberBuckets = 1,
|
||||||
|
std::function<std::string()> contextCallback = [] () -> std::string { return ""; }) :
|
||||||
|
_numFields(numFields)
|
||||||
|
_hashKey(hashKey),
|
||||||
|
_hashElement(hashElement),
|
||||||
|
_isEqualKeyElement(isEqualKeyElement),
|
||||||
|
_contextCallback(contextCallback) {
|
||||||
|
|
||||||
// Make the number of buckets a power of two:
|
// Make the number of buckets a power of two:
|
||||||
size_t ex = 0;
|
size_t ex = 0;
|
||||||
|
@ -99,7 +116,7 @@ class TRI_hash_array_t {
|
||||||
b._table = nullptr;
|
b._table = nullptr;
|
||||||
|
|
||||||
// may fail...
|
// may fail...
|
||||||
b._table = new TRI_index_element_t* [b._nrAlloc];
|
b._table = new Element* [b._nrAlloc];
|
||||||
|
|
||||||
for (uint64_t i = 0; i < b._nrAlloc; i++) {
|
for (uint64_t i = 0; i < b._nrAlloc; i++) {
|
||||||
b._table[i] = nullptr;
|
b._table[i] = nullptr;
|
||||||
|
@ -116,11 +133,11 @@ class TRI_hash_array_t {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief destructor
|
/// @brief destructor
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
~TRI_hash_array_t () {
|
~AssocUnique () {
|
||||||
for (auto& b : _buckets) {
|
for (auto& b : _buckets) {
|
||||||
delete [] b._table;
|
delete [] b._table;
|
||||||
b._table = nullptr;
|
b._table = nullptr;
|
||||||
|
@ -128,27 +145,21 @@ class TRI_hash_array_t {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief adhere to the rule of five
|
/// @brief adhere to the rule of five
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TRI_hash_array_t (TRI_hash_array_t const&) = delete; // copy constructor
|
AssocUnique (AssocUnique const&) = delete; // copy constructor
|
||||||
TRI_hash_array_t (TRI_hash_array_t&&) = delete; // move constructor
|
AssocUnique (AssocUnique&&) = delete; // move constructor
|
||||||
TRI_hash_array_t& operator= (TRI_hash_array_t const&) = delete; // op =
|
AssocUnique& operator= (AssocUnique const&) = delete; // op =
|
||||||
TRI_hash_array_t& operator= (TRI_hash_array_t&&) = delete; // op =
|
AssocUnique& operator= (AssocUnique&&) = delete; // op =
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief a type for a generic callback to run over all elements
|
/// @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
|
||||||
typedef std::function<void(TRI_index_element_t*)> CallbackElementFuncType;
|
/// reallocations/repositionings necessary when the table grows
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @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:
|
private:
|
||||||
|
|
||||||
|
@ -156,56 +167,128 @@ class TRI_hash_array_t {
|
||||||
return 251;
|
return 251;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief determines if a key corresponds to an element
|
/// @brief determines if a key corresponds to an element
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool isEqualKeyElement (TRI_index_search_value_t const* left,
|
bool isEqualKeyElement (Key const* left,
|
||||||
TRI_index_element_t const* right) const;
|
Element const* right) const;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief given a key generates a hash integer
|
/// @brief given a key generates a hash integer
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
uint64_t hashKey (TRI_index_search_value_t const* key) const;
|
uint64_t hashKey (Key const* key) const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief given an element generates a hash integer
|
/// @brief given an element generates a hash integer
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
uint64_t hashElement (TRI_index_element_t const* element) const;
|
uint64_t hashElement (Element const* element) const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief resize the hash array
|
/// @brief resizes the array
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int resizeInternal (triagens::arango::HashIndex* hashIndex,
|
void resizeInternal (Bucket& b,
|
||||||
Bucket& b,
|
|
||||||
uint64_t targetSize,
|
uint64_t targetSize,
|
||||||
bool allowShrink);
|
bool allowShrink) {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
if (b._nrAlloc >= targetSize && ! allowShrink) {
|
||||||
/// @brief check a resize of the hash array
|
return;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
}
|
||||||
|
|
||||||
bool checkResize (triagens::arango::HashIndex* hashIndex,
|
// only log performance infos for indexes with more than this number of entries
|
||||||
Bucket& b);
|
static uint64_t const NotificationSizeThreshold = 131072;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
double start = TRI_microtime();
|
||||||
// --SECTION-- public functions
|
if (targetSize > NotificationSizeThreshold) {
|
||||||
// -----------------------------------------------------------------------------
|
LOG_ACTION("index-resize %s, target size: %llu",
|
||||||
|
_contextCallback().c_str(),
|
||||||
|
(unsigned long long) targetSize);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
Element** oldTable = b._table;
|
||||||
/// @brief get the hash array's memory usage
|
uint64_t oldAlloc = b._nrAlloc;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
TRI_ASSERT(targetSize > 0);
|
||||||
|
|
||||||
|
// This might throw, is catched outside
|
||||||
|
b._table = new Element* [targetSize];
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < targetSize; i++) {
|
||||||
|
b._table[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
b._nrAlloc = targetSize;
|
||||||
|
|
||||||
|
if (b._nrUsed > 0) {
|
||||||
|
uint64_t const n = b._nrAlloc;
|
||||||
|
|
||||||
|
for (uint64_t j = 0; j < oldAlloc; j++) {
|
||||||
|
Element* element = oldTable[j];
|
||||||
|
|
||||||
|
if (element != nullptr) {
|
||||||
|
uint64_t i, k;
|
||||||
|
i = k = _hashElement(element) % n;
|
||||||
|
|
||||||
|
for (; i < n && b._table[i] != nullptr; ++i);
|
||||||
|
if (i == n) {
|
||||||
|
for (i = 0; i < k && b._table[i] != nullptr; ++i);
|
||||||
|
}
|
||||||
|
|
||||||
|
b._table[i] = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] oldTable;
|
||||||
|
|
||||||
|
LOG_TIMER((TRI_microtime() - start),
|
||||||
|
"index-resize %s, target size: %llu",
|
||||||
|
_contextCallback().c_str(),
|
||||||
|
(unsigned long long) targetSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief check a resize of the hash array
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool checkResize (Bucket& b) {
|
||||||
|
if (2 * b._nrAlloc < 3 * b._nrUsed) {
|
||||||
|
try {
|
||||||
|
resizeInternal(b, 2 * b._nrAlloc + 1, false);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
public:
|
public:
|
||||||
size_t memoryUsage ();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get the number of elements in the hash
|
/// @brief get the hash array's memory usage
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
size_t memoryUsage () {
|
||||||
|
size_t sum = 0;
|
||||||
|
for (auto& b : _buckets) {
|
||||||
|
sum += (size_t) (b._nrAlloc * sizeof(TRI_index_element_t*));
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief get the number of elements in the hash
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
size_t size () {
|
size_t size () {
|
||||||
size_t sum = 0;
|
size_t sum = 0;
|
||||||
|
@ -215,38 +298,164 @@ class TRI_hash_array_t {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief resizes the hash table
|
/// @brief resizes the hash table
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int resize (triagens::arango::HashIndex*, size_t);
|
int resize (size_t size) {
|
||||||
|
for (auto& b : _buckets) {
|
||||||
|
try {
|
||||||
|
resizeInternal(b,
|
||||||
|
(uint64_t) (3 * size / 2 + 1) / _buckets.size(),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRI_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief finds an element given a key, returns NULL if not found
|
/// @brief finds an element given a key, returns NULL if not found
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TRI_index_element_t* findByKey (TRI_index_search_value_t* key) const;
|
Element* findByKey (Key* key) const {
|
||||||
|
uint64_t i = _hashKey(key);
|
||||||
|
Bucket const& b = _buckets[i & _bucketsMask];
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
uint64_t const n = b._nrAlloc;
|
||||||
/// @brief adds an key/element to the array
|
i = i % n;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
uint64_t k = i;
|
||||||
|
|
||||||
int insert (triagens::arango::HashIndex*,
|
for (; i < n && b._table[i] != nullptr &&
|
||||||
TRI_index_search_value_t const* key,
|
! _isEqualKeyElement(key, b._table[i]); ++i);
|
||||||
TRI_index_element_t const* element,
|
if (i == n) {
|
||||||
bool isRollback);
|
for (i = 0; i < k && b._table[i] != nullptr &&
|
||||||
|
! _isEqualKeyElement(key, b._table[i]); ++i);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
// ...........................................................................
|
||||||
/// @brief removes an element from the array, returns nullptr if the element
|
// return whatever we found, this is nullptr if the thing was not found
|
||||||
/// was not found and the old value, if it was successfully removed
|
// and otherwise a valid pointer
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
// ...........................................................................
|
||||||
|
|
||||||
TRI_index_element_t* remove (triagens::arango::HashIndex*,
|
return b._table[i];
|
||||||
TRI_index_element_t* element);
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief a method to iterate over all elements in the hash
|
/// @brief adds an key/element to the array
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int insert (Key const* key,
|
||||||
|
Element const* element,
|
||||||
|
bool isRollback) {
|
||||||
|
// ...........................................................................
|
||||||
|
// we are adding and the table is more than half full, extend it
|
||||||
|
// ...........................................................................
|
||||||
|
|
||||||
|
uint64_t i = _hashKey(key);
|
||||||
|
Bucket& b = _buckets[i & _bucketsMask];
|
||||||
|
|
||||||
|
if (! checkResize(b)) {
|
||||||
|
return TRI_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t const n = b._nrAlloc;
|
||||||
|
i = i % n;
|
||||||
|
uint64_t k = i;
|
||||||
|
|
||||||
|
for (; i < n && b._table[i] != nullptr &&
|
||||||
|
! _isEqualKeyElement(key, b._table[i]); ++i);
|
||||||
|
if (i == n) {
|
||||||
|
for (i = 0; i < k && b._table[i] != nullptr &&
|
||||||
|
! _isEqualKeyElement(key, b._table[i]); ++i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Element* arrayElement = b._table[i];
|
||||||
|
|
||||||
|
// ...........................................................................
|
||||||
|
// if we found an element, return
|
||||||
|
// ...........................................................................
|
||||||
|
|
||||||
|
if (arrayElement != nullptr) {
|
||||||
|
return TRI_ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
b._table[i] = element;
|
||||||
|
TRI_ASSERT(b._table[i] != nullptr && b._table[i]->document() != nullptr);
|
||||||
|
b._nrUsed++;
|
||||||
|
|
||||||
|
return TRI_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief removes an element from the array, returns nullptr if the element
|
||||||
|
/// was not found and the old value, if it was successfully removed
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Element* remove (Element* element) {
|
||||||
|
uint64_t i = _hashElement(element);
|
||||||
|
Bucket& b = _buckets[i & _bucketsMask];
|
||||||
|
|
||||||
|
uint64_t const n = b._nrAlloc;
|
||||||
|
i = i % n;
|
||||||
|
uint64_t k = i;
|
||||||
|
|
||||||
|
for (; i < n && b._table[i] != nullptr &&
|
||||||
|
element->document() != b._table[i]->document(); ++i);
|
||||||
|
if (i == n) {
|
||||||
|
for (i = 0; i < k && b._table[i] != nullptr &&
|
||||||
|
element->document() != b._table[i]->document(); ++i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Element* old = b._table[i];
|
||||||
|
|
||||||
|
// ...........................................................................
|
||||||
|
// if we did not find such an item return error code
|
||||||
|
// ...........................................................................
|
||||||
|
|
||||||
|
if (old == nullptr) {
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...........................................................................
|
||||||
|
// remove item - destroy any internal memory associated with the
|
||||||
|
// element structure
|
||||||
|
// ...........................................................................
|
||||||
|
|
||||||
|
b._table[i] = nullptr;
|
||||||
|
b._nrUsed--;
|
||||||
|
|
||||||
|
// ...........................................................................
|
||||||
|
// and now check the following places for items to move closer together
|
||||||
|
// so that there are no gaps in the array
|
||||||
|
// ...........................................................................
|
||||||
|
|
||||||
|
k = TRI_IncModU64(i, 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))) {
|
||||||
|
b._table[i] = b._table[k];
|
||||||
|
b._table[k] = nullptr;
|
||||||
|
i = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
k = TRI_IncModU64(k, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b._nrUsed == 0) {
|
||||||
|
resizeInternal(b, initialSize(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief a method to iterate over all elements in the hash
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void invokeOnAllElements (CallbackElementFuncType callback) {
|
void invokeOnAllElements (CallbackElementFuncType callback) {
|
||||||
for (auto& b : _buckets) {
|
for (auto& b : _buckets) {
|
||||||
|
@ -260,7 +469,9 @@ class TRI_hash_array_t {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
} // namespace basics
|
||||||
|
} // namespace triagens
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue