Code Monkey home page Code Monkey logo

growt's Introduction

About

growt (GrowTable) is a header only library implementing a concurrent growing hash table. There are different variants depending on the use case. See explanation below.

Using the supplied cmake build system you can compile an example file (example/example.cpp) and a multitude of different tests/benchmarks. These were also used to generate the plots displayed in our scientific publications => TOPC journal technical report (outdated).

New Version (Changes)

  • complex data-types (arbitrary keys and values)
    • these tables work by allocating elements on the heap, but minimizing key-comparisons
    • new emplace/move functionality
  • new table dispatcher simplifies choosing the correct table

Hash table interface

To remain fast while storing some per thread data, we use handles. These help us to remain fast when accessing the hash table. Even though this is a change from the traditional interface, we try to remain as close to std::unordered_map as possible (within the handle). To achieve this we implemented an iterator based interface. Our iterators remain secure even when the table is migrated in the background. This is necessary because in concurrent scenarios one can never be certain, when a table migration occurs.

All our hash tables support the following functionality:

called on global object

  • HashTable(size_t n) - constructor allocating a table large enough to hold n elements.
  • HashTable::Handle getHandle() - create handles that can be used to access the table (alternatively HashTable::Handle(HashTable global_table_obj))

called through handles within the handles, we try to keep the interface as close to std::unordered_map as possible:

  • std::pair(iterator, bool) insert(uint64_t k, uint64_t d) - if no element with key k was present, insert stores the data element d at key k and returns an iterator (and true). Otherwise it returns an iterator to the already present element and false.
  • std::pair(iterator, bool) update(uint64_t k, UpdateFunction f, <parameters for f>...) - looks for an element with key k. If present, the stored data is changed atomically using the supplied update function (interface/instruction below). The returned iterator points to the found element (or end()), and the bool shows if an element was found.
  • std::pair(iterator, bool) insertOrUpdate(uint64_t k, uint64_t d, UpdateFunction f) - combines the two functions above. If no data was present with key k, then d is inserted, otherwise the stored data is updated. The bool can be used to find out which happened (true -> insertion, false -> update).
  • size_t erase(uint64_t k) - removes the stored key value pair, returns the number of erased entries (at most one). The memory is reclaimed once the table is migrated.
  • iterator find(uint64_t k) - finds the data element stored at key k and returns an iterator (end() if unfound).
  • const_iterator find(uint64_t k) const - same as find

Using handles is not necessary for our non-growing tables.

called through iterators

  • dereferencing/reading the values will return the values that were in the table when the iterator was created.
  • refresh will update the iterator to the current state of the table. This might make the iterator end() (cannot be dereferenced) if the element was erased in the meantime.

called through a reference

  • reading the values will return the values that were in the table when the iterator was created (that was dereferenced to become this reference).

About UpdateFunctions

Our update interface uses a user implemented update function. Any object given as an update function should have an operator()(uint64_t& cur_data, uint64_t key, uint64_t new_data) returning a uint64_t. This function will usually be called by our update operations to change a stored elements data field. This operations does not have to be atomic: it is made atomic using CAS operations. When an atomic version of the method exists, then it can be implemented as an additional function called .atomic(uint64_t& cur_data, uint64_t key, uint64_t new_data), which is only called iff atomics can be called safely (mostly in synchronized growing variants usGrow and psGrow). Presensce of the atomic variant is detected automatically. An example for a fully implemented UpdateFunction might look like this:

struct Increment
{
    uint64_t operator()(uint64_t& lhs, const uint64_t, const uint64_t rhs) const
    {
        return lhs += rhs;
    }

    // an atomic implementation can improve the performance of updates in .sGrow
    // this will be detected automatically
    uint64_t atomic    (uint64_t& lhs, const uint64_t, const uint64_t rhs) const
    {
        __sync_fetch_and_add(&lhs, rhs);
    }

};

Content

This package contains many different concurrent hash table variants that can be accessed through a dispatcher that automates choosing the correct implementation according to a set of parameters.

All our data structures and connected classes are declared in the growt namespace.

Non-growing hash tables

  • folklore is a simple linear probing hash table using atomic operations, to change cell contents.

Growing hash tables

