Skip to content

Commit 3973b26

Browse files
committed
database: use custom connection pool
This works around some performance issues with the db-lib connection pool (see racket/db#36).
1 parent 5e392a2 commit 3973b26

File tree

3 files changed

+80
-27
lines changed

3 files changed

+80
-27
lines changed

koyo-doc/scribblings/database.scrbl

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ working with database connections.
2424
@defproc[(make-database-factory [connector (-> connection?)]
2525
[#:log-statements? log-statements? boolean? #f]
2626
[#:max-connections max-connections exact-positive-integer? 16]
27+
[#:connection-idle-ttl connection-idle-ttl (or/c inf.0 exact-positive-integer?) (* 60 1000)]
2728
[#:max-idle-connections max-idle-connections exact-positive-integer? 2]) (-> database?)]{
2829

2930
Returns a function that will create a database component containing a
@@ -36,13 +37,21 @@ working with database connections.
3637
executed from, the name of the procedure that executed the query and
3738
the statement itself.
3839

40+
The @racket[#:connection-idle-ttl] argument controls the maximum
41+
amount of time (in milliseconds) that connections will remain idle
42+
in the pool for. The @racket[#:max-idle-connections] argument is
43+
deprecated and will be removed in a future release.
44+
3945
@history[
4046
#:changed "0.8" @elem{The component no longer forcefully shuts
4147
down its associated custodian when the component is stopped. There
4248
is now a lower bound on @tt{crypto-lib} for version 1.6 to ensure
4349
that shared libraries (eg. for libargon2) correctly get included in
4450
distributions (using @tt{koyo dist} or @tt{raco distribute}).}
4551
#:changed "0.20" @elem{Addded the @racket[#:log-statements?]
52+
argument.}
53+
#:changed "0.45" @elem{Added the @racket[#:connection-idle-ttl]
54+
argument. Deprecated the @racket[#:max-idle-connections]
4655
argument.}]
4756
}
4857

@@ -67,13 +76,12 @@ working with database connections.
6776

6877
Retrieves a database connection from the pool, enters a transaction
6978
with the requested @racket[#:isolation] level and passes the
70-
connection to @racket[proc]. If @racket[proc] completes
71-
successfully, the transaction is committed, otherwise it is rolled
72-
back.
79+
connection to @racket[proc]. If @racket[proc] completes successfully,
80+
the transaction is committed, otherwise it is rolled back.
7381

7482
Nested calls to @racket[call-with-database-transaction] reuse the
75-
same connection and, if the database supports it, create nested
76-
transactions.
83+
same connection and create nested transactions, if supported by the
84+
database.
7785
}
7886

7987
@deftogether[(
@@ -96,9 +104,8 @@ working with database connections.
96104
'read-uncommitted)])]
97105
)]{
98106

99-
These forms are syntactic sugar for calling @racket[call-with-database-connection]
100-
and @racket[call-with-database-transaction], respectively, with an
101-
anonymous thunk.
107+
These forms are syntactic sugar for calling @racket[call-with-database-connection] and
108+
@racket[call-with-database-transaction], respectively, with an anonymous thunk.
102109

103110
For example, the following forms are equivalent:
104111

koyo-lib/info.rkt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#lang info
22

33
(define license 'BSD-3-Clause)
4-
(define version "0.44.4")
4+
(define version "0.45")
55
(define collection 'multi)
66

77
(define deps
@@ -21,6 +21,7 @@
2121
"monocle-lib"
2222
"net-lib"
2323
"raco-invoke"
24+
"resource-pool-lib"
2425
"scribble-text-lib"
2526
"srfi-lite-lib"
2627
"struct-define"

koyo-lib/koyo/database.rkt

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
(require (for-syntax racket/base
44
syntax/parse/pre)
55
component
6+
data/pool
67
db
78
(only-in db/private/generic/interfaces
89
connection<%>
@@ -24,6 +25,7 @@
2425
(->* [(-> connection?)]
2526
[#:log-statements? boolean?
2627
#:max-connections exact-positive-integer?
28+
#:connection-idle-ttl (or/c +inf.0 exact-positive-integer?)
2729
#:max-idle-connections exact-positive-integer?]
2830
(-> database?))]
2931
[call-with-database-connection
@@ -46,32 +48,38 @@
4648
(connection-pool
4749
connector ;; noqa
4850
max-connections ;; noqa
49-
max-idle-connections ;; noqa
51+
connection-idle-ttl ;; noqa
5052
log-statements?)
5153
#:methods gen:component
5254
[(define (component-start db) ;; noqa
53-
(match-define (database _ connector max-conns max-idle-conns _log?)
54-
db)
55+
(match-define (database _ connector max-size idle-ttl _) db)
5556
(define pool
56-
(connection-pool
57-
#:max-connections max-conns
58-
#:max-idle-connections max-idle-conns
59-
connector))
57+
(make-pool
58+
#:max-size max-size
59+
#:idle-ttl idle-ttl
60+
(lambda ()
61+
;; This procedure must not raise an exception. So, on connect failure, return
62+
;; a dummy object whose connected? method re-raises the exception. This makes
63+
;; database-borrow-connection raise at the appropriate time.
64+
(with-handlers ([exn:fail? (λ (e) (new dummy-connection% [p pool] [e e]))])
65+
(connector)))
66+
disconnect))
6067
(struct-copy database db [connection-pool pool]))
6168

6269
(define (component-stop db) ;; noqa
63-
(send (database-connection-pool db) clear-idle)
70+
(pool-close! (database-connection-pool db))
6471
(struct-copy database db [connection-pool #f]))])
6572

6673
(define ((make-database-factory connector
6774
#:log-statements? [log-statements? #f]
6875
#:max-connections [max-connections 16]
69-
#:max-idle-connections [max-idle-connections 2]))
76+
#:connection-idle-ttl [connection-idle-ttl (* 60 1000)]
77+
#:max-idle-connections [_max-idle-connections 2]))
7078
(database
7179
#;connection-pool #f
7280
#;connector connector
7381
#;max-connections max-connections
74-
#;max-idle-connections max-idle-connections
82+
#;connection-idle-ttl connection-idle-ttl
7583
#;log-statements log-statements?))
7684

7785
(define current-database-connection
@@ -90,11 +98,9 @@
9098
(set! conn the-conn)
9199
(set! close void))]
92100
[else
93-
(define the-conn
94-
(connection-pool-lease
95-
(database-connection-pool db)))
101+
(define the-conn (database-borrow-connection db))
96102
(set! conn the-conn)
97-
(set! close (λ () (disconnect the-conn)))])))
103+
(set! close (λ () (database-release-connection db the-conn)))])))
98104
(lambda ()
99105
(with-timing "proc"
100106
(parameterize ([current-database-connection conn])
@@ -114,11 +120,19 @@
114120
(proc conn))))))
115121

116122
(define (database-borrow-connection db)
117-
(connection-pool-lease
118-
(database-connection-pool db)))
123+
(define the-pool
124+
(database-connection-pool db))
125+
(define the-conn
126+
(pool-take! the-pool))
127+
(cond
128+
[(send the-conn connected?)
129+
the-conn]
130+
[else
131+
(pool-abandon! the-pool the-conn)
132+
(database-borrow-connection db)]))
119133

120-
(define (database-release-connection _db conn)
121-
(disconnect conn))
134+
(define (database-release-connection db conn)
135+
(pool-release! (database-connection-pool db) conn))
122136

123137
(define-syntax (with-database-connection stx)
124138
(syntax-parse stx
@@ -140,6 +154,37 @@
140154
(lambda (name)
141155
e ...))]))
142156

157+
(define dummy-connection%
158+
(class* object% (connection<%>)
159+
(init-field p e)
160+
(super-new)
161+
162+
(define-syntax-rule (define-dummies [id arg ...] ...)
163+
(begin
164+
(define/public (id arg ...)
165+
(unless abandoned?
166+
(set! abandoned? #t)
167+
(pool-abandon! p this))
168+
(raise e)) ...))
169+
170+
(define abandoned? #f)
171+
172+
(define-dummies
173+
[connected?]
174+
[get-dbsystem]
175+
[query fsym stmt cursor?]
176+
[prepare fsym stmt close-on-exec?]
177+
[fetch/cursor fsym cursor fetch-size]
178+
[get-base]
179+
[list-tables fsym schema]
180+
[start-transaction fsym isolation option cwt?]
181+
[end-transaction fsym mode cwt?]
182+
[transaction-status fsym]
183+
[free-statement pst need-lock?])
184+
185+
(define/public (disconnect)
186+
(void))))
187+
143188

144189
;; Query Logging ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
145190

0 commit comments

Comments
 (0)