Add makePool method on ThreadMap#283
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process. |
makePool method on ThreadMapmakePool method on ThreadMap
d56e637 to
158f30d
Compare
makePool method on ThreadMapmakePool method on ThreadMap
| # Pre-allocate a pool of server threads for implicit dispatch. When a | ||
| # request arrives with no context.thread set, the server round-robins | ||
| # across the pool instead of returning an error. | ||
| makePool @1 (count :UInt32) -> (); |
There was a problem hiding this comment.
| makePool @1 (count :UInt32) -> (); | |
| makePool @1 (name: Text, count :UInt32) -> (); |
It would be usefull to have a name parameter like makeThread. Since each client may have its own thread pool, naming them would make log lines like "IPC server post request #{name} {pool/0}" attributable to a specific client
There was a problem hiding this comment.
Updated. How does that look?
There was a problem hiding this comment.
Nice, I just have this nit to make it more consistent with makeThread:
const std::string thread_name = pool_name + "/pool/" + std::to_string(i);
std::promise<ThreadContext*> thread_context;
std::thread thread([&loop, &thread_context, thread_name]() {
- g_thread_context.thread_name = ThreadName(loop.m_exe_name) + " (" + thread_name + ")";
+ g_thread_context.thread_name = ThreadName(loop.m_exe_name) + " (from " + thread_name + ")";
g_thread_context.waiter = std::make_unique<Waiter>();
Lock lock(g_thread_context.waiter->m_mutex);
thread_context.set_value(&g_thread_context);| kj::Promise<void> ProxyServer<ThreadMap>::makePool(MakePoolContext context) | ||
| { | ||
| EventLoop& loop{*m_connection.m_loop}; | ||
| const uint32_t count = context.getParams().getCount(); | ||
| for (uint32_t i = 0; i < count; ++i) { | ||
| const std::string name = "pool/" + std::to_string(i); | ||
| std::promise<ThreadContext*> thread_context; | ||
| std::thread thread([&loop, &thread_context, name]() { | ||
| g_thread_context.thread_name = ThreadName(loop.m_exe_name) + " (" + name + ")"; | ||
| g_thread_context.waiter = std::make_unique<Waiter>(); | ||
| Lock lock(g_thread_context.waiter->m_mutex); | ||
| thread_context.set_value(&g_thread_context); | ||
| g_thread_context.waiter->wait(lock, [] { return !g_thread_context.waiter; }); | ||
| }); | ||
| auto thread_server = kj::heap<ProxyServer<Thread>>(m_connection, *thread_context.get_future().get(), std::move(thread)); | ||
| m_connection.m_thread_pool.push_back(m_connection.m_threads.add(kj::mv(thread_server))); | ||
| } | ||
| return kj::READY_NOW; | ||
| } |
There was a problem hiding this comment.
Repeated calls silently grow the pool beyond the intended size, and since naming is based on the loop index starting from 0 each time, you'd end up with duplicate names like two threads both called pool/0 making logs ambiguous.
I'm not sure what would be the correct approach but I thought about:
- Return an error if m_connection.m_thread_pool is not empty
- Replace the old pool by cleaning the m_connection.m_thread_pool and create a fresh one with the new count. This makes sense if the client needs to resize its dedicated pool.
158f30d to
5808f62
Compare
This patch introduces a pool of threads to the `Connection` class, and allows this pool to be populated with the thread map via `makePool`. When a client thread is not set in a request context, it is delegated to the pool. This is unable to handle the guarentees with server-invoked callbacks that the current API offers, but these callbacks are not yet present in the interface. The pool is implemented as round-robin as it is simplest, but perhaps the pool could be a queue of requests with work-stealing for threads that are available. This was raised to me by Rust users, as they did not particularly care where work is executed on the server-side, but they have to set the thread regardless. ref: https://github.com/2140-dev/bitcoin-capnp-types/blob/master/tests/util/bitcoin_core.rs#L149
5808f62 to
d5bc804
Compare
This patch introduces a pool of threads to the
Connectionclass, and allows this pool to be populated with the thread map viamakePool. When a client thread is not set in a request context, it is delegated to the pool. This is unable to handle the guarentees with server-invoked callbacks that the current API offers, but these callbacks are not yet present in the interface.The pool is implemented as round-robin as it is simplest, but perhaps the pool could be a queue of requests with work-stealing for threads that are available.
This was raised to me by Rust users, as they did not particularly care where work is executed on the server-side, but they have to set the thread regardless.
Tests in Rust can be seen here: 2140-dev/bitcoin-capnp-types#24
ref: https://github.com/2140-dev/bitcoin-capnp-types/blob/master/tests/util/bitcoin_core.rs#L149
ref: #281