Question
Design and implement a thread-safe, lazily initialized connection pool.
You are given an immutable base class Connection (you cannot modify it) that exposes query() and close(). Implement two classes:
-
ConnectionPool
with
__init__(maxConnectionNum)
,
getConnection() -> PooledConnection
, and
close()
.
-
PooledConnection
with
__init__(parent: ConnectionPool, connection: Connection)
,
query()
, and
close()
.
Requirements:
-
Lazy initialization
— do not create any
Connection
in the pool's constructor. Only create a new
Connection
instance when
getConnection()
is actually called.
-
Reuse idle first
— when
getConnection()
is called, hand back an idle (already-created, returned) connection if one exists. Only create a new
Connection
when no idle connection is available
and
the number of active connections is below
maxConnectionNum
.
-
Cap active connections
— the total number of underlying connections (in-use + idle) must never exceed
maxConnectionNum
.
-
Exhaustion behavior
— define and implement what happens when the pool is exhausted (no idle connection and the cap is reached): block with a timeout, then raise an error on timeout (or block indefinitely if no timeout is configured).
-
Return semantics
—
PooledConnection.close()
must
return
the underlying connection to the pool for reuse rather than actually closing it.
ConnectionPool.close()
must close all underlying connections and reject any further operations.
-
PooledConnection.query()
— delegate to the underlying connection's
query()
, while guarding against use after the wrapper has been returned/closed.
-
Concurrency safety
— discuss and implement how to make the pool safe for concurrent callers: which synchronization primitives to use, and how to avoid double-return and connection leaks.
-
Complexity
— describe the core data structures and analyze the time/space complexity of
getConnection()
and
close()
.