-
Notifications
You must be signed in to change notification settings - Fork 6
/
sql-de-lite-cache.scm
122 lines (105 loc) · 3.35 KB
/
sql-de-lite-cache.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
(module sql-de-lite-cache
(make-lru-cache
lru-cache?
lru-cache-size
lru-cache-capacity
lru-cache-add! ; adds a new k,v pair in MRU position
lru-cache-remove! ; removes and returns entry by key; deleter not triggered
lru-cache-flush!
lru-cache-walk)
(import scheme)
(cond-expand
(chicken-4 (import chicken))
(else (import (chicken base))))
(define-record-type lru-cache
(%make-lru-cache head tail capacity comparator deleter size)
lru-cache?
(head lru-cache-head set-lru-cache-head!)
(tail lru-cache-tail set-lru-cache-tail!)
(capacity lru-cache-capacity)
(comparator lru-cache-comparator)
(deleter lru-cache-deleter)
(size lru-cache-size set-lru-cache-size!))
(define (make-lru-cache capacity comparator #!optional deleter)
(%make-lru-cache #f #f capacity comparator deleter 0))
(define-record-type lru-entry
(make-lru-entry prev next key value)
lru-entry?
(prev lru-entry-prev set-lru-entry-prev!)
(next lru-entry-next set-lru-entry-next!)
(key lru-entry-key)
(value lru-entry-value))
(define-syntax while
(syntax-rules ()
((while test body ...)
(let loop ()
(if test
(begin body ...
(loop)))))))
(define (lru-cache-shrink! c)
(let ((delete (lru-cache-deleter c)))
(while (> (lru-cache-size c)
(lru-cache-capacity c))
(let ((L (lru-cache-dequeue! c)))
(when delete
(delete (car L) (cdr L)))))))
(define (lru-cache-enqueue! c k v)
(let ((h (lru-cache-head c)))
(if h
(let ((e (make-lru-entry #f h k v)))
(set-lru-entry-prev! h e)
(set-lru-cache-head! c e))
(let ((e (make-lru-entry #f #f k v)))
(set-lru-cache-head! c e)
(set-lru-cache-tail! c e)))
(set-lru-cache-size! c (+ (lru-cache-size c) 1))))
(define (lru-cache-remove-entry! c e)
(let ((p (lru-entry-prev e))
(n (lru-entry-next e)))
(if p
(set-lru-entry-next! p n)
(set-lru-cache-head! c n))
(if n
(set-lru-entry-prev! n p)
(set-lru-cache-tail! c p)))
(set-lru-cache-size! c (- (lru-cache-size c) 1))
e)
(define (lru-cache-find-entry c k)
(do ((e (lru-cache-head c) (lru-entry-next e)))
((or (not e)
((lru-cache-comparator c) k (lru-entry-key e)))
e)))
(define (lru-cache-dequeue! c)
(let ((t (lru-cache-remove-entry! c (lru-cache-tail c))))
(cons (lru-entry-key t)
(lru-entry-value t))))
(define (lru-cache-walk c proc)
(let ((h (lru-cache-head c)))
(do ((e h (lru-entry-next e)))
((not e))
(proc (lru-entry-key e)
(lru-entry-value e)))))
(define (lru-cache-add! c k v)
(cond ((> (lru-cache-capacity c) 0)
(lru-cache-enqueue! c k v)
(lru-cache-shrink! c)
#t)
(else #f)))
;; returns (k . v) pair or #f
(define (lru-cache-remove! c k)
(and-let* ((e (lru-cache-find-entry c k)))
(lru-cache-remove-entry! c e) ; also returns e
(cons (lru-entry-key e)
(lru-entry-value e))))
;; flushes in lru->mru order, but flush order not defined
(define (lru-cache-flush! c)
(let ((delete (lru-cache-deleter c)))
(do ((e (lru-cache-tail c) (lru-entry-prev e)))
((not e))
(when delete
(delete (lru-entry-key e)
(lru-entry-value e)))))
(set-lru-cache-size! c 0)
(set-lru-cache-head! c #f)
(set-lru-cache-tail! c #f))
)