46 TypeOpsMap
A PersistStore has a single TypeOpsMap recorded in the RootPersistStoreObject.
A TypeOpsMap is a bijective persistent map between an integer TypeOpsId and a
ReflectionByteCodeValue.
(persistent
bijection)
TypeOpsId <---> ReflectionByteCodeValue
It also caches a mapping from TypeOpsId to const TypeOps*.
lazy binding
(cached)
TypeOpsId ---> const TypeOps*
This is possible under the assumption that each ReflectionByteCodeValue recorded in the
TypeOpsMap is also registered in the transient TypeOpsRegistry
singleton in the cxObject library.
TypeOps tends to be registered in the transient TypeOpsRegistrty
with calls to
bool RegisterTypeOps(const ReflectionByteCodeValue& rbcv, const TypeOps* t)
as application libraries are loaded. Therefore the TypeOpsMap cannot assume calls to
const TypeOps* FindRegisteredTypeOps(const ReflectionByteCodeValue& rbcv)
can be made eagerly - i.e. at the time the TypeOpsMap is read from disk.
Instead calls to FindRegisteredTypeOps are made lazily.
Purpose
Some persistent objects need to serialise some kind of type identifier. For example, the leaf
nodes of a dynamically typed B+Tree first deserialise type information that identifies both the key and
mapped value types, before deserialising an array of (key,mapped value) pairs.
The latter can be performed efficiently using a TypeOps.
Indeed what is needed is a space/time efficient mechanism to serialise some kind of type
identifier that can be mapped to a const TypeOps*.
One approach is to serialise a ReflectionByteCodeValue and use the transient TypeOpsRegistry
implemented in the cxObject library.
However for better efficiency we introduce a new kind of persistent type identifier:
typedef ssize_t TypeOpsId;
This can be serialised as a variable length integer, so is very space efficient on disk. Futhermore,
it can serve as an index in an array, to support very CPU efficient mapping to a const TypeOps*.
API usage
1. B+Tree leaf node deserialisesTypeOpsId, then calls method
std::pair<const ReflectionByteCodeValue*, const TypeOps*> GetTypeOps(TypeOpsId tid);
in order to bind to the const TypeOps*, allowing it to deserialise the (key,value) pairs
This method can be backed up by a corresponding global function which access TLS in order to bind to the TypeOpsMap.
2. $new B+Tree root node for the first time. Root node has two members of type TypeOpsId to record the types of the key and mapped value. These must be initialised just after calling $new.It is assumed the TypeOps for the ReflectionByteCode is registered when the DLLs are loaded. E.g.
$type+ int32[3];
This should allow for the following functions:
const TypeOps& GetTypeOps<T>()
ReflectionByteCode GetReflectionByteCode<T>();
const TypeOps* FindTypeOps(ReflectionByteCode rbc);
xmap
$new BTree
--> need to initialise TypeOpsId for K,V
--> can call GetReflectionByteCode() and GetTypeOps()
--> use PSpace in TLS to access PersistStore and hence the TypeOpsMap
--> register (ReflectionByteCodeValue,TypeOps) if not already. Map to TypeOpsId
TypeOpsId GetTypeOpsId(const ReflectionByteCodeValue& rbcv, const TypeOps* typeOps, bool& newEntry);
Problem: How do we ensure the TypeOps is always registered in the transient TypeOpsRegistry defined in cxObject.dll?
Proposal: Xcpp provide a special syntax for declaring types that need to be registered with TypeOps. E.g.
$type int32;
This causes RegisterTypeOps() to be called at $init time. What is also needed is access to the generated ReflectionByteCode. We seem to need a name, but that sounds like a $typedef!
$typedef int32 MyInt;
--> GetReflectionByteCode_MyInt();
GetTypeOps_MyInt();
Idea: for a given $typedef we introduce a forward declaration that serves to uniquely tag the typedef.
class _tag_MyInt; // serves as a unique type, which can be used to provide
// information about a typedef.
One TypeOpsMap per PersistStore
The PersistStore provides a single TypeOpsMap that can be shared for heterogeneous purposes (by different PSpaces).
It is better to make the TypeOpsMap global to the PersistStore so a B+Tree can easily be moved between PSpaces.
Thread safety
In order to support independent usage of the TypeOpsMap it is made threadsafe using a mutex
Thread local storage
It is important to be able to access the TypeOpsMap. This is achieved via the PSpace in TLS.
TypeOpsMap.h
Source: Ceda/cxPersistStore/src/TypeOpsMap.h
TypeOpsMap.cpp
Source: Ceda/cxPersistStore/src/TypeOpsMap.cpp