29#include <flow/util/util.hpp>
30#include <jemalloc/jemalloc.h>
53 cache->if_requested_destroy_tcaches_and_possibly_finish_arena_kills();
66 cache->if_requested_destroy_tcaches_and_possibly_finish_arena_kills();
72 m_thread_token(flow::util::this_thread_unique_token())
74 namespace this_thread = flow::util::this_thread;
75 using flow::util::Thread_id;
76 using flow::log::Logger;
84 FLOW_LOG_INFO_LOCKED(
"Jem_tcache[" << *
this <<
"]: "
85 "Created cache object for this thread (details to the left in this message); "
86 "no tcaches yet until next id() call.");
91 const auto this_thread_unique_token = flow::util::this_thread_unique_token();
94 FLOW_LOG_WARNING_LOCKED
95 (
"Jem_tcache[" << *
this <<
"]: "
96 "Shutting down from different thread (unique-token [" << this_thread_unique_token <<
"]) "
97 "than the one (unique-token [" <<
thread_token() <<
"]) that created us; "
98 "cannot flush/destroy anything; bailing out. In any case, this can conceivably -- in the "
99 "absence of misuse by the Thread_cache user -- only occur when program is exiting, at which "
100 "point graceful shutdown of jemalloc resources is arguably less essential.");
124 FLOW_LOG_INFO_LOCKED(
"Jem_tcache[" << *
this <<
"]: "
125 "Shutting down. First, will check for any pending arena destruction progress to push-forward; "
126 "this will destroy 0+ tcaches, destroy 0+ arenas, run 0+ on-done functors for the latter; next "
127 "will destroy (includes flushing) any remaining tcaches.");
140 using flow::util::this_thread_unique_token;
141 using boost::system::system_category;
143 assert((this_thread_unique_token() ==
thread_token()) &&
"Please don't flush/etc. across threads.");
145 FLOW_LOG_INFO_LOCKED(
"Jem_tcache[" << *
this <<
"]: Tcache-flush of tcache [" <<
id <<
"] requested: proceeding.");
150 const Error_code sys_err_code{code, system_category()};
151 FLOW_LOG_FATAL_LOCKED(
"System error occurred: [" << sys_err_code <<
"] [" << sys_err_code.message() <<
"].");
152 assert(
false &&
"Tcache-flush failed -- as of this writing we consider this catastrophic; "
153 "for some ops such as to allow for arena destruction subsequently it is essential "
154 "for it to succeed. We don't consider this recoverable. @todo Revisit.");
162 using flow::util::this_thread_unique_token;
163 using boost::system::system_category;
165 assert((this_thread_unique_token() ==
thread_token()) &&
"Please don't flush/etc. across threads.");
167 FLOW_LOG_INFO_LOCKED(
"Jem_tcache[" << *
this <<
"]: Tcache-destruction (includes flushing) of tcache [" <<
id <<
"] "
168 "requested: proceeding.");
173 const Error_code sys_err_code{code, system_category()};
174 FLOW_LOG_FATAL_LOCKED(
"System error occurred: [" << sys_err_code <<
"] [" << sys_err_code.message() <<
"].");
175 assert(
false &&
"Tcache-destruction failed -- as of this writing we consider this catastrophic; "
176 "for some ops such as to allow for arena destruction subsequently it is essential "
177 "for flushing and/or destruction to succeed. We don't consider this recoverable. "
193 using boost::system::system_category;
198 auto&
id = it_and_did_insert.first->second;
200 if (it_and_did_insert.second)
202 const auto mallctl_or_die = [&](
const char* op_name,
void* oldp,
size_t* oldlenp,
void* newp,
size_t newlen)
207 const Error_code sys_err_code{code, system_category()};
208 FLOW_LOG_FATAL_LOCKED(
"Op [" << op_name <<
"]: System error occurred: [" << sys_err_code <<
"] "
209 "[" << sys_err_code.message() <<
"].");
210 assert(
false &&
"Tcache-creation-related mallctl() failed -- as of this writing we consider this "
212 "@todo We could probably add contingency steps and deal with it; just for the time "
213 "being we've seen no legit reason for this to fail and decided not to spend effort "
214 "in coding and testing such contingencies.");
226 size_t output_sz =
sizeof(
id);
227 mallctl_or_die(
"tcache.create", &
id, &output_sz,
nullptr, 0);
229 FLOW_LOG_INFO_LOCKED(
"Jem_tcache[" << *
this <<
"]: A tcache ID was requested for an arena but did not exist; thus: "
230 "Tcache-create succeeded; tcache [" <<
id <<
"] for arena [" << arena_id <<
"] ready.");
255 auto& arenas_death_row_map = *arenas_death_row_map_ptr;
256 vector<arena_id_t> arenas_to_kill;
258 for (
auto& arena_and_progress : arenas_death_row_map)
260 auto& arena_death_progress = arena_and_progress.second;
261 auto& caches = arena_death_progress.m_caches_left_to_destroy;
262 if (caches.erase(
this) == 0)
268 const bool fatal_destroy = caches.empty();
269 const auto arena_id = arena_and_progress.first;
273 FLOW_LOG_INFO_LOCKED(
"Jem_tcache[" << *
this <<
"]: Arena [" << arena_id <<
"] is being destroyed; "
274 "this thread-cache object was marked to destroy any relevant tcache before "
275 "arena-destruction can proceed; however that arena has not been used w/r/t tcaching "
276 "in this thread yet; therefore there is nothing to destroy, and we shall cross ourselves "
277 "off that list. If that makes the list empty (does it? = [" << fatal_destroy <<
"]), "
278 "we shall imminently destroy arena.");
282 const auto id = it->second;
283 FLOW_LOG_INFO_LOCKED(
"Jem_tcache[" << *
this <<
"]: Arena [" << arena_id <<
"] is being destroyed; "
284 "this thread-cache object was marked to destroy any relevant tcache before "
285 "arena-destruction can proceed; and indeed we hold tcache [" <<
id <<
"]. "
286 "Proceeding with destruction to cross ourselves off the list. If that makes "
287 "the list empty (does it? = [" << fatal_destroy <<
"]), we shall imminently "
295 arenas_to_kill.push_back(arena_id);
297 on_done_funcs_to_execute.emplace_back(std::move(arena_death_progress.m_on_done_func));
298 arena_death_progress.m_on_done_func.clear();
303 for (
const auto arena_id : arenas_to_kill)
305 const auto it = arenas_death_row_map.find(arena_id);
307 auto& arena_death_progress = it->second;
309 assert(arena_death_progress.m_caches_left_to_destroy.empty());
310 assert(arena_death_progress.m_on_done_func.empty());
312 arenas_death_row_map.erase(it);
316 for (
auto& on_done_func : on_done_funcs_to_execute)
318 on_done_func(
static_cast<const Log_context_mt*
>(
this));
329 using flow::util::ostream_op_string;
330 using flow::util::Lock_guard;
331 using flow::util::Mutex_non_recursive;
332 using boost::system::system_category;
334 FLOW_LOG_SET_LOCKED_CONTEXT(log_ctx);
346 nullptr,
nullptr,
nullptr, input_sz);
356 const Error_code sys_err_code{code, system_category()};
357 FLOW_LOG_FATAL_LOCKED(
"Arena [" << arena_id <<
"] destruction: System error occurred: [" << sys_err_code <<
"] "
358 "[" << sys_err_code.message() <<
"].");
359 assert(
false &&
"Arena-destruction failed -- as of this writing we consider this catastrophic. @todo Revisit.");
363 FLOW_LOG_INFO_LOCKED(
"Destroyed arena [" << arena_id <<
"].");
373 Set_logger_registry::register_action([](flow::log::Logger* logger_ptr)
389 return os <<
"]]@" << &val;
jemalloc central thread cache manager, maintaining an explicitly identified tcache per allocating thr...
flow::util::Thread_token thread_token() const
Unique-token of thread in which *this was originally created via this_thread_cache() call.
void if_requested_destroy_tcaches_and_possibly_finish_arena_kills(bool assume_requested=false)
Perform deferred cross-thread tcache and arena-destruction as triggered by destroy_arena_safely() cal...
void flush_tcache(tcache_id_t id)
Flushes the given tcache as specified by its ID.
friend std::ostream & operator<<(std::ostream &, const Thread_cache &)
Prints string representation of the given Thread_cache to the given ostream.
static Static_state s_state
See doc header and especially member doc headers for Static_state.
flow::util::Thread_token m_thread_token
See thread_token().
std::string m_thread_nickname
See thread_nickname().
boost::unordered_flat_map< arena_id_t, tcache_id_t > m_tcaches_by_arena
See id(): for this thread, maps arena ID (that has been passed to id() at least once) to the jemalloc...
static constexpr tcache_id_t S_NO_TCACHE_ID
Special value returned by id_or_none() indicating no tcache yet exists for the given arena_id_t.
~Thread_cache()
Destructor that runs in each thread (potentially even after main() – the thread had not been joined b...
Thread_cache(flow::log::Logger *logger_ptr)
Constructs cache for this thread as invoked internally by this_thread_cache().
static Thread_cache * this_thread_cache_or_null()
Returns pointer to the one cache-object in the calling thread, or null if none exists (this_thread_ca...
static Thread_cache * this_thread_cache()
Returns pointer to the one cache-object in the calling thread, first creating it if it is the first s...
flow::util::Poll_flag m_destroy_tcaches_requested_poll_flag
Poll-flag corresponding to Static_state::m_arenas_death_row_map Polled_shared_state pattern.
tcache_id_t id(arena_id_t arena_id)
Returns tcache ID of the tcache in this thread with a 1-1 relationship to the given arena,...
const std::string & thread_nickname() const
Thread nickname, as from flow::log::Logger::set_thread_info(), corresponding to thread in which *this...
void destroy_tcache(tcache_id_t id)
Flushes/destroys the given tcache.
tcache_id_t id_or_none(arena_id_t arena_id) const
Returns tcache ID of the tcache in this thread with a 1-1 relationship to the given arena,...
static void destroy_arena(arena_id_t arena_id, const flow::log::Log_context_mt *log_ctx)
Destroys the given arena now.
static void caches_set_logger(flow::log::Logger *logger_ptr)
Sets the Logger to use (or null to skip logging) subsequently for logging in static calls; non-static...
flow::util::Mutex_non_recursive & jemalloc_arena_list_mutex()
Returns the process-global mutex serializing any mutation of jemalloc's arena set (arena create/destr...
ipc::shm sub-module with the SHM-jemalloc SHM-provider. See ipc::shm doc header for introduction.
unsigned int arena_id_t
Arena ID as dictated by jemalloc.
unsigned int tcache_id_t
Thread cache ID type as dictated by jemalloc.
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
#define IPC_SHM_ARENA_LEND_JEMALLOC_API(ARG_api_name)
To be used when invoking jemalloc public API functions, this evaluates to the given argument (which s...
Function< void(const flow::log::Log_context_mt *)> m_on_done_func
Functor to invoke, and then immediately destroy, once m_caches_left_to_destroy is ....
flow::util::Polled_shared_state< boost::unordered_map< arena_id_t, Arena_death_progress > > m_arenas_death_row_map
State shared – and acted upon using the Polled_shared_state pattern – between extant Thread_cache per...
Static_state()
Constructor.
flow::util::Thread_local_state_registry< Thread_cache > m_caches
The work-horse: registry of per-thread Thread_cache objects, each holding 0+ jemalloc tcaches.