Ruben's January update: presenting Boost.MySQL's new pool!
Jan 10, 2024In spite of it being winter here, Boost.MySQL is presenting a new pool this year! This was one of the most requested features in the library, and will finally be generally available as an experimental feature in Boost 1.85.
Connection pools manage tasks that are easy to get wrong, like reconnections, health checks and session cleanup. As they reuse physical connections, they also provide a nice efficiency boost.
Using a pool is as simple as:
boost::asio::awaitable<std::int64_t> get_num_employees(boost::mysql::connection_pool& pool)
{
// Get a fresh connection from the pool
auto conn = co_await pool.async_get_connection(boost::asio::use_awaitable);
// Use the connection. It will be returned to the pool on scope exit
results result;
co_await conn->async_execute("SELECT COUNT(*) FROM employee", result, boost::asio::use_awaitable);
co_return result.rows().at(0).at(0).as_int64();
}
Despite its simple interface, implementing connection_pool
has been a long and hard
task that has taken me a considerable effort. In the process, I’ve been able to
learn in-depth many things about Boost.Asio which I thought I knew, but it turns out I did not.
For instance, I’ve finally understood the Asio property system, and wrote
a blog post on it, hoping
that others will find it easier to understand. I’ve also managed to make connection_pool
easy to use in multi-threaded contexts using strands. I’ve found many subtle pitfalls
here that are easy to get wrong. Thread-sanitizer for the win!
In any case, I’ve been able to get help from other knowledgeable Asio developers, both from inside and outside the C++ Alliance, which has been really helpful to get this done.
I’m also pretty happy with the role that Boost ServerTech chat has played in this task. ServerTech chat is a project to showcase how Boost libraries can be used together, and a place to innovate. Thanks to it, I’ve had an almost real-world environment to battle-test my API in.
Type-erased connections
With connection_pool
, Boost.MySQL is getting a new type-erased connection
type, any_connection
, with much easier connection establishment semantics.
Connection pooling relies on such semantics to provide better efficiency.
any_connection
is currently experimental, but I expect it to become the
default connection type once it becomes stable.
Boost.Redis finally released!
Boost.Redis finally got its first release with Boost 1.84. I’m proud to have helped the author integrate this library into Boost.
Boost integration is not a trivial process. Most novice authors only have CMake experience, but Boost builds require some parts to use B2. Even with CMake, some parts need to adhere to certain conventions to integrate with the Boost superproject. I’ve recently gone through this, so I’ve been able to help here.
I’m also pretty happy about my teammate’s efforts on documenting these processes in the contributor guide.
Sans-io all the things
Up to Boost 1.84, all network algorithms in Boost.MySQL are internally
implemented as layered functions calling Boost.Asio primitives. As an overly
simplistic example, connection::execute
calls two functions, write_request
and read_response
, which end up in socket calls.
While this is the obvious way to implement such a library, it generates a lot of
duplication. There is connection::execute
and connection::async_execute
,
which yields two versions of every underlying function. It’s also slow
to compile (Asio async code is full of heavy templates) and hard to test.
Starting from Boost 1.85, all network algorithms are implemented as state machines. Such algorithms are called sans-io, because they don’t directly invoke any I/O functions. A thin layer of Asio code connects such algorithms to I/O, yielding the same interface as before. These algorithms are currently an implementation detail, and not exposed to the public. This change has made the library much simpler and enjoyable to test. Even if you’re not planning to support sync functions, consider going sans-io - your unit tests will thank you.
Next steps: SQL query formatting
The next big step is supporting client-side query composition. This makes use cases like dynamic filters much easier to implement, and can increase efficiency by saving round-trips to the server. I’m currently examining the great fmt library as a source of inspiration.