Our growing variants use the above non-growing tables. They grow by migrating the entire hash table once it gets too full for the current size. Migration is done in the background without the user knowing about it. During the migration hash table accesses may be delayed until the table is migrated (usually the waiting thread will help with the migration).

Threads can only access our growing hash tables by creating a thread specific handle. These handles cannot be shared between threads.

  • uaGrow is a growing table, where threads that access the table are responsible for eventual migrations. These will be performed automatically and asynchronously. Migrated cells are marked to ensure atomicity (this reduces the available key space by one bit. Keys >=2^63 cannot be inserted).
  • usGrow similar to uaGrow but growing steps are somewhat synchronized (ensures automatically that no updates run during growing phases) eliminating the need for marking.
  • paGrow where growing is done by a dedicated pool of growing threads. Similar to uaGrow marking is used to ensure atomicity of the hash table migration.
  • psGrow combining the thread pool of paGrow with the synchronized growing approach of usGrow.

Our tests and Benchmarks

All generated tests (make recipes) have the same name structure.

<test_abbrv>_<growing_indicator>_<hash_table_name> => e.g. ins_full_uaGrow

test_abbrv

  • ins - insertion and find test (seperate)
  • mix - mixed inserts and finds
  • agg - aggregation using insertOrUpdate on a skewed key sequence
  • con - updates and finds on a skewed key sequence
  • del - alternating inserts and deletions (approx. constant table size)

full list of hash tables

Some of the following tables have to be activated through cmake options.

  • sequential - our sequential table (use only one thread!)
  • folklore - our non growing tables
  • uaGrow, usGrow, paGrow, psGrow - our main growing tables with different growing strategies
  • junction_linear, junction_grampa, junction_leap, folly, cuckoo, tbb_hm, tbb_um - third party tables

Note: in the paper we have some additional third party hash tables. These depend on some additional wrappers and are not reproduced here. Wrappers for their libraries can be found in a branch called legacy_wrappers.

Usage in your own projects

Including our project

To make it easy, you can include the header data-structures/table_config.hpp, which includes all necessary files and offers an interface to choose the right hash table for your workload. Additional hash table modifications can be found in data-structures/hash_table_mods.hpp

#include "data-structures/table_config.hpp"
using table_type =  typename growt::table_config<key_type, mapped_type,
                                                 hash_function, allocator_type,
                                                 // any number of hash mods
                                                 hmod::growable,
                                                 hmod::deletions>::table_type;

About our utility functions

The utility functions are now placed in their own submodule github repository

Our Usage of Third Party Code

This package can be used all on its own (see example.cpp and …test.cpp). However third party codes are used for additional functionality/tests. Most of the third party libraries are either searched on your machine (TBB, pthread), or they are placed in submodules (downloaded through git).

We use the following libraries:

for utility:

  • TBB - to implement a fixed memory pool allocator
  • xxHash - usable hash function

as third party hash tables (for benchmarks):

  • TBB - tbb::concurrent_hash_map and tbb::concurrent_unordered_map
  • LibCuckoo - cuckoohash_map
  • Junction - junction::ConcurrentMap_Linear ..._Grampa ..._Leapfrog
  • Folly - folly::AtomicHashMap

Build Notes

Tested using current versions of g++.

Easy build without third party code

git clone https://github.com/TooBiased/growt.git
cd growt
mkdir build
cd build
cmake ..
make

Building with third party libraries

Third party libraries are either installed using your package manager or they are downloaded into the misc/submodules folder.

git clone https://github.com/TooBiased/growt.git
cd growt
git submodule init
mkdir build
cd build
cmake -D GROWT_BUILD_ALL_THIRD_PARTIES=ON ..
make

