Next: , Up: Design Patterns


6.2 File System Replacement

One of the more annoying time-wasting activities in programming is saving and restoring data from disk. Data in configuration files, static data such as graphics and other formats take time and attention away from solving the main problem and are additional sources of bugs. Because Elephant's serializer supports most lisp types, Elephant can greatly simplify ease these concerns and allow you to work directly with your natural in-memory representations with almost no work to encode/decode formats or manage files in the file system1.

The simplest way to accomplish this is to simply open a store controller and initialize a key-value pair in the root btree as a instead of a filename and file data in some system directory. Like the initialization process described for standard objects, you can hide some of the details like this:

     (defvar *resources* (make-hash-table))
     
     (defun get-resource (name)
       (multiple-value-bind (value foundp) (gethash name *resources*)
         (if foundp
             value
             (multiple-value-bind (value foundp) (get-from-root name)
                (if foundp
                    value
                    (error "Resource named ~A was not initialized" name))))))
     
     (defun set-resource (value name)
       (add-to-root name value)
       (setf (gethash name *resources*) value))
     
     (defsetf get-resource set-resource)

Another simple metaphor is to use Elephant btrees as persistent hash tables that persist key-value pairs for you. We'll wrap the Elephant btree in a simple class to provide a little conceptual isolation.

     (defclass phash ()
       ((btree :accessor phash-btree :initarg :btree
               :initform (make-btree))))
     
     (defun make-persistent-hash (name)
       (let ((btree (get-from-root name)))
         (if btree
             (make-instance 'phash :btree btree)
             (let ((phash (make-instance 'phash)))
                (add-to-root name (phash-btree phash))
                phash))))
     
     (defun getphash (key phash)
       (get-value key (phash-btree phash)))
     
     (defun setphash (value key phash)
       (setf (get-value key (phash-btree phash)) value))
     
     (defsetf getphash setphash)

Of course to make a proper abstraction we'd want to provide some conditions that allowed restarts that initialized values or allowed users to update the hash in the background and continue computation.


Footnotes

[1] Example provided by Ian Eslick, April 2007