Ref::Store::PROTOSPEC - Protocol specification for Ref::Store
This document is as much for my own sanity as it is for other readers. This describes the protocol used by Ref::Store to map objects to other objects.
Features and code are not necessarily symmetric because of the asymmetric nature of the module and for performance reasons.
This document describes the lower level methods, API, and protocol behavior. For a slightly higher level description, see Ref::Store::Guts
Ref::Store object should provide the following methods, each of which should return a reference to a hash
This maps user key input to a lookup object, and is specifically for one-to-one key lookups. Its keys are user input (in the code, this is often seen as
ukey), and its values are lookup objects. Lookup objects in this index are always weak.
The same as
scalar_lookup, but implemented for attributes. The reason being that it is permissible to use the same object as both a key and an attribute ( but it is not possible to use the same object for multiple keys).
For one-to-one lookups. Its keys are user input keys, like
scalar_lookup, but its values are lookup targets, or 'user values'. The value may be strong or weak, depending on what was specified in the store function
This is the reverse by-value lookup. Key is stringified reference address. Value is a hash reference known as a
The vhash's keys are lookup identifiers, of the same type as the keys of
The values are strong references to key objects.
Whenever a value is added to the store, a
drefis added for its vhash. When the value is destroyed or otherwise removed from the store, its vhash is deleted, and all of its associated lookups are destroyed as well, since there would be no more references to it.
A lookup object represents a lookup type. It is the layer which maps user input keys to actual stored object mappings.
A lookup can represent either a string key (simple lookup), or a user-provided opaque object (encapsulated lookup).
All lookup objects implement the following methods
This is a simple scalar string. This should return the lookup's key entry for
scalar_lookupand the like.
This value may change on thread cloning if the lookup object correlates to a user-provided object reference.
This method will do any extra initialization necessary to properly map the lookup to the value, and to possibly add extra
drefs in the case of encapsulating lookups
This method will do any deinitialization to dissociate the value from the lookup; this usually means deleting added
This should return the actual user key used to create the lookup object. This can be a stub function, in which case
If this lookup is prefixed, this is the length of the prefix. This is used to divide
kstringoutput into user-defined and internal portions.
The following methods are for the handling of thread cloning and object duplication A master hash is provided for all objects to store data needed for proper handling of duplication (for example, old addresses for various hash keys).
The table itself will traverse all the indexes scanning for publicly accessible objects and will store a weak reference to each of those objects keyed under its current (parent thread) reference address.
The table also has an implementation-specific
ithread_store_lookup_info which will store copies of the standard indexes in the master hash.
Lookup objects are free to store any data they wish. The master hash is deleted after
CLONE has returned.
This is called from the table's
CLONE_SKIPhandler, and is used for the lookup object to perform any form of preparation for cloning.
%ptr_mapis a hash whose data is persistent and will also be accessible in the soon-to-be-created thread. Keys are free
If the lookup object is a key,
$argwill be the value it stores, otherwise it is undefined.
This is called from the table's
CLONEmethod, after objects have been duplicated.
If the lookup object is stored in
scalar_lookup(i.e. it is a key), then
$argis the old reference address of the parent table.
Attributes require more complex handling than keys because multiple attributes can exist for the same object (as encapsulated), and multiple values can be stored inside an attribute.
Attributes conform to the lookup specification, and also implement one more method
This returns a hash reference known as an
The attrhash stores each mapped value by its reference address. The values may be strong or weak references, depending on what was specified during storage.
All mapped values have
drefswhich will delete their reference address mapping from the attrhash when they are destroyed; and this is done manually during the
The attribute object itself is stored multiple times as strong references in each of its values'
vhashes. When the last strong reference is deleted, the attribute
While this module is intended to solve the nasty problem of manual cleanup for dependent data, the implementation itself is full of it. This means lots of manual bookkeeping to remember, and many mines to step on if things go wrong.
The general policy is to prefer
drefs over DESTROY methods, if a complex destructor is not needed. If one is needed, however, then the DESTROY method in pure perl has less overhead than going in several layers via svt_free.
For C, a callback is often the best way to go about things as well.
There is a certain aim to maintain a parity of implementation detail between the C and pure perl versions.