db: fix finalization problems
A `this%` expression used in a finalization callback implicitly referred to `this`, since it's a dynamic reference to the object's class. As a result, the finalizer for `this` refers to `this`, so `this` never becomes collectable. The problem is fixed by lifting the `this%` out of the `lambda`. Less significantly, the finalizer thread in "prepared.rkt" captured various parameters on creation, including the current namespace. If a prepared statement is bound to a module-level variable, then the finalizer thread refers through the namespace to the prepared statement, so the prepared statement can never be finalized. Setting the current namespace to a fresh empty one while creating the thread avoids that specific problem. (Other parameters could cause similar problems, but solving the namespace one works well enough for now.)
This commit is contained in:
parent
857950a2b2
commit
5a8a0aff02
|
@ -102,18 +102,21 @@
|
||||||
(define will-executor (make-will-executor))
|
(define will-executor (make-will-executor))
|
||||||
|
|
||||||
(define finalizer-thread
|
(define finalizer-thread
|
||||||
(thread/suspend-to-kill
|
;; Set parameters for the new thread to avoid references to the
|
||||||
(lambda ()
|
;; namespace, since prepared statements may be bound to globals, etc.
|
||||||
(let loop ()
|
(parameterize ([current-namespace (make-empty-namespace)])
|
||||||
(with-handlers
|
(thread/suspend-to-kill
|
||||||
([(lambda (e) #t)
|
(lambda ()
|
||||||
(lambda (e)
|
(let loop ()
|
||||||
((error-display-handler)
|
(with-handlers
|
||||||
(cond [(exn? e)
|
([(lambda (e) #t)
|
||||||
(format "prepared statement finalizer thread handled exception:\n~a"
|
(lambda (e)
|
||||||
(exn-message e))]
|
((error-display-handler)
|
||||||
[else
|
(cond [(exn? e)
|
||||||
"prepared statement finalizer thread handled non-exception"])
|
(format "prepared statement finalizer thread handled exception:\n~a"
|
||||||
e))])
|
(exn-message e))]
|
||||||
(will-execute will-executor))
|
[else
|
||||||
(loop)))))
|
"prepared statement finalizer thread handled non-exception"])
|
||||||
|
e))])
|
||||||
|
(will-execute will-executor))
|
||||||
|
(loop))))))
|
||||||
|
|
|
@ -374,16 +374,16 @@
|
||||||
(handle-status* who full-s -db db-spec pst))
|
(handle-status* who full-s -db db-spec pst))
|
||||||
|
|
||||||
;; ----
|
;; ----
|
||||||
|
|
||||||
(super-new)
|
(super-new)
|
||||||
(register-finalizer-and-custodian-shutdown this
|
(register-finalizer-and-custodian-shutdown
|
||||||
(lambda (obj)
|
this
|
||||||
;; Keep a reference to the class to keep all FFI callout objects
|
;; Keep a reference to the class to keep all FFI callout objects
|
||||||
;; (eg, sqlite3_close) used by its methods from being finalized.
|
;; (eg, sqlite3_close) used by its methods from being finalized.
|
||||||
(let ([dont-gc this%])
|
(let ([dont-gc this%])
|
||||||
(send obj disconnect)
|
(lambda (obj)
|
||||||
;; Dummy result to prevent reference from being optimized away
|
(send obj disconnect)
|
||||||
dont-gc)))))
|
;; Dummy result to prevent reference from being optimized away
|
||||||
|
dont-gc)))))
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user