madeleine 0.8.0 → 0.9.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES.txt +2 -0
- data/README.md +84 -0
- data/lib/madeleine.rb +37 -35
- data/lib/madeleine/sanity.rb +6 -1
- data/lib/madeleine/version.rb +1 -1
- metadata +14 -22
- data/README +0 -55
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0254e4a5cd6fe35768ce76fb92b0804724a83663
|
4
|
+
data.tar.gz: cc5860e5c27def4543d104edc0ce30f0f6acf65a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e009aac28e96a06499feeff40c43156bc8dfa7139ae20588fc2c5eef88277868b77cbff63be153971b59230e956b35b91483783dd8983ce6e33a8837c301a343
|
7
|
+
data.tar.gz: c5c67ada967d93f9d280ade1304c07328b439acf4aa787e5c1441d68213394252c4bd8a1227a3f8485db46cfe98856969360b08e07fd896dcdc08ea87b4c65d2
|
data/CHANGES.txt
CHANGED
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Madeleine
|
2
|
+
|
3
|
+
Madeleine is a Ruby implementation of transparent persistence of business
|
4
|
+
objects, using command logging and complete system snapshots.
|
5
|
+
|
6
|
+
https://github.com/ghostganz/madeleine
|
7
|
+
|
8
|
+
### Usage
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
require 'madeleine'
|
12
|
+
|
13
|
+
# Create an application as a prevalent system
|
14
|
+
|
15
|
+
madeleine = SnapshotMadeleine.new("my_example_storage") {
|
16
|
+
# Creating the initial empty system. This is how the application
|
17
|
+
# is bootstrapped on each startup (until the first snapshot is taken).
|
18
|
+
# All the persistent data needs to be reachable from this object.
|
19
|
+
# For this example, the application's whole dataset is a hash
|
20
|
+
# with a counter:
|
21
|
+
{:counter => 0}
|
22
|
+
}
|
23
|
+
|
24
|
+
# To operate on the system, we need commands. For this example,
|
25
|
+
# we can do additions to our counter:
|
26
|
+
class AdditionCommand
|
27
|
+
def initialize(number)
|
28
|
+
@number = number
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute(system)
|
32
|
+
# This is the only place from where we're allowed to modify
|
33
|
+
# the system.
|
34
|
+
system[:counter] += @number
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Do modifications of the system by sending commands through
|
39
|
+
# the Madeleine instance:
|
40
|
+
|
41
|
+
command = AdditionCommand.new(12)
|
42
|
+
madeleine.execute_command(command)
|
43
|
+
|
44
|
+
# The commands are written to the command log before executed.
|
45
|
+
# The next time the application starts, all the commands in the
|
46
|
+
# log are re-applied to the system, returning it to the state it
|
47
|
+
# had when it was shut down.
|
48
|
+
|
49
|
+
# To avoid long start-up times when the command log gets large,
|
50
|
+
# you can do occasional snapshots of the entire system. You must
|
51
|
+
# also do a snapshot before deploying any changes in your application
|
52
|
+
# logic.
|
53
|
+
|
54
|
+
madeleine.take_snapshot
|
55
|
+
```
|
56
|
+
|
57
|
+
### Requirements
|
58
|
+
|
59
|
+
* Ruby 1.8.7 or later
|
60
|
+
|
61
|
+
### Contact
|
62
|
+
|
63
|
+
Homepage: https://github.com/ghostganz/madeleine
|
64
|
+
|
65
|
+
### License
|
66
|
+
|
67
|
+
BSD (see the file ```COPYING```)
|
68
|
+
|
69
|
+
### Credits
|
70
|
+
|
71
|
+
Anders Bengtsson - Prevalence core impl.
|
72
|
+
Stephen Sykes - Automatic commands impl.
|
73
|
+
|
74
|
+
Madeleine's design is based on Prevayler, the original Java
|
75
|
+
prevalence layer.
|
76
|
+
|
77
|
+
With the help of patches, testing and feedback from:
|
78
|
+
|
79
|
+
Steve Conover, David Heinemeier Hansson, Johan Lind, Håkan Råberg,
|
80
|
+
IIMA Susumu, Martin Tampe and Jon Tirsén
|
81
|
+
|
82
|
+
Thanks to Klaus Wuestefeld and the Prevayler developers for the
|
83
|
+
model of this software; to Minero Aoki for the installer; to Matz and
|
84
|
+
the core developers for the Ruby language!
|
data/lib/madeleine.rb
CHANGED
@@ -42,21 +42,32 @@ module Madeleine
|
|
42
42
|
# See: DefaultSnapshotMadeleine
|
43
43
|
#
|
44
44
|
# * <tt>directory_name</tt> - Storage directory to use. Will be created if needed.
|
45
|
-
# * <tt>
|
45
|
+
# * <tt>options</tt> - Options hash:
|
46
|
+
# * <tt>:snapshot_marshaller</tt> - Marshaller to use for system snapshots (defaults to Marshal)
|
47
|
+
# * <tt>:execution_context</tt> - Optional context to be passed to commands' execute() method as a second parameter
|
46
48
|
# * <tt>new_system_block</tt> - Block to create a new system (if no stored system was found).
|
47
|
-
def self.new(directory_name,
|
49
|
+
def self.new(directory_name, options = {}, &new_system_block)
|
50
|
+
if options.kind_of? Hash
|
51
|
+
options = {
|
52
|
+
:snapshot_marshaller => Marshal,
|
53
|
+
:execution_context => nil
|
54
|
+
}.merge(options)
|
55
|
+
else
|
56
|
+
# Backwards compat.
|
57
|
+
options = {:snapshot_marshaller => options}
|
58
|
+
end
|
59
|
+
|
48
60
|
log_factory = DefaultLogFactory.new
|
49
61
|
logger = Logger.new(directory_name,
|
50
62
|
log_factory)
|
51
63
|
snapshotter = Snapshotter.new(directory_name,
|
52
|
-
snapshot_marshaller)
|
53
|
-
lock = DefaultLock.new
|
64
|
+
options[:snapshot_marshaller])
|
54
65
|
recoverer = Recoverer.new(directory_name,
|
55
|
-
snapshot_marshaller)
|
66
|
+
options[:snapshot_marshaller])
|
56
67
|
system = recoverer.recover_snapshot(new_system_block)
|
57
|
-
executer = Executer.new(system)
|
68
|
+
executer = Executer.new(system, options[:execution_context])
|
58
69
|
recoverer.recover_logs(executer)
|
59
|
-
DefaultSnapshotMadeleine.new(system, logger, snapshotter,
|
70
|
+
DefaultSnapshotMadeleine.new(system, logger, snapshotter, executer)
|
60
71
|
end
|
61
72
|
end
|
62
73
|
|
@@ -65,13 +76,13 @@ module Madeleine
|
|
65
76
|
# The prevalent system
|
66
77
|
attr_reader :system
|
67
78
|
|
68
|
-
def initialize(system, logger, snapshotter,
|
79
|
+
def initialize(system, logger, snapshotter, executer)
|
69
80
|
SanityCheck.instance.run_once
|
70
81
|
|
71
82
|
@system = system
|
72
83
|
@logger = logger
|
73
84
|
@snapshotter = snapshotter
|
74
|
-
@lock =
|
85
|
+
@lock = Sync.new
|
75
86
|
@executer = executer
|
76
87
|
|
77
88
|
@closed = false
|
@@ -103,7 +114,7 @@ module Madeleine
|
|
103
114
|
#
|
104
115
|
# * <tt>query</tt> - The query command to execute
|
105
116
|
def execute_query(query)
|
106
|
-
@lock.
|
117
|
+
@lock.synchronize(:SH) do
|
107
118
|
@executer.execute(query)
|
108
119
|
end
|
109
120
|
end
|
@@ -168,31 +179,20 @@ module Madeleine
|
|
168
179
|
|
169
180
|
FILE_COUNTER_SIZE = 21 #:nodoc:
|
170
181
|
|
171
|
-
class DefaultLock #:nodoc:
|
172
|
-
|
173
|
-
def initialize
|
174
|
-
@lock = Sync.new
|
175
|
-
end
|
176
|
-
|
177
|
-
def synchronize(&block)
|
178
|
-
@lock.synchronize(&block)
|
179
|
-
end
|
180
|
-
|
181
|
-
def synchronize_shared(&block)
|
182
|
-
@lock.synchronize(:SH, &block)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
182
|
class Executer #:nodoc:
|
187
|
-
|
188
|
-
def initialize(system)
|
183
|
+
def initialize(system, context = nil)
|
189
184
|
@system = system
|
185
|
+
@context = context
|
190
186
|
@in_recovery = false
|
191
187
|
end
|
192
188
|
|
193
189
|
def execute(command)
|
194
190
|
begin
|
195
|
-
|
191
|
+
if @context
|
192
|
+
command.execute(@system, @context)
|
193
|
+
else
|
194
|
+
command.execute(@system)
|
195
|
+
end
|
196
196
|
rescue
|
197
197
|
raise unless @in_recovery
|
198
198
|
end
|
@@ -231,7 +231,7 @@ module Madeleine
|
|
231
231
|
def recover_logs(executer)
|
232
232
|
executer.recovery do
|
233
233
|
CommandLog.log_file_names(@directory_name, FileService.new).each do |file_name|
|
234
|
-
open(@directory_name
|
234
|
+
open("#{@directory_name}#{File::SEPARATOR}#{file_name}", "rb") do |log|
|
235
235
|
recover_log(executer, log)
|
236
236
|
end
|
237
237
|
end
|
@@ -255,11 +255,13 @@ module Madeleine
|
|
255
255
|
end
|
256
256
|
|
257
257
|
def name
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
258
|
+
[
|
259
|
+
@path,
|
260
|
+
File::SEPARATOR,
|
261
|
+
sprintf("%0#{FILE_COUNTER_SIZE}d", @id),
|
262
|
+
'.',
|
263
|
+
@name
|
264
|
+
].join
|
263
265
|
end
|
264
266
|
end
|
265
267
|
|
@@ -363,7 +365,7 @@ module Madeleine
|
|
363
365
|
private
|
364
366
|
|
365
367
|
def delete_log_files
|
366
|
-
names = Dir.glob(@directory_name
|
368
|
+
names = Dir.glob("#{@directory_name}#{File::SEPARATOR}*.command_log")
|
367
369
|
names.each do |name|
|
368
370
|
name.untaint
|
369
371
|
File.delete(name)
|
data/lib/madeleine/sanity.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#encoding:utf-8
|
1
2
|
#
|
2
3
|
# Author:: Anders Bengtsson <ndrsbngtssn@yahoo.se>
|
3
4
|
# Copyright:: Copyright (c) 2004-2006
|
@@ -11,7 +12,11 @@ module Madeleine
|
|
11
12
|
include Singleton
|
12
13
|
|
13
14
|
def initialize
|
14
|
-
@testdata = "\x85\x00\x0a\0x0d\x0a"
|
15
|
+
@testdata = "\x85\x00\x0a\0x0d\x0a"
|
16
|
+
if @testdata.respond_to?(:force_encoding)
|
17
|
+
@testdata.force_encoding('ASCII-8BIT')
|
18
|
+
end
|
19
|
+
@testdata.freeze
|
15
20
|
@was_run = false
|
16
21
|
end
|
17
22
|
|
data/lib/madeleine/version.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: madeleine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.9.0.pre
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
|
-
- Anders Bengtsson
|
7
|
+
- Anders Kindberg (Bengtsson)
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2013-08-25 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: minitest
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,33 +27,29 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rdoc
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
description: Transparent persistence of system state using logging and snapshots
|
@@ -81,11 +74,12 @@ files:
|
|
81
74
|
- contrib/test_batched.rb
|
82
75
|
- contrib/test_scalability.rb
|
83
76
|
- contrib/threaded_benchmark.rb
|
84
|
-
- README
|
77
|
+
- README.md
|
85
78
|
- CHANGES.txt
|
86
79
|
- COPYING
|
87
80
|
homepage: http://github.com/ghostganz/madeleine
|
88
81
|
licenses: []
|
82
|
+
metadata: {}
|
89
83
|
post_install_message:
|
90
84
|
rdoc_options:
|
91
85
|
- --exclude
|
@@ -97,21 +91,19 @@ rdoc_options:
|
|
97
91
|
require_paths:
|
98
92
|
- lib
|
99
93
|
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
-
none: false
|
101
94
|
requirements:
|
102
|
-
- -
|
95
|
+
- - '>='
|
103
96
|
- !ruby/object:Gem::Version
|
104
97
|
version: 1.8.7
|
105
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
99
|
requirements:
|
108
|
-
- -
|
100
|
+
- - '>'
|
109
101
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
102
|
+
version: 1.3.1
|
111
103
|
requirements: []
|
112
104
|
rubyforge_project:
|
113
|
-
rubygems_version:
|
105
|
+
rubygems_version: 2.0.5
|
114
106
|
signing_key:
|
115
|
-
specification_version:
|
107
|
+
specification_version: 4
|
116
108
|
summary: Madeleine is a Ruby implementation of Object Prevalence
|
117
109
|
test_files: []
|
data/README
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
|
2
|
-
Madeleine is a Ruby implementation of Object Prevalence: Transparent
|
3
|
-
persistence of business objects using command logging and complete
|
4
|
-
system snapshots.
|
5
|
-
|
6
|
-
https://github.com/ghostganz/madeleine
|
7
|
-
|
8
|
-
Madeleine's design is based on Prevayler, the original Java
|
9
|
-
prevalence layer.
|
10
|
-
|
11
|
-
|
12
|
-
Usage:
|
13
|
-
|
14
|
-
require 'madeleine'
|
15
|
-
|
16
|
-
# Create an application as a prevalent system
|
17
|
-
|
18
|
-
madeleine = SnapshotMadeleine.new("my_example_storage") {
|
19
|
-
SomeExampleApplication.new()
|
20
|
-
}
|
21
|
-
|
22
|
-
# Do modifications of the system by sending commands through
|
23
|
-
# the Madeleine instance. A command is an object with a suitable
|
24
|
-
# "execute(system)" method.
|
25
|
-
|
26
|
-
madeleine.execute_command(command)
|
27
|
-
|
28
|
-
|
29
|
-
Requirements:
|
30
|
-
|
31
|
-
* Ruby 1.8.7 or later
|
32
|
-
|
33
|
-
Contact:
|
34
|
-
|
35
|
-
Homepage:
|
36
|
-
https://github.com/ghostganz/madeleine
|
37
|
-
|
38
|
-
License:
|
39
|
-
|
40
|
-
BSD (see the file COPYING)
|
41
|
-
|
42
|
-
Credits:
|
43
|
-
|
44
|
-
Anders Bengtsson - Prevalence core impl.
|
45
|
-
Stephen Sykes - Automatic commands impl.
|
46
|
-
|
47
|
-
With the help of patches, testing and feedback from:
|
48
|
-
|
49
|
-
Steve Conover, David Heinemeier Hansson, Johan Lind, Håkan Råberg,
|
50
|
-
IIMA Susumu, Martin Tampe and Jon Tirsén
|
51
|
-
|
52
|
-
Thanks to Klaus Wuestefeld and the Prevayler developers for the
|
53
|
-
model of this software; to Minero Aoki for the installer; to Matz and
|
54
|
-
the core developers for the Ruby language!
|
55
|
-
|