Next: , Previous: The Store Controller, Up: Tutorial

2.14 Repository Migration

This version of Elephant supports migration between store controllers of any backend type.

The tests migrate1 - migrate5 are demonstrations of this capability.

There is a single generic function migrate that is used to copy different object types to a target repository. It is assumed that typically migrate will be called on two repositories and all live objects (those reachable in the root or class-root) will be copied to the target repository via recursive calls to migrate for specific objects.

When persistent instances are copied, their internal pointer will be updated to point to the new repository so after migration the lisp image should be merely updated to refer to the target repository in the *store-controller* variable or whatever variable the application is using to store the primary controller instance.

There are some limitations to the current migration implementation:

  1. Migrate currently will not handle circular list objects
  2. Migrate does not support arrays with nested persistent objects
  3. Indexed classes only have their class index copied if you use the top level migration. Objects will be copied without slot data if you try to migrate an object outside of a store-to-store migration due to the class object belonging to one store or another
  4. Migrate assumes that after migration, indexed classes belong to the target store.
  5. In general, migration is a one-time activity and afterwards (or after a validation test) the source store should be closed. Any failures in migration should then be easy to catch.
  6. Each call to migration will be good about keeping track of already copied objects to avoid duplication. Duplication shouldn't screw up the semantics, just add storage overhead but is to be avoided. However this information is not saved between calls and there's no other way to do comparisons between objects across stores (different oid namespaces) so user beware of the pitfalls of partial migrations...
  7. Migrate keeps a memory-resident hash of all objects; this means you cannot currently migrate a store that has more data than your main memory. (This could be fixed by keeping the oid table in the target store and deleting it on completion)
  8. Migration does not maintain OID equivalence so any datastructures which index into those will have to have a way to reconstruct themselves (better to keep the object references themselves rather than oids in general) but they can overload the migrate method to accomplish this cleanly

Users can customize migration if they create unusual datastructures that are not automatically supported by the existing migrate methods. For example, a datastructure that stores only object OIDs instead of serialized object references will need to overload migrate to ensure that all referenced objects are in fact copied (otherwise the OIDs will just be treated as fixnums potentially leaving dangling references.

To customize migration overload a version of migrate to specialize on your specific persistent class type.

     (defmethod migrate ((dst store-controller) (src my-class)))

In the body of this method you can call (call-next-method) to get a destination repository object with all the slots copied over to the target repository which you can then overwrite. To avoid the default persistent slot copying, bind the dynamic variable *inhibit-slot-writes* in your user method using () ...) a convenience macro.