I am re-implementing a web-application, partially as a learning exercise to learn nim as well as multi-threaded programming. As part of that learning exercise, I want to implement connection pooling as there is no library or package in nim that I am aware of that implements it for me, while also allowing me to use the ORM of my choosing. The database I am connecting to is sqlite.
As such, I wrote what I think is correct code: I made a global object POOL
of type ConnectionPool
that is merely a sequence of connections to the sqlite datbase and that also has a lock. Every connection has a clearly defined lifetime after which it gets destroyed, and new connections get made if a connection is needed but none is available. You can get a connection by using borrowConnection
, and return it by using recycleConnection
. Both of these procs lock the POOL
object to retrieve a connection or put said connection back.
import ../applicationSettings
import constructor/defaults
import std/[times, locks, db_sqlite]
proc createRawDatabaseConnection(): DbConn =
return open(applicationSettings.database, "", "", "")
type PoolConnection* {.defaults.} = object
connection*: DbConn = createRawDatabaseConnection()
deathTime: DateTime = now() + initTimeInterval(days = 1)
implDefaults(PoolConnection)
type ConnectionPool* = object
connections: seq[PoolConnection]
lock: Lock
var POOL {.global.}: ConnectionPool
proc isEmptyPool(): bool = POOL.connections.len() == 0
proc initConnectionPool*(initialPoolSize: static int) =
POOL.connections = @[]
initLock(POOL.lock)
withLock POOL.lock:
for i in 1..initialPoolSize:
POOL.connections.add(initPoolConnection())
proc borrowConnection*(): PoolConnection {.gcsafe.} =
{.cast(gcsafe).}:
withLock POOL.lock:
if isEmptyPool():
return initPoolConnection()
result = POOL.connections.pop()
proc recycleConnection*(connection: sink PoolConnection) {.gcsafe.} =
if connection.deathTime < now():
return
{.cast(gcsafe).}:
withLock POOL.lock:
POOL.connections.add(connection)
proc destroyConnectionPool*() =
deinitLock(POOL.lock)
Are there any glaring issues with the code above? I think this doesn't copy memory around wildly, but I could be wrong there, so please tell me if I am.