diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index 7b4855306d..5884a02219 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -501,8 +501,8 @@ namespace triagens { return TRI_ERROR_OUT_OF_MEMORY; } - size_t total = document->_primaryIndex._nrAlloc; - size_t pos = TRI_UInt32Random() % total; + uint32_t total = (uint32_t) document->_primaryIndex._nrAlloc; + uint32_t pos = TRI_UInt32Random() % total; void** beg = document->_primaryIndex._table; while (beg[pos] == 0) { @@ -564,7 +564,7 @@ namespace triagens { return TRI_ERROR_OUT_OF_MEMORY; } - ids.reserve(document->_primaryIndex._nrUsed); + ids.reserve((size_t) document->_primaryIndex._nrUsed); void** ptr = document->_primaryIndex._table; void** end = ptr + document->_primaryIndex._nrAlloc; diff --git a/arangod/V8Server/v8-query.cpp b/arangod/V8Server/v8-query.cpp index 2a3b073009..6fd8b66d56 100644 --- a/arangod/V8Server/v8-query.cpp +++ b/arangod/V8Server/v8-query.cpp @@ -1878,11 +1878,18 @@ static v8::Handle JS_ByExampleQuery (v8::Arguments const& argv) { // ........................................................................... // inside a read transaction // ........................................................................... + + vector filtered; trx.lockRead(); // find documents by example - vector filtered = TRI_SelectByExample(trx.trxCollection(), n, pids, values); + try { + filtered = TRI_SelectByExample(trx.trxCollection(), n, pids, values); + } + catch (std::exception& ex) { + TRI_V8_EXCEPTION_MEMORY(scope); + } trx.finish(res); diff --git a/arangod/VocBase/document-collection.cpp b/arangod/VocBase/document-collection.cpp index 9ccb8c9306..c66b44b08f 100644 --- a/arangod/VocBase/document-collection.cpp +++ b/arangod/VocBase/document-collection.cpp @@ -3033,7 +3033,7 @@ static int FillIndex (TRI_document_collection_t* document, if (idx->sizeHint != nullptr) { // give the index a size hint - idx->sizeHint(idx, document->_primaryIndex._nrUsed); + idx->sizeHint(idx, (size_t) document->_primaryIndex._nrUsed); } @@ -5216,7 +5216,8 @@ std::vector TRI_SelectByExample ( TRI_doc_mptr_t** end = (TRI_doc_mptr_t**) ptr + document->_primaryIndex._nrAlloc; for (; ptr < end; ++ptr) { - if (*ptr != nullptr && IsExampleMatch(trxCollection, shaper, *ptr, length, pids, values)) { + if (*ptr != nullptr && + IsExampleMatch(trxCollection, shaper, *ptr, length, pids, values)) { filtered.push_back(**ptr); } } diff --git a/arangod/VocBase/primary-index.cpp b/arangod/VocBase/primary-index.cpp index 89caf0ea0e..2c4b2b98a0 100644 --- a/arangod/VocBase/primary-index.cpp +++ b/arangod/VocBase/primary-index.cpp @@ -39,68 +39,55 @@ /// @brief initial number of elements in the index //////////////////////////////////////////////////////////////////////////////// -#define INITIAL_SIZE (11) +constexpr uint64_t InitialSize () { + return 11; +} // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief adds a new element -//////////////////////////////////////////////////////////////////////////////// - -static void AddNewElement (TRI_primary_index_t* idx, void* element) { - uint64_t hash = ((TRI_doc_mptr_t const*) element)->_hash; - - // search the table - uint64_t i = hash % idx->_nrAlloc; - - while (idx->_table[i] != nullptr) { - i = TRI_IncModU64(i, idx->_nrAlloc); - } - - // add a new element to the associative idx - idx->_table[i] = element; - idx->_nrUsed++; -} - //////////////////////////////////////////////////////////////////////////////// /// @brief resizes the index //////////////////////////////////////////////////////////////////////////////// static bool ResizePrimaryIndex (TRI_primary_index_t* idx, - uint32_t targetSize) { - void** oldTable; - uint32_t oldAlloc; - uint32_t j; + uint64_t targetSize) { + TRI_ASSERT(targetSize > 0); - oldTable = idx->_table; - oldAlloc = idx->_nrAlloc; + void** oldTable = idx->_table; - idx->_nrAlloc = targetSize; -#ifdef TRI_INTERNAL_STATS - idx->_nrResizes++; -#endif - - idx->_table = (void**) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (size_t) (idx->_nrAlloc * sizeof(void*)), true); + idx->_table = static_cast(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (size_t) (targetSize * sizeof(void*)), true)); if (idx->_table == nullptr) { - idx->_nrAlloc = oldAlloc; idx->_table = oldTable; return false; } - idx->_nrUsed = 0; + // table is already cleared by allocate, now copy old data + for (uint64_t j = 0; j < idx->_nrAlloc; j++) { + TRI_doc_mptr_t const* element = static_cast(oldTable[j]); - // table is already cleared by allocate, copy old data - for (j = 0; j < oldAlloc; j++) { - if (oldTable[j] != nullptr) { - AddNewElement(idx, oldTable[j]); + if (element != nullptr) { + uint64_t const hash = element->_hash; + uint64_t i, k; + + i = k = hash % targetSize; + + for (; i < targetSize && idx->_table[i] != nullptr; ++i); + if (i == targetSize) { + for (i = 0; i < k && idx->_table[i] != nullptr; ++i); + } + + TRI_ASSERT_EXPENSIVE(i < targetSize); + + idx->_table[i] = (void*) element; } } TRI_Free(TRI_UNKNOWN_MEM_ZONE, oldTable); + idx->_nrAlloc = targetSize; return true; } @@ -113,13 +100,9 @@ static inline bool IsEqualKeyElement (TRI_doc_mptr_t const* header, void const* element) { TRI_doc_mptr_t const* e = static_cast(element); - if (header->_hash != e->_hash) { - // first compare hash values - return false; - } - // only after that compare actual keys - return (strcmp(TRI_EXTRACT_MARKER_KEY(header), TRI_EXTRACT_MARKER_KEY(e)) == 0); // ONLY IN INDEX, PROTECTED by RUNTIME + return (header->_hash == e->_hash && + strcmp(TRI_EXTRACT_MARKER_KEY(header), TRI_EXTRACT_MARKER_KEY(e)) == 0); // ONLY IN INDEX, PROTECTED by RUNTIME } //////////////////////////////////////////////////////////////////////////////// @@ -129,10 +112,8 @@ static inline bool IsEqualKeyElement (TRI_doc_mptr_t const* header, static inline bool IsEqualHashElement (char const* key, uint64_t hash, void const* element) { TRI_doc_mptr_t const* e = static_cast(element); - if (hash != e->_hash) { - return false; - } - return (strcmp(key, TRI_EXTRACT_MARKER_KEY(e)) == 0); // ONLY IN INDEX, PROTECTED by RUNTIME + return (hash == e->_hash && + strcmp(key, TRI_EXTRACT_MARKER_KEY(e)) == 0); // ONLY IN INDEX, PROTECTED by RUNTIME } // ----------------------------------------------------------------------------- @@ -147,11 +128,13 @@ int TRI_InitPrimaryIndex (TRI_primary_index_t* idx) { idx->_nrAlloc = 0; idx->_nrUsed = 0; - if (nullptr == (idx->_table = (void**) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(void*) * INITIAL_SIZE, true))) { + idx->_table = static_cast(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (size_t) (InitialSize() * sizeof(void*)), true)); + + if (idx->_table == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } - idx->_nrAlloc = INITIAL_SIZE; + idx->_nrAlloc = InitialSize(); return TRI_ERROR_NO_ERROR; } @@ -182,14 +165,22 @@ void* TRI_LookupByKeyPrimaryIndex (TRI_primary_index_t* idx, } // compute the hash - uint64_t hash = TRI_FnvHashString((char const*) key); - uint64_t i = hash % idx->_nrAlloc; + uint64_t const hash = TRI_FnvHashString((char const*) key); + uint64_t const n = idx->_nrAlloc; + uint64_t i, k; + + i = k = hash % n; + + TRI_ASSERT_EXPENSIVE(n > 0); // search the table - while (idx->_table[i] != nullptr && ! IsEqualHashElement((char const*) key, hash, idx->_table[i])) { - i = TRI_IncModU64(i, idx->_nrAlloc); + for (; i < n && idx->_table[i] != nullptr && ! IsEqualHashElement((char const*) key, hash, idx->_table[i]); ++i); + if (i == n) { + for (i = 0; i < k && idx->_table[i] != nullptr && ! IsEqualHashElement((char const*) key, hash, idx->_table[i]); ++i); } + TRI_ASSERT_EXPENSIVE(i < n); + // return whatever we found return idx->_table[i]; } @@ -204,20 +195,27 @@ int TRI_InsertKeyPrimaryIndex (TRI_primary_index_t* idx, void const** found) { *found = nullptr; - // check for out-of-memory - if (idx->_nrAlloc == idx->_nrUsed) { - return TRI_ERROR_OUT_OF_MEMORY; + if (idx->_nrAlloc < 2 * idx->_nrUsed) { + // check for out-of-memory + if (! ResizePrimaryIndex(idx, (uint64_t) (2 * idx->_nrAlloc + 1))) { + return TRI_ERROR_OUT_OF_MEMORY; + } } - // compute the hash - uint64_t hash = header->_hash; - uint64_t i = hash % idx->_nrAlloc; + uint64_t const n = idx->_nrAlloc; + uint64_t i, k; - // search the table - while (idx->_table[i] != nullptr && ! IsEqualKeyElement(header, idx->_table[i])) { - i = TRI_IncModU64(i, idx->_nrAlloc); + TRI_ASSERT_EXPENSIVE(n > 0); + + i = k = header->_hash % n; + + for (; i < n && idx->_table[i] != nullptr && ! IsEqualKeyElement(header, idx->_table[i]); ++i); + if (i == n) { + for (i = 0; i < k && idx->_table[i] != nullptr && ! IsEqualKeyElement(header, idx->_table[i]); ++i); } + TRI_ASSERT_EXPENSIVE(i < n); + void* old = idx->_table[i]; // if we found an element, return @@ -227,23 +225,9 @@ int TRI_InsertKeyPrimaryIndex (TRI_primary_index_t* idx, return TRI_ERROR_NO_ERROR; } - // if we were adding and the table is more than half full, extend it - if (idx->_nrAlloc < 2 * idx->_nrUsed) { - if (! ResizePrimaryIndex(idx, (uint32_t) (2 * idx->_nrAlloc) + 1)) { - return TRI_ERROR_OUT_OF_MEMORY; - } - - // now we need to recalc the position - i = hash % idx->_nrAlloc; - // search the table - while (idx->_table[i] != nullptr && ! IsEqualKeyElement(header, idx->_table[i])) { - i = TRI_IncModU64(i, idx->_nrAlloc); - } - } - // add a new element to the associative idx idx->_table[i] = (void*) header; - idx->_nrUsed++; + ++idx->_nrUsed; return TRI_ERROR_NO_ERROR; } @@ -254,37 +238,43 @@ int TRI_InsertKeyPrimaryIndex (TRI_primary_index_t* idx, void* TRI_RemoveKeyPrimaryIndex (TRI_primary_index_t* idx, void const* key) { - uint64_t hash = TRI_FnvHashString((char const*) key); - uint64_t i = hash % idx->_nrAlloc; + uint64_t const hash = TRI_FnvHashString((char const*) key); + uint64_t const n = idx->_nrAlloc; + uint64_t i, k; + + i = k = hash % n; // search the table - while (idx->_table[i] != nullptr && ! IsEqualHashElement((char const*) key, hash, idx->_table[i])) { - i = TRI_IncModU64(i, idx->_nrAlloc); + for (; i < n && idx->_table[i] != nullptr && ! IsEqualHashElement((char const*) key, hash, idx->_table[i]); ++i); + if (i == n) { + for (i = 0; i < k && idx->_table[i] != nullptr && ! IsEqualHashElement((char const*) key, hash, idx->_table[i]); ++i); } + TRI_ASSERT_EXPENSIVE(i < n); + // if we did not find such an item return false if (idx->_table[i] == nullptr) { return nullptr; } // remove item - void*old = idx->_table[i]; + void* old = idx->_table[i]; idx->_table[i] = nullptr; idx->_nrUsed--; // and now check the following places for items to move here - uint64_t k = TRI_IncModU64(i, idx->_nrAlloc); + k = TRI_IncModU64(i, n); while (idx->_table[k] != nullptr) { - uint64_t j = (((TRI_doc_mptr_t const*) idx->_table[k])->_hash) % idx->_nrAlloc; + uint64_t j = (((TRI_doc_mptr_t const*) idx->_table[k])->_hash) % n; - if ((i < k && !(i < j && j <= k)) || (k < i && !(i < j || j <= k))) { + if ((i < k && ! (i < j && j <= k)) || (k < i && ! (i < j || j <= k))) { idx->_table[i] = idx->_table[k]; idx->_table[k] = nullptr; i = k; } - k = TRI_IncModU64(k, idx->_nrAlloc); + k = TRI_IncModU64(k, n); } // return success diff --git a/arangod/VocBase/primary-index.h b/arangod/VocBase/primary-index.h index a56674d61f..60e12138be 100644 --- a/arangod/VocBase/primary-index.h +++ b/arangod/VocBase/primary-index.h @@ -43,8 +43,8 @@ struct TRI_doc_mptr_t; //////////////////////////////////////////////////////////////////////////////// typedef struct TRI_primary_index_s { - uint32_t _nrAlloc; // the size of the table - uint32_t _nrUsed; // the number of used entries + uint64_t _nrAlloc; // the size of the table + uint64_t _nrUsed; // the number of used entries void** _table; // the table itself }