static bool CheckResize (TRI_hash_array_multi_t* array) { if (array->_nrAlloc < 2 * array->_nrUsed) { int res = ResizeHashArray(array, 2 * array->_nrAlloc + 1, false); if (res != TRI_ERROR_NO_ERROR) { return false; } } return true; }
int TRI_ResizeHashArrayMulti (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(array, (uint64_t) targetSize, false); }
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_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; }
int TRI_InsertKeyHashArrayMulti (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; 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])) { i = (i + 1) % array->_nrAlloc; #ifdef TRI_INTERNAL_STATS array->_nrProbesA++; #endif } arrayElement = &array->_table[i]; // ........................................................................... // We do not look for an element (as opposed to the function above). So whether // or not there exists a duplicate we do not care. // ........................................................................... // ........................................................................... // add a new element to the associative array // ........................................................................... *arrayElement = * element; array->_nrUsed++; // ........................................................................... // if we were 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; }
int TRI_InsertElementHashArrayMulti (TRI_hash_array_t* array, 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 = HashElement(array, element); i = hash % array->_nrAlloc; // ........................................................................... // update statistics // ........................................................................... #ifdef TRI_INTERNAL_STATS array->_nrAdds++; #endif // ........................................................................... // search the table // ........................................................................... while (! IsEmptyElement(array, &array->_table[i]) && ! IsEqualElementElement(array, element, &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. 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. // ........................................................................... 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_ELEMENT_EXISTS; } // ........................................................................... // add a new element to the associative array // ........................................................................... *arrayElement = *element; array->_nrUsed++; // ........................................................................... // if we were 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; }