You can enable/disable class indexing for an entire class. When you disable
indexing all references to instances of that class are lost. If you re-enable
class indexing only newly created classes will be stored in the class index.
You can manually restore them by using
find-class-index to get the
clas index BTree if you have an alternate in-memory index.
You can add/remove a secondary index for a slot. So long as the class index remains, this can be done multiple times without losing any data.
There is also a facility for defining 'derived slots'. These can be non-slot parameters which are a function of the class's persistent slot values. For example you can use an index to keep an alternate representation available for fast indexing. If an object has an x,y coordinate, you could define a derived index for r,theta which stored references in polar coordinates. These would be ordered so you could iterate over a class-index to get objects in order of increasing radius from the origin or over a range of theta.
Beware, however, that derived indices have to compute their result every time you update any persistent instance's slot. This is because there is no way to know which persistent slots the derived index value(s) depends on. Thus there is a fairly significant computational cost to objects with frequent updates having derived indices. The storage cost, however, may be less as all that is added is the index value and an OID reference into the class index. To add a slot value you add a serialized OID+class-ref+slotname to index value which can be much larger if you use long slotnames and package names and unicode.
Thus, the question of if and how a given class should be indexed is very flexible and dynamic, and does not need to be determined at the beginning of your development. This represents the ability to “late bind” the decision of what to index.
In general, there is always a tradeoff: an indexed slot increases storage associated with that slot and slows down write operations. Reads however remain as fast as for unindexed persistent slots. The Elephant system makes it simple to choose where and when one wants to utilize this tradeoff.
Finally, that file src/elephant/classindex-utils.lisp documents tools for handling class redefinitions and the policy that should be used for synchronizing the classes with the database. This process is somewhat user customizable; documentation for this exists in the source file referenced above.
Sometimes you may change a defclass form and then connect to a
database with instances that do not match the current defclass
definition. Because of the defclass behavior above, there is no need
to detect this case as the behavior will be as if all instances were
non-resident at redefinition time. However, this is an issue for
indexed classes as the cost of indexing is high. There is a
synchronization policy which updates either the class or the online
class indexing mechanism at the time you try to perform an index
operation (i.e. when
find-class-index is called).
A policy is selected by setting the value of
*default-indexed-class-synch-policy* with the appropriate
class-indexedp-by-nameare isomorphic to the existing indices in the db.
Derived slots can be problematic as they may depend on slot values that no longer exist in the changed defclass. This will result in an error, so for now you will have to manage any mismatches such as this yourself.
Note: release 0.9.1 should fix both mismatches and performance issues related to derived indices by allowing the user to provide hints as to which slot values the index depends. This will allow the system to only update when the appropriate slots change and to delete or inhibit derived indicies when slots are deleted. We will also improve error handling for this case, so you can delete the derived index and continue performing the write to a persistent object that flagged the error.