note that folly needs quite a lot of extern libraries (zstd, glog, …) those have to be installed, to compile any test using folly (checkout their github https://github.com/facebook/folly).

growt's People

Contributors

danielseemaier avatar toobiased avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

growt's Issues

Not compiling under clang 12

Unfortunately, the project does not compile due to some constexpr violations for the _mapper type in base_linear.hpp as seen below:

/home/user/build/project/libs/growt/./data-structures/base_linear.hpp:1160:19: error: constexpr if condition is not a constant expression
    if constexpr (_mapper.cyclic_mapping)
                  ^~~~~~~~~~~~~~~~~~~~~~

I got this behavior for both clang 12 and 10.

utils/hash/murmur2_hash.hpp compiler error

Ubuntu 18.04. clang++ 12.0.1.

In my project I add #include "utils/hash/murmur2_hash.hpp" and I see this error at compile time:

/home/xander/dev/my_model/../growt/utils/hash/murmur2_hash.hpp:75:31: error: member reference base
type 'const long' is not a structure or union
        return MurmurHash64A(k.data(), k.size(), seed);
                             ~^~~~~
/home/xander/dev/my_model/../growt/data-structures/base_linear.hpp:245:63: note: in instantiation o
f function template specialization 'utils_tm::hash_tm::murmur2_hash::operator()<long>' requested here
    inline size_type h    (const key_type & k) const { return _hash(k); }
                                                              ^
/home/xander/dev/my_model/../growt/data-structures/base_linear.hpp:1189:23: note: in instantiation
of member function 'growt::base_linear<growt::base_linear_config<growt::complex_slot<long, std::shared_
ptr<ccmydata::MyBook>, true>, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAllocator
<char, 128>, false, false, false>>::h' requested here
    size_type htemp = h(k);
                      ^
/home/xander/dev/my_model/../growt/data-structures/base_linear.hpp:1071:24: note: in instantiation
of member function 'growt::base_linear<growt::base_linear_config<growt::complex_slot<long, std::shared_
ptr<ccmydata::MyBook>, true>, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAllocator
<char, 128>, false, false, false>>::insert_unsafe' requested here
                target.insert_unsafe(curr);
                       ^
/home/xander/dev/my_model/../growt/data-structures/strategies/estrat_async.hpp:294:22: note: in ins
tantiation of member function 'growt::base_linear<growt::base_linear_config<growt::complex_slot<long, s
td::shared_ptr<ccmydata::MyBook>, true>, utils_tm::hash_tm::murmur2_hash, growt::GenericAlign
edAllocator<char, 128>, false, false, false>>::migrate' requested here
        n += source->migrate(*target, temp,
                     ^
/home/xander/dev/my_model/../growt/data-structures/strategies/estrat_async.hpp:269:5: note: in inst
antiation of member function 'growt::estrat_async<growt::migration_table_data<growt::migration_table<gr
owt::base_linear<growt::base_linear_config<growt::complex_slot<long, std::shared_ptr<ccmydata::MyBook>, true>, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAllocator<char, 128>, false, fa
lse, false>>, workerstrat, exclstrat>>>::local_data_type::blockwise_migrate' requested here
    blockwise_migrate(curr, next);//,

The error is similar when I compile with g++ 10.3.0:

In file included from /home/xander/dev/my_model/../growt/utils/default_hash.hpp:41,                                 from /home/xander/dev/my_model/../growt/data-structures/base_linear.hpp:24,
                 from /home/xander/dev/my_model/../growt/data-structures/table_config.hpp:15,                       from /home/xander/dev/my_model/pymydata/pymydata/MyWebsocketClient.h:21,
                 from /home/xander/dev/my_model/pymydata/pymydata/DataFeed.cc:11:          /home/xander/dev/my_model/../growt/utils/hash/murmur2_hash.hpp: In instantiation of ‘uint64_t util$
_tm::hash_tm::murmur2_hash::operator()(const Type&) const [with Type = long int; uint64_t = long unsig$ed int]’:
/home/xander/dev/my_model/../growt/data-structures/base_linear.hpp:245:68:   required from ‘growt:$
base_linear<Config>::size_type growt::base_linear<Config>::h(const key_type&) const [with Config = gro$
t::base_linear_config<growt::complex_slot<long int, std::shared_ptr<ccmydata::MyBook>, true,
tbb::scalable_allocator<void> >, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAllocator<char,
128>, false, false, false>; growt::base_linear<Config>::size_type = long unsigned int; growt::base_lin$
ar<Config>::key_type = long int]’
/home/xander/dev/my_model/../growt/data-structures/base_linear.hpp:825:23:   required from ‘growt:$
base_linear<Config>::iterator growt::base_linear<Config>::find(const key_type&) [with Config = growt::$
ase_linear_config<growt::complex_slot<long int, std::shared_ptr<ccmydata::MyBook>, true, tbb$
:scalable_allocator<void> >, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAllocator<char, 128$
, false, false, false>; growt::base_linear<Config>::iterator = growt::base_linear_iterator<growt::base$
linear<growt::base_linear_config<growt::complex_slot<long int, std::shared_ptr<ccmydata::MyB$
ok>, true, tbb::scalable_allocator<void> >, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAllo$
ator<char, 128>, false, false, false> >, false>; growt::base_linear<Config>::key_type = long int]’
/home/xander/dev/my_model/../growt/data-structures/migration_table.hpp:818:103:   required from ‘g$
owt::migration_table_handle< <template-parameter-1-1> >::iterator growt::migration_table_handle< <temp$
ate-parameter-1-1> >::find(const key_type&) [with migration_table_data = growt::migration_table_data<g$
owt::migration_table<growt::base_linear<growt::base_linear_config<growt::complex_slot<long int, std::s$
ared_ptr<ccmydata::MyBook>, true, tbb::scalable_allocator<void> >, utils_tm::hash_tm::murmur$
_hash, growt::GenericAlignedAllocator<char, 128>, false, false, false> >, growt::table_config<long int$
 std::shared_ptr<ccmydata::MyBook>, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAl$
ocator<char, 128>, hmod::growable, hmod::deletion>::workerstrat, growt::table_config<long int, std::sh$
red_ptr<ccmydata::MyBook>, utils_tm::hash_tm::murmur2_hash, growt::GenericAlignedAllocator<c$
ar, 128>, hmod::growable, hmod::deletion>::exclstrat> >; growt::migration_table_handle< <template-para$
eter-1-1> >::iterator = growt::migration_table_iterator<growt::migration_table_handle<growt::migration$
table_data<growt::migration_table<growt::base_linear<growt::base_linear_config<growt::complex_slot<lon$
 int, std::shared_ptr<ccmydata::MyBook>, true, tbb::scalable_allocator<void> >, utils_tm::ha$
h_tm::murmur2_hash, growt::GenericAlignedAllocator<char, 128>, false, false, false> >, growt::table_co$
fig<long int, std::shared_ptr<ccmydata::MyBook>, utils_tm::hash_tm::murmur2_hash, growt::Gene
ricAlignedAllocator<char, 128>, hmod::growable, hmod::deletion>::workerstrat, growt::table_config<long
int, std::shared_ptr<ccmydata::MyBook>, utils_tm::hash_tm::murmur2_hash, growt::GenericAligne
dAllocator<char, 128>, hmod::growable, hmod::deletion>::exclstrat> > >, false>; growt::migration_table_
handle< <template-parameter-1-1> >::key_type = long int]’
/home/xander/dev/my_model/pymydata/pymydata/MyWebsocketClient.h:105:32:   required from he
re
/home/xander/dev/my_model/../growt/utils/hash/murmur2_hash.hpp:75:32: error: request for member ‘da
ta’ in ‘k’, which is of non-class type ‘const long int’
   75 |         return MurmurHash64A(k.data(), k.size(), seed);
      |                              ~~^~~~
/home/xander/dev/my_model/../growt/utils/hash/murmur2_hash.hpp:75:42: error: request for member ‘si
ze’ in ‘k’, which is of non-class type ‘const long int’
   75 |         return MurmurHash64A(k.data(), k.size(), seed);
      |                                        ~~^~~~

Let UpdateFunction decide to cancel update after seeing current data

Hey Tobias, first thanks a lot for your work on this library!

I noted you made extensive experiments in your paper regarding the performance under contention for a subset of keys (ie. Zipf distributed keys). In the particular case where one wants to count the occurrence of the keys in some dataset, contention can be reduced by using statistical counters (e.g. Dice et. al. "Scalable statistics counters."). Such counters provide a tradeoff between statistical guarantees about the accurateness of a count versus the number of writes necessary to the counter. In the concurrent case the number of writes is the number of CAS operations. For more contended counters, the probability of requiring a write during counter increment decreases.

The increment opreation of such counter is quite simple to implement:

  void inc(uint32_t random) {
    while (true) {
      double seenT = threshold.load();
      if (random > seenT) {
        return;
      }
      bool overflow = (seenT < (a + 1.0));
      double newT = seenT * probFactor;
      if (overflow) newT = (double)MaxInt;

      if (std::atomic_compare_exchange_weak(&threshold, &seenT, newT)) {
        return;
      }
    }
  }

Based on a random number, either an update of the stored value is performed or the stored value is left as it is. In case of CAS failure the operation is retried.

It would be very useful, to store such statistical counters as values in a concurrent hash map. However, in the current implementation, whenever update or insertOrUpdate is called, CAS will be executed. The UpdateFunction has no option to cancel the update.

I believe only few changes would be required to make this work though.

  1. UpdateFunction must return bool to indicate if the update shall be cancelled or not
  2. In TAtomic::execute (for SimpleElement) and atomicUpdate (for MarkableElement) check the return value of UpdateFunction and skip the CIS if false is returned (still indicating that the update was successful).

Would you suggest any other / better solution? Would you welcome a contribution to the library to implement this feature?

Unrelated: Your paper describes a strategy to support complex key and value types. Do you have any plans to support it for growt? I have a use-case for complex keys (strings) and if it is feasible without too many changes, would be happy to use / adapt growt for that.

Building with TBB

Hello 👋

I've been trying to build this project with GROWT_BUILD_TBB=ON and I cannot seem to be able to do it (log file).
I noticed the latest commit on CMakeLists.txt is titled Disable TBB stuff, is TBB still supported, along with the related functionalities?

When trying to compile without the flag, it works without issues.

Cheers

TBB is a Prerequisite to include table_config.hpp

The README indicates that grow can be used all on its own without any third part libraries. However, data-structures/table_config.hpp includes data-structures/element_types/complex_slot.hpp, which includes tbb/scalable_allocator.h. TBB must be installed to use growt's hash map.

Including headers causes compilation failure

When I ran into your manuscript on arxiv, I was quite excited by your results and wanted to try your tables, but I am unable to build any files including either definitions.h or tsxdefinitions.h. The only difference between this and a branch of our project which is building as expected is the include line. tsxdefinitions seems to die much sooner.

It outputs:

In file included from growt/data-structures/tsxdefinitions.h:18:0,
                 from lib/db.h:6,
                 from lib/db.cpp:1:
growt/data-structures/simpleelement.h:24:18: warning: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
 using int128_t = __int128;
                  ^~~~~~~~
In file included from growt/data-structures/tsxdefinitions.h:19:0,
                 from lib/db.h:6,
                 from lib/db.cpp:1:
growt/data-structures/markableelement.h:28:18: warning: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
 using int128_t = __int128;
                  ^~~~~~~~
growt/data-structures/markableelement.h: In member function ‘int128_t& growt::MarkableElement::as128i()’:
growt/data-structures/markableelement.h:152:37: warning: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
 { return *reinterpret_cast<__int128 *>(this); }
                                     ^
growt/data-structures/markableelement.h: In member function ‘const int128_t& growt::MarkableElement::as128i() const’:
growt/data-structures/markableelement.h:155:43: warning: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
 { return *reinterpret_cast<const __int128 *>(this); }
                                           ^
In file included from growt/data-structures/tsxdefinitions.h:26:0,
                 from lib/db.h:6,
                 from lib/db.cpp:1:
growt/data-structures/growtable.h: At global scope:
growt/data-structures/growtable.h:280:2: warning: extra ‘;’ [-Wpedantic]
 };
  ^
growt/data-structures/growtable.h:292:2: warning: extra ‘;’ [-Wpedantic]
 };
  ^
