This document desribes the Speedo software. The target of this document is
the developers and contributors of Speedo itself. It is not required to read
this document for using Speedo.
Speedo is in fact a assembly of several existing products solving a
part of the problem. Then to understand the Speedo architecture,
knownledges on the following topics are required:
Warning: This document must be read in the speedo distribution
(output/dist/doc), because most images and links are based on this
hypothesis.
A persistent instance
This chapter explains how the persistent instance are organized in order to
interact with the Speedo runtime. The first chapter describes the main
principles and concepts. The second chapter is dedicated to the persistent
class written by the user, whereas the thrird chapter explains how speedo
supports the generic class such as Collection, Set, List, Map, ...
The main principle
This chapter explains the main principle for the persistent instances.
The HomeItf concept
The HomeItf describes common fields and methods for a
persistent class.There is only one HomeItf instance per persistent
class.
It extends the JORM PClassMapping interface: the PClassMapping
interface defines the behaviour of objects that contain all information
required to map a JORM class.
The PersistentObjectItf concept
The persistent instance is enhanced in order to become a
PersistentObjectItf implementation. A PersistentObjectItf instance supports the
PBinding interface (see JORM
concepts), the CacheEntry interface (see Perseus concepts). , and the
javax.jdo.PersistenceCapable concept.
PBinding: The PBinding is in charge of loading and storing
a persistent instance. It provides read(Object, PAccessor) and
write(Object, PAccessor) methods. The PAccessor permits to get/set
value from/into the memory. A PBinding represents the link between a
memory instance and its image on a persistent support. Then this
binding and the persistent object are identified by a PName (Persistent
Name, see JORM concepts).
According to the PBinding status, it can be bound or not to a PName.
CacheEntry: This interface enables to manage persistent
instances into a cache. In case of Speedo, the CacheEntry is also the
persistent instance, and the identifier is the PName (Jorm identifier).
The consequence is that Speedo provides always the same instance for an
identifier. The persistent instance is shared between transactions but
according to the transaction policy, the StateItf could not be
shared.
During the enhancement process persistent fields declared in the
persistent class are moved to the StateItf generated class.
The StateItf concept
A
StateItf is a java instance containing the persistent fields.
Externalizing the state from the persistent class
enables to choose easily the concurrency policy:
Pessimistic: one state is shared by all
transactions/working sets,
Optimistic (Copy on write): one by writer and one state
shared for readers.
...
The StateItf is a JORM
PAccessor. Then It implements the paGet/paSet methods to get the
value to write them, or to set the value during loading.
The StateItf is also a
State containingg the status (dirty, new, clean, deleted, ...) of
the persistent instance in the context (working set /transaction).
Overall organisation of a
persistence instance
In memory there is only one HomeItf per persistent class.
And there is only one persistent instance (PersistentObjectItf) per persitent
object with a particular identifier, but there is one or several states
(StateItf). A StateItf can be shared or not according to
the concurrency policy.
If the instance of the persistent class is not persistent (normal java
instance), the PersistentObjectItf uses a unique StateItf instance
referenced through the field 'speedoRefState'.
If the java instance is persistent, the PersistentObjectItf knows directly
which StateItf to use. It depends on the context (working set/
transaction). Each StateItf references the PersistentObjectItf. For some
transactionnal policy (optimistic for instance) the speedoRefState
field is used to maintain in memory the latest valid state of a
persistent instance. It is a data cache.
The user user persistent class
T
The Generic persistent classes (Collection, Set,
Map
Speedo runtime
This chapter describes the Speedo runtime. It proposes an overview of the
speedo architecture following by a description of the role, the behavior and
the implementation of some important components.
The overall speedo architecture
This diagram shows the big blocks of the Speedo runtime. The PMF is a set
of component managing the PM. Both set of component are describes in the next
chapter. The second important component is the TPM which is core of
speedo managing concurrency and caching. the TPM component is provided by
Perseus framework and does not depends on Speedo. The MIM component is a
personalization of the TPM component for Speedo. The Mapper component is in
charge of the storage of persistent class. Finally the query manager is a set
of component managing the query aspect and in particular the translation from
the Speedo to MEDOR.
The PM component
The POManager component is a primitive component exporting the
POManagerItf
interface. There is a generic and abstract implementation
AbstractPOManager.
This abstract class is subclassed for implementing Speedo personalities:
The POManager is in charge of managing persistent objects. It
permits:
to make persistent non managed java instance (of enhanced classes),
to delete persistent objects,
to detach persistent objects,
to attach (ie merge) detached instance,
to fetch persistent object from the identifier,
to find persistent objects using a query.
The POManager implementation is mainly based on the use of the TPM
component (TransactionPersistenceManager). This perseus component manages
several aspects of the persistence such as the concurrency control, the
data caching or the data loading.
The POManager is higly linked to a working set. The working set contains all
persistent objects used by a process of the application. A typical working set
is a transaction. This working set is a component in the speedo architecture.
As the POManager, the working set concept has a generic and abtract
implementation (
AbstractTransaction
) with subclasses for each personality:
The first one is
JDOTransaction.
This subclass implements all methods of the javax.jdo.Transaction
interface for implementing the JDO personality
For supporting the query feature, a POManager uses a
QueryManager responsible of the
CompiledQuery allocation. In Speedo architecture the query definition
is separated to the query implementation. The POManager is in charge of the
query filling, whereas the compiled query (provided by the query manager)
takes this defintion and executes the really the query. As each persistence
specification has its own definition of a query, the specialized POManagers
have their own definition and their own compiled query.
The POManager uses a
JormFactory to fetch PClassMapping instances and to perform the
initialization of the JORM persistent classes.
The POManager uses a PNameCoder
(org.objectweb.jorm.naming.api.PNameCoder) in order to convert identifiers of
persistent classes. The translation is bidirectional between internal
identifier (org.objectweb.jorm.naming.api.PName) and user identifier (String,
object id class, ..).
The PMF component
The set of components behind PMF box
The POManagerFactory component:
The POManagerFactory is a factory of POManager. This
primitive component exports the
POManagerFactoryItf interface, enabling to manage the POManager
allocations. Due to a high cost of POManager instances allocation, the
unsused POManagers are pooled. For this reason, the POManagerFactory uses a Pool
(org.objectweb.perseus.pool.api.Pool) managing POManager instances. The
POManagerFactory manages also the attachement of POManager
to the current thread through the POManagerSwitch component
(see below).
The POManagerInstanciator component:
The
POManagerInstanciator is a primitive component in charge of the
allocation of the POManager and the Transaction components. It exports the
PoolMatchFactory interface in order to be used by a Pool as Factory of pool resource.
The pool resource is the POManager instance.
It uses a ConnectionHolderFactory for allocating ConnectionHolder to
the created Transaction components.
The POManagerSwitch component:
The
POManagerSwitchImpl is an implementation of the
POManagerSwitchItf based on the use of a ThreadLocal
field, for binding POManager instances to threads. The ThreadLocal
field contains an instance of POManager of an ArrayList of
POManager. A POManagerSwitch is a fractal component whithout dependency.
The TPM (TransactionalPersistenceManager) component
The perseus library provides the TPM composite component. Perseus is more
than a simple library, it proposes a framework for structuring persistence
container. The framework defines the following component:
The Cache responsible of maintaining in memory the persistent data
The concurrency manager responsible of the implementation of the
concurrency policy such as pessimistic, pessimistic or delegated to the
database.
The dependency graph permitting to detect dead locks when the
concurrency policy is based on locking
The storage manager responsible of the data loading and the
identifier allocation,
The TPM responsible of the orchestration components defined by the
framework. It is the core component of the framework. Its interface is
directly used by the Perseus user (Speedo).
In addition to this component, the framework defines APIs in order to
specialize the framework for a given specification. In particular, the framwork
defines the following interfaces:
MemoryInstanceManager permetting to allocate new persistent object,
StateManager permetting to manage the state of the persistent objects
(allocation, status, ...).
These interfaces are of course implemented in Speedo for specialising
Perseus to JDO and EJB.
Below the figure shows the overall architecture of the perseus framework.
The TPM
component
The MIM component
The MIM components is the component responsible of the specialization
of the Perseus framwork for Speedo. Its provides the following
interfaces:
MemoryInstanceManager: allocation of new persistent object,
StateManager: management of the state of the persistent objects
(allocation, status, ...).
CacheEntryFactory: allocation of new persistent object from a
persistent object. The implementation is very simple because in case of
Speedo the persistent object is the cache entry.
The Mapper component including the JormFactory
The mapper component groups two aspect: the naming and the storage. Both
aspects are implemented by JORM.
Below the figure represents the mapper composite component :
The set components around the mapper
The figure show three important component:
The JormStorageManager is the implementation of the
StorageManager perseus concept dedicated to JORM and a bit Speedo,
The JormFactory is in charge of the creation of the JORM
classes around each persistent class (PClassMapping, PBinder,
PNamingContext, ...),
The primitive Mapper component corresponds to the PMapper concept
from JORM,
In case of Speedo used directly a JDBC driver (not via a
javax.sql.DataSource), Speedo is able to pool JDBC connection in order to avoid
physical connection allocation each time a connection is required. For this
the mapper which is also a connection provider can use a Pool component
dedicated to the pooling of connection to the underlying persistence
support.
The NamingManagerFactory component
The NamingManagerFactory component
This small component is in charge of the naming specialization in Speedo.
This component is a factory of
NamingManager. Each NamingManager manages a type of naming. Currently Speedo
provides the following naming manager implementations:
UserIdCompositeNamingManager: identifier based on an object identifier class.
The fields of the Object identifier class are used as identifier value and
corresponds to persistent fields of the persistent class. Generally this
identifier is composite (several field(s)). The value of this identifier
is provided by the application (before the makePersistent of course).
UserIdSingleNamingManager: identifier based on a single persistent field of
the persistent class. The value of this field is provided by the application
(before the makePersistent of course).
LongIdNamingManager: identifier based on a long value generated by Speedo,
using a persistent generator (Speedo structure in database). The long value
is composed of two parts. Some bits are used for the class identifier, and the
rest is used to identify the object instance in the class. This identifier
format supports very well the polymorphism. The null reference is represented
by the -1 value. The long field can be a visible persistent field, otherwise it
is hidden by Speedo/JORM implementation.
OLongIdNamingManager: identifier based on a java.lang.Long value generated
by Speedo, using a persistent generator (Speedo structure in database). The
long value is composed of two parts. Some bits are used for the class
identifier, and the rest is used to identify the object instance in the class.
This identifier format supports very well the polymorphism. The null reference
is represented by the NULL value. The java.lang.Long field can be a visible
persistent field, otherwise it is hidden by Speedo/JORM implementation.
RdbSequenceNamingManager: identifier based on sequence in database (SQL
sequence or simple counter managed by Speedo). This
identifier can be mapped over a persistent field (type must be long or
java.lang.Long). This identifier format does not support polymorphism directly.
You have to specify discriminator(s). But in all case, this naming is not an
efficient choice when there is polymorphism (ex inheritance). Indeed SQL request
to find a corresponding object is more complex. The null reference depends on
the field type: -1 for long field and NULL or java.lang.Long field type.
The NamingManagerFactory has 3 dependencies:
CacheManager: It permits for some PNamingContext to
lookup persistent object in the cache before doing I/O (polymorphism case
for instance).
POManagerFactory: It permits to fetch the
SequenceManager associated to the POMF.
PMapper: It permits to NamingManager to use some
internal persistent classes (ex generator).
The Queries management
Main principles
The query management is based on
MEDOR framework. The main principle is the following sequence:
The user defines a query using its favorite API (the personality).The
JDOQuery class implements a JDO query definition whereas the
EJBQuery class implements the EJB definition.
From the definition, the query manager associates a
CompiledQuery instance. This instance can be newly allocated or can be
found from the cache of compiled queries. In all cases the compiled query
is
also specific to a personality.
The compiled query makes several tasks:
to translate the query definition (specific to a personality) into
an
initial MEDOR QueryTree.
to optimise the initial QueryTree thanks to optimisation rules
provided
in MEDOR. The result of the optimisation is still a MEDOR QueryTree but
optimised.
to execute the optimised QueryTree thanks to medor evaluator.
to encapsulate the query result (the projection) into the expected
format (persistent classes, holder classes).
The caching of compiled queries permits to make both first steps only the
first
time. The first time a query is translated, compiled and executed. The next
times, the query is simply evaluated.
The SpeedoQueryManager component
This component maintains the association between query definition and its
corresponding compiled query. The query manager uses a cache to realize it.
The cache implementation is same than the L2 cache used in the TPM component
for caching persistent object between transactions. This component offers the
QueryManager interface. Speedo has a generic and abstract implementation
SpeedoQueryManager. This generic class is subclassed for each
personality:
TODO: explain the parsing, the rule used for optimiation, the result class
The EJB query
TODO: explain the parsing, the rule used for optimiation, the result class
The detach/attach management
TODO
The user cache management
TODO
The JMX support
TODO
Speedo meta information
The Speedo meta information is a representation of the persistent classes. It
describes which classes are persistent, the mapping on the data support and lot
configuration stuffs. This meta information is built and used only at
enhancement time. It is based on information fetch from persistent descriptor
(.jdo files, persistence.xml, ...) and from the persistent classes themselves
(thanks byte analyzing or java reflect).
This chapter describes the meta objets composing the SMI (Speedo Meta
information). And a second sub chapter there is a description the use of the
meta information for the O/R Mapping.
Speedo meta information overview
The figure below is an UML class diagram of the Speedo Meta information.
The Speedo Meta information big picture
The entry point of the Speedo meta information is the SMI class
(bottom-left). This meta objet is unique in theory. It manages a set of xml
descriptors (SpeedoXMLDescriptor). Each descriptor contains package meta objects
(SpeedoPackage). A package meta object represents a java package and contains
persistent classes (SpeedoClass) and sequence (SpeedoSequence). A persistent
class has persistent fields (SpeedoField). Each field is mapped on column(s)
(SpeedoColumn) of a table (SpeedoTable). The identity of a persistent class
is defined by the SpeedoIdentity meta object. A persistent class is mapped into
a main table and maybe in secondary table. Each secondary table has a join
(SpeedoJoin) to the main table.
Speedo meta information and the O/R Mapping
This chapter describes how the Speedo meta information supports the O/R
mapping. Each sub chapter describes a mapping case and how the meta information
must be built. Diagrams about the meta information represents meta object
instances with the UML notation.