diff --git a/include/shad/data_structures/abstract_data_structure.h b/include/shad/data_structures/abstract_data_structure.h index cb85308e..de8231ec 100644 --- a/include/shad/data_structures/abstract_data_structure.h +++ b/include/shad/data_structures/abstract_data_structure.h @@ -64,6 +64,7 @@ class AbstractDataStructure { /// @brief Default constructor AbstractDataStructure() = default; + /// @brief Create method. /// /// Creates a global instance of DataStructure, and associates to it a unique @@ -85,7 +86,9 @@ class AbstractDataStructure { ObjectID id = catalogRef->GetNextID(); std::tuple tuple(id, args...); rt::executeOnAll(CreateFunWrapper, tuple); - return catalogRef->GetPtr(id); + auto ret= catalogRef->GetPtr(id); + ret->DataStructurePointerCommunication(); + return ret; } /// @brief Destroy method. @@ -150,6 +153,8 @@ class AbstractDataStructure { CreateFunInnerWrapper(std::move(args), std::index_sequence_for()); } + void DataStructurePointerCommunication(){} + class Catalog { public: void Insert(const ObjectID &oid, const SharedPtr ce) { @@ -196,6 +201,7 @@ class AbstractDataStructure { } private: + Catalog() : register_(rt::numLocalities()), oidCache_(), registerLock_() {} /// The Type storing the counter to obtain new DataStructure object IDs. diff --git a/include/shad/data_structures/array.h b/include/shad/data_structures/array.h index a2929009..55a84f6a 100644 --- a/include/shad/data_structures/array.h +++ b/include/shad/data_structures/array.h @@ -701,6 +701,18 @@ void PrintAllElements() { } } + constexpr void DataStructurePointerCommunication() { + rt::executeOnAll([](const ObjectID &oid) { + auto This = Array::GetPtr(oid); + rt::executeOnAll([](const std::tuple &args) { + auto This = Array::GetPtr(std::get<0>(args)); + + This->ptrs_[(uint32_t)std::get<1>(args)] = std::get<2>(args); + }, + std::make_tuple(This->GetGlobalID(), rt::thisLocality(), This->data_.data())); + }, GetGlobalID()); + } + private: ObjectID oid_; size_t size_; @@ -948,6 +960,9 @@ void PrintAllElements() { } }; +template <> +constexpr void Array::DataStructurePointerCommunication() {} + static std::pair getTargetLocalityFromTargePosition( const std::vector> &dataDistribution, size_t position) { diff --git a/include/shad/data_structures/local_multimap.h b/include/shad/data_structures/local_multimap.h index b4dbfe11..82d4bd6a 100644 --- a/include/shad/data_structures/local_multimap.h +++ b/include/shad/data_structures/local_multimap.h @@ -48,6 +48,27 @@ class lmultimap_iterator; template class lmultimap_key_iterator; +template +struct Overwriter { + bool operator()(std::vector *const lhs, const T &rhs, bool) { + lhs->push_back(rhs); + return true; + } + static bool Insert(std::vector *const lhs, const T &rhs, bool) { + lhs->push_back(rhs); + return true; + } + bool operator()(rt::Handle&, std::vector *const lhs, const T &rhs, bool) { + lhs->push_back(rhs); + return true; + } + static bool Insert(rt::Handle&, std::vector *const lhs, const T &rhs, bool) { + lhs->push_back(rhs); + return true; + } +}; + + /// @brief The LocalMultimap data structure. /// /// SHAD's LocalMultimap is a "local", thread-safe, associative container. @@ -55,15 +76,16 @@ class lmultimap_key_iterator; /// @tparam KTYPE type of the multimap keys. /// @tparam VTYPE type of the multimap values. /// @tparam KEY_COMPARE key comparison function; default is MemCmp. -template > +template , + typename INSERTER = Overwriter> class LocalMultimap { - template + template friend class Multimap; - friend class lmultimap_iterator, + friend class lmultimap_iterator, const std::pair>; friend class lmultimap_key_iterator< - LocalMultimap, + LocalMultimap, const std::pair>>; template @@ -74,16 +96,16 @@ class LocalMultimap { public: using inner_type = VTYPE; - using iterator = lmultimap_iterator, + using iterator = lmultimap_iterator, const std::pair>; using const_iterator = - lmultimap_iterator, + lmultimap_iterator, const std::pair>; using key_iterator = - lmultimap_key_iterator, + lmultimap_key_iterator, const std::pair>>; using const_key_iterator = - lmultimap_key_iterator, + lmultimap_key_iterator, const std::pair>>; /// @brief Constructor. @@ -120,6 +142,15 @@ class LocalMultimap { /// @param[in] value the value to copy into the multimap. /// @return an iterator to the inserted value std::pair Insert(const KTYPE &key, const VTYPE &value); + /// @brief Insert a key-value pair in the hashmap, + /// with a custom inserter. + /// @param[in] insfun inserter function or functor. + /// Look at the default inserter for an example. + /// @param[in] key the key. + /// @param[in] value the value to copy into the hashMap. + /// @return an iterator to the inserted value and true if value was inserted. + template + std::pair Insert(FUNTYPE &insfun,const KTYPE &key, const VTYPE &value); template std::pair Insert(const KTYPE &key, const ELTYPE &value); @@ -267,7 +298,7 @@ class LocalMultimap { /// @return SUCCESS if the function has been successfully applied, /// NOT_FOUND if the key is not found, FAILED otherwise. template - LocalMultimap::ApplyResult + LocalMultimap::ApplyResult TryBlockingApply(const KTYPE &key, ApplyFunT &&function, Args &...args); /// @brief Asynchronously apply a user-defined function to a key-value pair. @@ -508,7 +539,7 @@ class LocalMultimap { }; uint32_t has_deleter = 0xffffffff; - + INSERTER InsertPolicy_; KeyCompare KeyComp_; size_t numBuckets_; std::atomic numberKeys_; @@ -518,7 +549,7 @@ class LocalMultimap { template static void CallForEachEntryFun( - const size_t i, LocalMultimap *mapPtr, + const size_t i, LocalMultimap *mapPtr, ApplyFunT function, std::tuple &args, std::index_sequence) { Bucket *bucket = &mapPtr->buckets_array_[i]; @@ -553,7 +584,7 @@ class LocalMultimap { template static void AsyncCallForEachEntryFun( rt::Handle &handle, const size_t i, - LocalMultimap *mapPtr, ApplyFunT function, + LocalMultimap *mapPtr, ApplyFunT function, std::tuple &args, std::index_sequence) { Bucket *bucket = &mapPtr->buckets_array_[i]; @@ -588,7 +619,7 @@ class LocalMultimap { template static void CallForEachKeyFun( - const size_t i, LocalMultimap *mapPtr, + const size_t i, LocalMultimap *mapPtr, ApplyFunT function, std::tuple &args, std::index_sequence) { size_t cnt = 0; @@ -623,7 +654,7 @@ class LocalMultimap { template static void AsyncCallForEachKeyFun( rt::Handle &handle, const size_t i, - LocalMultimap *mapPtr, ApplyFunT function, + LocalMultimap *mapPtr, ApplyFunT function, std::tuple &args, std::index_sequence) { Bucket *buckets_array = mapPtr->buckets_array_.data(); Bucket *bucket = &buckets_array[i]; @@ -657,7 +688,7 @@ class LocalMultimap { template static void AsyncCallApplyFun( - rt::Handle &handle, LocalMultimap *mapPtr, + rt::Handle &handle, LocalMultimap *mapPtr, const KTYPE &key, ApplyFunT function, std::tuple &args, std::index_sequence) { size_t bucketIdx = shad::hash{}(key) % mapPtr->numBuckets_; @@ -688,7 +719,7 @@ class LocalMultimap { template static void AsyncCallApplyWithRetBuffFun( - rt::Handle &handle, LocalMultimap *mapPtr, + rt::Handle &handle, LocalMultimap *mapPtr, const KTYPE &key, ApplyFunT function, std::tuple &args, std::index_sequence, uint8_t* result, uint32_t* resultSize) { size_t bucketIdx = shad::hash{}(key) % mapPtr->numBuckets_; @@ -719,7 +750,7 @@ class LocalMultimap { } template - static void CallApplyFun(LocalMultimap *mapPtr, + static void CallApplyFun(LocalMultimap *mapPtr, const KTYPE &key, ApplyFunT function, std::tuple &args, std::index_sequence) { @@ -750,7 +781,7 @@ class LocalMultimap { } template - static void CallBlockingApplyFun(LocalMultimap *mapPtr, + static void CallBlockingApplyFun(LocalMultimap *mapPtr, const KTYPE &key, ApplyFunT function, std::tuple &args, std::index_sequence) { @@ -758,8 +789,8 @@ class LocalMultimap { } template - static LocalMultimap::ApplyResult - CallTryBlockingApplyFun(LocalMultimap *mapPtr, + static LocalMultimap::ApplyResult + CallTryBlockingApplyFun(LocalMultimap *mapPtr, const KTYPE &key, ApplyFunT function, std::tuple &args, std::index_sequence) { @@ -780,7 +811,7 @@ class LocalMultimap { template static void CallAsyncBlockingApplyFun(rt::Handle &h, - LocalMultimap *mapPtr, + LocalMultimap *mapPtr, const KTYPE &key, ApplyFunT function, std::tuple &args, std::index_sequence) { @@ -802,10 +833,10 @@ class LocalMultimap { } }; -template -void LocalMultimap::AsyncLookup( +template +void LocalMultimap::AsyncLookup( rt::Handle &handle, const KTYPE &key, LookupResult *result) { - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; auto args = std::tuple(this, key, result); auto lookupLambda = [](rt::Handle &, @@ -816,18 +847,16 @@ void LocalMultimap::AsyncLookup( rt::asyncExecuteAt(handle, rt::thisLocality(), lookupLambda, args); } -template -bool LocalMultimap::Lookup(const KTYPE &key, +template +bool LocalMultimap::Lookup(const KTYPE &key, LookupResult *result) { size_t bucketIdx = shad::hash{}(key) % numBuckets_; Bucket *bucket = &(buckets_array_[bucketIdx]); // concurrent inserts okay; concurrent delete not okay allow_inserter(bucketIdx); - while (bucket != nullptr) { for (size_t i = 0; i < bucket->BucketSize(); ++i) { Entry *entry = &bucket->getEntry(i); - // Reached first unused entry, key not found, break if (entry->state == EMPTY) break; @@ -840,11 +869,9 @@ bool LocalMultimap::Lookup(const KTYPE &key, PENDING_INSERT)) { rt::impl::yield(); } - result->found = true; result->size = entry->value.size(); result->value = entry->value; - entry->state = USED; release_inserter(bucketIdx); return true; @@ -861,8 +888,8 @@ bool LocalMultimap::Lookup(const KTYPE &key, return false; // key not found } -template -void LocalMultimap::LookupFromRemote( +template +void LocalMultimap::LookupFromRemote( const KTYPE &key, LookupRemoteResult *result) { size_t bucketIdx = shad::hash{}(key) % numBuckets_; Bucket *bucket = &(buckets_array_[bucketIdx]); @@ -914,8 +941,8 @@ void LocalMultimap::LookupFromRemote( release_inserter(bucketIdx); } -template -void LocalMultimap::PrintAllEntries() { +template +void LocalMultimap::PrintAllEntries() { for (auto itr = begin(); itr != end(); ++itr) { auto key = (*itr).first; auto value = (*itr).second; @@ -923,16 +950,16 @@ void LocalMultimap::PrintAllEntries() { } } -template -void LocalMultimap::PrintAllKeys() { +template +void LocalMultimap::PrintAllKeys() { for (auto itr = key_begin(); itr != key_end(); ++itr) { auto key = (*itr).first; std::cout << key << std::endl; } } -template -void LocalMultimap::Erase(const KTYPE &key) { +template +void LocalMultimap::Erase(const KTYPE &key) { size_t bucketIdx = shad::hash{}(key) % numBuckets_; Bucket *bucket = &(buckets_array_[bucketIdx]); std::vector emptyValue; @@ -1015,10 +1042,10 @@ void LocalMultimap::Erase(const KTYPE &key) { release_deleter(bucketIdx); } -template -void LocalMultimap::AsyncErase(rt::Handle &handle, +template +void LocalMultimap::AsyncErase(rt::Handle &handle, const KTYPE &key) { - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; auto args = std::tuple(this, key); auto eraseLambda = [](rt::Handle &, const std::tuple &t) { @@ -1027,10 +1054,19 @@ void LocalMultimap::AsyncErase(rt::Handle &handle, rt::asyncExecuteAt(handle, rt::thisLocality(), eraseLambda, args); } +template +std::pair::iterator, bool> +LocalMultimap::Insert(const KTYPE &key, + const VTYPE &value) { + return Insert(InsertPolicy_, key, value); + } + + -template -std::pair::iterator, bool> -LocalMultimap::Insert(const KTYPE &key, +template +template +std::pair::iterator, bool> +LocalMultimap::Insert(FUNTYPE &insfun,const KTYPE &key, const VTYPE &value) { size_t bucketIdx = shad::hash{}(key) % numBuckets_; Bucket *bucket = &(buckets_array_[bucketIdx]); @@ -1044,8 +1080,7 @@ LocalMultimap::Insert(const KTYPE &key, // Reached end of used entries without finding key, so new key if (__sync_bool_compare_and_swap(&entry->state, EMPTY, PENDING_INSERT)) { entry->key = std::move(key); - entry->value.push_back(value); - + bool inserted = insfun(&entry->value, value, false); numberKeys_ += 1; entry->state = USED; release_inserter(bucketIdx); @@ -1064,8 +1099,7 @@ LocalMultimap::Insert(const KTYPE &key, PENDING_INSERT)) { rt::impl::yield(); } - entry->value.push_back(value); - + bool inserted = insfun(&entry->value, value, false); entry->state = USED; release_inserter(bucketIdx); return std::make_pair( @@ -1093,11 +1127,11 @@ LocalMultimap::Insert(const KTYPE &key, } // Outer for loop } -template -void LocalMultimap::AsyncInsert(rt::Handle &handle, +template +void LocalMultimap::AsyncInsert(rt::Handle &handle, const KTYPE &key, const VTYPE &value) { - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; auto args = std::tuple(this, key, value); auto insertLambda = [](rt::Handle &, @@ -1108,13 +1142,13 @@ void LocalMultimap::AsyncInsert(rt::Handle &handle, rt::asyncExecuteAt(handle, rt::thisLocality(), insertLambda, args); } -template +template template -void LocalMultimap::ForEachEntry( +void LocalMultimap::ForEachEntry( ApplyFunT &&function, Args &...args) { using FunctionTy = void (*)(const KTYPE &, std::vector &, Args &...); FunctionTy fn = std::forward(function); - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; using ArgsTuple = std::tuple>; ArgsTuple argsTuple(this, fn, std::tuple(args...)); @@ -1122,14 +1156,14 @@ void LocalMultimap::ForEachEntry( argsTuple, numBuckets_); } -template +template template -void LocalMultimap::AsyncForEachEntry( +void LocalMultimap::AsyncForEachEntry( rt::Handle &handle, ApplyFunT &&function, Args &...args) { using FunctionTy = void (*)(rt::Handle &, const KTYPE &, std::vector &, Args &...); FunctionTy fn = std::forward(function); - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; using ArgsTuple = std::tuple>; ArgsTuple argsTuple(this, fn, std::tuple(args...)); @@ -1138,13 +1172,13 @@ void LocalMultimap::AsyncForEachEntry( numBuckets_); } -template +template template -void LocalMultimap::ForEachKey(ApplyFunT &&function, +void LocalMultimap::ForEachKey(ApplyFunT &&function, Args &...args) { using FunctionTy = void (*)(const KTYPE &, Args &...); FunctionTy fn = std::forward(function); - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; using ArgsTuple = std::tuple>; ArgsTuple argsTuple(this, fn, std::tuple(args...)); @@ -1152,14 +1186,14 @@ void LocalMultimap::ForEachKey(ApplyFunT &&function, argsTuple, numBuckets_); } -template +template template -void LocalMultimap::AsyncForEachKey( +void LocalMultimap::AsyncForEachKey( rt::Handle &handle, ApplyFunT &&function, Args &...args) { using FunctionTy = void (*)(rt::Handle &, const KTYPE &, - std::vector &, Args &...); + Args &...); FunctionTy fn = std::forward(function); - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; using ArgsTuple = std::tuple>; ArgsTuple argsTuple(this, fn, std::tuple(args...)); @@ -1168,16 +1202,16 @@ void LocalMultimap::AsyncForEachKey( numBuckets_); } -template +template template -void LocalMultimap::AsyncApply(rt::Handle &handle, +void LocalMultimap::AsyncApply(rt::Handle &handle, const KTYPE &key, ApplyFunT &&function, Args &...args) { using FunctionTy = void (*)(rt::Handle &, const KTYPE &, std::vector &, Args &...); FunctionTy fn = std::forward(function); - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; using ArgsTuple = std::tuple>; @@ -1186,9 +1220,9 @@ void LocalMultimap::AsyncApply(rt::Handle &handle, AsyncApplyFunWrapper, argsTuple); } -template +template template -void LocalMultimap:: +void LocalMultimap:: AsyncApplyWithRetBuff(rt::Handle &handle, const KTYPE &key, ApplyFunT &&function, uint8_t* result, uint32_t* resultSize, Args &...args) { @@ -1196,7 +1230,7 @@ AsyncApplyWithRetBuff(rt::Handle &handle, const KTYPE &key, std::vector &, Args &..., uint8_t*, uint32_t*); FunctionTy fn = std::forward(function); - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; using ArgsTuple = std::tuple>; @@ -1206,10 +1240,10 @@ AsyncApplyWithRetBuff(rt::Handle &handle, const KTYPE &key, result, resultSize); } -template +template template -std::pair::iterator, bool> -LocalMultimap::Insert(const KTYPE &key, +std::pair::iterator, bool> +LocalMultimap::Insert(const KTYPE &key, const ELTYPE &value) { size_t bucketIdx = shad::hash{}(key) % numBuckets_; Bucket *bucket = &(buckets_array_[bucketIdx]); @@ -1272,11 +1306,11 @@ LocalMultimap::Insert(const KTYPE &key, } // Outer for loop } -template +template template -void LocalMultimap::AsyncInsert( +void LocalMultimap::AsyncInsert( rt::Handle &handle, const KTYPE &key, const ELTYPE &value) { - using LMapPtr = LocalMultimap *; + using LMapPtr = LocalMultimap *; auto args = std::tuple(this, key, value); auto insertLambda = [](rt::Handle &, @@ -1287,9 +1321,9 @@ void LocalMultimap::AsyncInsert( rt::asyncExecuteAt(handle, rt::thisLocality(), insertLambda, args); } -template +template template -void LocalMultimap::BlockingApply(const KTYPE &key, +void LocalMultimap::BlockingApply(const KTYPE &key, ApplyFunT &&function, Args &...args) { size_t bucketIdx = shad::hash{}(key) % numBuckets_; @@ -1330,10 +1364,10 @@ void LocalMultimap::BlockingApply(const KTYPE &key, release_inserter(bucketIdx); } -template +template template -typename LocalMultimap::ApplyResult -LocalMultimap::TryBlockingApply( +typename LocalMultimap::ApplyResult +LocalMultimap::TryBlockingApply( const KTYPE &key, ApplyFunT &&function, Args &...args) { @@ -1373,9 +1407,9 @@ LocalMultimap::TryBlockingApply( return ApplyResult::NOT_FOUND; } -template +template template -void LocalMultimap::AsyncBlockingApply(rt::Handle &h, +void LocalMultimap::AsyncBlockingApply(rt::Handle &h, const KTYPE &key, ApplyFunT &&function, Args &...args) { diff --git a/include/shad/data_structures/multimap.h b/include/shad/data_structures/multimap.h index d365a955..00135a6b 100644 --- a/include/shad/data_structures/multimap.h +++ b/include/shad/data_structures/multimap.h @@ -55,36 +55,36 @@ class multimap_iterator; /// @tparam VTYPE type of the multimap values. /// @tparam KEY_COMPARE key comparison function; default is MemCmp. /// @warning obects of type KTYPE and VTYPE need to be trivially copiable. -template < typename KTYPE, typename VTYPE, typename KEY_COMPARE = MemCmp > -class Multimap : public AbstractDataStructure< Multimap > { +template < typename KTYPE, typename VTYPE, typename KEY_COMPARE = MemCmp, typename INSERT_POLICY = Overwriter > +class Multimap : public AbstractDataStructure< Multimap > { template friend class AbstractDataStructure; - friend class multimap_iterator, + friend class multimap_iterator, const std::pair, std::pair>; - friend class multimap_iterator, + friend class multimap_iterator, const std::pair, std::pair>; public: using value_type = std::pair; - using HmapT = Multimap; - using LMapT = LocalMultimap; + using HmapT = Multimap; + using LMapT = LocalMultimap; using ObjectID = typename AbstractDataStructure::ObjectID; using ShadMultimapPtr = typename AbstractDataStructure::SharedPtr; using iterator = - multimap_iterator, + multimap_iterator, const std::pair, std::pair>; using const_iterator = - multimap_iterator, + multimap_iterator, const std::pair, std::pair>; using local_iterator = - lmultimap_iterator, + lmultimap_iterator, const std::pair>; using const_local_iterator = - lmultimap_iterator, + lmultimap_iterator, const std::pair>; struct EntryT { @@ -113,7 +113,7 @@ class Multimap : public AbstractDataStructure< Multimap * GetLocalMultimap() { + LocalMultimap * GetLocalMultimap() { return &localMultimap_; }; @@ -210,8 +210,8 @@ class Multimap : public AbstractDataStructure< Multimap::LookupResult; - using LookupRemoteResult = typename LocalMultimap::LookupRemoteResult; + using LookupResult = typename LocalMultimap::LookupResult; + using LookupRemoteResult = typename LocalMultimap::LookupRemoteResult; /// @brief Get all the values associated to a key. /// @param[in] key the key. @@ -471,7 +471,7 @@ class Multimap : public AbstractDataStructure< Multimap localMultimap_; + LocalMultimap localMultimap_; BuffersVector buffers_; struct InsertArgs { @@ -498,8 +498,8 @@ class Multimap : public AbstractDataStructure< Multimap -inline size_t Multimap::Size() const { +template +inline size_t Multimap::Size() const { size_t remoteSize, size = 0; auto sizeLambda = [](const ObjectID & oid, size_t * res) { @@ -514,8 +514,8 @@ inline size_t Multimap::Size() const { return size; } -template -inline size_t Multimap::NumberKeys() const { +template +inline size_t Multimap::NumberKeys() const { size_t size = localMultimap_.numberKeys_.load(); size_t remoteKeys; @@ -534,9 +534,9 @@ inline size_t Multimap::NumberKeys() const { return size; } -template -inline std::pair < typename Multimap::iterator, bool > -Multimap::Insert(const KTYPE &key, const VTYPE &value) { +template +inline std::pair < typename Multimap::iterator, bool > +Multimap::Insert(const KTYPE &key, const VTYPE &value) { using itr_traits = distributed_iterator_traits; size_t targetId = shad::hash{}(key) % rt::numLocalities(); @@ -565,8 +565,8 @@ Multimap::Insert(const KTYPE &key, const VTYPE &value return res; } -template -inline void Multimap::AsyncInsert( +template +inline void Multimap::AsyncInsert( rt::Handle &handle, const KTYPE &key, const VTYPE &value) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -583,15 +583,15 @@ inline void Multimap::AsyncInsert( } } -template -inline void Multimap::BufferedInsert(const KTYPE &key, const VTYPE &value) { +template +inline void Multimap::BufferedInsert(const KTYPE &key, const VTYPE &value) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); buffers_.Insert(EntryT(key, value), targetLocality); } -template -inline void Multimap:: +template +inline void Multimap:: BufferedAsyncInsert(rt::Handle &handle, const KTYPE &key, const VTYPE &value) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); @@ -599,8 +599,8 @@ inline void Multimap:: buffers_.AsyncInsert(handle, EntryT(key, value), targetLocality); } -template -inline void Multimap::Erase(const KTYPE &key) { +template +inline void Multimap::Erase(const KTYPE &key) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -616,8 +616,8 @@ inline void Multimap::Erase(const KTYPE &key) { } } -template -inline void Multimap::AsyncErase(rt::Handle &handle, const KTYPE &key) { +template +inline void Multimap::AsyncErase(rt::Handle &handle, const KTYPE &key) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -633,16 +633,16 @@ inline void Multimap::AsyncErase(rt::Handle &handle, } } -template -inline bool Multimap::Lookup(const KTYPE &key, LookupResult *res) { +template +inline bool Multimap::Lookup(const KTYPE &key, LookupResult *res) { rt::Handle handle; AsyncLookup(handle, key, res); waitForCompletion(handle); return res->found; } -template -inline void Multimap::AsyncLookup( +template +inline void Multimap::AsyncLookup( rt::Handle & handle, const KTYPE & key, LookupResult * result) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); @@ -685,8 +685,8 @@ inline void Multimap::AsyncLookup( } } -template -inline void Multimap::readFromFiles( +template +inline void Multimap::readFromFiles( rt::Handle & handle, std::string prefix, uint64_t lb, uint64_t ub) { auto readFileLambda = [](rt::Handle & handle, const RFArgs & args, size_t it) { @@ -711,9 +711,9 @@ inline void Multimap::readFromFiles( rt::asyncForEachOnAll(handle, readFileLambda, args, ub - lb + 1); } -template +template template -void Multimap::ForEachEntry(ApplyFunT &&function, Args &... args) { +void Multimap::ForEachEntry(ApplyFunT &&function, Args &... args) { using FunctionTy = void (*)(const KTYPE &, std::vector &, Args &...); FunctionTy fn = std::forward(function); @@ -731,9 +731,9 @@ void Multimap::ForEachEntry(ApplyFunT &&function, Arg rt::executeOnAll(feLambda, arguments); } -template +template template -void Multimap::AsyncForEachEntry( +void Multimap::AsyncForEachEntry( rt::Handle &handle, ApplyFunT &&function, Args &... args) { using FunctionTy = void (*)(rt::Handle &, const KTYPE &, std::vector &, Args &...); @@ -755,9 +755,9 @@ void Multimap::AsyncForEachEntry( rt::asyncExecuteOnAll(handle, feLambda, arguments); } -template +template template -void Multimap::ForEachKey(ApplyFunT &&function, Args &... args) { +void Multimap::ForEachKey(ApplyFunT &&function, Args &... args) { using FunctionTy = void (*)(const KTYPE &, Args &...); FunctionTy fn = std::forward(function); @@ -775,9 +775,9 @@ void Multimap::ForEachKey(ApplyFunT &&function, Args rt::executeOnAll(feLambda, arguments); } -template +template template -void Multimap::AsyncForEachKey( +void Multimap::AsyncForEachKey( rt::Handle &handle, ApplyFunT &&function, Args &... args) { using FunctionTy = void (*)(rt::Handle &, const KTYPE &, Args &...); FunctionTy fn = std::forward(function); @@ -797,9 +797,9 @@ void Multimap::AsyncForEachKey( rt::asyncExecuteOnAll(handle, feLambda, arguments); } -template +template template -void Multimap::Apply(const KTYPE &key, ApplyFunT &&function, Args &... args) { +void Multimap::Apply(const KTYPE &key, ApplyFunT &&function, Args &... args) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -824,9 +824,9 @@ void Multimap::Apply(const KTYPE &key, ApplyFunT &&fu } } -template +template template -void Multimap::AsyncApply( +void Multimap::AsyncApply( rt::Handle &handle, const KTYPE &key, ApplyFunT &&function, Args &... args) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -852,9 +852,9 @@ void Multimap::AsyncApply( } } -template +template template -void Multimap::BlockingApply(const KTYPE &key, +void Multimap::BlockingApply(const KTYPE &key, ApplyFunT &&function, Args &... args) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -881,10 +881,10 @@ void Multimap::BlockingApply(const KTYPE &key, } } -template +template template -typename Multimap::LMapT::ApplyResult -Multimap::TryBlockingApply(const KTYPE &key, +typename Multimap::LMapT::ApplyResult +Multimap::TryBlockingApply(const KTYPE &key, ApplyFunT &&function, Args &... args) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -910,9 +910,9 @@ Multimap::TryBlockingApply(const KTYPE &key, } } -template +template template -void Multimap::AsyncBlockingApply( +void Multimap::AsyncBlockingApply( rt::Handle &handle, const KTYPE &key, ApplyFunT &&function, Args &... args) { size_t targetId = shad::hash{}(key) % rt::numLocalities(); rt::Locality targetLocality(targetId); @@ -938,9 +938,9 @@ void Multimap::AsyncBlockingApply( } } -template +template template -void Multimap::AsyncApplyWithRetBuff( +void Multimap::AsyncApplyWithRetBuff( rt::Handle &handle, const KTYPE &key, ApplyFunT &&function, uint8_t* result, uint32_t* resultSize, Args &... args) { @@ -984,7 +984,7 @@ class multimap_iterator : public std::iterator { multimap_iterator() {} multimap_iterator(uint32_t locID, const OIDT mapOID, local_iterator_type &lit, T element) { - data_ = {locID, mapOID, lit, element}; + data_ = {locID, mapOID, lit, element }; } multimap_iterator(uint32_t locID, const OIDT mapOID, local_iterator_type &lit) { diff --git a/test/unit_tests/data_structures/CMakeLists.txt b/test/unit_tests/data_structures/CMakeLists.txt index 6da60b3f..493420cc 100644 --- a/test/unit_tests/data_structures/CMakeLists.txt +++ b/test/unit_tests/data_structures/CMakeLists.txt @@ -7,7 +7,9 @@ set(tests set_test local_set_test vector_test -) + multimap_test + local_multimap_test +) foreach(t ${tests}) add_executable(${t} ${t}.cc) diff --git a/test/unit_tests/data_structures/local_multimap_test.cc b/test/unit_tests/data_structures/local_multimap_test.cc new file mode 100644 index 00000000..44d655f6 --- /dev/null +++ b/test/unit_tests/data_structures/local_multimap_test.cc @@ -0,0 +1,527 @@ + +#include + +#include "gtest/gtest.h" +#include "shad/runtime/runtime.h" + +#include "shad/data_structures/local_multimap.h" + +class LocalMultimapTest : public ::testing::Test { + public: + LocalMultimapTest() {} + void SetUp() {} + void TearDown() {} + static const uint64_t kToInsert = 128; + static const uint64_t kNumBuckets = kToInsert / 16; + static const uint64_t kKeysPerEntry = 3; + static const uint64_t kValuesPerEntry = 5; + static const uint64_t kMagicValue = 9999; + + struct Key { + uint64_t key[kKeysPerEntry]; + friend std::ostream &operator<<(std::ostream &os, const Key &rhs) { + return os << rhs.key[0]; + } + }; + + struct Value { + uint64_t value[kValuesPerEntry]; + friend std::ostream &operator<<(std::ostream &os, const Value &rhs) { + return os << rhs.value[0]; + } + }; + + typedef shad::LocalMultimap MultimapType; + static void FillKey(Key *keys, uint64_t key_seed) { + for (uint64_t i = 0; i < kKeysPerEntry; ++i) { + keys->key[i] = (key_seed + i); + } + } + + static void FillValue(Value *values, uint64_t value_seed) { + for (uint64_t i = 0; i < kValuesPerEntry; ++i) { + values->value[i]=(value_seed + i); + } + } + + static void CheckValue( std::vector values, const uint64_t value_seed) { + bool found=false; + for(uint64_t i=0; i< values.size();i++){ + for(uint64_t j=0 ;jkey[i], (key_seed + i)); + } + } + + static void CheckKeyValue(typename MultimapType::iterator entry, + uint64_t key_seed, uint64_t value_seed) { + auto &obs_keys((*entry).first); + auto &obs_values((*entry).second); + Key exp_keys; + Value exp_values; + FillKey(&exp_keys, key_seed); + FillValue(&exp_values, value_seed); + for (uint64_t i = 0; i < kKeysPerEntry; ++i) + ASSERT_EQ(obs_keys.key[i], exp_keys.key[i]); + for (uint64_t i = 0; i < kValuesPerEntry; ++i) + ASSERT_EQ(obs_values.value[i], obs_values.value[i]); + } + + // Returns the seed used for this key + static uint64_t GetSeed(const Key *keys) { return keys->key[0]; } + + // Returns the seed used for this value + static uint64_t GetSeed(const Value * values) { return values->value[0]; } + + static std::pair DoInsert( + MultimapType *h0, const uint64_t key_seed, const uint64_t value_seed) { + Key keys; + Value values; + FillKey(&keys, key_seed); + FillValue(&values, value_seed); + return (h0->Insert(keys, values)); + } + + static void DoAsyncInsert(shad::rt::Handle &handle, MultimapType *h0, + const uint64_t key_seed, + const uint64_t value_seed) { + Key keys; + Value values; + FillKey(&keys, key_seed); + FillValue(&values, value_seed); + h0->AsyncInsert(handle, keys, values); + } + + static bool DoLookup(MultimapType *h0, const uint64_t key_seed, + std::vector * values) { + Key keys; + FillKey(&keys, key_seed); + MultimapType::LookupResult lr; + bool LookupCheck= h0->Lookup(keys,&lr ); + *values=lr.value; + return LookupCheck; + } + + static void DoAsyncLookup(shad::rt::Handle &handle, MultimapType *h0, + const uint64_t key_seed, MultimapType::LookupResult *lr) { + Key keys; + FillKey(&keys, key_seed); + h0->AsyncLookup(handle, keys, lr); + // h0->Lookup(keys, values); + } + + + static void InsertTestParallelFunc(shad::rt::Handle & /*unused*/, + const std::tuple &t, + const size_t iter) { + MultimapType *mm = std::get<0>(t); + const uint64_t start_it = std::get<1>(t); + DoInsert(mm, start_it + iter, start_it + iter); + } + + static void + LookupTestParallelFunc( + const std::tuple &t, const size_t iter) { + MultimapType *mm = std::get<0>(t); + const uint64_t start_it = std::get<1>(t); + std::vector values; + ASSERT_TRUE(DoLookup(mm, start_it + iter, &values)); + CheckValue(values, start_it + iter); + } +}; +TEST_F(LocalMultimapTest, InsertLookupTest) { + MultimapType mmap(kNumBuckets); + uint64_t i; + for (i = 1; i <= kToInsert; i++) { + DoInsert(&mmap, i, i + 11); + } + size_t toinsert = kToInsert; + ASSERT_EQ(mmap.Size(), toinsert); + std::vector values; + for (i = 1; i <= kToInsert; i++) { + ASSERT_TRUE(DoLookup(&mmap, i, &values)); + CheckValue(values, i + 11); + } + ASSERT_FALSE(DoLookup(&mmap, 1234567890, &values)); +} + + +TEST_F(LocalMultimapTest, InsertReturnTest) { + MultimapType mmap(kNumBuckets); + uint64_t i; + // successful inserts + for (i = 1; i <= kToInsert; i++) { + auto res = DoInsert(&mmap, i, i + 11); + ASSERT_TRUE(res.second); + CheckKeyValue(res.first, i, i + 11); + } + + // overwriting inserts + for (i = 1; i <= kToInsert; i++) { + auto res = DoInsert(&mmap, i, i + 11); + ASSERT_TRUE(res.second); + CheckKeyValue(res.first, i, i + 11); + } +} + +TEST_F(LocalMultimapTest, AsyncInsertLookupTest) { + MultimapType mmap(kNumBuckets); + uint64_t i; + shad::rt::Handle handle; + for (i = 1; i <= kToInsert; i++) { + DoAsyncInsert(handle, &mmap, i, i + 11); + } + shad::rt::waitForCompletion(handle); + size_t toinsert = kToInsert; + std::vector values; + for (i = 1; i <= kToInsert; i++) { + ASSERT_TRUE(DoLookup(&mmap, i, &values)); + CheckValue(values, i + 11); + } + ASSERT_FALSE(DoLookup(&mmap, 1234567890, &values)); +} + +TEST_F(LocalMultimapTest, AsyncInsertAsyncLookupTest) { + MultimapType mmap(kNumBuckets); + uint64_t i; + shad::rt::Handle handle; + for (i = 1; i <= kToInsert; i++) { + DoAsyncInsert(handle, &mmap, i, i + 11); + } + shad::rt::waitForCompletion(handle); + // Lookup + MultimapType::LookupResult *values = new MultimapType::LookupResult [kToInsert]; + + for (i = 1; i < kToInsert; i++) { + DoAsyncLookup(handle, &mmap, i, &values[i]); + } + + shad::rt::waitForCompletion(handle); + for (i = 1; i < kToInsert; i++) { + ASSERT_NE(&values[i], nullptr); + CheckValue(values[i].value, i + 11); + } + delete[] values; +} + + +TEST_F(LocalMultimapTest, InsertLookupParallel1) { + MultimapType mmap(kNumBuckets); + size_t it_chunk = 1; + shad::rt::Handle handle; + for (size_t i = 0; i < kToInsert;) { + auto args = std::make_tuple(&mmap, i); + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, + kToInsert / it_chunk); + i += (kToInsert / it_chunk); + } + shad::rt::waitForCompletion(handle); + size_t toinsert = kToInsert; + ASSERT_EQ(mmap.Size(), toinsert); + for (size_t i = 0; i < kToInsert;) { + auto args = std::make_tuple(&mmap, i); + shad::rt::forEachAt(shad::rt::thisLocality(), LookupTestParallelFunc, args, + kToInsert / it_chunk); + i += (kToInsert / it_chunk); + } +} + +TEST_F(LocalMultimapTest, Erase) { + MultimapType mmap(kNumBuckets); + size_t it_chunk = 1; + shad::rt::Handle handle; + for (size_t i = 0; i < kToInsert;) { + auto args = std::make_tuple(&mmap, i); + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, + kToInsert / it_chunk); + i += (kToInsert / it_chunk); + } + shad::rt::waitForCompletion(handle); + size_t currSize = mmap.Size(); + size_t i; + for (i = 0; i < kToInsert; i++) { + if ((i % 3) != 0u) { + Key k; + FillKey(&k, i); + mmap.Erase(k); + currSize--; + } + } + ASSERT_EQ(mmap.Size(), currSize); + for (i = 0; i < kToInsert; i++) { + std::vectorvalues; + + if ((i % 3) != 0u) { + ASSERT_FALSE(DoLookup(&mmap, i, &values)); + } else { + DoLookup(&mmap, i, &values); + ASSERT_NE(&values, nullptr); + CheckValue(values, i); + } + } +} + +TEST_F(LocalMultimapTest, AsyncErase) { + MultimapType mmap(kNumBuckets); + size_t it_chunk = 1; + shad::rt::Handle handle; + for (size_t i = 0; i < kToInsert;) { + auto args = std::make_tuple(&mmap, i); + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, + kToInsert / it_chunk); + i += (kToInsert / it_chunk); + } + shad::rt::waitForCompletion(handle); + size_t currSize = mmap.Size(); + size_t i; + for (i = 0; i < kToInsert; i++) { + if ((i % 3) != 0u) { + Key k; + FillKey(&k, i); + mmap.AsyncErase(handle, k); + currSize--; + } + } + shad::rt::waitForCompletion(handle); + ASSERT_EQ(mmap.Size(), currSize); + + for (i = 0; i < kToInsert; i++) { + std::vectorvalues; + + if ((i % 3) != 0u) { + ASSERT_FALSE(DoLookup(&mmap, i, &values)); + } else { + DoLookup(&mmap, i, &values); + ASSERT_NE(&values, nullptr); + CheckValue(values, i); + } + } +} + +TEST_F(LocalMultimapTest, ForEachEntry) { + MultimapType mmap(kNumBuckets); + auto args = std::make_tuple(&mmap, 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + uint64_t cnt = 0; + auto VisitLambda0args = [](const Key &key, std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto VisitLambda1arg = [](const Key &key, std::vector &value, uint64_t *&cntPtr) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + auto VisitLambda = [](const Key &key, std::vector &value, uint64_t &magicValue, + uint64_t *&cntPtr) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + uint64_t magicValue = kMagicValue; + uint64_t *cntPtr = &cnt; + mmap.ForEachEntry(VisitLambda0args); + mmap.ForEachEntry(VisitLambda1arg, cntPtr); + mmap.ForEachEntry(VisitLambda, magicValue, cntPtr); + auto toinsert = kToInsert; + ASSERT_EQ(cnt, toinsert * 2); +} + +TEST_F(LocalMultimapTest, AsyncForEachEntry) { + MultimapType mmap(kNumBuckets); + auto args = std::make_tuple(&mmap, 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + uint64_t cnt = 0; + auto AsyncVisitLambda0args = [](shad::rt::Handle &, const Key &key, + std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto AsyncVisitLambda1arg = [](shad::rt::Handle &, const Key &key, + std::vector &value, uint64_t *&cntPtr) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + auto AsyncVisitLambda = [](shad::rt::Handle &, const Key &key, std::vector &value, + uint64_t &magicValue, uint64_t *&cntPtr) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + uint64_t magicValue = kMagicValue; + uint64_t *cntPtr = &cnt; + mmap.AsyncForEachEntry(handle, AsyncVisitLambda0args); + mmap.AsyncForEachEntry(handle, AsyncVisitLambda1arg, cntPtr); + mmap.AsyncForEachEntry(handle, AsyncVisitLambda, magicValue, cntPtr); + shad::rt::waitForCompletion(handle); + auto toinsert = kToInsert; + ASSERT_EQ(cnt, toinsert * 2); +} + +TEST_F(LocalMultimapTest, ForEachKey) { + MultimapType mmap(kNumBuckets); + auto args = std::make_tuple(&mmap, 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + uint64_t cnt = 0; + auto ForEachKeyLambda0args = [](const Key &key) { + CheckKey(&key, GetSeed(&key)); + }; + auto ForEachKeyLambda1arg = [](const Key &key, uint64_t *&cntPtr) { + CheckKey(&key, GetSeed(&key)); + __sync_fetch_and_add(cntPtr, 1); + }; + auto ForEachKeyLambda = [](const Key &key, uint64_t &magicValue, + uint64_t *&cntPtr) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + __sync_fetch_and_add(cntPtr, 1); + }; + uint64_t magicValue = kMagicValue; + uint64_t *cntPtr = &cnt; + mmap.ForEachKey(ForEachKeyLambda0args); + mmap.ForEachKey(ForEachKeyLambda1arg, cntPtr); + mmap.ForEachKey(ForEachKeyLambda, magicValue, cntPtr); + auto toinsert = kToInsert; + ASSERT_EQ(cnt, toinsert * 2); +} + +TEST_F(LocalMultimapTest, AsyncForEachKey) { + MultimapType mmap(kNumBuckets); + auto args = std::make_tuple(&mmap, 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + uint64_t cnt = 0; + uint64_t magicValue = kMagicValue; + uint64_t *cntPtr = &cnt; + auto AsyncForEachKeyLambda0args = [](shad::rt::Handle &, const Key &key) { + CheckKey(&key, GetSeed(&key)); + }; + auto AsyncForEachKeyLambda1arg = [](shad::rt::Handle &, const Key &key, + uint64_t *&cntPtr) { + CheckKey(&key, GetSeed(&key)); + __sync_fetch_and_add(cntPtr, 1); + }; + auto AsyncForEachKeyLambda = [](shad::rt::Handle &, const Key &key, + uint64_t &magicValue, uint64_t *&cntPtr) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + __sync_fetch_and_add(cntPtr, 1); + }; + mmap.AsyncForEachKey(handle, AsyncForEachKeyLambda0args); + mmap.AsyncForEachKey(handle, AsyncForEachKeyLambda1arg, cntPtr); + mmap.AsyncForEachKey(handle, AsyncForEachKeyLambda, magicValue, cntPtr); + shad::rt::waitForCompletion(handle); + auto toinsert = kToInsert; + ASSERT_EQ(cnt, toinsert * 2); +} + +TEST_F(LocalMultimapTest, Apply) { + MultimapType mmap(kNumBuckets); + auto args = std::make_tuple(&mmap, 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + + auto toinsert = kToInsert; + ASSERT_EQ(mmap.Size(), toinsert); + + uint64_t cnt = 0; + auto ApplyLambda0args = [](const Key &key, std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto ApplyLambda1arg = [](const Key &key, std::vector &value, uint64_t *&cntPtr) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + auto ApplyLambda = [](const Key &key, std::vector &value, uint64_t &magicValue, + uint64_t *&cntPtr) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + uint64_t magicValue = kMagicValue; + uint64_t *cntPtr = &cnt; + for (size_t i = 0; i < kToInsert; i++) { + Key keys; + FillKey(&keys, i); + mmap.Apply(keys, ApplyLambda0args); + mmap.Apply(keys, ApplyLambda1arg, cntPtr); + mmap.Apply(keys, ApplyLambda, magicValue, cntPtr); + } + ASSERT_EQ(cnt, toinsert * 2); +} + +TEST_F(LocalMultimapTest, AsyncApply) { + MultimapType mmap(kNumBuckets); + auto args = std::make_tuple(&mmap, 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + + auto AsyncApplyLambda0args = [](shad::rt::Handle &, const Key &key, + std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto AsyncApplyLambda1arg = [](shad::rt::Handle &, const Key &key, + std::vector &value, uint64_t *&cntPtr) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + auto AsyncApplyLambda = [](shad::rt::Handle &, const Key &key, std::vector &value, + uint64_t &magicValue, uint64_t *&cntPtr) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + __sync_fetch_and_add(cntPtr, 1); + }; + + auto toinsert = kToInsert; + ASSERT_EQ(toinsert, mmap.Size()); + + uint64_t cnt = 0; + uint64_t magicValue = kMagicValue; + uint64_t *cntPtr = &cnt; + for (size_t i = 0; i < kToInsert; i++) { + Key keys; + FillKey(&keys, i); + mmap.AsyncApply(handle, keys, AsyncApplyLambda0args); + mmap.AsyncApply(handle, keys, AsyncApplyLambda1arg, cntPtr); + mmap.AsyncApply(handle, keys, AsyncApplyLambda, magicValue, cntPtr); + } + shad::rt::waitForCompletion(handle); + ASSERT_EQ(cnt, toinsert * 2); +} + diff --git a/test/unit_tests/data_structures/multimap_test.cc b/test/unit_tests/data_structures/multimap_test.cc new file mode 100644 index 00000000..1ae63eae --- /dev/null +++ b/test/unit_tests/data_structures/multimap_test.cc @@ -0,0 +1,561 @@ +#include + +#include "gtest/gtest.h" +#include "shad/runtime/runtime.h" + +#include "shad/data_structures/multimap.h" + +static const size_t kToInsert = 1000; + +class MultimapTest : public ::testing::Test { + public: + MultimapTest() {} + void SetUp() {} + void TearDown() {} + static const uint64_t kKeysPerEntry = 3; + static const uint64_t kValuesPerEntry = 5; + static const uint64_t kMagicValue = 9999; + + struct Key { + uint64_t key[kKeysPerEntry]; + friend std::ostream &operator<<(std::ostream &os, const Key &rhs) { + return os << rhs.key; + } + }; + + struct Value { + uint64_t value[kValuesPerEntry]; + friend std::ostream &operator<<(std::ostream &os, const Value &rhs) { + return os << rhs.value; + } + }; + + typedef shad::Multimap MultimapType; + static void FillKey(Key *keys, uint64_t key_seed) { + for (uint64_t i = 0; i < kKeysPerEntry; ++i) { + keys->key[i] = (key_seed + i); + } + // keys->key=key_seed; + } + + static void FillValue(Value *values, uint64_t value_seed) { + for (uint64_t i = 0; i < kValuesPerEntry; ++i) { + values->value[i]=(value_seed + i); + } + } + + static void CheckValue( std::vector values, const uint64_t value_seed) { + bool found=false; + for(uint64_t i=0; i< values.size();i++){ + for(uint64_t j=0 ;jkey[i], (key_seed + i)); + } + } + + static void CheckKeyValue(typename MultimapType::iterator entry, + uint64_t key_seed, uint64_t value_seed) { + auto &obs_keys((*entry).first); + auto &obs_values((*entry).second); + Key exp_keys; + Value exp_values; + FillKey(&exp_keys, key_seed); + FillValue(&exp_values, value_seed); + for (uint64_t i = 0; i < kKeysPerEntry; ++i) + ASSERT_EQ(obs_keys.key[i], exp_keys.key[i]); + for (uint64_t i = 0; i < kValuesPerEntry; ++i) + ASSERT_EQ(obs_values.value[i], obs_values.value[i]); + } + + // Returns the seed used for this key + static uint64_t GetSeed(const Key *keys) { return keys->key[0]; } + + // Returns the seed used for this value + static uint64_t GetSeed(const Value * values) { return values->value[0]; } + + static void DoInsert(MultimapType::ObjectID oid, const uint64_t key_seed, const uint64_t value_seed) { + auto m0 = MultimapType::GetPtr(oid); + Key keys; + Value values; + + FillKey(&keys, key_seed); + FillValue(&values, value_seed); + m0->Insert(keys, values); + } + static void DoBufferedInsert(MultimapType::ObjectID oid, + const uint64_t key_seed, + const uint64_t value_seed) { + auto m0 = MultimapType::GetPtr(oid); + Key keys; + Value values; + FillKey(&keys, key_seed); + FillValue(&values, value_seed); + m0->BufferedInsert(keys, values); + } + + static void DoAsyncInsert(shad::rt::Handle &handle, MultimapType::ObjectID oid, + const uint64_t key_seed, + const uint64_t value_seed) { + auto m0 = MultimapType::GetPtr(oid); + Key keys; + Value values; + FillKey(&keys, key_seed); + FillValue(&values, value_seed); + m0->AsyncInsert(handle, keys, values); + } + + static void DoBufferedAsyncInsert(shad::rt::Handle &handle, + MultimapType::ObjectID oid, + const uint64_t key_seed, + const uint64_t value_seed) { + auto m0 = MultimapType::GetPtr(oid); + Key keys; + Value values; + FillKey(&keys, key_seed); + FillValue(&values, value_seed); + m0->BufferedAsyncInsert(handle, keys, values); + } + + static bool DoLookup(MultimapType::ObjectID oid, const uint64_t key_seed, + std::vector * values) { + auto m0 = MultimapType::GetPtr(oid); + Key keys; + FillKey(&keys, key_seed); + MultimapType::LookupResult lr; + bool LookupCheck= m0->Lookup(keys,&lr ); + if (LookupCheck){ + *values=lr.value; + } + return LookupCheck; + } + + static void DoAsyncLookup(shad::rt::Handle &handle, MultimapType::ObjectID oid, + const uint64_t key_seed, MultimapType::LookupResult *lr) { + auto m0 = MultimapType::GetPtr(oid); + Key keys; + FillKey(&keys, key_seed); + m0->AsyncLookup(handle, keys, lr); + } + + + static void InsertTestParallelFunc( + shad::rt::Handle &handle, + const std::tuple &t, const size_t iter) { + MultimapType::ObjectID id = std::get<0>(t); + const uint64_t start_it = std::get<1>(t); + DoAsyncInsert(handle, id, start_it + iter, start_it + iter); + } + +}; + +TEST_F(MultimapTest, InsertLookupTest) { + auto mapPtr = MultimapType::Create(kToInsert); + uint64_t i; + for (i = 1; i <= kToInsert; i++) { + DoInsert(mapPtr->GetGlobalID(), i, i + 11); + } + ASSERT_EQ(mapPtr->Size(), kToInsert); + std::vector values; + for (i = 1; i <= kToInsert; i++) { + ASSERT_TRUE(DoLookup(mapPtr->GetGlobalID(), i, &values)); + CheckValue(values, i + 11); + } + ASSERT_FALSE(DoLookup(mapPtr->GetGlobalID(), 1234567890, &values)); + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, AsyncInsertLookupTest) { + auto mapPtr = MultimapType::Create(kToInsert); + shad::rt::Handle handle; + uint64_t i; + for (i = 1; i <= kToInsert; i++) { + DoAsyncInsert(handle, mapPtr->GetGlobalID(), i, i + 11); + } + shad::rt::waitForCompletion(handle); + ASSERT_EQ(mapPtr->Size(), kToInsert); + std::vector values; + for (i = 1; i <= kToInsert; i++) { + ASSERT_TRUE(DoLookup(mapPtr->GetGlobalID(), i, &values)); + CheckValue(values, i + 11); + } + ASSERT_FALSE(DoLookup(mapPtr->GetGlobalID(), 1234567890, &values)); + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, AsyncInsertAsyncLookupTest) { + auto mapPtr = MultimapType::Create(kToInsert); + shad::rt::Handle handle; + uint64_t i; + for (i = 1; i <= kToInsert; i++) { + DoAsyncInsert(handle, mapPtr->GetGlobalID(), i, i + 11); + } + shad::rt::waitForCompletion(handle); + ASSERT_EQ(mapPtr->Size(), kToInsert); + MultimapType::LookupResult *values = new MultimapType::LookupResult [kToInsert]; + for (i = 1; i < kToInsert; i++) { + DoAsyncLookup(handle, mapPtr->GetGlobalID(), i, &values[i]); + } + shad::rt::waitForCompletion(handle); + for (i = 1; i < kToInsert; i++) { + CheckValue((values[i].value), i + 11); + } + delete[] values; + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, BufferedInsertAsyncLookupTest) { + auto mapPtr = MultimapType::Create(kToInsert); + uint64_t i; + for (i = 0; i < kToInsert; i++) { + DoBufferedInsert(mapPtr->GetGlobalID(), i, i + 11); + } + mapPtr->WaitForBufferedInsert(); + ASSERT_EQ(mapPtr->Size(), kToInsert); + MultimapType::LookupResult *values = new MultimapType::LookupResult [kToInsert]; + shad::rt::Handle handle; + for (i = 0; i < kToInsert; i++) { + DoAsyncLookup(handle, mapPtr->GetGlobalID(), i, &values[i]); + } + shad::rt::waitForCompletion(handle); + for (i = 0; i < kToInsert; i++) { + CheckValue((values[i].value), i + 11); + } + delete[] values; + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, BufferedAsyncInsertAsyncLookupTest) { + auto mapPtr = MultimapType::Create(kToInsert); + shad::rt::Handle handle; + uint64_t i; + for (i = 0; i < kToInsert; i++) { + DoBufferedAsyncInsert(handle, mapPtr->GetGlobalID(), i, i + 11); + } + shad::rt::waitForCompletion(handle); + mapPtr->WaitForBufferedInsert(); + ASSERT_EQ(mapPtr->Size(), kToInsert); + MultimapType::LookupResult *values = new MultimapType::LookupResult [kToInsert]; + for (i = 0; i < kToInsert; i++) { + DoAsyncLookup(handle, mapPtr->GetGlobalID(), i, &values[i]); + } + shad::rt::waitForCompletion(handle); + for (i = 0; i < kToInsert; i++) { + CheckValue((values[i].value), i + 11); + } + delete[] values; + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, FEBufferedAsyncInsertAsyncLookupTest) { + auto mapPtr = MultimapType::Create(kToInsert); + shad::rt::Handle handle; + auto insertLambda = [](shad::rt::Handle &handle, + const std::tuple &t, size_t i) { + uint64_t value = i; + DoBufferedAsyncInsert(handle, std::get<0>(t), value, value + 11); + }; + shad::rt::asyncForEachOnAll( + handle, insertLambda, std::make_tuple(mapPtr->GetGlobalID()), kToInsert); + shad::rt::waitForCompletion(handle); + mapPtr->WaitForBufferedInsert(); + ASSERT_EQ(mapPtr->Size(), kToInsert); + MultimapType::LookupResult *values = new MultimapType::LookupResult [kToInsert]; + for (size_t i = 0; i < kToInsert; i++) { + DoAsyncLookup(handle, mapPtr->GetGlobalID(), i, &values[i]); + } + shad::rt::waitForCompletion(handle); + for (uint64_t i = 0; i < kToInsert; i++) { + CheckValue((values[i].value), i + 11); + } + delete[] values; + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, FEBufferedInsertAsyncLookupTest) { + auto mapPtr = MultimapType::Create(kToInsert); + shad::rt::Handle handle; + auto insertLambda = [](shad::rt::Handle &handle, + const std::tuple &t, size_t i) { + uint64_t value = i; + DoBufferedInsert(std::get<0>(t), value, value + 11); + }; + shad::rt::asyncForEachOnAll( + handle, insertLambda, std::make_tuple(mapPtr->GetGlobalID()), kToInsert); + shad::rt::waitForCompletion(handle); + mapPtr->WaitForBufferedInsert(); + ASSERT_EQ(mapPtr->Size(), kToInsert); + MultimapType::LookupResult *values = new MultimapType::LookupResult [kToInsert]; + for (size_t i = 0; i < kToInsert; i++) { + DoAsyncLookup(handle, mapPtr->GetGlobalID(), i, &values[i]); + } + shad::rt::waitForCompletion(handle); + for (uint64_t i = 0; i < kToInsert; i++) { + CheckValue((values[i].value), i + 11); + } + delete[] values; + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, Erase) { + auto mapPtr = MultimapType::Create(kToInsert); + shad::rt::Handle handle; + for (uint64_t i = 1; i < kToInsert; i++) { + DoAsyncInsert(handle, mapPtr->GetGlobalID(), i, i + 11); + } + shad::rt::waitForCompletion(handle); + size_t currSize = mapPtr->Size(); + + Key k; + FillKey(&k,1); + mapPtr->Erase(k); + currSize--; + + + for (uint64_t i = 1; i < kToInsert; i++) { + std::vector values; + bool found = DoLookup(mapPtr->GetGlobalID(), i, &values); + if (i ==1) { + ASSERT_FALSE(found); + } else { + ASSERT_TRUE(found); + CheckValue(values, i + 11); + } + } + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + + + +TEST_F(MultimapTest, AsyncErase) { + auto mapPtr = MultimapType::Create(kToInsert); + shad::rt::Handle handle; + for (uint64_t i = 1; i < kToInsert; i++) { + DoAsyncInsert(handle, mapPtr->GetGlobalID(), i, i + 11); + } + shad::rt::waitForCompletion(handle); + ASSERT_EQ(mapPtr->Size(), kToInsert-1); + size_t currSize = mapPtr->Size(); + Key k; + FillKey(&k, 1); + mapPtr->AsyncErase(handle, k); + currSize--; + + shad::rt::waitForCompletion(handle); + for (uint64_t i = 1; i < kToInsert; i++) { + Key k; + FillKey(&k, i); + std::vector values; + bool found = DoLookup(mapPtr->GetGlobalID(), i, &values); + if (i==1) { + ASSERT_FALSE(found); + } else { + ASSERT_TRUE(found); + CheckValue(values, i + 11); + } + } + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, ForEachEntry) { + auto mapPtr = MultimapType::Create(kToInsert); + auto args = std::make_tuple(mapPtr->GetGlobalID(), 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachOnAll(handle, InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + auto VisitLambda0args = [](const Key &key, std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + + auto VisitLambda1arg = [](const Key &key, std::vector &value, + uint64_t &magicValue) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + + auto VisitLambda = [](const Key &key, std::vector &value, uint64_t &magicValue, + uint64_t &magicValue2) { + ASSERT_TRUE(magicValue == kMagicValue); + ASSERT_TRUE(magicValue2 == kMagicValue * 2); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + uint64_t magicValue = kMagicValue; + uint64_t magicValue2 = kMagicValue * 2; + mapPtr->ForEachEntry(VisitLambda0args); + mapPtr->ForEachEntry(VisitLambda1arg, magicValue); + mapPtr->ForEachEntry(VisitLambda, magicValue, magicValue2); + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, AsyncForEachEntry) { + auto mapPtr = MultimapType::Create(kToInsert); + auto args = std::make_tuple(mapPtr->GetGlobalID(), 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachOnAll(handle, InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + auto VisitLambda0args = [](shad::rt::Handle &, const Key &key, std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto VisitLambda1arg = [](shad::rt::Handle &, const Key &key, std::vector &value, + uint64_t &magicValue) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto VisitLambda = [](shad::rt::Handle &, const Key &key, std::vector &value, + uint64_t &magicValue, uint64_t &magicValue2) { + ASSERT_TRUE(magicValue == kMagicValue); + ASSERT_TRUE(magicValue2 == kMagicValue * 2); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + uint64_t magicValue = kMagicValue; + uint64_t magicValue2 = kMagicValue * 2; + mapPtr->AsyncForEachEntry(handle, VisitLambda0args); + mapPtr->AsyncForEachEntry(handle, VisitLambda1arg, magicValue); + mapPtr->AsyncForEachEntry(handle, VisitLambda, magicValue, magicValue2); + shad::rt::waitForCompletion(handle); + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + + +TEST_F(MultimapTest, ForEachKey) { + auto mapPtr = MultimapType::Create(kToInsert); + auto args = std::make_tuple(mapPtr->GetGlobalID(), 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachOnAll(handle, InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + auto VisitLambda0args = [](const Key &key) { CheckKey(&key, GetSeed(&key)); }; + auto VisitLambda1arg = [](const Key &key, uint64_t &magicValue) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + }; + auto VisitLambda = [](const Key &key, uint64_t &magicValue, + uint64_t &magicValue2) { + ASSERT_TRUE(magicValue == kMagicValue); + ASSERT_TRUE(magicValue2 == kMagicValue * 2); + CheckKey(&key, GetSeed(&key)); + }; + uint64_t magicValue = kMagicValue; + uint64_t magicValue2 = kMagicValue * 2; + mapPtr->ForEachKey(VisitLambda0args); + mapPtr->ForEachKey(VisitLambda1arg, magicValue); + mapPtr->ForEachKey(VisitLambda, magicValue, magicValue2); + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, AsyncForEachKey) { + auto mapPtr = MultimapType::Create(kToInsert); + auto args = std::make_tuple(mapPtr->GetGlobalID(), 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachOnAll(handle, InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + auto VisitLambda0args = [](shad::rt::Handle &, const Key &key) { + CheckKey(&key, GetSeed(&key)); + }; + auto VisitLambda1arg = [](shad::rt::Handle &, const Key &key, + uint64_t &magicValue) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + }; + auto VisitLambda = [](shad::rt::Handle &, const Key &key, + uint64_t &magicValue, uint64_t &magicValue2) { + ASSERT_TRUE(magicValue == kMagicValue); + ASSERT_TRUE(magicValue2 == kMagicValue * 2); + CheckKey(&key, GetSeed(&key)); + }; + uint64_t magicValue = kMagicValue; + uint64_t magicValue2 = kMagicValue * 2; + mapPtr->AsyncForEachKey(handle, VisitLambda0args); + mapPtr->AsyncForEachKey(handle, VisitLambda1arg, magicValue); + mapPtr->AsyncForEachKey(handle, VisitLambda, magicValue, magicValue2); + shad::rt::waitForCompletion(handle); + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + +TEST_F(MultimapTest, Apply) { + auto mapPtr = MultimapType::Create(kToInsert); + auto args = std::make_tuple(mapPtr->GetGlobalID(), 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + auto ApplyLambda0args = [](const Key &key, std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto ApplyLambda1arg = [](const Key &key, std::vector &value, + uint64_t &magicValue) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto ApplyLambda = [](const Key &key, std::vector &value, uint64_t &magicValue, + uint64_t &magicValue2) { + ASSERT_TRUE(magicValue == kMagicValue); + ASSERT_TRUE(magicValue2 == kMagicValue * 2); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + uint64_t magicValue = kMagicValue; + uint64_t magicValue2 = kMagicValue * 2; + for (size_t i = 0; i < kToInsert; i++) { + Key keys; + FillKey(&keys, i); + mapPtr->Apply(keys, ApplyLambda0args); + mapPtr->Apply(keys, ApplyLambda1arg, magicValue); + mapPtr->Apply(keys, ApplyLambda, magicValue, magicValue2); + } + MultimapType::Destroy(mapPtr->GetGlobalID()); +} + + +TEST_F(MultimapTest, AsyncApply) { + auto mapPtr = MultimapType::Create(kToInsert); + auto args = std::make_tuple(mapPtr->GetGlobalID(), 0lu); + shad::rt::Handle handle; + shad::rt::asyncForEachAt(handle, shad::rt::thisLocality(), + InsertTestParallelFunc, args, kToInsert); + shad::rt::waitForCompletion(handle); + auto AsyncApplyLambda0args = [](shad::rt::Handle &, const Key &key, + std::vector &value) { + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto AsyncApplyLambda1arg = [](shad::rt::Handle &, const Key &key, + std::vector &value, uint64_t &magicValue) { + ASSERT_TRUE(magicValue == kMagicValue); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + auto AsyncApplyLambda = [](shad::rt::Handle &, const Key &key, std::vector &value, + uint64_t &magicValue, uint64_t &magicValue2) { + ASSERT_TRUE(magicValue == kMagicValue); + ASSERT_TRUE(magicValue2 == kMagicValue * 2); + CheckKey(&key, GetSeed(&key)); + CheckValue(value, GetSeed(&value[0])); + }; + uint64_t magicValue = kMagicValue; + uint64_t magicValue2 = kMagicValue * 2; + for (size_t i = 0; i < kToInsert; i++) { + Key keys; + FillKey(&keys, i); + mapPtr->AsyncApply(handle, keys, AsyncApplyLambda0args); + mapPtr->AsyncApply(handle, keys, AsyncApplyLambda1arg, magicValue); + mapPtr->AsyncApply(handle, keys, AsyncApplyLambda, magicValue, magicValue2); + } + shad::rt::waitForCompletion(handle); + MultimapType::Destroy(mapPtr->GetGlobalID()); +}