ANN: Madeleine 0.1

http://sourceforge.net/project/showfiles.php?group_id=74624

What is Madeleine?

“Are you still using a database?”

Madeleine is a Ruby implementation of Object Prevalence[1]:
Transparent persistence of business objects using command
logging and snapshots.

http://madeleine.sourceforge.net/

This is the first release of Madeleine. Later releases will have
features like transparent command generation and clustering, but for
now the focus is a simple and well-designed implementation of the
basics.

Requirements:

  • Ruby 1.7/1.8 (uses File#fsync which isn’t in 1.6)

Known problems:

  • Doesn’t work in Windows yet.
  • Short on documentation. You’ll have to do with Prevayler’s
    docs for now.

[1] Learn more about object prevalence at http://www.prevayler.org/.

···

A n d e r s B e n g t s s o n | ndrsbngtssn@yahoo.se
Stockholm, Sweden |


Gå före i kön och få din sajt värderad på nolltid med Yahoo! Express
Se mer på: http://se.docs.yahoo.com/info/express/help/index.html

Madeleine - Ruby Object Prevalence - Browse Files at SourceForge.net

What is Madeleine?

“Are you still using a database?”

Madeleine is a Ruby implementation of Object Prevalence[1]:
Transparent persistence of business objects using command
logging and snapshots.

http://madeleine.sourceforge.net/

This is the first release of Madeleine. Later releases will have
features like transparent command generation and clustering, but for
now the focus is a simple and well-designed implementation of the
basics.

How does this compare with Mnemonic?
http://raa.ruby-lang.org/list.rhtml?name=mnemonic

“Mnemonic is object prevalence layer for Ruby. It provides a persistence mechanism that is orders of magnitude FASTER and SIMPLER
than a DBMS. It is based on the work of the Prevayler project at http://www.prevayler.org

James

This is beautiful.

Small suggestion: take class ‘Marshal’ as a parameter. Then you can choose a
different Marshal-type class like ‘YAML’. Although right now YAML is slow,
this would give a language-independent database which you could even edit
with ‘vi’ (great for data recovery). It might end up containing a lot of
spaces, but it should gzip very well.

Note to WHY: please can we have a YAML::dump(object [,IO]) method, for
symmetry with Marshal?

For testing I just replaced ‘Marshal’ with ‘YAML’, added the following:

require ‘yaml’
module YAML
def self.dump(obj,stream)
stream.write(obj.to_yaml)
end
end

This gives a database which looks like this:

$ cat dictionary-base/000000000000000000001.snapshot
— !ruby/object:Dictionary
data:
foo: the opposite of bar
bar: the opposite of foo

and a logfile like this:

$ cat dictionary-base/000000000000000000001.command_log
— !ruby/object:Addition
key: baz
value: the opposite of foobar

Having such readable files could go a long way towards addressing the
resistance which may arise towards treating your entire database of (say)
a million customer records as a single opaque binary blob…

Cheers,

Brian.

P.S. Another note to WHY: the last line of YAML output doesn’t seem to
contain a trailing newline, which is just a slight nuisance.

···

On Mon, Mar 17, 2003 at 07:00:35AM +0900, Anders Bengtsson wrote:

This is the first release of Madeleine. Later releases will have
features like transparent command generation and clustering, but for
now the focus is a simple and well-designed implementation of the
basics.

jbritt@ruby-doc.org wrote:

What is Madeleine?

“Are you still using a database?”

Madeleine is a Ruby implementation of Object Prevalence[1]:
Transparent persistence of business objects using command
logging and snapshots.

How does this compare with Mnemonic?
http://raa.ruby-lang.org/list.rhtml?name=mnemonic

“Mnemonic is object prevalence layer for Ruby. It provides a persistence mechanism that is orders of magnitude FASTER and SIMPLER
than a DBMS. It is based on the work of the Prevayler project at http://www.prevayler.org

Madeleine is an alive project and the author is responding to emails,
that’s the biggest difference at this point. :slight_smile:

The big feature difference at this point is that Mnemonic has a
(broken!) implementation of automatic commands.

/Anders

···

A n d e r s B e n g t s s o n | ndrsbngtssn@yahoo.se
Stockholm, Sweden |


Gå före i kön och få din sajt värderad på nolltid med Yahoo! Express
Se mer på: http://se.docs.yahoo.com/info/express/help/index.html

Small suggestion: take class ‘Marshal’ as a parameter. Then you can choose
a different Marshal-type class like ‘YAML’. Although right now YAML is
slow, this would give a language-independent database which you could even
edit with ‘vi’ (great for data recovery). It might end up containing a lot
of spaces, but it should gzip very well.

Brilliant.

Note to WHY: please can we have a YAML::dump(object [,IO]) method, for
symmetry with Marshal?

Yeah. Will be in YAML.rb 0.60.

P.S. Another note to WHY: the last line of YAML output doesn’t seem to
contain a trailing newline, which is just a slight nuisance.

Okay, fair enough. I’ll release YAML.rb 0.50 with this change, 0.60 as well.

_why

···

On Monday 17 March 2003 06:54 am, Brian Candler wrote:

— Brian Candler B.Candler@pobox.com skrev:

This is beautiful.

Thanks! :slight_smile:

Small suggestion: take class ‘Marshal’ as a parameter. Then you can
choose a
different Marshal-type class like ‘YAML’. Although right now YAML is
slow,
this would give a language-independent database which you could even
edit
with ‘vi’ (great for data recovery). It might end up containing a lot
of
spaces, but it should gzip very well.

Good idea. I like the YAML concept a lot.

Note to WHY: please can we have a YAML::dump(object [,IO]) method,
for
symmetry with Marshal?

I could just add wrapping classes that wrap either Marshal or YAML, so
a change in YAML won’t be necessary. Unless it’s a good idea for YAML
anyway?

For testing I just replaced ‘Marshal’ with ‘YAML’, added the
following:

[readable data example snipped]

Having such readable files could go a long way towards addressing the
resistance which may arise towards treating your entire database of
(say)
a million customer records as a single opaque binary blob…

There has been some talk about XML serialization on the Prevayler
lists, which gives the advantage of using XSL to upgrade the data
format. But I hope YAML’s closer integration with Ruby itself makes
upgrading even simpler.

Cheers,

Brian.

/Anders

···

=====


Anders Bengtsson ndrsbngtssn@yahoo.se
Stockholm, Sweden


Gå före i kön och få din sajt värderad på nolltid med Yahoo! Express
Se mer på: http://se.docs.yahoo.com/info/express/help/index.html

I’ve also started benchmarking Syck against the current YAML parser and things
are getting speedy. Here’s loading a comparable XML document 100 times in
REXML, Marshal, Syck, and YAML.rb:

  user     system      total        real

rexml: 0.437500 0.000000 0.437500 ( 0.458832)
syck: 0.023438 0.000000 0.023438 ( 0.030030)
marshal: 0.007812 0.000000 0.007812 ( 0.008570)
yaml: 2.359375 0.000000 2.359375 ( 2.388540)

Syck is averaging speeds 100x that of YAML.rb.

_why

···

On Monday 17 March 2003 06:54 am, Brian Candler wrote:

Although right now YAML is slow…

Excellent. Now just to make it dump at that speed as well :slight_smile:

···

On Mon, Mar 17, 2003 at 11:57:07PM +0900, why the lucky stiff wrote:

I’ve also started benchmarking Syck against the current YAML parser and things
are getting speedy. Here’s loading a comparable XML document 100 times in
REXML, Marshal, Syck, and YAML.rb:

  user     system      total        real

rexml: 0.437500 0.000000 0.437500 ( 0.458832)
syck: 0.023438 0.000000 0.023438 ( 0.030030)
marshal: 0.007812 0.000000 0.007812 ( 0.008570)
yaml: 2.359375 0.000000 2.359375 ( 2.388540)

Syck is averaging speeds 100x that of YAML.rb.

Note to WHY: please can we have a YAML::dump(object [,IO]) method,
for
symmetry with Marshal?

I could just add wrapping classes that wrap either Marshal or YAML, so
a change in YAML won’t be necessary. Unless it’s a good idea for YAML
anyway?

I don’t think your code should have anything YAML-specific, because there
are many other marshalling modules you might want to use (SOAP being another
example). I think it should be up to the end-user to wrap them so that there
is a Foo::load and Foo::dump, if they don’t have them already.

There has been some talk about XML serialization on the Prevayler
lists, which gives the advantage of using XSL to upgrade the data
format. But I hope YAML’s closer integration with Ruby itself makes
upgrading even simpler.

And XML serialisation means SOAP, and if you want to use XSL to apply
on-the-fly changes to SOAP object structure, well good luck to you :slight_smile:

The point about the Prevayler approach is that your whole database is in RAM

  • so if you want to make wholesale changes to its format, you just read it
    in, modify it using code, and write it back out again.

Regards,

Brian.

···

On Mon, Mar 17, 2003 at 11:37:56PM +0900, Anders Bengtsson wrote:

Madeleine is an alive project and the author is responding to emails,
that’s the biggest difference at this point. :slight_smile:

The big feature difference at this point is that Mnemonic has a
(broken!) implementation of automatic commands.

I wonder in what way are Mnemonic’s automatic commands broken?
I’d like to know because I am actively using it, and I don’t seem to
have any problems.

I do find that I need to use my own method wrapper module for objects
that are contained in my persisted class, so that changes in these
objects are also persisted. But it is quite easy to intercept method
calls to these objects, I just need to include my little module in
each class.

Are you planning to implement some kind of automatic commands?

/haldane
http://www.stephensykes.com

I don’t think your code should have anything YAML-specific, because
there
are many other marshalling modules you might want to use (SOAP being
another
example). I think it should be up to the end-user to wrap them so
that there
is a Foo::load and Foo::dump, if they don’t have them already.

I’ll probably ship a few out-of-the-box wrappers for different
marshalling implementations with Madeleine and at the same time give
the user the option to write their own. This won’t really affect the
core parts of Madeleine.
I already have an option to provide different command loggers, by
giving a logger-factory as an argument.

And XML serialisation means SOAP

Does it? :slight_smile:

, and if you want to use XSL to apply
on-the-fly changes to SOAP object structure, well good luck to you
:slight_smile:

I was more thinking in terms of how to migrate a snapshot of one
version of a program to a newer version, where the class structure has
changed. Nothing on-the-fly, really.

/Anders

···

— Brian Candler B.Candler@pobox.com wrote:

=====


Anders Bengtsson ndrsbngtssn@yahoo.se
Stockholm, Sweden


Gå före i kön och få din sajt värderad på nolltid med Yahoo! Express
Se mer på: http://se.docs.yahoo.com/info/express/help/index.html

— haldane jbshaldane@hotmail.com wrote:

I wonder in what way are Mnemonic’s automatic commands broken?
I’d like to know because I am actively using it, and I don’t seem to
have any problems.

I do find that I need to use my own method wrapper module for objects
that are contained in my persisted class, so that changes in these
objects are also persisted. But it is quite easy to intercept method
calls to these objects, I just need to include my little module in
each class.

Hi Haldane,

You kind of answered your own question here. :slight_smile: With one exception, the
root class of the system, the automatic commands are broken.

Are you planning to implement some kind of automatic commands?

Yes. There is a nice implementation for Java included as a sample in
the Aspect Oriented Programming project “Nanning”, that I intended to
use as the model for Madeleine’s design. Of course, in Ruby you can do
things directly in the language that in Java requires tools like AOP.
Lovely language, this.

Could you share your method wrapping code? It seems to be something
like what I intended to write.

/Anders

···

=====


Anders Bengtsson ndrsbngtssn@yahoo.se
Stockholm, Sweden


Gå före i kön och få din sajt värderad på nolltid med Yahoo! Express
Se mer på: http://se.docs.yahoo.com/info/express/help/index.html

And XML serialisation means SOAP

Does it? :slight_smile:

From what poking around I’ve managed to do, I don’t think there is any determination on what Prevayler XML serialization would look
like. And, as has been discussed on this list numerous times before, there are many ways besides SOAP to use XML for serialization.

, and if you want to use XSL to apply
on-the-fly changes to SOAP object structure, well good luck to you
:slight_smile:

SOAP or not, XPath queries would be nice. Or using an XForms UI to manage objects.
Anyway, XSLT on SOAP is not rocket science.

I was more thinking in terms of how to migrate a snapshot of one
version of a program to a newer version, where the class structure has
changed. Nothing on-the-fly, really.

Interesting idea.

James

···

/Anders

=====


Anders Bengtsson ndrsbngtssn@yahoo.se
Stockholm, Sweden


Gå före i kön och få din sajt värderad på nolltid med Yahoo! Express
Se mer på: http://se.docs.yahoo.com/info/express/help/index.html

I’ve not come across anything else which does the job. It would have to be
able to cope with cyclic graphs of object references, for example. Are the
Prevayler people really thinking of inventing a new standard for serialising
objects to XML?

Regards,

Brian.

···

On Tue, Mar 18, 2003 at 01:18:09AM +0900, Anders Bengtsson wrote:

And XML serialisation means SOAP

Does it? :slight_smile:

I thought that SOAP::Marshal didn’t need any wrapping:

irb(main):001:0> require ‘soap/marshal’
true
irb(main):002:0> a = SOAP::Marshal.dump(“abc”)
“<?xml version=\"1.0\" encoding=\"us-ascii\" ?>\n<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema\” xmlns:env="http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance\“>\nenv:Body\n<String xmlns:n1="http://schemas.xmlsoap.org/soap/encoding/\” xsi:type="xsd:string" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/\“>abc</String>\n</env:Body>\n</env:Envelope>\n”
irb(main):003:0> b = SOAP::Marshal.load(a)
“abc”

but actually it’s not compatible with Marshal, because:

  • you can’t pass an IO object to load, it must be a string
  • you can’t pass an IO object as the second parameter to dump
    (it takes a mappingRegistry instead)

I think that’s a weakness of soap4r, because if you have a 100MB database,
it forces you to create (say) 400MB of XML, and then write it to a file.
Suddenly you need 5 times as much RAM as you did originally, and also
concatenation of large strings is inefficient in Ruby 1.6.

For the purposes of a database, I think it’s reasonable for you to require
dump(obj,IO) and load(IO).

Regards,

Brian.

···

On Tue, Mar 18, 2003 at 01:18:09AM +0900, Anders Bengtsson wrote:

— Brian Candler B.Candler@pobox.com wrote:

I don’t think your code should have anything YAML-specific, because
there
are many other marshalling modules you might want to use (SOAP being
another
example). I think it should be up to the end-user to wrap them so
that there
is a Foo::load and Foo::dump, if they don’t have them already.

I’ll probably ship a few out-of-the-box wrappers for different
marshalling implementations with Madeleine and at the same time give
the user the option to write their own. This won’t really affect the
core parts of Madeleine.

Could you share your method wrapping code? It seems to be something
like what I intended to write.

Um, sure. Except that just looking closely at this part of my system
(which I am not using for anything important) I notice it is utterly
broken. The problem is that the persistence layer needs to remember
which objects the commands were for exactly because the object ids
will be different next time they are Marshal.load -ed. And there is
no way of doing that implemented at present in Mnemonic.

This is one way to wrap method calls anyway. Note that I am careful
to not make any singleton methods - these cannot be marshaled.

Need recent Ruby

Command module - sends any method calls through the persisted object

note that include Command should be the last line (not first) in

your class

module Command
class <<self
def included(klass)
klass.instance_methods.each {|m|
eval %{
klass.class_eval {
alias_method :cmdnew_#{m}, :#{m}
def #{m}(*args, &block)
Persisted.thing.execute(self.id, :cmdnew_#{m}, *args,
&block)
end
}
}
}
end
end
end

Assuming you have a persisted thing like this:

this is the persisted object

all commands come through here

class Thing
#…
def execute(objid, method, *args, &block)
ObjectSpace._id2ref(objid).send(method, *args, &block)
end
end

this class is for convenience only - could use a global variable too

class Persisted
include Singleton
attr_reader :x
def initialize
@x = Mnemonic.new(Thing.new, “thingstore”, “execute”)
end
def Persisted.thing
Persisted.instance.x
end
end

Any classes that include Command at the bottom will have all their
method calls persisted.

Except, as I say, it won’t work because we don’t know which objects
were which the next time we load up the commands. Creating objects is
not deterministic - they come with a different id each time.

Tricky.

/haldane

irb(main):001:0> require ‘soap/marshal’
true
irb(main):002:0> a = SOAP::Marshal.dump(“abc”)
“<?xml version=\"1.0\" encoding=\"us-ascii\" ?>\n<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema\” xmlns:env="http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance\“>\nenv:Body\n<String xmlns:n1="http://schemas.xmlsoap.org/soap/encoding/\” xsi:type="xsd:string" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/\“>abc</String>\n</env:Body>\n</env:Envelope>\n”
irb(main):003:0> b = SOAP::Marshal.load(a)
“abc”

but actually it’s not compatible with Marshal, because:

  • you can’t pass an IO object to load, it must be a string

Sorry I was wrong, it takes an IO object quite happily (but I can’t see
easily whether it reads the whole thing, or reads it in chunks)

  • you can’t pass an IO object as the second parameter to dump
    (it takes a mappingRegistry instead)

I can’t see how to get around that one though.

Regards,

Brian.

···

On Mon, Mar 17, 2003 at 06:05:02PM +0000, Brian Candler wrote:

For Prevayler, there’s just an interface for plugging in your own
logging and snapshot stuff, nothing more really.
There has been a lot of talk about different formats, but I don’t think
I’ve seen SOAP mentioned.
Anyway, it’s not that big an issue. Unless you want to use external
tools on the snapshot, for whatever reason, the default
serialization/marshalling will do.

/Anders

···

On 2003-03-17 Brian Candler wrote:

And XML serialisation means SOAP

Does it? :slight_smile:

I’ve not come across anything else which does the job. It would have to be
able to cope with cyclic graphs of object references, for example. Are the
Prevayler people really thinking of inventing a new standard for serialising
objects to XML?

A n d e r s B e n g t s s o n | ndrsbngtssn@yahoo.se
Stockholm, Sweden |


Gå före i kön och få din sajt värderad på nolltid med Yahoo! Express
Se mer på: http://se.docs.yahoo.com/info/express/help/index.html

Hi,

From: jbritt@ruby-doc.org
Sent: Tuesday, March 18, 2003 1:45 AM

And XML serialisation means SOAP

Does it? :slight_smile:

From what poking around I’ve managed to do, I don’t think
there is any determination on what Prevayler XML
serialization would look
like. And, as has been discussed on this list numerous times
before, there are many ways besides SOAP to use XML for serialization.

FYI: XML Protocol Comparisons

Once upon a time in 1999, he looked for XML serialization
format instead of using CSV or proprietary text format for
his product. He found several candidates; XML-RPC, WDDX,
XMOP, or so but only SOAP seems to be promising for him.
XMOP seems too COMed. Other formats is too simple for
serialization. Is SOAP Envelop complicated? It’s only an
envelope. Is SOAP Encoding complicated? It’s only
WXS Part 2 + array + struct. He thought that anyone cannot
simplify SOAP’s array and struct anymore (SOAP/1.2 simplified
the array though. sigh.)

Back to the topic, though I know nothing about Preveyler
now, SOAP can be used for the serialization format or not,
depends on Preveyler’s Data model. SOAP Data Model is
“graph of typed node”. Table data model does not fit SOAP.

Regards,
// NaHi

Just a note.

In the past day or two I’ve started to use irb as a shell to work in,
and it’s very helpful, although not earth-shattering.

For example, I did the following in irb to unzip a bunch of files in my
working directory:

system(“ls *gz > list”)
a=File.open(“list”,“r”)
b=a.readlines
b.each { |f| system(“gtar -zxf #{f}”) }
b.each { |f| system(“rm -rf #{f}”) }

I think this could be done with an ordinary shell, using xargs maybe,
but I know how to do it in Ruby. If you have a more elegant way to
write the Ruby lines, let me know. Looking at it, I can see that if I
remembered the directory methods I could make the first 3 lines one
line.