We can get rid of all the lock contention by using
tbb::concurrent_hash_map. Unfortunately tbb::concurrent_hash_map doesn't let us
iterate over it while we concurrently do inserts. Work around this limitation by
keeping a copy of all the counter keys in a concurrent_vector which does let us
concurrently insert and iterate.
On lookup / insert, we first look into concurrent_hash_map for the key. If key
already exists, return the value. Otherwise, we insert into both the map and the
list.
On export, we iterate over the list and look up each key from the map.
This a simpler / cleaner version of fbcode's ServiceData for hphp. Currently we
support only flat counters, MultiLevelTimeSeries and Histograms. We can add more
stats types later on as needed.
ServiceData is a global entry point for all this stuff. The current idea is to
completely decouple data input and export. ServiceData internally has three
separate maps tracking flat counters, timeseries and histograms. These maps are
wrapped by spin locks and protected by folly::Synchronized.
ServiceData provides three functions to create/retrive counter objects. The
counter objects are thread safe (protected again by spin locks and
folly::Synchronized).