NAME
Ref::Store::PROTOSPEC - Protocol specification for Ref::Store
DESCRIPTION
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
MASTER INDEXES
The Ref::Store
object should provide the following methods, each of which should return a reference to a hash
scalar_lookup
-
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. attr_lookup
-
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). forward
-
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 reverse
-
This is the reverse by-value lookup. Key is stringified reference address. Value is a hash reference known as a
vhash
.The vhash's keys are lookup identifiers, of the same type as the keys of
scalar_lookup
,attr_lookup
andforward
.The values are strong references to key objects.
Whenever a value is added to the store, a
dref
is 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.
LOOKUP OBJECTS
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
kstring()
-
This is a simple scalar string. This should return the lookup's key entry for
scalar_lookup
and the like.This value may change on thread cloning if the lookup object correlates to a user-provided object reference.
link_value($value)
-
This method will do any extra initialization necessary to properly map the lookup to the value, and to possibly add extra
dref
s in the case of encapsulating lookups unlink_value($value)
-
This method will do any deinitialization to dissociate the value from the lookup; this usually means deleting added
drefs
. - ukey
-
This should return the actual user key used to create the lookup object. This can be a stub function, in which case
kstring
is used - prefix_len
-
If this lookup is prefixed, this is the length of the prefix. This is used to divide
kstring
output 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.
ithread_predup($table,\%ptr_map, $arg)
-
This is called from the table's
CLONE_SKIP
handler, and is used for the lookup object to perform any form of preparation for cloning.%ptr_map
is a hash whose data is persistent and will also be accessible in the soon-to-be-created thread. Keys are freeIf the lookup object is a key,
$arg
will be the value it stores, otherwise it is undefined. ithread_postdup($new_table,\%ptr_map,$arg)
-
This is called from the table's
CLONE
method, after objects have been duplicated.If the lookup object is stored in
scalar_lookup
(i.e. it is a key), then$arg
is the old reference address of the parent table.
ATTRIBUTES
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
get_hash
-
This returns a hash reference known as an
attrhash
.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
drefs
which will delete their reference address mapping from the attrhash when they are destroyed; and this is done manually during thedissoc
,unlink
andpurge
operations.The attribute object itself is stored multiple times as strong references in each of its values'
vhash
es. When the last strong reference is deleted, the attribute
CLEANUP AND DESTROY METHODS
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.