Multiple stores in Elephant

For simplicity, it’s good to have only one store in Elephant.
Often however this doesn’t scale well with reality :)

For example, in the browser game I am developing, we have separate “worlds” with separate sets of players.
The items are to be administrated centrally, though, so the natural solution is having one shared store for them.

The easiest way to do this is having two store controllers. An alternative would be rolling your own solution using separate indexed B trees (I went down that road first), but handling things at the store controller level lets us use all the existing indexed class infrastructure.

Now there’s good and bad news: the good news is that it’s possible to do this. The bad news is that the interface is a bit clumsy. Most functions do not accept a store controller argument but refer directly to the global *store-controller*. Yuk.

So what we need to do is find the set of functions that need to refer to the alternative store controller and let them have a nice interface. For the item example (consider all Elephant symbols to be imported, I just added the package prefix to the functions for clarity):

(defun get-items-by-type (type)
  (let ((*store-controller* *item-sc*))
    (elephant:get-instances-by-class type)))

Try exceptionally hard to draw clear lines between the different store controllers, or you’ll be in imperative hell before you can say “Practical Extraction and Report Language”. If you’re nesting those functions, use dynamic variables (also known as “globals done right”):

(defun first-thing ()
  (declare (special *store-controller*)) ; refer to the dynamic binding
  (get-instances-by-value 'item 'price 5))
 
(defun do-complex-things ()
  (let ((*store-controller* *item-sc*))
    (declare (special *store-controller*)) ; provide a dynamic binding
    (first-thing)))

EDIT: As instructive as this is, Mikael Jansson has pointed out that we don’t need the whole DECLARE hanky-panky since DEFVAR/DEFPARAMETER automatically establish variables as dynamic. Seems to be another case of the “do what I mean” support in Common Lisp.

Another thing to take care of is opening and closing alternative stores.

Self-explanatory, but not that easy to find out if you’re just starting out with Elephant:

;;; init
(defvar *item-sc* nil) ; newbies note that DEFVAR only assigns to non-existing variables
(when (null *item-sc*)
  (setf *item-sc* (elephant:open-store *item-store*)) ; *item-store* defined elsewhere
 
;;; shutdown
(elephant:close-store *item-sc*)

If you’re interested in more Elephant posts, drop me a short comment.

Comments

  1. Alec
    February 7th, 2008 | 4:31 pm

    I am interested in more Elephant posts.

  2. February 7th, 2008 | 5:37 pm

    This post shows how to manage special variables with unruly scope by hiding them behind an interface that guarantees good behavior, and by declaring special local variables. It subtly makes the case that special variables really are “globals done right.”

    I’m interested in Elephant too. Thanks for the post!

  3. Thom
    February 7th, 2008 | 5:46 pm

    Honestly, I read that as, “If you’re interested in more Elephant droppings, post a short comment.”

    Anyway, yes, I am too am interested in more Elephant posts.

  4. February 7th, 2008 | 10:53 pm

    Are you /really/ sure you need (declare (special *store-controller*))?

    If *store-controller* is defined using either DEFVAR or DEFPARAMETER, you don’t need to declare it special, rebinding it with LET will suffice.

  5. February 8th, 2008 | 10:04 am

    I haven’t looked it up in the CLHS (“Caveat emptor”, as Kent Pitman likes to say). Let’s do it now:

    “defparameter and defvar establish name as a dynamic variable.”

    Yes, you’re right :)

    Thanks, Mikael; I’m going to change the post to reflect that.

  6. February 8th, 2008 | 5:30 pm

    Hi,

    – quote –
    (defvar *item-sc* nil) ; newbies note that DEFVAR only assigns to non-existing variables
    (when (null *item-sc*)
    (setf *item-sc* (elephant:open-store *item-store*)) ; *item-store* defined elsewhere
    – /quote –

    If your comment to newbies is true, how about

    (defvar *item-sc* (elephant:open-store *item-store*)))

    then? :)

  7. February 8th, 2008 | 5:51 pm

    Problematic if you’re developing and closing the store somewhere in between. Who will open it again?

Leave a reply