*build*/
CMakeLists.txt.user
*~
+*.log
m_cell = Details::find(hash, m_table, m_sizeMask);
if (!m_cell)
return;
- m_value = m_cell->value.load(turf::Consume);
- if (m_value != Value(ValueTraits::Redirect))
- return; // Found an existing value
+ Value value = m_cell->value.load(turf::Consume);
+ if (value != Value(ValueTraits::Redirect)) {
+ // Found an existing value
+ m_value = value;
+ return;
+ }
// We've encountered a Redirect value. Help finish the migration.
TURF_TRACE(ConcurrentMap_Grampa, 11, "[Mutator] find was redirected", uptr(m_table), 0);
m_table->jobCoordinator.participate();
}
case Details::InsertResult_AlreadyFound: {
// The hash was already found in the table.
- m_value = m_cell->value.load(turf::Consume);
- if (m_value == Value(ValueTraits::Redirect)) {
+ Value value = m_cell->value.load(turf::Consume);
+ if (value == Value(ValueTraits::Redirect)) {
// We've encountered a Redirect value.
TURF_TRACE(ConcurrentMap_Grampa, 13, "[Mutator] insertOrFind was redirected", uptr(m_table), uptr(m_value));
break; // Help finish the migration.
}
- return; // Found an existing value
+ // Found an existing value
+ m_value = value;
+ return;
}
case Details::InsertResult_Overflow: {
Details::beginTableMigration(m_map, m_table, overflowIdx);
m_cell = Details::find(hash, m_table);
if (!m_cell)
return;
- m_value = m_cell->value.load(turf::Consume);
- if (m_value != Value(ValueTraits::Redirect))
- return; // Found an existing value
+ Value value = m_cell->value.load(turf::Consume);
+ if (value != Value(ValueTraits::Redirect)) {
+ // Found an existing value
+ m_value = value;
+ return;
+ }
// We've encountered a Redirect value. Help finish the migration.
TURF_TRACE(ConcurrentMap_Leapfrog, 1, "[Mutator] find was redirected", uptr(m_table), 0);
m_table->jobCoordinator.participate();
}
case Details::InsertResult_AlreadyFound: {
// The hash was already found in the table.
- m_value = m_cell->value.load(turf::Consume);
- if (m_value == Value(ValueTraits::Redirect)) {
+ Value value = m_cell->value.load(turf::Consume);
+ if (value == Value(ValueTraits::Redirect)) {
// We've encountered a Redirect value.
TURF_TRACE(ConcurrentMap_Leapfrog, 3, "[Mutator] insertOrFind was redirected", uptr(m_table), uptr(m_value));
break; // Help finish the migration.
}
- return; // Found an existing value
+ // Found an existing value
+ m_value = value;
+ return;
}
case Details::InsertResult_Overflow: {
// Unlike ConcurrentMap_Linear, we don't need to keep track of & pass a "mustDouble" flag.
m_cell = Details::find(hash, m_table);
if (!m_cell)
return;
- m_value = m_cell->value.load(turf::Consume);
- if (m_value != Value(ValueTraits::Redirect))
- return; // Found an existing value
+ Value value = m_cell->value.load(turf::Consume);
+ if (value != Value(ValueTraits::Redirect)) {
+ // Found an existing value
+ m_value = value;
+ return;
+ }
// We've encountered a Redirect value. Help finish the migration.
TURF_TRACE(ConcurrentMap_Linear, 1, "[Mutator] find was redirected", uptr(m_table), 0);
m_table->jobCoordinator.participate();
}
case Details::InsertResult_AlreadyFound: {
// The hash was already found in the table.
- m_value = m_cell->value.load(turf::Consume);
- if (m_value == Value(ValueTraits::Redirect)) {
+ Value value = m_cell->value.load(turf::Consume);
+ if (value == Value(ValueTraits::Redirect)) {
// We've encountered a Redirect value.
TURF_TRACE(ConcurrentMap_Linear, 3, "[Mutator] insertOrFind was redirected", uptr(m_table), uptr(m_value));
break; // Help finish the migration.
}
- return; // Found an existing value
+ // Found an existing value
+ m_value = value;
+ return;
}
case Details::InsertResult_Overflow: {
Details::beginTableMigration(m_map, m_table, mustDouble);
#include "TestInsertSameKeys.h"
#include "TestInsertDifferentKeys.h"
#include "TestChurn.h"
+#include "TestDoubleAssign.h"
#include <turf/extra/Options.h>
#include <junction/details/Grampa.h> // for GrampaStats
TestInsertSameKeys testInsertSameKeys(env);
TestInsertDifferentKeys testInsertDifferentKeys(env);
TestChurn testChurn(env);
+ TestDoubleAssign testDoubleAssign(env);
for (;;) {
for (ureg c = 0; c < IterationsPerLog; c++) {
testInsertSameKeys.run();
testInsertDifferentKeys.run();
testChurn.run();
+ testDoubleAssign.run();
}
turf::Trace::Instance.dumpStats();
--- /dev/null
+/*------------------------------------------------------------------------
+ Junction: Concurrent data structures in C++
+ Copyright (c) 2016, 2017 Jeff Preshing
+
+ Distributed under the Simplified BSD License.
+ Original location: https://github.com/preshing/junction
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the LICENSE file for more information.
+------------------------------------------------------------------------*/
+
+#ifndef SAMPLES_MAPCORRECTNESSTESTS_TESTDOUBLEASSIGN_H
+#define SAMPLES_MAPCORRECTNESSTESTS_TESTDOUBLEASSIGN_H
+
+#include <junction/Core.h>
+#include "TestEnvironment.h"
+#include <turf/extra/Random.h>
+
+class TestDoubleAssign {
+public:
+ static const ureg KeysToInsert = 1000;
+ TestEnvironment& m_env;
+ MapAdapter::Map* m_map;
+ turf::Atomic<u32> m_index;
+
+ TestDoubleAssign(TestEnvironment& env) : m_env(env), m_map(NULL), m_index(0) {
+ }
+
+ void doubleAssignKeys(ureg threadIndex) {
+ for (;;) {
+ u32 key = m_index.fetchAdd(1, turf::Relaxed);
+ if (key >= KeysToInsert + 2)
+ break;
+
+ m_map->assign(key, (void*) (key * 20));
+ m_map->erase(key);
+ m_map->assign(key, (void*) (key * 20));
+ }
+ m_env.threads[threadIndex].update();
+ }
+
+ void checkMapContents() {
+#if TEST_CHECK_MAP_CONTENTS
+ for (MapAdapter::Map::Iterator iter(*m_map); iter.isValid(); iter.next()) {
+ u32 key = iter.getKey();
+ if (iter.getValue() != (void*) (key * 20))
+ TURF_DEBUG_BREAK();
+ }
+
+ for (ureg i = 2; i < KeysToInsert + 2; i++) {
+ auto r = m_map->find(i);
+ if (r.getValue() != (void*) (i * 20))
+ TURF_DEBUG_BREAK();
+ }
+#endif
+ }
+
+ void run() {
+ m_map = new MapAdapter::Map(MapAdapter::getInitialCapacity(KeysToInsert));
+ m_index = 2;
+ m_env.dispatcher.kick(&TestDoubleAssign::doubleAssignKeys, *this);
+ checkMapContents();
+ delete m_map;
+ m_map = NULL;
+ }
+};
+
+#endif // SAMPLES_MAPCORRECTNESSTESTS_TESTDOUBLEASSIGN_H