For Prevayler users
Some of the topics below assume you have some knowledge of Prevayler
Please note, Prevayler is a special object-oriented, in-memory
database. It has advantages like:
- simplicity of use,
- speed of accessing your
- speed for searching your data,
- data recovery after failure,
But it may have one disadvantage for your project: your data may not fit
in memory to use it. Actual 64-bit architecture allows to use a lot of data.
Are present JVMs prepared for memory hungry applications? Many people still
But facts are: my friends run ~100K of business objects on 32-bit
machine and they fit in 2G of RAM.
I run a simple application consisting of 13.000 objects and with historical
information of changes on the objects. JMeter load test of concurrent users
searching data in the application just rocks!
The choice is yours..
How it happens that it works?
The answer is simple. Imagine there is only one, very generic command
It's purpose is just like any other Prevayler command.
- stores information of objects which participate in transaction (*)
- run 'execute' method, which involves your business logic
(*) - stores OID
s instead of BO
Another part of systems takes care of storing/creating BOs themselves.
Data saved in GenericCommand consists of three parts:
- business method name - command name
- target object on which method is invoked (OID only)
- arguments passed to business method (OIDs only)
- First snapshot of data is taken right after construction
of ROOT object
- Every BO is put into IdentityMap
and stored within command right after construction
- Every BO in argument list of a transaction is translated (recovered)
to simple OID and OID is stored instead - prevents "baptism" problem
With this data saved, with proper order of every command executed, Prevayler
users may safely use PAT - you're able to write ZERO Prevayler's commands
Assume that I pass my object graph's root as an argument to transacted
method. What then? It's insane to store it automatically!
Yes, that's true. That is why PAT tests whether argument is one of your
business objects or not
(you've specified @@pat.bo
comment for it, or @@pat.root
If so, then I do not simply store arguments in
Instead I store only his OID
(object identifier). During
deserialising I restore original object based on his OID and pass it to
Keep in mind you cannot simply have
any arguments in transactions.
Where do you get OID from?
AOP allows you to use so called 'introductions'. JBossAOP does this by
so called Mixins.
I introduced IdentityMap into your root class. Keys in the map are OIDs of
objects, and values are real objects from your world - business objects.
Do I have to set OIDs by myself?
No. PAT framework does this for you.
During creation of every BO PAT attaches OID to it and puts object into
So the IdentityMap must be quite big..
Yes. It is. Number of objects it holds is even bigger than number of your
business objects. This is so, because _every_ BO
is put there. Even those
which you create only temporarily, or those that are not needed by you.
There is feature of removing them from IdentityMap (
WeakHashMap might help - but it isn't Serializable)
Can I get OID for my object?
Yes, you can. Although it is not necessary to use them or even to know about
Cast any of your @@pat.bo'ed objects to
org.nthx.pat.Identifiable and get its OID.
Because I've chosen to make only one command (transaction
) - generic one,
there must be some way to recover data from it and execute business logic
- your original annotated method.
There is no other way as through reflection. So: reflection will be used
during reading (deserialising) of commands (_transactions_).