with-cache
(require with-cache) | package: with-cache |
Simple, filesystem-based caching. Wrap your large computations in a thunk and let with-cache deal with saving and retrieving the result.
(define fish (with-cache (cachefile "stdfish.rktd") (λ () (standard-fish 100 50))))
By default, any cache built by an older version of with-cache is invalid. Set *current-cache-keys* to override this default.
Here’s a diagram of what’s happening in with-cache:
The dollar sign on the left represents a value that is expensive to compute.
The box in the left-middle is a serialized version of the expensive value.
The yellow box in the right-middle is the serialized data paired with a (yellow) label.
The file symbol on the right represents a location on the filesystem.
#:write and #:read are optional arguments to with-cache. They default to serialize and deserialize.
add-keys is a hidden function that adds the value of *current-cache-keys* to a cached value.
keys-equal? compares the keys in a cache file to the now-current value of *current-cache-keys*.
write-data and read-data are s-exp->fasl and fasl->s-exp when the parameter *with-cache-fasl?* is #t. Otherwise, these functions are write and read.
procedure
(with-cache cache-path thunk [ #:read read-proc #:write write-proc #:use-cache? use-cache? #:fasl? fasl? #:keys keys #:keys-equal? keys-equal?]) → any cache-path : path-string? thunk : (-> any) read-proc : (-> any/c any) = deserialize write-proc : (-> any/c any) = serialize use-cache? : boolean? = (*use-cache?*) fasl? : boolean? = (*with-cache-fasl?*)
keys : (or/c #f (listof (or/c parameter? (-> any/c)))) = (*current-cache-keys*) keys-equal? : equivalence/c = (*keys-equal?*)
reads the contents of cache-path (using s-exp->fasl if *with-cache-fasl?* is #t and read otherwise);
checks whether the result contains keys equal to *current-cache-keys*, where "equal" is determined by keys-equal?;
if so, removes the keys and deserializes a value.
executes thunk, obtains result r;
retrieves the values of *current-cache-keys*;
saves the keys and r to cache-path;
returns r
Uses call-with-file-lock/timeout to protect concurrent reads and writes to the same cache-path. If a thread fails to lock cache-path, with-cache throws an exception (exn:fail:filesystem) giving the location of the problematic lock file. All lock files are generated by make-lock-file-name and stored in (find-system-path 'temp-dir).
Diagnostic information is logged under the with-cache topic. To see logging information, use either:
racket -W with-cache <file.rkt>
or, if you are not invoking racket directly:
PLTSTDERR="error info@with-cache" <CMD>
1 Parameters
parameter
(*use-cache?*) → boolean?
(*use-cache?* use-cache?) → void? use-cache? : boolean?
= #t
parameter
(*with-cache-fasl?* fasl?) → void? fasl? : boolean?
= #t
Note that byte strings written using s-exp->fasl cannot be read by code running a different version of Racket.
parameter
→ (and/c path-string? directory-exists?) (*current-cache-directory* cache-dir) → void? cache-dir : (and/c path-string? directory-exists?)
= (build-path (current-directory) "compiled" "with-cache")
parameter
→ (or/c #f (listof (or/c parameter? (-> any/c)))) (*current-cache-keys* params) → void? params : (or/c #f (listof (or/c parameter? (-> any/c))))
= (list get-with-cache-version)
Before writing a cache file, with-cache gets the value of *current-cache-keys* (by taking the value of the parameters and forcing the thunks) and writes the result to the file. When reading a cache file, with-cache gets the current value of *current-cache-keys* and compares this value to the value written in the cache file. If the current keys are NOT equal to the old keys (equal in the sense of *keys-equal?*), then the cache is invalid.
For example, (*current-cache-keys* (list current-seconds)) causes with-cache to ignore cachefiles written more than 1 second ago.
(define (fresh-fish) (parameterize ([*current-cache-keys* (list current-seconds)]) (with-cache (cachefile "stdfish.rktd") (λ () (standard-fish 100 50))))) (fresh-fish) ; Writes to "compiled/with-cache/stdfish.rktd" (fresh-fish) ; Reads from "compiled/with-cache/stdfish.rktd" (sleep 1) (fresh-fish) ; Writes to "compiled/with-cache/stdfish.rktd"
By default, the only key is a thunk that retrieves the installed version of the with-cache package.
parameter
(*keys-equal?* =?) → void? =? : equivalence/c
= equal?
A cache is invalid if (=? old-keys current-keys) returns #false, where current-keys is the current value of *current-cache-keys*.
(=? k k) returns a true value for all k;
(=? k1 k2) returns the same value as (=? k2 k1); and
(and (=? k1 k2) (=? k2 k3)) implies (=? k1 k3) is true.
The contract equivalence/c does not enforce these laws, but it might in the future.
2 Utilities
procedure
(cachefile filename) → parent-directory-exists?
filename : path-string?
procedure
x : any/c
procedure
(equivalence/c x) → boolean?
x : any/c
procedure
value