[clouchdb-cvs] CVS clouchdb/src
peddy
peddy at common-lisp.net
Sat Jan 12 20:44:42 UTC 2008
Update of /project/clouchdb/cvsroot/clouchdb/src
In directory clnet:/tmp/cvs-serv5413
Modified Files:
cache.lisp
Log Message:
Fixed bug in mru cache, added tests
--- /project/clouchdb/cvsroot/clouchdb/src/cache.lisp 2008/01/07 01:23:41 1.1
+++ /project/clouchdb/cvsroot/clouchdb/src/cache.lisp 2008/01/12 20:44:41 1.2
@@ -24,9 +24,13 @@
(in-package :clouchdb)
+;;; This is an implementation of a most recently used cache. It's
+;;; primary data structures are a hashtable and a doubly linked list
+;;; list.
+
(proclaim '(inline cache-size rmcache))
-;; Representation of cached value
+;; Representation of cached value (hash table value)
(defstruct cached key value previous next)
;; The cache data structure
@@ -34,10 +38,8 @@
hashtable head tail
(max-size 300 :type integer))
-(defun new-mru-cache (&key (size 100)
- (rehash-size 100)
- (rehash-threshold 0.9)
- (max-size 100)
+(defun make-mru-cache (&key (size 100) (rehash-size 100)
+ (rehash-threshold 0.9) (max-size 300)
(test #'eql))
"Make a new MRU cache."
(make-cache :hashtable (make-hash-table :size size
@@ -59,7 +61,7 @@
"Return number of elements in cache."
(hash-table-count (cache-hashtable cache)))
-(defun move-to-top (element cache)
+(defun move-to-head (element cache)
"Move specified cache element to top of cache"
(unless (eq (cache-head cache) element)
(remove-element element cache)
@@ -74,9 +76,11 @@
(defun set-cache-top (element cache)
"Set the element at the top of the cache. Used when adding new
element."
+ (setf (cached-previous element) nil)
(let ((head (cache-head cache)))
(cond ((null head)
- (setf (cache-tail cache) element))
+ (setf (cache-tail cache) element)
+ (setf (cached-next element) nil))
(t
(setf (cached-previous head) element)
(setf (cached-next element) head)))
@@ -86,7 +90,7 @@
"Get cached value by key."
(let ((element (gethash key (cache-hashtable cache))))
(when element
- (move-to-top element cache)
+ (move-to-head element cache)
(cached-value element))))
(defun rmcache (element cache)
@@ -100,20 +104,73 @@
recently used element element being removed."
(let ((element (gethash key (cache-hashtable cache))))
(cond ((null element)
- (let ((new-element (make-cached :key key :value value)))
- (setf (gethash key (cache-hashtable cache)) new-element)
- (set-cache-top new-element cache)))
+ (set-cache-top
+ (setf (gethash key (cache-hashtable cache))
+ (make-cached :key key :value value))
+ cache))
(t
- (move-to-top element cache)
+ (move-to-head element cache)
(setf (cached-value element) value)
- (move-to-top element cache)))
+ (move-to-head element cache)))
(when (> (cache-size cache)
(cache-max-size cache))
(rmcache (cache-tail cache) cache))
- cache))
+ value))
(defun remove-cached (key cache)
"Remove specified element from cache"
(let ((element (gethash key (cache-hashtable cache))))
(when element
- (rmcache element cache))))
\ No newline at end of file
+ (rmcache element cache))))
+
+;;
+;; Tests and test helper functions
+;;
+
+(defun cached-keys (cache)
+ "For testing, quick way to view keys in hashtable."
+ (let ((keys))
+ (maphash #'(lambda (k v) (push k keys)) (cache-hashtable cache))
+ keys))
+
+(defun linked-list-length (cache)
+ (labels ((lllen (ll len)
+ (if (null ll)
+ len
+ (lllen (cached-next ll) (1+ len)))))
+ (lllen (cache-head cache) 0)))
+
+(defun list-vals-not-in-hash (cache)
+ "Return items in the mru cache's linked list that are not in the cache."
+ (let ((res))
+ (labels ((lvnic (ll)
+ (when ll
+ (format t "testing: ~s~%" (cached-key ll))
+ (when (null (gethash (cached-key ll) (cache-hashtable cache)))
+ (format t "found uncached: ~s~%" (cached-key ll))
+ (push ll res))
+ (lvnic (cached-next ll)))))
+ (lvnic (cache-head cache)))
+ res))
+
+(defun find-key-in-list (cache key)
+ (labels ((fkil (ll)
+ (cond ((null ll)
+ nil)
+ ((equal (cached-key ll) key)
+ ll)
+ (t (fkil (cached-next ll))))))
+ (fkil (cache-head cache))))
+
+(defun hash-keys-not-in-list (cache)
+ (let ((res))
+ (maphash #'(lambda (k v)
+ (unless (find-key-in-list cache k)
+ (push k res)))
+ (cache-hashtable cache))))
+
+(defun test-cache-consistency (cache)
+ (format t "Cache size: ~S, linked list length: ~S~%"
+ (cache-size cache) (linked-list-length cache))
+ (format t "Keys not in list: ~S~%" (hash-keys-not-in-list cache))
+ (format t "List values not in hash: ~S~%" (list-vals-not-in-hash cache)))
More information about the clouchdb-cvs
mailing list