mirror of https://gitee.com/bigwinds/arangodb
Removed obsolete hash index implementation
This commit is contained in:
parent
40c1361244
commit
c308065eec
|
@ -121,7 +121,6 @@ add_executable(
|
|||
FulltextIndex/fulltext-result.cpp
|
||||
FulltextIndex/fulltext-wordlist.cpp
|
||||
GeoIndex/GeoIndex.cpp
|
||||
HashIndex/hash-array.cpp
|
||||
HttpServer/ApplicationEndpointServer.cpp
|
||||
HttpServer/AsyncJobManager.cpp
|
||||
HttpServer/HttpCommTask.cpp
|
||||
|
|
|
@ -1,790 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief multi-hash array implementation, using a linked-list for collisions
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Dr. Oreste Costa-Panaia
|
||||
/// @author Martin Schoenert
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2004-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "hash-array-multi.h"
|
||||
#include "Basics/logging.h"
|
||||
#include "Basics/fasthash.h"
|
||||
#include "Indexes/HashIndex.h"
|
||||
#include "Indexes/Index.h"
|
||||
#include "VocBase/document-collection.h"
|
||||
#include "VocBase/VocShaper.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- COMPARISON
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief determines if a key corresponds to an element
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsEqualKeyElement (TRI_hash_array_multi_t const* array,
|
||||
TRI_index_search_value_t const* left,
|
||||
TRI_hash_index_element_multi_t const* right) {
|
||||
TRI_ASSERT_EXPENSIVE(right->_document != nullptr);
|
||||
|
||||
for (size_t j = 0; j < array->_numFields; ++j) {
|
||||
TRI_shaped_json_t* leftJson = &left->_values[j];
|
||||
TRI_shaped_sub_t* rightSub = &right->_subObjects[j];
|
||||
|
||||
if (leftJson->_sid != rightSub->_sid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto length = leftJson->_data.length;
|
||||
|
||||
char const* rightData;
|
||||
size_t rightLength;
|
||||
TRI_InspectShapedSub(rightSub, right->_document, rightData, rightLength);
|
||||
|
||||
if (length != rightLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length > 0 && memcmp(leftJson->_data.data, rightData, length) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief given a key generates a hash integer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static uint64_t HashKey (TRI_hash_array_multi_t const* array,
|
||||
TRI_index_search_value_t const* key) {
|
||||
uint64_t hash = 0x0123456789abcdef;
|
||||
|
||||
for (size_t j = 0; j < array->_numFields; ++j) {
|
||||
// ignore the sid for hashing
|
||||
hash = fasthash64(key->_values[j]._data.data, key->_values[j]._data.length, hash);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief given an element generates a hash integer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static uint64_t HashElement (TRI_hash_array_multi_t const* array,
|
||||
TRI_hash_index_element_multi_t const* element) {
|
||||
uint64_t hash = 0x0123456789abcdef;
|
||||
|
||||
for (size_t j = 0; j < array->_numFields; j++) {
|
||||
char const* data;
|
||||
size_t length;
|
||||
TRI_InspectShapedSub(&element->_subObjects[j], element->_document, data, length);
|
||||
|
||||
// ignore the sid for hashing
|
||||
// only hash the data block
|
||||
hash = fasthash64(data, length, hash);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a block size for hash elements batch allocation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline size_t GetBlockSize (size_t blockNumber) {
|
||||
static size_t const BLOCK_SIZE_UNIT = 128;
|
||||
|
||||
if (blockNumber >= 7) {
|
||||
blockNumber = 7;
|
||||
}
|
||||
return (size_t) (BLOCK_SIZE_UNIT << blockNumber);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the size of a single entry
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline size_t TableEntrySize () {
|
||||
return sizeof(TRI_hash_index_element_multi_t);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the size of a single overflow entry
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline size_t OverflowEntrySize () {
|
||||
return sizeof(TRI_hash_index_element_multi_t);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a storage location from the freelist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_hash_index_element_multi_t* GetFromFreelist (TRI_hash_array_multi_t* array) {
|
||||
if (array->_freelist == nullptr) {
|
||||
size_t blockSize = GetBlockSize(array->_blocks._length);
|
||||
TRI_ASSERT(blockSize > 0);
|
||||
|
||||
auto begin = static_cast<TRI_hash_index_element_multi_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, blockSize * OverflowEntrySize(), true));
|
||||
|
||||
if (begin == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ptr = begin;
|
||||
auto end = begin + (blockSize - 1);
|
||||
|
||||
while (ptr < end) {
|
||||
ptr->_next = (ptr + 1);
|
||||
++ptr;
|
||||
}
|
||||
|
||||
array->_freelist = begin;
|
||||
TRI_PushBackVectorPointer(&array->_blocks, begin);
|
||||
|
||||
array->_nrOverflowAlloc += blockSize;
|
||||
}
|
||||
|
||||
auto next = array->_freelist;
|
||||
TRI_ASSERT(next != nullptr);
|
||||
array->_freelist = next->_next;
|
||||
array->_nrOverflowUsed++;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return an element to the freelist
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ReturnToFreelist (TRI_hash_array_multi_t* array,
|
||||
TRI_hash_index_element_multi_t* element) {
|
||||
TRI_ASSERT(element->_subObjects == nullptr);
|
||||
|
||||
element->_document = nullptr;
|
||||
element->_subObjects = nullptr;
|
||||
element->_next = array->_freelist;
|
||||
array->_freelist = element;
|
||||
array->_nrOverflowUsed--;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys an element, removing any allocated memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void DestroyElement (TRI_hash_array_multi_t* array,
|
||||
TRI_hash_index_element_multi_t* element) {
|
||||
TRI_ASSERT_EXPENSIVE(element != nullptr);
|
||||
TRI_ASSERT_EXPENSIVE(element->_document != nullptr);
|
||||
|
||||
if (element->_subObjects != nullptr) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, element->_subObjects);
|
||||
}
|
||||
element->_document = nullptr;
|
||||
element->_subObjects = nullptr;
|
||||
element->_next = nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief allocate memory for the hash table
|
||||
///
|
||||
/// the hash table memory will be aligned on a cache line boundary
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int AllocateTable (TRI_hash_array_multi_t* array,
|
||||
uint64_t numElements) {
|
||||
size_t const size = (size_t) (TableEntrySize() * numElements + 64);
|
||||
|
||||
TRI_hash_index_element_multi_t* table = static_cast<TRI_hash_index_element_multi_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, size, true));
|
||||
|
||||
if (table == nullptr) {
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
array->_tablePtr = table;
|
||||
array->_table = static_cast<TRI_hash_index_element_multi_t*>(TRI_Align64(table));
|
||||
array->_nrAlloc = numElements;
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief resizes the array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int ResizeHashArray (triagens::arango::HashIndex* hashIndex,
|
||||
TRI_hash_array_multi_t* array,
|
||||
uint64_t targetSize,
|
||||
bool allowShrink) {
|
||||
if (array->_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_hash_index_element_multi_t* oldTable = array->_table;
|
||||
TRI_hash_index_element_multi_t* oldTablePtr = array->_tablePtr;
|
||||
uint64_t oldAlloc = array->_nrAlloc;
|
||||
|
||||
TRI_ASSERT(targetSize > 0);
|
||||
|
||||
int res = AllocateTable(array, targetSize);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (array->_nrUsed > 0) {
|
||||
uint64_t const n = array->_nrAlloc;
|
||||
|
||||
for (uint64_t j = 0; j < oldAlloc; j++) {
|
||||
TRI_hash_index_element_multi_t* element = &oldTable[j];
|
||||
|
||||
if (element->_document != nullptr) {
|
||||
uint64_t i, k;
|
||||
i = k = HashElement(array, element) % n;
|
||||
|
||||
for (; i < n && array->_table[i]._document != nullptr; ++i);
|
||||
if (i == n) {
|
||||
for (i = 0; i < k && array->_table[i]._document != 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
|
||||
// ...........................................................................
|
||||
|
||||
memcpy(&array->_table[i], element, TableEntrySize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, oldTablePtr);
|
||||
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool CheckResize (triagens::arango::HashIndex* hashIndex,
|
||||
TRI_hash_array_multi_t* array) {
|
||||
if (array->_nrAlloc < 2 * array->_nrUsed) {
|
||||
int res = ResizeHashArray(hashIndex, array, 2 * array->_nrAlloc + 1, false);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialises an array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_InitHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||
size_t numFields) {
|
||||
|
||||
TRI_ASSERT(numFields > 0);
|
||||
|
||||
array->_numFields = numFields;
|
||||
array->_tablePtr = nullptr;
|
||||
array->_table = nullptr;
|
||||
array->_nrUsed = 0;
|
||||
array->_nrAlloc = 0;
|
||||
array->_nrOverflowUsed = 0;
|
||||
array->_nrOverflowAlloc = 0;
|
||||
array->_freelist = nullptr;
|
||||
|
||||
TRI_InitVectorPointer(&array->_blocks, TRI_UNKNOWN_MEM_ZONE, 16);
|
||||
|
||||
return AllocateTable(array, InitialSize());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys an array, but does not free the pointer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_DestroyHashArrayMulti (TRI_hash_array_multi_t* array) {
|
||||
// ...........................................................................
|
||||
// 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_hash_index_element_multi_t* p;
|
||||
TRI_hash_index_element_multi_t* e;
|
||||
|
||||
p = array->_table;
|
||||
e = p + array->_nrAlloc;
|
||||
|
||||
for (; p < e; ++p) {
|
||||
if (p->_document != nullptr) {
|
||||
// destroy overflow elements
|
||||
auto current = p->_next;
|
||||
while (current != nullptr) {
|
||||
auto ptr = current->_next;
|
||||
DestroyElement(array, current);
|
||||
current = ptr;
|
||||
}
|
||||
|
||||
// destroy the element itself
|
||||
DestroyElement(array, p);
|
||||
}
|
||||
}
|
||||
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, array->_tablePtr);
|
||||
}
|
||||
|
||||
// free overflow elements
|
||||
for (size_t i = 0; i < array->_blocks._length; ++i) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, array->_blocks._buffer[i]);
|
||||
}
|
||||
|
||||
TRI_DestroyVectorPointer(&array->_blocks);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the hash array's memory usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t TRI_MemoryUsageHashArrayMulti (TRI_hash_array_multi_t const* array) {
|
||||
if (array == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t tableSize = (size_t) (array->_nrAlloc * TableEntrySize() + 64);
|
||||
size_t memberSize = (size_t) (array->_nrUsed * array->_numFields * sizeof(TRI_shaped_sub_t));
|
||||
size_t overflowAlloc = (size_t) (array->_nrOverflowAlloc * OverflowEntrySize());
|
||||
|
||||
return (size_t) (tableSize + memberSize + overflowAlloc);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief resizes the hash table
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_ResizeHashArrayMulti (triagens::arango::HashIndex* hashIndex,
|
||||
TRI_hash_array_multi_t* array,
|
||||
size_t size) {
|
||||
// use less than 1 element per number of documents
|
||||
// we does this because expect duplicate values, which are stored in the overflow
|
||||
// items (which are allocated separately)
|
||||
size_t targetSize = static_cast<size_t>(0.75 * size);
|
||||
if ((targetSize & 1) == 0) {
|
||||
// make odd
|
||||
targetSize++;
|
||||
}
|
||||
return ResizeHashArray(hashIndex, array, (uint64_t) targetSize, false);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookups an element given a key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const* array,
|
||||
TRI_index_search_value_t const* key) {
|
||||
TRI_ASSERT_EXPENSIVE(array->_nrUsed < array->_nrAlloc);
|
||||
|
||||
// ...........................................................................
|
||||
// initialise the vector which will hold the result if any
|
||||
// ...........................................................................
|
||||
|
||||
TRI_vector_pointer_t result;
|
||||
TRI_InitVectorPointer(&result, TRI_UNKNOWN_MEM_ZONE);
|
||||
|
||||
uint64_t const n = array->_nrAlloc;
|
||||
uint64_t i, k;
|
||||
|
||||
i = k = HashKey(array, key) % n;
|
||||
|
||||
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
if (i == n) {
|
||||
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
}
|
||||
|
||||
TRI_ASSERT_EXPENSIVE(i < n);
|
||||
|
||||
if (array->_table[i]._document != nullptr) {
|
||||
// add the element itself
|
||||
TRI_PushBackVectorPointer(&result, array->_table[i]._document);
|
||||
|
||||
// add the overflow elements
|
||||
auto current = array->_table[i]._next;
|
||||
while (current != nullptr) {
|
||||
TRI_PushBackVectorPointer(&result, current->_document);
|
||||
current = current->_next;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookups an element given a key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const* array,
|
||||
TRI_index_search_value_t const* key,
|
||||
std::vector<TRI_doc_mptr_copy_t>& result) {
|
||||
TRI_ASSERT_EXPENSIVE(array->_nrUsed < array->_nrAlloc);
|
||||
|
||||
uint64_t const n = array->_nrAlloc;
|
||||
uint64_t i, k;
|
||||
|
||||
i = k = HashKey(array, key) % n;
|
||||
|
||||
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
if (i == n) {
|
||||
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
}
|
||||
|
||||
TRI_ASSERT_EXPENSIVE(i < n);
|
||||
|
||||
if (array->_table[i]._document != nullptr) {
|
||||
// add the element itself
|
||||
result.emplace_back(*(array->_table[i]._document));
|
||||
|
||||
// add the overflow elements
|
||||
auto current = array->_table[i]._next;
|
||||
while (current != nullptr) {
|
||||
result.emplace_back(*(current->_document));
|
||||
current = current->_next;
|
||||
}
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookups an element given a key and a state
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const* array,
|
||||
TRI_index_search_value_t const* key,
|
||||
std::vector<TRI_doc_mptr_copy_t>& result,
|
||||
TRI_hash_index_element_multi_t*& next,
|
||||
size_t batchSize) {
|
||||
size_t const initialSize = result.size();
|
||||
TRI_ASSERT_EXPENSIVE(array->_nrUsed < array->_nrAlloc);
|
||||
TRI_ASSERT(batchSize > 0);
|
||||
|
||||
if (next == nullptr) {
|
||||
// no previous state. start at the beginning
|
||||
uint64_t const n = array->_nrAlloc;
|
||||
uint64_t i, k;
|
||||
|
||||
i = k = HashKey(array, key) % n;
|
||||
|
||||
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
if (i == n) {
|
||||
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
}
|
||||
|
||||
TRI_ASSERT_EXPENSIVE(i < n);
|
||||
|
||||
if (array->_table[i]._document != nullptr) {
|
||||
result.emplace_back(*(array->_table[i]._document));
|
||||
}
|
||||
next = array->_table[i]._next;
|
||||
}
|
||||
|
||||
if (next != nullptr) {
|
||||
// we already had a state
|
||||
size_t total = result.size() - initialSize;
|
||||
|
||||
while (next != nullptr && total < batchSize) {
|
||||
result.emplace_back(*(next->_document));
|
||||
next = next->_next;
|
||||
++total;
|
||||
}
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds an element to the array
|
||||
///
|
||||
/// This function claims the owenship of the sub-objects in the inserted
|
||||
/// element.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_InsertElementHashArrayMulti (triagens::arango::HashIndex* hashIndex,
|
||||
TRI_hash_array_multi_t* array,
|
||||
TRI_index_search_value_t const* key,
|
||||
TRI_hash_index_element_multi_t* element,
|
||||
bool isRollback) {
|
||||
if (! CheckResize(hashIndex, array)) {
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint64_t const n = array->_nrAlloc;
|
||||
uint64_t i, k;
|
||||
|
||||
i = k = HashKey(array, key) % n;
|
||||
|
||||
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
if (i == n) {
|
||||
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
}
|
||||
|
||||
TRI_ASSERT_EXPENSIVE(i < n);
|
||||
|
||||
TRI_hash_index_element_multi_t* arrayElement = &array->_table[i];
|
||||
|
||||
// ...........................................................................
|
||||
// If we found an element, return. While we allow duplicate entries in the
|
||||
// hash table, we do not allow duplicate elements. Elements would refer to the
|
||||
// (for example) an actual row in memory. This is different from the
|
||||
// TRI_InsertElementMultiArray function below where we only have keys to
|
||||
// differentiate between elements.
|
||||
// ...........................................................................
|
||||
|
||||
bool found = (arrayElement->_document != nullptr);
|
||||
|
||||
if (found) {
|
||||
if (isRollback) {
|
||||
if (arrayElement->_document == element->_document) {
|
||||
DestroyElement(array, element);
|
||||
|
||||
return TRI_RESULT_ELEMENT_EXISTS;
|
||||
}
|
||||
|
||||
auto current = arrayElement->_next;
|
||||
while (current != nullptr) {
|
||||
if (current->_document == element->_document) {
|
||||
DestroyElement(array, element);
|
||||
|
||||
return TRI_RESULT_ELEMENT_EXISTS;
|
||||
}
|
||||
current = current->_next;
|
||||
}
|
||||
}
|
||||
|
||||
auto ptr = GetFromFreelist(array);
|
||||
|
||||
if (ptr == nullptr) {
|
||||
return TRI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// link our element at the list head
|
||||
ptr->_document = element->_document;
|
||||
ptr->_subObjects = element->_subObjects;
|
||||
ptr->_next = arrayElement->_next;
|
||||
arrayElement->_next = ptr;
|
||||
|
||||
// it is ok to destroy the element here, because we have copied its internal before!
|
||||
element->_subObjects = nullptr;
|
||||
DestroyElement(array, element);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
TRI_ASSERT(arrayElement->_next == nullptr);
|
||||
|
||||
// not found in list, now insert
|
||||
element->_next = nullptr;
|
||||
*arrayElement = *element;
|
||||
array->_nrUsed++;
|
||||
|
||||
TRI_ASSERT(arrayElement->_next == nullptr);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes an element from the array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_RemoveElementHashArrayMulti (triagens::arango::HashIndex* hashIndex,
|
||||
TRI_hash_array_multi_t* array,
|
||||
TRI_index_search_value_t const* key,
|
||||
TRI_hash_index_element_multi_t* element) {
|
||||
uint64_t const n = array->_nrAlloc;
|
||||
uint64_t i, k;
|
||||
|
||||
i = k = HashKey(array, key) % n;
|
||||
|
||||
for (; i < n && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
if (i == n) {
|
||||
for (i = 0; i < k && array->_table[i]._document != nullptr && ! IsEqualKeyElement(array, key, &array->_table[i]); ++i);
|
||||
}
|
||||
|
||||
TRI_ASSERT_EXPENSIVE(i < n);
|
||||
|
||||
TRI_hash_index_element_multi_t* arrayElement = &array->_table[i];
|
||||
|
||||
bool found = (arrayElement->_document != nullptr);
|
||||
|
||||
if (! found) {
|
||||
return TRI_RESULT_ELEMENT_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (arrayElement->_document != element->_document) {
|
||||
// look in the overflow list for the sought document
|
||||
auto next = &(arrayElement->_next);
|
||||
while (*next != nullptr) {
|
||||
if ((*next)->_document == element->_document) {
|
||||
auto ptr = (*next)->_next;
|
||||
DestroyElement(array, *next);
|
||||
ReturnToFreelist(array, *next);
|
||||
*next = ptr;
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
next = &((*next)->_next);
|
||||
}
|
||||
|
||||
return TRI_RESULT_ELEMENT_NOT_FOUND;
|
||||
}
|
||||
|
||||
// the element itself is the document to remove
|
||||
TRI_ASSERT(arrayElement->_document == element->_document);
|
||||
|
||||
if (arrayElement->_next != nullptr) {
|
||||
auto next = arrayElement->_next;
|
||||
|
||||
// destroy our own data first, otherwise we'll leak
|
||||
TRI_ASSERT(arrayElement->_subObjects != nullptr);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, arrayElement->_subObjects);
|
||||
|
||||
// copy data from first overflow element into ourselves
|
||||
arrayElement->_document = next->_document;
|
||||
arrayElement->_subObjects = next->_subObjects;
|
||||
arrayElement->_next = next->_next;
|
||||
|
||||
// and remove the first overflow element
|
||||
next->_subObjects = nullptr;
|
||||
DestroyElement(array, next);
|
||||
ReturnToFreelist(array, next);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
TRI_ASSERT(arrayElement->_next == nullptr);
|
||||
|
||||
DestroyElement(array, arrayElement);
|
||||
array->_nrUsed--;
|
||||
|
||||
// ...........................................................................
|
||||
// and now check the following places for items to move here
|
||||
// ...........................................................................
|
||||
|
||||
k = TRI_IncModU64(i, n);
|
||||
|
||||
while (array->_table[k]._document != nullptr) {
|
||||
uint64_t j = HashElement(array, &array->_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]._document = nullptr;
|
||||
array->_table[k]._next = nullptr;
|
||||
array->_table[k]._subObjects = nullptr;
|
||||
i = k;
|
||||
}
|
||||
|
||||
k = TRI_IncModU64(k, n);
|
||||
}
|
||||
|
||||
if (array->_nrUsed == 0) {
|
||||
TRI_ASSERT(array->_nrOverflowUsed == 0);
|
||||
ResizeHashArray(hashIndex, array, InitialSize(), true);
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a selectivity estimate for the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double TRI_SelectivityHashArrayMulti (TRI_hash_array_multi_t const* array) {
|
||||
size_t numTotal = static_cast<size_t>(array->_nrUsed + array->_nrOverflowUsed);
|
||||
|
||||
if (numTotal == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
return static_cast<double>(array->_nrUsed) / static_cast<double>(numTotal);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -1,177 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief multi-hash array implementation, using a linked-list for collisions
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Dr. Oreste Costa-Panaia
|
||||
/// @author Martin Schoenert
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2006-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_HASH_INDEX_HASH__ARRAY_MULTI_H
|
||||
#define ARANGODB_HASH_INDEX_HASH__ARRAY_MULTI_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/vector.h"
|
||||
#include "VocBase/document-collection.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- forward declarations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct TRI_hash_index_element_overflow_s;
|
||||
struct TRI_hash_index_element_multi_s;
|
||||
struct TRI_index_search_value_s;
|
||||
|
||||
namespace triagens {
|
||||
namespace arango {
|
||||
class HashIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief associative array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct TRI_hash_array_multi_s {
|
||||
size_t _numFields; // the number of fields indexes
|
||||
|
||||
uint64_t _nrAlloc; // the size of the table
|
||||
uint64_t _nrUsed; // the number of used entries
|
||||
uint64_t _nrOverflowUsed; // the number of overflow entries used
|
||||
uint64_t _nrOverflowAlloc; // the number of overflow entries allocated
|
||||
|
||||
struct TRI_hash_index_element_multi_s* _table; // the table itself, aligned to a cache line boundary
|
||||
struct TRI_hash_index_element_multi_s* _tablePtr; // the table itself
|
||||
|
||||
struct TRI_hash_index_element_multi_s* _freelist;
|
||||
|
||||
TRI_vector_pointer_t _blocks;
|
||||
}
|
||||
TRI_hash_array_multi_t;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- HASH ARRAY
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief initialises an array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_InitHashArrayMulti (TRI_hash_array_multi_t*,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys an array, but does not free the pointer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_DestroyHashArrayMulti (TRI_hash_array_multi_t*);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the hash array's memory usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t TRI_MemoryUsageHashArrayMulti (TRI_hash_array_multi_t const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief resizes the hash table
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_ResizeHashArrayMulti (triagens::arango::HashIndex*,
|
||||
TRI_hash_array_multi_t*,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookups an element given a key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const*,
|
||||
struct TRI_index_search_value_s const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookups an element given a key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const*,
|
||||
struct TRI_index_search_value_s const*,
|
||||
std::vector<TRI_doc_mptr_copy_t>&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookups an element given a key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const*,
|
||||
struct TRI_index_search_value_s const*,
|
||||
std::vector<TRI_doc_mptr_copy_t>&,
|
||||
struct TRI_hash_index_element_multi_s*&,
|
||||
size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief adds an element to the array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_InsertElementHashArrayMulti (triagens::arango::HashIndex*,
|
||||
TRI_hash_array_multi_t*,
|
||||
struct TRI_index_search_value_s const*,
|
||||
struct TRI_hash_index_element_multi_s*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes an element from the array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_RemoveElementHashArrayMulti (triagens::arango::HashIndex*,
|
||||
TRI_hash_array_multi_t*,
|
||||
struct TRI_index_search_value_s const*,
|
||||
struct TRI_hash_index_element_multi_s*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a selectivity estimate for the index
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double TRI_SelectivityHashArrayMulti (TRI_hash_array_multi_t const*);
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
Loading…
Reference in New Issue