1
0
Fork 0

Fix bug in associative-multi-pointer hash.

Also finish unittest for it.
This commit is contained in:
Max Neunhoeffer 2014-04-01 20:28:58 +02:00
parent 7549c13bc5
commit 0b80d25c29
2 changed files with 183 additions and 55 deletions

View File

@ -158,8 +158,8 @@ BOOST_AUTO_TEST_CASE (tst_insert_few) {
// Note MODULUS must be a divisor of NUMBER_OF_ELEMENTS // Note MODULUS must be a divisor of NUMBER_OF_ELEMENTS
// and NUMBER_OF_ELEMENTS must be a multiple of 3. // and NUMBER_OF_ELEMENTS must be a multiple of 3.
#define NUMBER_OF_ELEMENTS 24 #define NUMBER_OF_ELEMENTS 3000
#define MODULUS 4 #define MODULUS 10
BOOST_AUTO_TEST_CASE (tst_insert_delete_many) { BOOST_AUTO_TEST_CASE (tst_insert_delete_many) {
INIT_MULTI INIT_MULTI
@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE (tst_insert_delete_many) {
BOOST_CHECK_EQUAL(p,v[i]); BOOST_CHECK_EQUAL(p,v[i]);
} }
// This should not be there: // This should not be there:
p = static_cast<data_container_t*> p = static_cast<data_container_t*>
(TRI_LookupByElementMultiPointer(&a1, one_more)); (TRI_LookupByElementMultiPointer(&a1, one_more));
BOOST_CHECK_EQUAL(n, p); BOOST_CHECK_EQUAL(n, p);
@ -218,17 +218,68 @@ BOOST_AUTO_TEST_CASE (tst_insert_delete_many) {
for (i = 0;i < v.size();i += 3) { for (i = 0;i < v.size();i += 3) {
BOOST_CHECK_EQUAL(v[i], TRI_RemoveElementMultiPointer(&a1, v[i])); BOOST_CHECK_EQUAL(v[i], TRI_RemoveElementMultiPointer(&a1, v[i]));
} }
for (i = 0;i < v.size();i += 3) {
BOOST_CHECK_EQUAL(n, TRI_RemoveElementMultiPointer(&a1, v[i]));
}
// Now check which are there (by element):
for (i = 0;i < NUMBER_OF_ELEMENTS;i++) {
p = static_cast<data_container_t*>
(TRI_LookupByElementMultiPointer(&a1, v[i]));
if (i % 3 == 0) {
BOOST_CHECK_EQUAL(p,n);
}
else {
BOOST_CHECK_EQUAL(p,v[i]);
}
}
// This should not be there:
p = static_cast<data_container_t*>
(TRI_LookupByElementMultiPointer(&a1, one_more));
BOOST_CHECK_EQUAL(n, p);
// Delete some more: // Delete some more:
for (i = 1;i < v.size();i += 3) { for (i = 1;i < v.size();i += 3) {
BOOST_CHECK_EQUAL(v[i], TRI_RemoveElementMultiPointer(&a1, v[i])); BOOST_CHECK_EQUAL(v[i], TRI_RemoveElementMultiPointer(&a1, v[i]));
} }
for (i = 1;i < v.size();i += 3) {
BOOST_CHECK_EQUAL(n, TRI_RemoveElementMultiPointer(&a1, v[i]));
}
// Now check which are there (by element):
for (i = 0;i < NUMBER_OF_ELEMENTS;i++) {
p = static_cast<data_container_t*>
(TRI_LookupByElementMultiPointer(&a1, v[i]));
if (i % 3 == 2) {
BOOST_CHECK_EQUAL(p,v[i]);
}
else {
BOOST_CHECK_EQUAL(p,n);
}
}
// This should not be there:
p = static_cast<data_container_t*>
(TRI_LookupByElementMultiPointer(&a1, one_more));
BOOST_CHECK_EQUAL(n, p);
// Delete the rest: // Delete the rest:
for (i = 2;i < v.size();i += 3) { for (i = 2;i < v.size();i += 3) {
BOOST_CHECK_EQUAL(v[i], TRI_RemoveElementMultiPointer(&a1, v[i])); BOOST_CHECK_EQUAL(v[i], TRI_RemoveElementMultiPointer(&a1, v[i]));
} }
for (i = 2;i < v.size();i += 3) {
BOOST_CHECK_EQUAL(n, TRI_RemoveElementMultiPointer(&a1, v[i]));
}
// Now check which are there (by element):
for (i = 0;i < NUMBER_OF_ELEMENTS;i++) {
p = static_cast<data_container_t*>
(TRI_LookupByElementMultiPointer(&a1, v[i]));
BOOST_CHECK_EQUAL(p,n);
}
// This should not be there:
p = static_cast<data_container_t*>
(TRI_LookupByElementMultiPointer(&a1, one_more));
BOOST_CHECK_EQUAL(n, p);
// Pull down data again: // Pull down data again:
for (i = 0;i < NUMBER_OF_ELEMENTS;i++) { for (i = 0;i < NUMBER_OF_ELEMENTS;i++) {
delete v[i]; delete v[i];

View File

@ -122,6 +122,99 @@ void TRI_FreeMultiPointer (TRI_memory_zone_t* zone, TRI_multi_pointer_t* array)
// --SECTION-- private functions // --SECTION-- private functions
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#if 0
// Activate for additional debugging:
#define TRI_CHECK_MULTI_POINTER_HASH 1
#endif
#ifdef TRI_CHECK_MULTI_POINTER_HASH
bool TRI_CheckMultiPointerHash (TRI_multi_pointer_t* array, bool checkCount,
bool checkPositions) {
uint64_t i,ii,j,k;
bool ok;
uint64_t count;
uint64_t hash;
ok = true;
count = 0;
for (i = 0;i < array->_nrAlloc;i++) {
if (array->_table[i].ptr != NULL) {
count++;
if (array->_table[i].prev != TRI_MULTI_POINTER_INVALID_INDEX) {
if (array->_table[array->_table[i].prev].next != i) {
printf("Alarm prev %llu\n",(unsigned long long) i);
ok = false;
}
}
if (array->_table[i].next != TRI_MULTI_POINTER_INVALID_INDEX) {
if (array->_table[array->_table[i].next].prev != i) {
printf("Alarm next %llu\n",(unsigned long long) i);
ok = false;
}
}
ii = i;
j = array->_table[ii].next;
while (j != TRI_MULTI_POINTER_INVALID_INDEX) {
if (j == i) {
printf("Alarm cycle %llu\n",(unsigned long long) i);
ok = false;
break;
}
ii = j;
j = array->_table[ii].next;
}
}
}
if (checkCount && count != array->_nrUsed) {
printf("Alarm nrUsed wrong %llu != %llu!\n",
(unsigned long long) array->_nrUsed,
(unsigned long long) count);
ok = false;
}
if (checkPositions) {
for (i = 0;i < array->_nrAlloc;i++) {
if (array->_table[i].ptr != NULL) {
if (array->_table[i].prev == TRI_MULTI_POINTER_INVALID_INDEX) {
// We are the first in a linked list.
hash = array->hashElement(array, array->_table[i].ptr,true);
j = hash % array->_nrAlloc;
for (k = j; k != i; ) {
if (array->_table[k].ptr == NULL ||
(array->_table[k].prev == TRI_MULTI_POINTER_INVALID_INDEX &&
array->isEqualElementElement(array, array->_table[i].ptr,
array->_table[k].ptr,
true))) {
ok = false;
printf("Alarm pos bykey: %llu\n", (unsigned long long) i);
}
k = TRI_IncModU64(k, array->_nrAlloc);
}
}
else {
// We are not the first in a linked list.
hash = array->hashElement(array, array->_table[i].ptr, false);
j = hash % array->_nrAlloc;
for (k = j; k != i; ) {
if (array->_table[k].ptr == NULL ||
array->isEqualElementElement(array, array->_table[i].ptr,
array->_table[k].ptr, false)) {
ok = false;
printf("Alarm unique: %llu, %llu\n", (unsigned long long) k,
(unsigned long long) i);
}
k = TRI_IncModU64(k, array->_nrAlloc);
}
}
}
}
}
if (!ok) {
printf("Something is wrong!");
}
return ok;
}
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief find an element or its place using the element hash function /// @brief find an element or its place using the element hash function
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -294,6 +387,10 @@ void* TRI_InsertElementMultiPointer (TRI_multi_pointer_t* array,
uint64_t i, j; uint64_t i, j;
void* old; void* old;
#ifdef TRI_CHECK_MULTI_POINTER_HASH
TRI_CheckMultiPointerHash(array, true, true);
#endif
// if we were adding and the table is more than half full, extend it // if we were adding and the table is more than half full, extend it
if (array->_nrAlloc < 2 * array->_nrUsed) { if (array->_nrAlloc < 2 * array->_nrUsed) {
ResizeMultiPointer(array, 2 * array->_nrAlloc + 1); ResizeMultiPointer(array, 2 * array->_nrAlloc + 1);
@ -314,6 +411,9 @@ void* TRI_InsertElementMultiPointer (TRI_multi_pointer_t* array,
array->_table[i].next = TRI_MULTI_POINTER_INVALID_INDEX; array->_table[i].next = TRI_MULTI_POINTER_INVALID_INDEX;
array->_table[i].prev = TRI_MULTI_POINTER_INVALID_INDEX; array->_table[i].prev = TRI_MULTI_POINTER_INVALID_INDEX;
array->_nrUsed++; array->_nrUsed++;
#ifdef TRI_CHECK_MULTI_POINTER_HASH
TRI_CheckMultiPointerHash(array, true, true);
#endif
return NULL; return NULL;
} }
@ -337,6 +437,9 @@ void* TRI_InsertElementMultiPointer (TRI_multi_pointer_t* array,
array->_table[i].next = TRI_MULTI_POINTER_INVALID_INDEX; array->_table[i].next = TRI_MULTI_POINTER_INVALID_INDEX;
array->_table[i].prev = TRI_MULTI_POINTER_INVALID_INDEX; array->_table[i].prev = TRI_MULTI_POINTER_INVALID_INDEX;
array->_nrUsed++; array->_nrUsed++;
#ifdef TRI_CHECK_MULTI_POINTER_HASH
TRI_CheckMultiPointerHash(array, true, true);
#endif
return NULL; return NULL;
} }
@ -349,6 +452,9 @@ void* TRI_InsertElementMultiPointer (TRI_multi_pointer_t* array,
if (overwrite) { if (overwrite) {
array->_table[i].ptr = element; array->_table[i].ptr = element;
} }
#ifdef TRI_CHECK_MULTI_POINTER_HASH
TRI_CheckMultiPointerHash(array, true, true);
#endif
return old; return old;
} }
@ -362,6 +468,9 @@ void* TRI_InsertElementMultiPointer (TRI_multi_pointer_t* array,
if (overwrite) { if (overwrite) {
array->_table[j].ptr = element; array->_table[j].ptr = element;
} }
#ifdef TRI_CHECK_MULTI_POINTER_HASH
TRI_CheckMultiPointerHash(array, true, true);
#endif
return old; return old;
} }
@ -372,10 +481,13 @@ void* TRI_InsertElementMultiPointer (TRI_multi_pointer_t* array,
array->_table[i].next = j; array->_table[i].next = j;
// Finally, we need to find the successor to patch it up: // Finally, we need to find the successor to patch it up:
if (array->_table[j].next != TRI_MULTI_POINTER_INVALID_INDEX) { if (array->_table[j].next != TRI_MULTI_POINTER_INVALID_INDEX) {
array->_table[array->_table[j].next].prev = i; array->_table[array->_table[j].next].prev = j;
} }
array->_nrUsed++; array->_nrUsed++;
#ifdef TRI_CHECK_MULTI_POINTER_HASH
TRI_CheckMultiPointerHash(array, true, true);
#endif
return NULL; return NULL;
} }
@ -445,29 +557,6 @@ void* TRI_LookupByElementMultiPointer (TRI_multi_pointer_t* array,
/// @brief removes an element from the array /// @brief removes an element from the array
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static bool CHECK (TRI_multi_pointer_t* array) {
uint64_t i,ii,j;
for (i = 0;i < array->_nrAlloc;i++) {
if (array->_table[i].ptr != NULL &&
array->_table[i].prev == TRI_MULTI_POINTER_INVALID_INDEX) {
ii = i;
j = array->_table[ii].next;
while (j != TRI_MULTI_POINTER_INVALID_INDEX) {
if (array->_table[j].prev != ii) {
printf("Alarm: %llu %llu %llu\n",(unsigned long long) i,
(unsigned long long) ii,
(unsigned long long) j);
return true;
}
ii = j;
j = array->_table[ii].next;
}
}
}
return false;
}
void* TRI_RemoveElementMultiPointer (TRI_multi_pointer_t* array, void const* element) { void* TRI_RemoveElementMultiPointer (TRI_multi_pointer_t* array, void const* element) {
uint64_t i, j; uint64_t i, j;
void* old; void* old;
@ -477,17 +566,14 @@ void* TRI_RemoveElementMultiPointer (TRI_multi_pointer_t* array, void const* ele
array->_nrRems++; array->_nrRems++;
#endif #endif
if (CHECK(array)) { #ifdef TRI_CHECK_MULTI_POINTER_HASH
printf("Alarm 1\n"); TRI_CheckMultiPointerHash(array, true, true);
} #endif
i = LookupByElement(array, element); i = LookupByElement(array, element);
if (array->_table[i].ptr == NULL) { if (array->_table[i].ptr == NULL) {
return NULL; return NULL;
} }
printf("Removing %llu with links %llu %llu\n",
(unsigned long long) i,
(unsigned long long) array->_table[i].prev,
(unsigned long long) array->_table[i].next);
old = array->_table[i].ptr; old = array->_table[i].ptr;
// We have to delete entry i // We have to delete entry i
if (array->_table[i].prev == TRI_MULTI_POINTER_INVALID_INDEX) { if (array->_table[i].prev == TRI_MULTI_POINTER_INVALID_INDEX) {
@ -497,25 +583,19 @@ void* TRI_RemoveElementMultiPointer (TRI_multi_pointer_t* array, void const* ele
// The only one in its linked list, simply remove it and heal // The only one in its linked list, simply remove it and heal
// the hole: // the hole:
InvalidateEntry(array, i); InvalidateEntry(array, i);
if (CHECK(array)) { #ifdef TRI_CHECK_MULTI_POINTER_HASH
printf("Alarm 2\n"); TRI_CheckMultiPointerHash(array, false, false);
} #endif
HealHole(array, i); HealHole(array, i);
if (CHECK(array)) {
printf("Alarm 3\n");
}
} }
else { else {
// There is at least one successor in position j. // There is at least one successor in position j.
array->_table[j].prev = TRI_MULTI_POINTER_INVALID_INDEX; array->_table[j].prev = TRI_MULTI_POINTER_INVALID_INDEX;
MoveEntry(array, j, i); MoveEntry(array, j, i);
if (CHECK(array)) { #ifdef TRI_CHECK_MULTI_POINTER_HASH
printf("Alarm 4\n"); TRI_CheckMultiPointerHash(array, false, false);
} #endif
HealHole(array, j); HealHole(array, j);
if (CHECK(array)) {
printf("Alarm 5\n");
}
} }
} }
else { else {
@ -527,19 +607,16 @@ void* TRI_RemoveElementMultiPointer (TRI_multi_pointer_t* array, void const* ele
// We are not the last in the linked list. // We are not the last in the linked list.
array->_table[j].prev = array->_table[i].prev; array->_table[j].prev = array->_table[i].prev;
} }
printf("prev=%llu next=%llu\n",(unsigned long long) array->_table[i].prev,
(unsigned long long) array->_table[i].next);
InvalidateEntry(array, i); InvalidateEntry(array, i);
if (CHECK(array)) { #ifdef TRI_CHECK_MULTI_POINTER_HASH
printf("Alarm 6\n"); TRI_CheckMultiPointerHash(array, false, false);
} #endif
HealHole(array, i); HealHole(array, i);
if (CHECK(array)) {
printf("Alarm 7\n");
}
} }
array->_nrUsed--; array->_nrUsed--;
#ifdef TRI_CHECK_MULTI_POINTER_HASH
TRI_CheckMultiPointerHash(array, true, true);
#endif
// return success // return success
return old; return old;
} }