diff options
author | Jordi Olivares Provencio <jordi.olivares-provencio@mongodb.com> | 2023-03-21 10:44:20 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-03-21 11:23:14 +0000 |
commit | 33cc6a588ccb17078d3e942e57a097a89fb71250 (patch) | |
tree | e733e52d35647f60c67cc15284db5c30ec15e2c0 /src/mongo/util/concurrent_shared_values_map.h | |
parent | 1bc404dc1a90bfb1ccd95aa9e92c35f314c1e6b3 (diff) | |
download | mongo-33cc6a588ccb17078d3e942e57a097a89fb71250.tar.gz |
SERVER-75006 Add updateWith method to read-copy-update map
Diffstat (limited to 'src/mongo/util/concurrent_shared_values_map.h')
-rw-r--r-- | src/mongo/util/concurrent_shared_values_map.h | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/src/mongo/util/concurrent_shared_values_map.h b/src/mongo/util/concurrent_shared_values_map.h index 55acbeb12f0..fe2351ea157 100644 --- a/src/mongo/util/concurrent_shared_values_map.h +++ b/src/mongo/util/concurrent_shared_values_map.h @@ -49,16 +49,9 @@ namespace mongo { */ template <typename Key, typename Value, typename... ExtraAbslArgs> class ConcurrentSharedValuesMap { -private: +public: using Map = absl::flat_hash_map<Key, std::shared_ptr<Value>, ExtraAbslArgs...>; - ConcurrentSharedValuesMap(std::shared_ptr<Map> otherMap) : _map(std::move(otherMap)){}; - - // shared_ptr in order to allow lock-free reads of the values. - std::shared_ptr<Map> _map; - // Locked in order to modify the map by either inserting or removing an element. - Mutex _mapModificationMutex; -public: ConcurrentSharedValuesMap() : _map(std::make_shared<Map>()) {} /** @@ -136,5 +129,32 @@ public: auto emptyMap = std::make_shared<Map>(); atomic_store(&_map, std::move(emptyMap)); } + + /** + * Updates the map atomically, this method accepts a function that will return the new map to + * use. Existing copies of the map or values previously obtained via find() will not be + * invalidated. + * + * This is a blocking operation as all writes are serialized. As the function can be expensive + * to execute, care must be taken in order to minimize its cost. Otherwise it risks blocking + * writes for longer than desired. + */ + template <typename F> + void updateWith(F&& updateFunc) { + static_assert(std::is_invocable_r_v<Map, F, const Map&>, + "Function must be of type Map(const Map&)"); + stdx::lock_guard lk(_mapModificationMutex); + auto currentMap = atomic_load(&_map); + auto newMap = std::make_shared<Map>(std::forward<F>(updateFunc)(*currentMap)); + atomic_store(&_map, std::move(newMap)); + } + +private: + ConcurrentSharedValuesMap(std::shared_ptr<Map> otherMap) : _map(std::move(otherMap)){}; + + // shared_ptr in order to allow lock-free reads of the values. + std::shared_ptr<Map> _map; + // Locked in order to modify the map by either inserting or removing an element. + Mutex _mapModificationMutex; }; } // namespace mongo |