Skip to content

Commit 91ab256

Browse files
yfeldblumfacebook-github-bot
authored andcommitted
no key copies in TLStatNameSet
Summary: Instead of copying the stat names into the map keys, use a set with specialized key-hash and key-equal functions. Reviewed By: Gownta Differential Revision: D68386450 fbshipit-source-id: 4994ab45c9f4d47fb42fd54739763c69ab95ac98
1 parent dcfc88d commit 91ab256

File tree

1 file changed

+37
-5
lines changed

1 file changed

+37
-5
lines changed

fb303/ThreadLocalStats.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,37 @@ class TLStatNameSet::Impl {
7474
}
7575
};
7676

77-
using Set = folly::F14FastMap<std::string, Wp>;
77+
/// typical layout of std::shared_ptr and std::weak_ptr
78+
/// need controlled access to address of object even from weak_ptr
79+
///
80+
/// layout consistent with libstdc++, libc++, microsoft-stl
81+
template <typename T>
82+
struct WpLayout {
83+
T* const object{};
84+
void const* const control{};
85+
86+
explicit WpLayout(std::weak_ptr<T> const& wp) noexcept
87+
: WpLayout(reinterpret_cast<WpLayout const&>(wp)) {}
88+
};
89+
90+
struct Key {
91+
Wp weak;
92+
/* implicit */ operator std::string_view() const noexcept {
93+
return *WpLayout(weak).object; // assume lockable - not-null, still-alive
94+
}
95+
};
96+
97+
struct KeyHash : std::hash<std::string_view> {
98+
using is_transparent = void;
99+
using std::hash<std::string_view>::operator();
100+
};
101+
102+
struct KeyEqual : std::equal_to<std::string_view> {
103+
using is_transparent = void;
104+
using std::equal_to<std::string_view>::operator();
105+
};
106+
107+
using Set = folly::F14FastSet<Key, KeyHash, KeyEqual>;
78108

79109
/// split to reduce potential lock contention at startup for threads looking
80110
/// up distinct names
@@ -94,7 +124,8 @@ class TLStatNameSet::Impl {
94124
void clean(std::string const& name) {
95125
auto const wlock = set(name).wlock();
96126
if (auto const it = wlock->find(name); it != wlock->end()) {
97-
if (!it->second.lock()) {
127+
if (WpLayout(it->weak).object == &name) {
128+
assert(!it->weak.lock());
98129
wlock->erase(it);
99130
}
100131
}
@@ -103,19 +134,20 @@ class TLStatNameSet::Impl {
103134
Sp getSlow(std::string_view const name) {
104135
auto const wlock = set(name).wlock();
105136
if (auto const it = wlock->find(name); it != wlock->end()) {
106-
if (auto sp = it->second.lock()) {
137+
if (auto sp = it->weak.lock()) {
107138
return sp;
108139
}
140+
wlock->erase(it); // in case this call races with corresponding clean()
109141
}
110142
auto sp = Sp{new std::string(name), SpDeleter{}};
111-
(*wlock)[std::string(name)] = sp;
143+
wlock->insert(Key{sp});
112144
return sp;
113145
}
114146

115147
Sp getFast(std::string_view const name) {
116148
auto const rlock = set(name).rlock();
117149
if (auto const it = rlock->find(name); it != rlock->end()) {
118-
if (auto sp = it->second.lock()) {
150+
if (auto sp = it->weak.lock()) {
119151
return sp;
120152
}
121153
}

0 commit comments

Comments
 (0)