mirror of https://gitee.com/bigwinds/arangodb
optimized memory usage of multi hash index
This commit is contained in:
parent
fefd527b9f
commit
ce8ac10f59
|
@ -126,16 +126,32 @@ static inline size_t GetBlockSize (size_t blockNumber) {
|
||||||
return (size_t) (BLOCK_SIZE_UNIT << blockNumber);
|
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_overflow_t);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get a storage location from the freelist
|
/// @brief get a storage location from the freelist
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static TRI_hash_index_element_multi_t* GetFromFreelist (TRI_hash_array_multi_t* array) {
|
static TRI_hash_index_element_overflow_t* GetFromFreelist (TRI_hash_array_multi_t* array) {
|
||||||
if (array->_freelist == nullptr) {
|
if (array->_freelist == nullptr) {
|
||||||
size_t blockSize = GetBlockSize(array->_blocks._length);
|
size_t blockSize = GetBlockSize(array->_blocks._length);
|
||||||
TRI_ASSERT(blockSize > 0);
|
TRI_ASSERT(blockSize > 0);
|
||||||
|
|
||||||
auto begin = static_cast<TRI_hash_index_element_multi_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, blockSize * sizeof(TRI_hash_index_element_multi_t), true));
|
auto begin = static_cast<TRI_hash_index_element_overflow_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, blockSize * OverflowEntrySize(), true));
|
||||||
|
|
||||||
if (begin == nullptr) {
|
if (begin == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -168,7 +184,7 @@ static TRI_hash_index_element_multi_t* GetFromFreelist (TRI_hash_array_multi_t*
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void ReturnToFreelist (TRI_hash_array_multi_t* array,
|
static void ReturnToFreelist (TRI_hash_array_multi_t* array,
|
||||||
TRI_hash_index_element_multi_t* element) {
|
TRI_hash_index_element_overflow_t* element) {
|
||||||
element->_document = nullptr;
|
element->_document = nullptr;
|
||||||
element->_next = array->_freelist;
|
element->_next = array->_freelist;
|
||||||
array->_freelist = element;
|
array->_freelist = element;
|
||||||
|
@ -189,6 +205,19 @@ static void DestroyElement (TRI_hash_array_multi_t* array,
|
||||||
element->_next = nullptr;
|
element->_next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief destroys an element, removing any allocated memory
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static void DestroyElement (TRI_hash_array_multi_t* array,
|
||||||
|
TRI_hash_index_element_overflow_t* element) {
|
||||||
|
TRI_ASSERT_EXPENSIVE(element != nullptr);
|
||||||
|
TRI_ASSERT_EXPENSIVE(element->_document != nullptr);
|
||||||
|
|
||||||
|
element->_document = nullptr;
|
||||||
|
element->_next = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief initial preallocation size of the hash table when the table is
|
/// @brief initial preallocation size of the hash table when the table is
|
||||||
/// first created
|
/// first created
|
||||||
|
@ -200,18 +229,6 @@ static inline uint64_t InitialSize () {
|
||||||
return 251;
|
return 251;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- private functions
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief return the size of a single entry
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static inline size_t TableEntrySize () {
|
|
||||||
return sizeof(TRI_hash_index_element_multi_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief allocate memory for the hash table
|
/// @brief allocate memory for the hash table
|
||||||
///
|
///
|
||||||
|
@ -351,13 +368,18 @@ void TRI_DestroyHashArrayMulti (TRI_hash_array_multi_t* array) {
|
||||||
e = p + array->_nrAlloc;
|
e = p + array->_nrAlloc;
|
||||||
|
|
||||||
for (; p < e; ++p) {
|
for (; p < e; ++p) {
|
||||||
auto current = p;
|
if (p->_document != nullptr) {
|
||||||
|
// destroy overflow elements
|
||||||
while (current != nullptr && current->_document != nullptr) {
|
auto current = p->_next;
|
||||||
|
while (current != nullptr) {
|
||||||
auto ptr = current->_next;
|
auto ptr = current->_next;
|
||||||
DestroyElement(array, current);
|
DestroyElement(array, current);
|
||||||
current = ptr;
|
current = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// destroy the element itself
|
||||||
|
DestroyElement(array, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, array->_tablePtr);
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, array->_tablePtr);
|
||||||
|
@ -397,10 +419,9 @@ size_t TRI_MemoryUsageHashArrayMulti (TRI_hash_array_multi_t const* array) {
|
||||||
|
|
||||||
size_t tableSize = (size_t) (array->_nrAlloc * TableEntrySize() + 64);
|
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 memberSize = (size_t) (array->_nrUsed * array->_numFields * sizeof(TRI_shaped_sub_t));
|
||||||
size_t overflowUsed = (size_t) (array->_nrOverflowUsed * array->_numFields * sizeof(TRI_shaped_sub_t));
|
size_t overflowAlloc = (size_t) (array->_nrOverflowAlloc * OverflowEntrySize());
|
||||||
size_t overflowAlloc = (size_t) (array->_nrOverflowAlloc * TableEntrySize());
|
|
||||||
|
|
||||||
return (size_t) (tableSize + memberSize + overflowUsed + overflowAlloc);
|
return (size_t) (tableSize + memberSize + overflowAlloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -409,7 +430,15 @@ size_t TRI_MemoryUsageHashArrayMulti (TRI_hash_array_multi_t const* array) {
|
||||||
|
|
||||||
int TRI_ResizeHashArrayMulti (TRI_hash_array_multi_t* array,
|
int TRI_ResizeHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
return ResizeHashArray(array, (uint64_t) (2 * size + 1), false);
|
// 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 = 0.75 * size;
|
||||||
|
if ((targetSize & 1) == 0) {
|
||||||
|
// make odd
|
||||||
|
targetSize++;
|
||||||
|
}
|
||||||
|
return ResizeHashArray(array, (uint64_t) targetSize, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -444,20 +473,17 @@ TRI_vector_pointer_t TRI_LookupByKeyHashArrayMulti (TRI_hash_array_multi_t const
|
||||||
TRI_ASSERT_EXPENSIVE(i < n);
|
TRI_ASSERT_EXPENSIVE(i < n);
|
||||||
|
|
||||||
if (array->_table[i]._document != nullptr) {
|
if (array->_table[i]._document != nullptr) {
|
||||||
auto current = &array->_table[i];
|
// add the element itself
|
||||||
|
TRI_PushBackVectorPointer(&result, array->_table[i]._document);
|
||||||
|
|
||||||
|
// add the overflow elements
|
||||||
|
auto current = array->_table[i]._next;
|
||||||
while (current != nullptr) {
|
while (current != nullptr) {
|
||||||
if (IsEqualKeyElement(array, key, current)) {
|
TRI_PushBackVectorPointer(&result, current->_document);
|
||||||
TRI_PushBackVectorPointer(&result, current);
|
|
||||||
}
|
|
||||||
current = current->_next;
|
current = current->_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// return whatever we found -- which could be an empty vector list if nothing
|
|
||||||
// matches.
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,8 +502,6 @@ int TRI_InsertElementHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||||
return TRI_ERROR_OUT_OF_MEMORY;
|
return TRI_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
element->_next = nullptr;
|
|
||||||
|
|
||||||
uint64_t const n = array->_nrAlloc;
|
uint64_t const n = array->_nrAlloc;
|
||||||
uint64_t i, k;
|
uint64_t i, k;
|
||||||
|
|
||||||
|
@ -504,7 +528,13 @@ int TRI_InsertElementHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
if (isRollback) {
|
if (isRollback) {
|
||||||
auto current = arrayElement;
|
if (arrayElement->_document == element->_document) {
|
||||||
|
DestroyElement(array, element);
|
||||||
|
|
||||||
|
return TRI_RESULT_ELEMENT_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current = arrayElement->_next;
|
||||||
while (current != nullptr) {
|
while (current != nullptr) {
|
||||||
if (current->_document == element->_document) {
|
if (current->_document == element->_document) {
|
||||||
DestroyElement(array, element);
|
DestroyElement(array, element);
|
||||||
|
@ -521,13 +551,21 @@ int TRI_InsertElementHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||||
return TRI_ERROR_OUT_OF_MEMORY;
|
return TRI_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
element->_next = arrayElement->_next;
|
// link our element at the list head
|
||||||
*ptr = *element;
|
ptr->_document = element->_document;
|
||||||
|
ptr->_next = arrayElement->_next;
|
||||||
arrayElement->_next = ptr;
|
arrayElement->_next = ptr;
|
||||||
|
|
||||||
|
// it is ok to destroy the element here, because we have copied its internal before!
|
||||||
|
DestroyElement(array, element);
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
return TRI_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(arrayElement->_next == nullptr);
|
||||||
|
|
||||||
|
// not found in list, now insert insert
|
||||||
|
element->_next = nullptr;
|
||||||
*arrayElement = *element;
|
*arrayElement = *element;
|
||||||
array->_nrUsed++;
|
array->_nrUsed++;
|
||||||
|
|
||||||
|
@ -555,10 +593,6 @@ int TRI_RemoveElementHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||||
|
|
||||||
TRI_hash_index_element_multi_t* arrayElement = &array->_table[i];
|
TRI_hash_index_element_multi_t* arrayElement = &array->_table[i];
|
||||||
|
|
||||||
// ...........................................................................
|
|
||||||
// if we did not find such an item return false
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
bool found = (arrayElement->_document != nullptr);
|
bool found = (arrayElement->_document != nullptr);
|
||||||
|
|
||||||
if (! found) {
|
if (! found) {
|
||||||
|
@ -566,34 +600,39 @@ int TRI_RemoveElementHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arrayElement->_document != element->_document) {
|
if (arrayElement->_document != element->_document) {
|
||||||
auto current = arrayElement;
|
// look in the overflow list for the sought document
|
||||||
while (current->_next != nullptr) {
|
auto next = &(arrayElement->_next);
|
||||||
if (current->_next->_document == element->_document) {
|
while (*next != nullptr) {
|
||||||
auto ptr = current->_next->_next;
|
if ((*next)->_document == element->_document) {
|
||||||
DestroyElement(array, current->_next);
|
auto ptr = (*next)->_next;
|
||||||
ReturnToFreelist(array, current->_next);
|
DestroyElement(array, *next);
|
||||||
|
ReturnToFreelist(array, *next);
|
||||||
current->_next = ptr;
|
*next = ptr;
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
return TRI_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
current = current->_next;
|
next = &((*next)->_next);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRI_RESULT_ELEMENT_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the element itself is the document to remove
|
||||||
if (arrayElement->_next != nullptr) {
|
if (arrayElement->_next != nullptr) {
|
||||||
auto ptr = arrayElement->_next;
|
auto next = arrayElement->_next;
|
||||||
DestroyElement(array, arrayElement);
|
|
||||||
|
|
||||||
*arrayElement = *ptr;
|
// copy data from first overflow element into ourselves
|
||||||
ReturnToFreelist(array, ptr);
|
arrayElement->_document = next->_document;
|
||||||
|
arrayElement->_next = next->_next;
|
||||||
|
|
||||||
|
// and remove the first overflow element
|
||||||
|
DestroyElement(array, next);
|
||||||
|
ReturnToFreelist(array, next);
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
return TRI_ERROR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...........................................................................
|
TRI_ASSERT(arrayElement->_next == nullptr);
|
||||||
// remove item
|
|
||||||
// ...........................................................................
|
|
||||||
|
|
||||||
DestroyElement(array, arrayElement);
|
DestroyElement(array, arrayElement);
|
||||||
array->_nrUsed--;
|
array->_nrUsed--;
|
||||||
|
@ -617,6 +656,7 @@ int TRI_RemoveElementHashArrayMulti (TRI_hash_array_multi_t* array,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array->_nrUsed == 0) {
|
if (array->_nrUsed == 0) {
|
||||||
|
TRI_ASSERT(array->_nrOverflowUsed == 0);
|
||||||
ResizeHashArray(array, InitialSize(), true);
|
ResizeHashArray(array, InitialSize(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
// --SECTION-- forward declarations
|
// --SECTION-- forward declarations
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct TRI_hash_index_element_overflow_s;
|
||||||
struct TRI_hash_index_element_multi_s;
|
struct TRI_hash_index_element_multi_s;
|
||||||
struct TRI_index_search_value_s;
|
struct TRI_index_search_value_s;
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ typedef struct TRI_hash_array_multi_s {
|
||||||
struct TRI_hash_index_element_multi_s* _table; // the table itself, aligned to a cache line boundary
|
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* _tablePtr; // the table itself
|
||||||
|
|
||||||
struct TRI_hash_index_element_multi_s* _freelist;
|
struct TRI_hash_index_element_overflow_s* _freelist;
|
||||||
|
|
||||||
TRI_vector_pointer_t _blocks;
|
TRI_vector_pointer_t _blocks;
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,7 +411,7 @@ static TRI_index_result_t MultiHashIndex_find (TRI_hash_index_t* hashIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t j = 0; j < result._length; ++j) {
|
for (size_t j = 0; j < result._length; ++j) {
|
||||||
results._documents[j] = ((TRI_hash_index_element_multi_t*)(result._buffer[j]))->_document;
|
results._documents[j] = ((TRI_doc_mptr_t*) result._buffer[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,10 +64,16 @@ typedef struct TRI_hash_index_element_s {
|
||||||
}
|
}
|
||||||
TRI_hash_index_element_t;
|
TRI_hash_index_element_t;
|
||||||
|
|
||||||
|
typedef struct TRI_hash_index_element_overflow_s {
|
||||||
|
struct TRI_doc_mptr_t* _document;
|
||||||
|
struct TRI_hash_index_element_overflow_s* _next;
|
||||||
|
}
|
||||||
|
TRI_hash_index_element_overflow_t;
|
||||||
|
|
||||||
typedef struct TRI_hash_index_element_multi_s {
|
typedef struct TRI_hash_index_element_multi_s {
|
||||||
struct TRI_doc_mptr_t* _document;
|
struct TRI_doc_mptr_t* _document;
|
||||||
struct TRI_shaped_sub_s* _subObjects;
|
struct TRI_shaped_sub_s* _subObjects;
|
||||||
struct TRI_hash_index_element_multi_s* _next;
|
struct TRI_hash_index_element_overflow_s* _next;
|
||||||
}
|
}
|
||||||
TRI_hash_index_element_multi_t;
|
TRI_hash_index_element_multi_t;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*global require, db, assertEqual, assertTrue, ArangoCollection */
|
/*global require, db, assertEqual, assertTrue */
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief test the unique constraint
|
/// @brief test the unique constraint
|
||||||
|
@ -356,6 +356,143 @@ function HashIndexSuite() {
|
||||||
|
|
||||||
var doc2 = collection.save({ a : "test3", b : 1});
|
var doc2 = collection.save({ a : "test3", b : 1});
|
||||||
assertTrue(doc2._key !== "");
|
assertTrue(doc2._key !== "");
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test multi hash querying
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultiHashQuery1 : function () {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
collection.ensureHashIndex("value");
|
||||||
|
for (i = 0; i < 1000; ++i) {
|
||||||
|
collection.save({ _key: "test" + i, value: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(1000, collection.byExampleHash(collection.getIndexes()[1], { value: 1 }).toArray().length);
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test multi hash querying
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultiHashQuery2 : function () {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
collection.ensureHashIndex("value");
|
||||||
|
for (i = 0; i < 1000; ++i) {
|
||||||
|
collection.save({ _key: "test" + i, value: i });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 1000; ++i) {
|
||||||
|
var docs = collection.byExampleHash(collection.getIndexes()[1], { value: i }).toArray();
|
||||||
|
assertEqual(1, docs.length);
|
||||||
|
assertEqual("test" + i, docs[0]._key);
|
||||||
|
assertEqual(i, docs[0].value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test multi hash querying
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultiHashQuery3 : function () {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
collection.ensureHashIndex("value");
|
||||||
|
for (i = 0; i < 1000; ++i) {
|
||||||
|
collection.save({ _key: "test" + i, value: i % 4 });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
var docs = collection.byExampleHash(collection.getIndexes()[1], { value: i }).toArray();
|
||||||
|
assertEqual(250, docs.length);
|
||||||
|
docs.forEach(function(doc) {
|
||||||
|
assertEqual(i, doc.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test collisions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultiHashQuery4 : function () {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
collection.ensureHashIndex("value");
|
||||||
|
for (i = 0; i < 10000; ++i) {
|
||||||
|
collection.save({ _key: "test" + i, value: "testvalue" + i });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 10000; ++i) {
|
||||||
|
var docs = collection.byExampleHash(collection.getIndexes()[1], { value: "testvalue" + i }).toArray();
|
||||||
|
assertEqual(1, docs.length);
|
||||||
|
assertEqual("test" + i, docs[0]._key);
|
||||||
|
assertEqual("testvalue" + i, docs[0].value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test multi hash updating
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultiHashUpdate : function () {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
collection.ensureHashIndex("value");
|
||||||
|
for (i = 0; i < 1000; ++i) {
|
||||||
|
collection.save({ _key: "test" + i, value: i % 4 });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
var docs = collection.byExampleHash(collection.getIndexes()[1], { value: i }).toArray();
|
||||||
|
assertEqual(250, docs.length);
|
||||||
|
docs.forEach(function(doc) {
|
||||||
|
assertEqual(i, doc.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 500; i < 1000; ++i) {
|
||||||
|
collection.update("test" + i, { value: (i % 4) + 4 });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
var docs = collection.byExampleHash(collection.getIndexes()[1], { value: i }).toArray();
|
||||||
|
assertEqual(125, docs.length);
|
||||||
|
docs.forEach(function(doc) {
|
||||||
|
assertEqual(i, doc.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief multi hash index removal
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testMultiHashRemoval : function () {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
collection.ensureHashIndex("value");
|
||||||
|
for (i = 0; i < 1000; ++i) {
|
||||||
|
collection.save({ _key: "test" + i, value: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEqual(1000, collection.byExampleHash(collection.getIndexes()[1], { value: 1 }).toArray().length);
|
||||||
|
|
||||||
|
// remove head of list
|
||||||
|
collection.remove("test0");
|
||||||
|
assertEqual(999, collection.byExampleHash(collection.getIndexes()[1], { value: 1 }).toArray().length);
|
||||||
|
|
||||||
|
// remove new head of list
|
||||||
|
collection.remove("test999");
|
||||||
|
assertEqual(998, collection.byExampleHash(collection.getIndexes()[1], { value: 1 }).toArray().length);
|
||||||
|
|
||||||
|
for (i = 1; i < 998; ++i) {
|
||||||
|
collection.remove("test" + i);
|
||||||
|
assertEqual(998 - i, collection.byExampleHash(collection.getIndexes()[1], { value: 1 }).toArray().length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue