madeleine 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +31 -0
- data/NEWS +55 -0
- data/README +78 -0
- data/contrib/batched.rb +298 -0
- data/contrib/benchmark.rb +35 -0
- data/contrib/test_batched.rb +245 -0
- data/contrib/test_scalability.rb +248 -0
- data/contrib/threaded_benchmark.rb +44 -0
- data/lib/madeleine.rb +419 -0
- data/lib/madeleine/automatic.rb +418 -0
- data/lib/madeleine/clock.rb +94 -0
- data/lib/madeleine/files.rb +19 -0
- data/lib/madeleine/zmarshal.rb +60 -0
- data/samples/clock_click.rb +73 -0
- data/samples/dictionary_client.rb +23 -0
- data/samples/dictionary_server.rb +94 -0
- data/samples/painter.rb +60 -0
- metadata +53 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Wrapper for Ruby's file services, replaced during testing
|
3
|
+
# so we can run tests without touching a real filesystem.
|
4
|
+
#
|
5
|
+
|
6
|
+
class FileService
|
7
|
+
|
8
|
+
def open(*args)
|
9
|
+
super(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def exist?(name)
|
13
|
+
File.exist?(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def dir_entries(name)
|
17
|
+
Dir.entries(name)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Anders Bengtsson <ndrsbngtssn@yahoo.se>
|
3
|
+
# Copyright:: Copyright (c) 2004
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'zlib'
|
7
|
+
|
8
|
+
module Madeleine
|
9
|
+
#
|
10
|
+
# Snapshot marshaller for compressed snapshots.
|
11
|
+
#
|
12
|
+
# Compresses the snapshots created by another marshaller. Uses either
|
13
|
+
# Marshal (the default) or another supplied marshaller.
|
14
|
+
#
|
15
|
+
# Uses <tt>zlib</tt> to do on-the-fly compression/decompression.
|
16
|
+
#
|
17
|
+
# ZMarshal works with Ruby's own Marshal and YAML, but not with SOAP
|
18
|
+
# marshalling.
|
19
|
+
#
|
20
|
+
# Usage:
|
21
|
+
#
|
22
|
+
# require 'madeleine'
|
23
|
+
# require 'madeleine/zmarshal'
|
24
|
+
#
|
25
|
+
# marshaller = Madeleine::ZMarshal.new(YAML)
|
26
|
+
# madeleine = SnapshotMadeleine.new("my_example_storage", marshaller) {
|
27
|
+
# SomeExampleApplication.new()
|
28
|
+
# }
|
29
|
+
#
|
30
|
+
class ZMarshal
|
31
|
+
|
32
|
+
def initialize(marshaller=Marshal)
|
33
|
+
@marshaller = marshaller
|
34
|
+
end
|
35
|
+
|
36
|
+
def load(stream)
|
37
|
+
zstream = Zlib::GzipReader.new(stream)
|
38
|
+
begin
|
39
|
+
# Buffer into a string first, since GzipReader can't handle
|
40
|
+
# Marshal's 0-sized reads and SOAP can't handle streams at all.
|
41
|
+
# In a bright future we can revert to reading directly from the
|
42
|
+
# stream again.
|
43
|
+
buffer = zstream.read
|
44
|
+
return @marshaller.load(buffer)
|
45
|
+
ensure
|
46
|
+
zstream.finish
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def dump(system, stream)
|
51
|
+
zstream = Zlib::GzipWriter.new(stream)
|
52
|
+
begin
|
53
|
+
@marshaller.dump(system, zstream)
|
54
|
+
ensure
|
55
|
+
zstream.finish
|
56
|
+
end
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#
|
2
|
+
# Simple example of using time with Madeleine.
|
3
|
+
#
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(".." + File::SEPARATOR + "lib")
|
6
|
+
|
7
|
+
require 'madeleine/clock'
|
8
|
+
require 'tk'
|
9
|
+
|
10
|
+
# The Clicker keeps track of when it was last clicked.
|
11
|
+
#
|
12
|
+
# To access the time it extends ClockedSystem, which provides
|
13
|
+
# it with the 'clock' attribute.
|
14
|
+
#
|
15
|
+
class Clicker
|
16
|
+
include Madeleine::Clock::ClockedSystem
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@last_clicked = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def click
|
23
|
+
@last_clicked = clock.time
|
24
|
+
end
|
25
|
+
|
26
|
+
def last_clicked
|
27
|
+
return '-' if @last_clicked.nil?
|
28
|
+
@last_clicked.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# A command to update the Clicker with.
|
33
|
+
#
|
34
|
+
class Click
|
35
|
+
def execute(system)
|
36
|
+
system.click
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Launch a ClockedSnapshotMadeleine.
|
41
|
+
#
|
42
|
+
# ClockedSnapshotMadeleine works like the regular SnapshotMadeleine, but
|
43
|
+
# optimizes away redundant commands from TimeActor.
|
44
|
+
#
|
45
|
+
madeleine = ClockedSnapshotMadeleine.new("clock-demo") { Clicker.new }
|
46
|
+
|
47
|
+
# Launch the TimeActor.
|
48
|
+
#
|
49
|
+
# This provides time commands, without which the system's time would stand still.
|
50
|
+
#
|
51
|
+
Madeleine::Clock::TimeActor.launch(madeleine)
|
52
|
+
|
53
|
+
clicker = madeleine.system
|
54
|
+
|
55
|
+
# The GUI
|
56
|
+
|
57
|
+
root = TkRoot.new() { title "Madeleine Clock Example" }
|
58
|
+
label = TkLabel.new(root) {
|
59
|
+
text "Last clicked " + clicker.last_clicked
|
60
|
+
width 40
|
61
|
+
pack
|
62
|
+
}
|
63
|
+
button = TkButton.new(root) {
|
64
|
+
text 'Click'
|
65
|
+
command proc {
|
66
|
+
madeleine.execute_command(Click.new)
|
67
|
+
label.text("Last clicked " + clicker.last_clicked)
|
68
|
+
}
|
69
|
+
pack
|
70
|
+
}
|
71
|
+
|
72
|
+
Tk.mainloop
|
73
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Dictionary client
|
3
|
+
#
|
4
|
+
# See dictionary_server.rb for details
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'drb'
|
8
|
+
|
9
|
+
DRb.start_service
|
10
|
+
dictionary = DRbObject.new(nil, "druby://localhost:1234")
|
11
|
+
|
12
|
+
if ARGV.length == 1
|
13
|
+
puts dictionary.lookup(ARGV[0])
|
14
|
+
elsif ARGV.length == 2
|
15
|
+
dictionary.add(ARGV[0], ARGV[1])
|
16
|
+
puts "Stored"
|
17
|
+
else
|
18
|
+
puts "Usage: dictionary_client <key> [<value>]"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#
|
2
|
+
# A dictionary server using Distributed Ruby (DRb).
|
3
|
+
#
|
4
|
+
# All modifications to the dictionary are done as commands,
|
5
|
+
# while read-only queries (i.e 'lookup') are done directly.
|
6
|
+
#
|
7
|
+
# First launch this server in the background, then use
|
8
|
+
# dictionary_client.rb to look up and add items to the
|
9
|
+
# dictionary.
|
10
|
+
# You can kill the server at any time. The contents of the
|
11
|
+
# dictionary will still be there when you restart it.
|
12
|
+
#
|
13
|
+
# DRb is available at http://raa.ruby-lang.org/list.rhtml?name=druby
|
14
|
+
#
|
15
|
+
|
16
|
+
$LOAD_PATH.unshift(".." + File::SEPARATOR + "lib")
|
17
|
+
require 'madeleine'
|
18
|
+
|
19
|
+
require 'drb'
|
20
|
+
|
21
|
+
|
22
|
+
class Dictionary
|
23
|
+
def initialize
|
24
|
+
@data = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(key, value)
|
28
|
+
@data[key] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def lookup(key)
|
32
|
+
@data[key]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
class Addition
|
38
|
+
def initialize(key, value)
|
39
|
+
@key, @value = key, value
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute(system)
|
43
|
+
system.add(@key, @value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
class Lookup
|
49
|
+
def initialize(key)
|
50
|
+
@key = key
|
51
|
+
end
|
52
|
+
|
53
|
+
def execute(system)
|
54
|
+
system.lookup(@key)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
class DictionaryServer
|
60
|
+
|
61
|
+
def initialize(madeleine)
|
62
|
+
@madeleine = madeleine
|
63
|
+
@dictionary = madeleine.system
|
64
|
+
end
|
65
|
+
|
66
|
+
def add(key, value)
|
67
|
+
# When adding a new key-value pair we modify the system, so
|
68
|
+
# this operation has to be done through a command.
|
69
|
+
@madeleine.execute_command(Addition.new(key, value))
|
70
|
+
end
|
71
|
+
|
72
|
+
def lookup(key)
|
73
|
+
# A lookup is a read-only operation, so we can do it as a non-logged
|
74
|
+
# query. If we weren't worried about concurrency problems we could
|
75
|
+
# have just called @dictionary.lookup(key) directly instead.
|
76
|
+
@madeleine.execute_query(Lookup.new(key))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
madeleine = SnapshotMadeleine.new("dictionary-base") { Dictionary.new }
|
82
|
+
|
83
|
+
Thread.new(madeleine) {
|
84
|
+
puts "Taking snapshot every 30 seconds."
|
85
|
+
while true
|
86
|
+
sleep(30)
|
87
|
+
madeleine.take_snapshot
|
88
|
+
end
|
89
|
+
}
|
90
|
+
|
91
|
+
DRb.start_service("druby://localhost:1234",
|
92
|
+
DictionaryServer.new(madeleine))
|
93
|
+
DRb.thread.join
|
94
|
+
|
data/samples/painter.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Simple drawing program to show Madeleine's logging feature.
|
3
|
+
#
|
4
|
+
# When you restart the program, your old artwork is still there.
|
5
|
+
#
|
6
|
+
# (Note: The GUI components used here aren't marshal-able,
|
7
|
+
# so in a real app you would have to do custom marshaling for
|
8
|
+
# the Painter class to get working snapshots. Then again, in a real
|
9
|
+
# app you wouldn't use the GUI components to hold the app's data,
|
10
|
+
# would you?)
|
11
|
+
#
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(".." + File::SEPARATOR + "lib")
|
14
|
+
|
15
|
+
require 'madeleine'
|
16
|
+
|
17
|
+
require 'tkclass'
|
18
|
+
|
19
|
+
class Painter
|
20
|
+
|
21
|
+
def initialize(canvas)
|
22
|
+
@canvas = canvas
|
23
|
+
end
|
24
|
+
|
25
|
+
def draw(x, y)
|
26
|
+
line = Line.new(@canvas, x, y, x + 1, y + 1)
|
27
|
+
line.fill('black')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class PaintCommand
|
32
|
+
|
33
|
+
def initialize(x, y)
|
34
|
+
@x, @y = x, y
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute(system)
|
38
|
+
system.draw(@x, @y)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
root = TkRoot.new() { title "Madeleine Painter" }
|
43
|
+
canvas = Canvas.new(root)
|
44
|
+
canvas.pack
|
45
|
+
|
46
|
+
$madeleine = Madeleine::SnapshotMadeleine.new("painter-demo") { Painter.new(canvas) }
|
47
|
+
|
48
|
+
canvas.bind("1",
|
49
|
+
proc {|x, y|
|
50
|
+
$madeleine.execute_command(PaintCommand.new(x, y))
|
51
|
+
},
|
52
|
+
"%x %y")
|
53
|
+
canvas.bind("B1-Motion",
|
54
|
+
proc {|x, y|
|
55
|
+
$madeleine.execute_command(PaintCommand.new(x, y))
|
56
|
+
},
|
57
|
+
"%x %y")
|
58
|
+
|
59
|
+
Tk.mainloop
|
60
|
+
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.4
|
3
|
+
specification_version: 1
|
4
|
+
name: madeleine
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.7.1
|
7
|
+
date: 2005-01-06
|
8
|
+
summary: Madeleine is a Ruby implementation of Object Prevalence
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: ndrsbngtssn@yahoo.se
|
12
|
+
homepage: http://madeleine.sourceforge.net
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: madeleine
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.8.1
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Anders Bengtsson
|
29
|
+
files:
|
30
|
+
- lib/madeleine.rb
|
31
|
+
- lib/madeleine/automatic.rb
|
32
|
+
- lib/madeleine/clock.rb
|
33
|
+
- lib/madeleine/files.rb
|
34
|
+
- lib/madeleine/zmarshal.rb
|
35
|
+
- samples/clock_click.rb
|
36
|
+
- samples/dictionary_client.rb
|
37
|
+
- samples/dictionary_server.rb
|
38
|
+
- samples/painter.rb
|
39
|
+
- contrib/batched.rb
|
40
|
+
- contrib/benchmark.rb
|
41
|
+
- contrib/test_batched.rb
|
42
|
+
- contrib/test_scalability.rb
|
43
|
+
- contrib/threaded_benchmark.rb
|
44
|
+
- README
|
45
|
+
- NEWS
|
46
|
+
- COPYING
|
47
|
+
test_files: []
|
48
|
+
rdoc_options: []
|
49
|
+
extra_rdoc_files: []
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
requirements: []
|
53
|
+
dependencies: []
|