perf: cache walked authority suffixes in find-authority
ober
6bdd841c95fe085d49fe288340e3d9f72a7c7b1b
--- a/lib/jerboa-dns/lookup.ss +++ b/lib/jerboa-dns/lookup.ss @@ -59,6 +59,40 @@ ;; ========== Authority Detection ========== + ;; check-authority's result depends only on the walked suffix, so it is + ;; cached to avoid one CDB lookup per label on deep names. The cache is + ;; keyed by the snapshot reader (a fresh one per CDB generation) so a hot + ;; reload starts clean, is bounded to cap memory under diverse query + ;; traffic, and is guarded by a mutex since workers query concurrently. + (def *authority-mutex* (make-mutex)) + (def *authority-reader* #f) + (def *authority-cache* (make-hash-table)) + (def *authority-count* 0) + (def authority-cache-limit 4096) + + (def (with-authority-lock thunk) + (dynamic-wind + (lambda () (mutex-acquire *authority-mutex*)) + thunk + (lambda () (mutex-release *authority-mutex*)))) + + (def (authority-cache-ref cdb-reader key) + (with-authority-lock + (lambda () + (unless (eq? cdb-reader *authority-reader*) + (set! *authority-reader* cdb-reader) + (set! *authority-cache* (make-hash-table)) + (set! *authority-count* 0)) + (hash-ref *authority-cache* key #f)))) + + (def (authority-cache-put! cdb-reader key has-soa? has-ns?) + (with-authority-lock + (lambda () + (when (and (eq? cdb-reader *authority-reader*) + (< *authority-count* authority-cache-limit)) + (hash-put! *authority-cache* key (cons has-soa? has-ns?)) + (set! *authority-count* (+ *authority-count* 1)))))) + (def (find-authority cdb-reader qname) ;; Walk up the domain hierarchy looking for SOA/NS records. ;; Returns (values auth-offset has-soa? has-ns?) or (values #f #f #f) @@ -78,12 +112,19 @@ (def (check-authority cdb-reader qname offset) ;; Check if domain at offset has SOA and/or NS records in CDB (let* ([key (dns-domain-copy qname offset)] - [records (cdb-find-all cdb-reader key 0 (bytevector-length key))] - [has-soa? (any-record-type? records DNS-T-SOA)] - [has-ns? (any-record-type? records DNS-T-NS)]) - (if (or has-soa? has-ns?) - (values offset has-soa? has-ns?) - (values #f #f #f)))) + [cached (authority-cache-ref cdb-reader key)]) + (if cached + (let ([has-soa? (car cached)] [has-ns? (cdr cached)]) + (if (or has-soa? has-ns?) + (values offset has-soa? has-ns?) + (values #f #f #f))) + (let* ([records (cdb-find-all cdb-reader key 0 (bytevector-length key))] + [has-soa? (any-record-type? records DNS-T-SOA)] + [has-ns? (any-record-type? records DNS-T-NS)]) + (authority-cache-put! cdb-reader key has-soa? has-ns?) + (if (or has-soa? has-ns?) + (values offset has-soa? has-ns?) + (values #f #f #f)))))) (def (any-record-type? records rtype) (any (lambda (val) (= (cdb-val-type val) rtype)) records))