|(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.
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.
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*.
(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?*)
executes thunk, obtains result r;
retrieves the values of *current-cache-keys*;
saves the keys and r to cache-path;
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>
Note that byte strings written using s-exp->fasl cannot be read by code running a different version of Racket.
→ (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")
→ (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.
(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.
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.