[reports] use gnc:make-split->owner with guardian

Instead of a gnc:split->owner, use gnc:make-split->owner instead which
generates a split->owner function with its own hashtable. This
function (and its hash table) will be garbage collected in due course,
triggering the gncOwnerFreeing of all owners.

This is a better approach than gnc:split->owner which maintains a
single hash table. It could be buggy: a report calls gnc:split->owner
to query a split, fails to reset its hashtable via #f; the split's
owner is assigned or modified, and the next call to gnc:split->owner
will return the incorrect cached owner.
This commit is contained in:
Christopher Lam
2023-02-13 23:04:26 +08:00
parent 2b32382c78
commit 4953cf94fa
3 changed files with 48 additions and 20 deletions

View File

@@ -32,6 +32,7 @@
(export gnc:owner-get-owner-id)
(export gnc:owner-from-split)
(export gnc:split->owner)
(export gnc:make-split->owner)
(define (gnc:owner-get-address owner)
(let ((type (gncOwnerGetType owner)))
@@ -114,7 +115,7 @@
(define (gnc:owner-from-split split result-owner)
(define (notnull x) (and (not (null? x)) x))
(issue-deprecation-warning
"gnc:owner-from-split is deprecated in 4.x. use gnc:split->owner instead.")
"gnc:owner-from-split is deprecated in 4.x. use gnc:make-split->owner instead.")
(let* ((trans (xaccSplitGetParent split))
(invoice (notnull (gncInvoiceGetInvoiceFromTxn trans)))
(temp (gncOwnerNew))
@@ -139,6 +140,8 @@
(define gnc:split->owner
(let ((ht (make-hash-table)))
(lambda (split)
(issue-deprecation-warning
"gnc:split->owner is deprecated in 4.x. use gnc:make-split->owner instead.")
(cond
((not split)
(hash-for-each (lambda (k v) (gncOwnerFree v)) ht)
@@ -154,3 +157,33 @@
owner))
(hash-set! ht (gncSplitGetGUID split) owner)
owner))))))
(define owner-guardian (make-guardian))
(define (reclaim-owners)
(let ((owner (owner-guardian)))
(when owner
(gncOwnerFree owner)
(reclaim-owners))))
(add-hook! after-gc-hook reclaim-owners)
;; Create a function which helps find a split's gncOwner. It will
;; allocate and memoize the owners in a hash table because
;; gncOwnerGetOwnerFromLot is slow. When the function is out of scope,
;; and gc is run, the hash table is destroyed and the above hook will
;; run, releasing the owners via gncOwnerFree.
(define (gnc:make-split->owner)
(let ((ht (make-hash-table)))
(lambda (split)
(or (hash-ref ht (gncSplitGetGUID split))
(let ((lot (xaccSplitGetLot split))
(owner (gncOwnerNew)))
(unless (gncOwnerGetOwnerFromLot lot owner)
(gncOwnerCopy (gncOwnerGetEndOwner
(gncInvoiceGetOwner
(gncInvoiceGetInvoiceFromLot lot)))
owner))
(hash-set! ht (gncSplitGetGUID split) owner)
(owner-guardian owner)
owner)))))