summaryrefslogtreecommitdiff
path: root/src/mongo/util/concurrent_shared_values_map.h
diff options
context:
space:
mode:
authorJordi Olivares Provencio <jordi.olivares-provencio@mongodb.com>2023-03-21 10:44:20 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-03-21 11:23:14 +0000
commit33cc6a588ccb17078d3e942e57a097a89fb71250 (patch)
treee733e52d35647f60c67cc15284db5c30ec15e2c0 /src/mongo/util/concurrent_shared_values_map.h
parent1bc404dc1a90bfb1ccd95aa9e92c35f314c1e6b3 (diff)
downloadmongo-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.h36
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