Hone logo
Hone
Problems

Implementing a Database Connection Pool in Go

Database connection pools are crucial for efficient application performance, especially in high-traffic scenarios. This challenge asks you to implement a basic database connection pool in Go, allowing applications to reuse database connections instead of constantly establishing new ones, significantly reducing overhead and improving response times. A well-implemented pool will manage a set of connections, providing them on demand and returning them to the pool when finished.

Problem Description

You are tasked with creating a Pool type that manages a pool of database connections. The Pool should provide the following functionalities:

  • Initialization: The Pool should be initialized with a connection function (e.g., database.Connect()), a maximum pool size, and a connection timeout. The connection function is responsible for establishing a new database connection.
  • Acquire Connection: A method Acquire() should retrieve a connection from the pool. If no connections are available and the pool is not full, it should wait for a connection to become available (up to the connection timeout). If the timeout expires, it should return an error.
  • Release Connection: A method Release(conn) should return a connection to the pool, making it available for reuse.
  • Close: A method Close() should gracefully shut down the pool, closing all active connections.

The pool should handle concurrency safely using appropriate synchronization mechanisms (e.g., channels, mutexes) to prevent race conditions. Connections should be closed when the pool is closed.

Examples

Example 1:

Input:
connectionFunc: func() (database.DB, error) { return database.Connect() },
maxPoolSize: 3,
connectionTimeout: 1 * time.Second

Output: A Pool instance ready to acquire and release database connections.

Explanation: This initializes a pool that can hold up to 3 connections. The connectionFunc will be used to create new connections when needed.

Example 2:

Input:
pool: (initialized pool from Example 1)

Output: conn, err := pool.Acquire() where conn is a database.DB and err is nil if a connection was acquired successfully, or an error if the timeout expired.

Explanation: This demonstrates acquiring a connection from the pool. If connections are available, one will be returned immediately. Otherwise, the program will wait up to the connection timeout.

Example 3:

Input:
pool: (initialized pool from Example 1)
conn: (a database.DB connection)

Output: pool.Release(conn) - No return value.

Explanation: This demonstrates releasing a connection back to the pool for reuse.

Constraints

  • maxPoolSize must be a positive integer.
  • connectionTimeout must be a positive duration.
  • The connectionFunc must return a database.DB (interface) and an error.
  • The pool should handle concurrent Acquire() and Release() calls safely.
  • The Close() method should close all connections in the pool.
  • Assume database.DB is an interface with a Close() method.
  • The pool should not leak connections.

Notes

  • Consider using a buffered channel to manage the connections in the pool.
  • Implement a timeout mechanism for acquiring connections.
  • Proper error handling is essential.
  • Think about how to handle errors returned by the connectionFunc.
  • The database.DB interface is assumed to exist. You don't need to implement it, just assume it has a Close() method. For testing purposes, you can create a mock database.DB implementation.
  • Focus on the core logic of the connection pool. Error handling can be simplified for brevity, but should be present.
  • Consider using sync.Mutex to protect shared resources within the pool.
  • The Acquire function should return the connection and an error if the timeout is reached.
  • The Release function should not return anything.
  • The Close function should close all connections and prevent further acquisitions.
Loading editor...
go