mirror of https://gitee.com/bigwinds/arangodb
Fix bug in associative-multi-pointer hash.
Also finish unittest for it.
This commit is contained in:
parent
7549c13bc5
commit
0b80d25c29
|
@ -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
|
||||||
|
@ -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];
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue