SPrevayler
Last updated at 12:51 am UTC on 17 January 2006
SPrevayler is a prevalence layer for Squeak. System prevalence is based on the idea that all data is kept in RAM. So the system runs very fast without any lack of data security.
It can render your data out as XML or as binary Squeak Format, which is very fast. You can simply make your classes persistent by using a simple transparent proxy or you can use the full power of this solution and write your own commands.
In order to use this project you need to have SIXX in your image!
Download
There are two ways to install it.
Contact me via mail: mailto:slomo.minnowwiki.5.marco_paga@dfgh.net
Abstract
- Data is kept in RAM
- Editable via Command objects (Protocol: >>executeOn: aPrevaylentSystem atTime: anAlarmClock)
- The system and updates are written to disk (fault tolerance)
- You can use prevayler as a transparent persistence mechanism that is only working in the background.
Technique
Transparent prevalence
Quote of mail:
Marco Paga mail at marco-paga.de
Fri Feb 28 13:48:04 CET 2003
I wrote a little Proxy that does the things you wanted. Here an example:
| p c base proxy|
base_ FileDirectory on: (FileDirectory default pathName,
FileDirectory slash , 'testBase').
p := Prevayler withSystem: (MPTestSystem value: 0) on: base.
proxy_ PrevalenceProxy prevayler: p.
proxy addValue: 17.
every message that goes to the proxy is handeld by the prevalence layer. You have to pay attention in the case of creating a new prevayler because then you have to create a new proxy too.
Regards,
Marco
Here you can find a UML sequence diagram:

The Formats
You can easily change how Sprevayler writes Objects to disk by changing Prevayler>>getDiskIOClass. To use XML you need to have SIXX installed!
Currently two possibilities:
- for XML: ^SixxAdapter
- just squeak readable: ^DataStreamAdapter
General
But that idea alone doesn't keep your data. The system gets fotographed from time to time and the snapshot gets written to disk. So we can rebuild the state of some particular points in timeline.
But now we want to run transactions on it. How to do that without taking snapshots of the whole huge system every time?
We write the commands to disk, too. The commands that are issued to the system get written to disk and the executed on the hot system.
To rebuild the state we look for the newest snapshot and go through the command logfiles that follow the snapshot and execute one command after another.
That's all.
Time related
But what about commands that need the current time and date? These can work,too. There is one limitation: Your commands need to always give the same results based on a time (determenistic commands).
Before the commands are stored to disk they are put in an ClockRecoveryCommand that restores the time before the real command is executed in the case of restorage (Design Pattern: Decorator).
Example
- You need a System that keeps your data. This is the system that is surrounded by the Prevayler as the persistence layer. You can start by subclassing any useful class. There is no specific needed protocol to implement!
Object subclass: #MPTestSystem
instanceVariableNames: 'value '
classVariableNames: ''
poolDictionaries: ''
category: 'Prevayler-Tests'
- After that you need to add methods that can change the systems state. Theses methods will be used by your commands. You shouldn't use these methods directly. Just use these methods within your commands (later).
We just want to provide a method to add a number to the value of the system.
addValue: anObject
value_ value + anObject.
Transcript show: 'Added value: ',value asString, 'Time: ',clock time asString ; cr.
setValue: anObject
value_anObject.
- Now you need to define your commands. These commands will be used to edit the state of your system. If your commands need to have the current time and date it is very important that you use the provided AlarmClock; you can get the time by using AlarmClock>>time and the date by using AlarmClock>>date.
PrevaylerCommand subclass: #MPTestCommand
instanceVariableNames: 'value '
classVariableNames: ''
poolDictionaries: ''
category: 'Prevayler-Tests'
As a class method you need to add one that adds parameters to it.
value: anObject
^super new setValue: anObject "Add the setValue: Method!"
On the instance side we need to add the executeOn method to override the super class method.
executeOn: aSystem atTime: anAlarmClock
aSystem addValue: value.
This should be the one command that is enough for our exmple. Just adding a nmber, not more. If you want to access the "current" time you have to use the provided AlarmClock not any other timesource.
- Now we start using it. Just take a workspace and go ahead:
| p c base |
base_ FileDirectory on: (FileDirectory default pathName ,
FileDirectory slash , 'testBase').
p := Prevayler withSystem: (MPTestSystem value: 0) on: base.
c_ MPTestCommand value:5.
p executeCommand: c.
- Save the image and execute the bunch of commands. If you have Transcript open you can see that 5 was added at jour local time. Then close squeak without saving and open again. Just execute the bunch again and you'll see that the state is rebuild correct and that the commands seem to be executed in the past (That is correct because to rebuild correctly the commands must believe that it is the correct time).
UML
Here you can have a look at a UML class dia of the system. I just created it that you can have a short overview.

Roadmap
Next features to implement:
- fault tolerance (working with corrupted files)
- Ability to work in a replicated environment.
Version Comments:
- 9: Works stable without problems. You should use Prevayler withSystem: (without base path) and it works just fine!
- 7: Added Comments and tested the whole thing. Seems stable. If the system is crashed you perhaps have to edit the last XML command file manually and remove the last (half written) command.
- 3: Now you don't need to subclass PrevalentSystem anymore. The clock is managed by the Prevayler. Refactored the file-in and file-out mechanism out of the prevayler class. It should now be easier to extend the whole package.
- Monticello 2: Refactored the output handling out of the Prevayler class.
- 2.1a: This version can be used. The basic features are implemented and should now be tested. If you understand a bit of XML you can use SPrevayler for your projects.
- 1.?: This version is outdated and can not be found on the net. I started SPrevayler2 to fully rewrite the whole package.
Misc
Author: Marco Paga (Contact: mailto:slomo.minnowwiki.5.marco_paga@dfgh.net)
Developers : David Salamon and Adrian Lienhard
License: The license I use for SPrevayler is the MIT license.
Your comments:
what is the MIT license? What if you have no license?
where is a website running this?
maszproduction@yahoo.com gavin schuette
You can find the mit license here: http://www.opensource.org/licenses/mit-license.php . It is a very free license, so I thought it would be a good choice. I wanted to choose a license but a very free one because I don't like source that is not covered with any license, becuase then you don't really know if you can use it and of course I want to protect myself.
Right at the moment there is no webiste running it. SPrevayler is just for transparent persistence in squeak. To make a app persistent you can just use your source and add the proxy to it as the model and it will work.
Hi. Thanx u, kbye.
I've been trying to use this in my Seaside application and ran into some problems concerning the continuations. Weird to trace down though –
Hi if you can send me an email with more detailed information I could have an eye on it.
You can find my address on this page or on my personal page.
According to this page, we should have a SixxAdapter. In the mcz attached, we don’t.
I don’t think anyone has tried running the code in the mcz against sixx.
When you try to bring up the Prevayler against an xml-based directory of snapshots and clogs, you get a problem with DiskIOClass returning a SixxWriteStream which doesn’t understand “readOnlyFileNamed”.
oldFileNamed: aFilename
^ self new setStream: (self DiskIOClass readOnlyFileNamed: aFilename).
All I’ve done to get this is swich around the commenting in PIOAdapter>>DiskIOClass, so that it returns SixxWriteStream, and not the default ReferenceStream.
Thank you for your comment. I will have a look on it asap and release a new monticello version.
I tested it on a clean 3.7 under Linux with Sixx and ReferenceStreams and the test cases worked well.