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; }
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; }
TRI_hash_index_element_t* TRI_FindByKeyHashArray (TRI_hash_array_t* array, TRI_index_search_value_t* key) { TRI_hash_index_element_t* element; element = TRI_LookupByKeyHashArray(array, key); if (! IsEmptyElement(array, element) && IsEqualKeyElement(array, key, element)) { return element; } return NULL; }
TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_t* array, TRI_index_search_value_t* key) { TRI_vector_pointer_t result; uint64_t hash; uint64_t i; // ........................................................................... // initialise the vector which will hold the result if any // ........................................................................... TRI_InitVectorPointer(&result, TRI_UNKNOWN_MEM_ZONE); // ........................................................................... // compute the hash // ........................................................................... hash = HashKey(array, key); i = hash % array->_nrAlloc; // ........................................................................... // update statistics // ........................................................................... #ifdef TRI_INTERNAL_STATS array->_nrFinds++; #endif // ........................................................................... // search the table // ........................................................................... while (! IsEmptyElement(array, &array->_table[i])) { if (IsEqualKeyElement(array, key, &array->_table[i])) { TRI_PushBackVectorPointer(&result, &array->_table[i]); } #ifdef TRI_INTERNAL_STATS else { array->_nrProbesF++; } #endif i = (i + 1) % array->_nrAlloc; } // ........................................................................... // return whatever we found -- which could be an empty vector list if nothing // matches. // ........................................................................... return result; }
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; }
TRI_hash_index_element_t* TRI_LookupByKeyHashArray (TRI_hash_array_t* array, TRI_index_search_value_t* key) { uint64_t hash; uint64_t i; // ........................................................................... // compute the hash // ........................................................................... hash = HashKey(array, key); i = hash % array->_nrAlloc; // ........................................................................... // update statistics // ........................................................................... #ifdef TRI_INTERNAL_STATS array->_nrFinds++; #endif // ........................................................................... // search the table // ........................................................................... while (! IsEmptyElement(array, &array->_table[i]) && ! IsEqualKeyElement(array, key, &array->_table[i])) { i = (i + 1) % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS array->_nrProbesF++; #endif } // ........................................................................... // return whatever we found // ........................................................................... return &array->_table[i]; }
int TRI_RemoveElementHashArrayMulti (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(array, InitialSize(), true); } return TRI_ERROR_NO_ERROR; }
int TRI_InsertElementHashArrayMulti (TRI_hash_array_multi_t* array, TRI_index_search_value_t const* key, TRI_hash_index_element_multi_t* element, bool isRollback) { if (! CheckResize(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; }
int TRI_RemoveKeyHashArray (TRI_hash_array_t* array, TRI_index_search_value_t* key) { uint64_t hash; uint64_t i; uint64_t k; bool found; void* arrayElement; // ........................................................................... // compute the hash // ........................................................................... hash = HashKey(array, key); i = hash % array->_nrAlloc; // ........................................................................... // update statistics // ........................................................................... #ifdef TRI_INTERNAL_STATS array->_nrRems++; #endif // ........................................................................... // search the table // ........................................................................... while (! IsEmptyElement(array, &array->_table[i]) && ! IsEqualKeyElement(array, key, &array->_table[i])) { i = (i + 1) % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS array->_nrProbesD++; #endif } arrayElement = &array->_table[i]; // ........................................................................... // if we did not find such an item return false // ........................................................................... found = ! IsEmptyElement(array, arrayElement); if (! found) { return TRI_RESULT_KEY_NOT_FOUND; } // ........................................................................... // remove item // ........................................................................... DestroyElement(array, arrayElement); array->_nrUsed--; // ........................................................................... // and now check the following places for items to move here // ........................................................................... k = (i + 1) % array->_nrAlloc; while (! IsEmptyElement(array, &array->_table[k])) { uint64_t j = HashElement(array, &array->_table[k]) % array->_nrAlloc; if ((i < k && !(i < j && j <= k)) || (k < i && !(i < j || j <= k))) { array->_table[i] = array->_table[k]; ClearElement(array, &array->_table[k]); i = k; } k = (k + 1) % array->_nrAlloc; } // ........................................................................... // return success // ........................................................................... return TRI_ERROR_NO_ERROR; }
int TRI_InsertKeyHashArray (TRI_hash_array_t* array, TRI_index_search_value_t* key, TRI_hash_index_element_t* element, bool overwrite) { uint64_t hash; uint64_t i; bool found; int res; TRI_hash_index_element_t* arrayElement; // ........................................................................... // compute the hash // ........................................................................... hash = HashKey(array, key); i = hash % array->_nrAlloc; // ........................................................................... // update statistics // ........................................................................... #ifdef TRI_INTERNAL_STATS array->_nrAdds++; #endif // ........................................................................... // search the table // ........................................................................... while (! IsEmptyElement(array, &array->_table[i]) && ! IsEqualKeyElement(array, key, &array->_table[i])) { i = (i + 1) % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS array->_nrProbesA++; #endif } arrayElement = &array->_table[i]; // ........................................................................... // if we found an element, return // ........................................................................... found = ! IsEmptyElement(array, arrayElement); if (found) { if (overwrite) { // destroy the underlying element since we are going to stomp on top if it DestroyElement(array, arrayElement); *arrayElement = *element; } else { DestroyElement(array, element); } return TRI_RESULT_KEY_EXISTS; } // ........................................................................... // add a new element to the associative array // ........................................................................... *arrayElement = *element; array->_nrUsed++; // ........................................................................... // we are adding and the table is more than half full, extend it // ........................................................................... if (array->_nrAlloc < 2 * array->_nrUsed) { res = ResizeHashArray(array); if (res != TRI_ERROR_NO_ERROR) { return res; } } return TRI_ERROR_NO_ERROR; }