-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LRU cache for curie lookup #61
base: master
Are you sure you want to change the base?
Changes from 4 commits
894aa81
2c51cec
c69be54
ebc671b
8c00a95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
#lang racket | ||
(provide | ||
make-lru | ||
lru-ref | ||
) | ||
(require chk) | ||
|
||
|
||
(define (assert k st) | ||
(if (not k) | ||
(raise (format "assertion failure: ~a" st)) | ||
#f)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dead code. Otherwise, use |
||
|
||
(struct payload (k v)) | ||
|
||
(struct lrun ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does the |
||
(older #:mutable) | ||
payload | ||
(newer #:mutable))) | ||
|
||
(struct lru ( | ||
behind-ref | ||
hash | ||
(lrun-oldest #:mutable) | ||
(lrun-newest #:mutable) | ||
(num-entries #:mutable) | ||
num-entries-max)) | ||
|
||
(define (make-lru behind-ref #:num-entries-max (num-entries-max 1000)) | ||
(lru | ||
behind-ref | ||
(make-hash) | ||
#f | ||
#f | ||
0 | ||
num-entries-max)) | ||
|
||
;;; Add a newest entry to the lru. | ||
(define (lru-put-newest ths payload1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(let* ( | ||
(lrun1 (lru-lrun-newest ths)) | ||
(k (payload-k payload1)) | ||
(lrun0 (lrun lrun1 payload1 #f)) | ||
) | ||
; connect lrun fields | ||
; lrun0.older is already connected | ||
(set-lrun-older! lrun0 lrun1) | ||
(if lrun1 | ||
(set-lrun-newer! lrun1 lrun0) | ||
#f) | ||
gregr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
; connect lru fields | ||
(set-lru-lrun-newest! ths lrun0) | ||
(if (not (lru-lrun-oldest ths)) ; are we brand new? | ||
(set-lru-lrun-oldest! ths lrun0) | ||
#f) | ||
gregr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(set-lru-num-entries! ths (+ (lru-num-entries ths) 1)) | ||
(hash-set! (lru-hash ths) k lrun0))) | ||
|
||
(define (lru-remove ths lrun1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(let* ( | ||
(payload1 (lrun-payload lrun1)) | ||
(k (payload-k payload1)) | ||
(lrun0 (lrun-older lrun1)) | ||
(lrun2 (lrun-newer lrun1)) | ||
) | ||
(if lrun0 | ||
(set-lrun-newer! lrun0 lrun2) | ||
(begin | ||
; we are removing the oldest | ||
(set-lru-lrun-oldest! ths lrun2) | ||
(set-lrun-older! lrun2 #f))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(if lrun2 | ||
(set-lrun-older! lrun2 lrun0) | ||
(begin | ||
; we are removing the newest | ||
(set-lru-lrun-newest! ths lrun0) | ||
(set-lrun-newer! lrun0 #f))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue with |
||
(set-lru-num-entries! ths (- (lru-num-entries ths) 1)) | ||
(hash-remove! (lru-hash ths) k))) | ||
|
||
|
||
;;; If the lru is full, remove the oldest entry. | ||
(define (lru-evict ths) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(if (> (lru-num-entries ths) (lru-num-entries-max ths)) | ||
(let* ((lrun1 (lru-lrun-oldest ths))) | ||
(lru-remove ths lrun1)) | ||
#f)) | ||
gregr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
;;; Make the entry with key k the newest entry. | ||
(define (lru-freshen ths k) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(let* ( | ||
(lrun1 (hash-ref (lru-hash ths) k)) | ||
(payload1 (lrun-payload lrun1)) | ||
) | ||
(lru-remove ths lrun1) | ||
(lru-put-newest ths payload1))) | ||
|
||
|
||
;;; Fetch item from lru cache, or if absent, from ref-behind. | ||
(define (lru-ref ths k) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(match (hash-ref! (lru-hash ths) k #f) | ||
(#f | ||
(let ((v ((lru-behind-ref ths) k))) | ||
(lru-put-newest ths (payload k v)) | ||
(lru-evict ths) | ||
v)) | ||
(lrun | ||
(if (>= (lru-num-entries ths) 2) ; freshen 1 entry is noop | ||
(lru-freshen ths k) | ||
#f) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might make sense to put this short-circuit case into |
||
(payload-v (lrun-payload lrun))))) | ||
|
||
|
||
|
||
(module+ test | ||
(define (make-test-hash n) | ||
(define h (make-hash)) | ||
(for ((i (range n))) | ||
(hash-set! h i (+ i 100))) | ||
h) | ||
|
||
;; do we get a correct value back on a miss? | ||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (define v (lru-ref l 5)) | ||
#:= v 105) | ||
|
||
;; do we get a correct value back on a hit? | ||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (lru-ref l 5) | ||
#:do (define v (lru-ref l 5)) | ||
#:= v 105) | ||
|
||
;; do we initialize properly? | ||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (define v (lru-ref l 5)) | ||
#:t (lru-lrun-newest l) | ||
#:t (lru-lrun-oldest l)) | ||
|
||
;; when the oldest entry becomes the newest entry, is the next eviction correct? | ||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 6) | ||
#:do (lru-ref l 7) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 8) | ||
#:t (not (hash-has-key? (lru-hash l) 6))) | ||
|
||
;; does num-entries grow as expeced? | ||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (lru-ref l 5) | ||
#:= (lru-num-entries l) 1) | ||
|
||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 6) | ||
#:= (lru-num-entries l) 2) | ||
|
||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 6) | ||
#:do (lru-ref l 7) | ||
#:= (lru-num-entries l) 3) | ||
|
||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define l (make-lru (lambda (k) (hash-ref h1 k #f)) #:num-entries-max 3)) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 6) | ||
#:do (lru-ref l 7) | ||
#:do (lru-ref l 8) | ||
#:= (lru-num-entries l) 3) | ||
|
||
;; do we make the expected number of upstream calls? | ||
|
||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define num-calls (box 0)) | ||
#:do (define (incr) (set-box! num-calls (+ 1 (unbox num-calls)))) | ||
#:do (define l (make-lru | ||
(lambda (k) (incr) (hash-ref h1 k #f)) | ||
#:num-entries-max 2)) | ||
#:do (lru-ref l 5) | ||
#:= (unbox num-calls) 1) | ||
|
||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define num-calls (box 0)) | ||
#:do (define (incr) (set-box! num-calls (+ 1 (unbox num-calls)))) | ||
#:do (define l (make-lru | ||
(lambda (k) (incr) (hash-ref h1 k #f)) | ||
#:num-entries-max 2)) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 5) | ||
#:= (unbox num-calls) 1) | ||
|
||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define num-calls (box 0)) | ||
#:do (define (incr) (set-box! num-calls (+ 1 (unbox num-calls)))) | ||
#:do (define l (make-lru | ||
(lambda (k) (incr) (hash-ref h1 k #f)) | ||
#:num-entries-max 2)) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 6) | ||
#:do (lru-ref l 5) | ||
#:= (unbox num-calls) 2) | ||
|
||
(chk | ||
#:do (define h1 (make-test-hash 100)) | ||
#:do (define num-calls (box 0)) | ||
#:do (define (incr) (set-box! num-calls (+ 1 (unbox num-calls)))) | ||
#:do (define l (make-lru | ||
(lambda (k) (incr) (hash-ref h1 k #f)) | ||
#:num-entries-max 2)) | ||
#:do (lru-ref l 5) | ||
#:do (lru-ref l 6) | ||
#:do (lru-ref l 7) | ||
#:do (lru-ref l 5) | ||
#:= (unbox num-calls) 4) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there an issue using the flat form of
apply
?