-
Motivation: Users of Redis will frequently want to be able to run queries in parallel, while bounding the number of connections they use. They will also often want to be able to reuse connections, without having to arrange to manage those connections themselves. These are jobs usually done by a Connection Pool. This new connection pool will conform to `RedisClient` so a pool of clients and a single connection are interchangeable. Connection Pools come in a wide range of shapes and sizes. In NIO applications and frameworks, there are a number of questions that have to be answered by any pool implementation: 1. Is the pool safe to share across EventLoops: that is, is its interface thread-safe? 2. Is the pool _tied_ to an EventLoop: that is, can the pool return connections that belong on lots of event loops, or just one? 3. If the pool is not tied to an EventLoop, is it possible to influence its choice about what event loop it uses for a given connection? Question 1 is straightforward: it is almost always a trivial win to ensure that the public interface to a connection pool is thread-safe. NIO makes it possible to do this fairly cheaply in the case when the pool is only used on a single loop. Question 2 is a lot harder. Pools that are not tied to a specific EventLoop have two advantages. The first is that it is easier to bound maximum concurrency by simply configuring the pool, instead of needing to do math on the number of pools and the number of event loops. The second is that non-tied pools can arrange to keep busy applications close to this maximum concurrency regardless of how the application spreads its load across loops. However, pools that are tied to a specific EventLoop have advantages too. The first is one of implementation simplicity. As they always serve connections on a single EventLoop, they can arrange to have all of their state on that event loop too. This avoids the need to acquire locks on that loop, making internal state management easier and more obviously correct without having to worry about how long locks are held for. The second advantage is that they can be used for latency sensitive use-cases without needing to go to the work of (3). In cases where latency is very important, it can be valuable to ensure that any Channel that needs a connection can get one on the same event loop as itself. This avoids the need to thread-hop in order to communicate between the pooled connection and the user connection, reducing the latency of operations. Given the simplicity and latency benefits (which we deem particularly important for Redis use-cases), we concluded that a good initial implementation will be a pool that has a thread-safe interface, but is tied to a single EventLoop. This allows a compact, easy-to-verify implementation of the pool with great low-latency performance and simple implementation logic, that can still be accessed from any EventLoop in cases when latency is not a concern. Modifications: - Add new internal `ConnectionPool` object - Add new `RedisConnectionPool` object - Add new `RedisConnectionPoolError` type - Add tests for new types Results: Users will have access to a pooled Redis client.
5dbd716a