In file included from lib/db.h:6:0,
                 from lib/db.cpp:1:
growt/data-structures/tsxdefinitions.h:30:99: error: ‘E’ was not declared in this scope
 template<class HashFct = std::hash<typename SimpleElement::Key>, class Allocator = std::allocator<E> >
                                                                                                   ^
growt/data-structures/tsxdefinitions.h:30:100: error: template argument 1 is invalid
 template<class HashFct = std::hash<typename SimpleElement::Key>, class Allocator = std::allocator<E> >
                                                                                                    ^
make: *** [lib/db.o] Error 1

From definitions.h, I get the following errors:

lib/db.o: In function `growt::SimpleElement::CAS(growt::SimpleElement&, growt::SimpleElement const&)':
db.cpp:(.text+0xf5): undefined reference to `__sync_bool_compare_and_swap_16'
lib/db.o: In function `growt::SimpleElement::atomicDelete(growt::SimpleElement const&)':
db.cpp:(.text+0x123): undefined reference to `__sync_bool_compare_and_swap_16'
lib/db.o: In function `growt::MarkableElement::atomicDelete(growt::MarkableElement const&)':
db.cpp:(.text+0x173): undefined reference to `__sync_bool_compare_and_swap_16'
collect2: error: ld returned 1 exit status
make: *** [taxmap] Error 1
make: *** Waiting for unfinished jobs....
src/mapmake.o: In function `growt::successful(growt::ReturnCode)':
mapmake.cpp:(.text+0xff0): multiple definition of `growt::successful(growt::ReturnCode)'
lib/db.o:db.cpp:(.text+0x0): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement()':
mapmake.cpp:(.text+0x1000): multiple definition of `growt::SimpleElement::SimpleElement()'
lib/db.o:db.cpp:(.text+0x10): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement()':
mapmake.cpp:(.text+0x1000): multiple definition of `growt::SimpleElement::SimpleElement()'
lib/db.o:db.cpp:(.text+0x10): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement(unsigned long, unsigned long)':
mapmake.cpp:(.text+0x1010): multiple definition of `growt::SimpleElement::SimpleElement(unsigned long, unsigned long)'
lib/db.o:db.cpp:(.text+0x20): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement(unsigned long, unsigned long)':
mapmake.cpp:(.text+0x1010): multiple definition of `growt::SimpleElement::SimpleElement(unsigned long, unsigned long)'
lib/db.o:db.cpp:(.text+0x20): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement(growt::SimpleElement const&&)':
mapmake.cpp:(.text+0x1020): multiple definition of `growt::SimpleElement::SimpleElement(growt::SimpleElement const&&)'
lib/db.o:db.cpp:(.text+0x30): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement(growt::SimpleElement const&&)':
mapmake.cpp:(.text+0x1020): multiple definition of `growt::SimpleElement::SimpleElement(growt::SimpleElement const&&)'
lib/db.o:db.cpp:(.text+0x30): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement(growt::SimpleElement const&)':
mapmake.cpp:(.text+0x1030): multiple definition of `growt::SimpleElement::SimpleElement(growt::SimpleElement const&)'
lib/db.o:db.cpp:(.text+0x40): first defined here
src/mapmake.o: In function `growt::SimpleElement::SimpleElement(growt::SimpleElement const&)':
mapmake.cpp:(.text+0x1030): multiple definition of `growt::SimpleElement::SimpleElement(growt::SimpleElement const&)'
lib/db.o:db.cpp:(.text+0x40): first defined here
src/mapmake.o: In function `growt::SimpleElement::operator=(growt::SimpleElement const&)':
mapmake.cpp:(.text+0x1040): multiple definition of `growt::SimpleElement::operator=(growt::SimpleElement const&)'
lib/db.o:db.cpp:(.text+0x50): first defined here
src/mapmake.o: In function `growt::SimpleElement::isEmpty() const':
mapmake.cpp:(.text+0x1050): multiple definition of `growt::SimpleElement::isEmpty() const'
lib/db.o:db.cpp:(.text+0x60): first defined here
src/mapmake.o: In function `growt::SimpleElement::isDeleted() const':
mapmake.cpp:(.text+0x1060): multiple definition of `growt::SimpleElement::isDeleted() const'
lib/db.o:db.cpp:(.text+0x70): first defined here
src/mapmake.o: In function `growt::SimpleElement::isMarked() const':
mapmake.cpp:(.text+0x1080): multiple definition of `growt::SimpleElement::isMarked() const'
lib/db.o:db.cpp:(.text+0x90): first defined here
src/mapmake.o: In function `growt::SimpleElement::compareKey(unsigned long const&) const':
mapmake.cpp:(.text+0x1090): multiple definition of `growt::SimpleElement::compareKey(unsigned long const&) const'
lib/db.o:db.cpp:(.text+0xa0): first defined here
src/mapmake.o: In function `growt::SimpleElement::atomicMark(growt::SimpleElement&)':
mapmake.cpp:(.text+0x10a0): multiple definition of `growt::SimpleElement::atomicMark(growt::SimpleElement&)'
lib/db.o:db.cpp:(.text+0xb0): first defined here
src/mapmake.o: In function `growt::SimpleElement::getKey() const':
mapmake.cpp:(.text+0x10b0): multiple definition of `growt::SimpleElement::getKey() const'
lib/db.o:db.cpp:(.text+0xc0): first defined here
src/mapmake.o: In function `growt::SimpleElement::getData() const':
mapmake.cpp:(.text+0x10c0): multiple definition of `growt::SimpleElement::getData() const'
lib/db.o:db.cpp:(.text+0xd0): first defined here
src/mapmake.o: In function `growt::SimpleElement::CAS(growt::SimpleElement&, growt::SimpleElement const&)':
mapmake.cpp:(.text+0x10d0): multiple definition of `growt::SimpleElement::CAS(growt::SimpleElement&, growt::SimpleElement const&)'
lib/db.o:db.cpp:(.text+0xe0): first defined here
src/mapmake.o: In function `growt::SimpleElement::atomicDelete(growt::SimpleElement const&)':
mapmake.cpp:(.text+0x10f0): multiple definition of `growt::SimpleElement::atomicDelete(growt::SimpleElement const&)'
lib/db.o:db.cpp:(.text+0x100): first defined here
src/mapmake.o: In function `growt::SimpleElement::as128i()':
mapmake.cpp:(.text+0x1120): multiple definition of `growt::SimpleElement::as128i()'
lib/db.o:db.cpp:(.text+0x130): first defined here
src/mapmake.o: In function `growt::SimpleElement::as128i() const':
mapmake.cpp:(.text+0x1130): multiple definition of `growt::SimpleElement::as128i() const'
lib/db.o:db.cpp:(.text+0x140): first defined here
src/mapmake.o: In function `growt::MarkableElement::atomicDelete(growt::MarkableElement const&)':
mapmake.cpp:(.text+0x1140): multiple definition of `growt::MarkableElement::atomicDelete(growt::MarkableElement const&)'
lib/db.o:db.cpp:(.text+0x150): first defined here
src/mapmake.o: In function `growt::SimpleElement::CAS(growt::SimpleElement&, growt::SimpleElement const&)':
mapmake.cpp:(.text+0x10e5): undefined reference to `__sync_bool_compare_and_swap_16'
src/mapmake.o: In function `growt::SimpleElement::atomicDelete(growt::SimpleElement const&)':
mapmake.cpp:(.text+0x1113): undefined reference to `__sync_bool_compare_and_swap_16'
src/mapmake.o: In function `growt::MarkableElement::atomicDelete(growt::MarkableElement const&)':
mapmake.cpp:(.text+0x1163): undefined reference to `__sync_bool_compare_and_swap_16'
lib/db.o: In function `growt::SimpleElement::CAS(growt::SimpleElement&, growt::SimpleElement const&)':
db.cpp:(.text+0xf5): undefined reference to `__sync_bool_compare_and_swap_16'
lib/db.o: In function `growt::SimpleElement::atomicDelete(growt::SimpleElement const&)':
db.cpp:(.text+0x123): undefined reference to `__sync_bool_compare_and_swap_16'
lib/db.o:db.cpp:(.text+0x173): more undefined references to `__sync_bool_compare_and_swap_16' follow
collect2: error: ld returned 1 exit status
make: *** [mapmake] Error 1

Now, the tsx might die sooner because I may not have transactional memory on these Xeon R processors. This is with gcc6.2.1 on RedHat.

Edit: Adding -latomic and -lgcc_s and -lgcc seem to have eliminated the undefineed __sync_bool_compare_and_swap_16s, but I still am encountering the multiple definitions. Maybe a static declaration is needed?

Any idea why that might be?

Thanks!

find not working for 0 value and above 0xfffffffffffffff (15 bytes)

Hi,
I am using

template<typename KeyType, typename ValueStorage>
using GrowtConcurrentHashtable = typename growt::table_config<KeyType, ValueStorage,
                                                              utils_tm::hash_tm::crc_hash, growt::AlignedAllocator<>,
                                                              hmod::growable>::table_type;

With KeyType=uint64_t ValueStorage=int8_t

When I insert value 0 or value above 0xfffffffffffffff and right after I call find with the value I get that the value is not present.
I could not find the root cause for this, any idea what is wrong?

Thanks

Missing size function

Your table does not implement a .size() function. This is a major issue, preventing widespread adoption.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.