hprevalence 0.1.1 → 0.2.0
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.
- data/lib/hprevalence.rb +28 -181
- data/lib/internal/command_logger.rb +11 -34
- data/lib/internal/marshallers/default.rb +17 -0
- data/lib/internal/marshallers/soap_marshaller.rb +26 -0
- data/lib/internal/marshallers/yaml_marshaller.rb +22 -0
- data/lib/internal/serializer.rb +38 -52
- data/lib/internal/store_manager.rb +9 -24
- data/rakefile.rb +1 -1
- data/samples/simple/main.rb +10 -0
- data/{test → samples/simple}/task_model.rb +0 -12
- data/samples/transparent/task_model.rb +36 -0
- data/test/command_logger_test.rb +2 -6
- data/test/default_model_serializer_test.rb +9 -8
- data/test/marshaller_test.rb +68 -0
- data/test/models/task_model.rb +91 -0
- data/test/simple_engine_test.rb +22 -5
- data/test/simple_engine_with_soap_test.rb +94 -0
- data/test/simple_engine_with_yaml_test.rb +94 -0
- metadata +12 -10
- data/lib/transparent.rb +0 -245
- data/test/circular_reference_test.rb +0 -96
- data/test/dvd_store_model.rb +0 -97
- data/test/natural_object_model_test.rb +0 -143
- data/test/project_model.rb +0 -99
- data/test/restoring_test.rb +0 -54
- data/test/transparent_module_test.rb +0 -115
data/lib/hprevalence.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
|
2
2
|
require 'thread'
|
3
|
-
require 'guid'
|
4
|
-
require 'transparent'
|
5
3
|
require 'internal/command_logger'
|
6
4
|
require 'internal/iomanager'
|
7
5
|
require 'internal/serializer'
|
8
6
|
require 'internal/store_manager'
|
7
|
+
require 'internal/marshallers/default'
|
9
8
|
|
10
9
|
module HPrevalence
|
11
10
|
|
12
11
|
#
|
13
12
|
class EngineBuilder
|
14
13
|
|
15
|
-
def self.build(
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
def self.build(
|
15
|
+
target_dir,
|
16
|
+
marshaller = DefaultMarshaller.new(),
|
17
|
+
iomanager = FileIOManager.new(target_dir),
|
18
|
+
model_serializer = DefaultModelSerializer.new(iomanager, marshaller),
|
19
|
+
&system_init )
|
20
|
+
|
22
21
|
ensure_dir( target_dir )
|
23
22
|
system = system_init.call
|
24
|
-
|
23
|
+
raise 'System nil ?' if system.nil?
|
24
|
+
SimpleEngine.new( target_dir, system, iomanager, marshaller, model_serializer )
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
private
|
28
28
|
|
29
29
|
def self.ensure_dir( dir )
|
@@ -34,12 +34,18 @@ module HPrevalence
|
|
34
34
|
|
35
35
|
end
|
36
36
|
|
37
|
-
#
|
37
|
+
#
|
38
38
|
class SimpleEngine
|
39
|
-
|
40
39
|
attr_reader :system, :target_dir
|
41
40
|
|
42
|
-
def initialize(
|
41
|
+
def initialize(
|
42
|
+
target_dir,
|
43
|
+
system,
|
44
|
+
iomanager = FileIOManager.new(target_dir),
|
45
|
+
marshaller = DefaultMarshaller.new(),
|
46
|
+
model_serializer = DefaultModelSerializer.new(iomanager, marshaller),
|
47
|
+
store_manager = StorageManager.new(target_dir, iomanager, marshaller, model_serializer) )
|
48
|
+
|
43
49
|
@lock = Mutex.new
|
44
50
|
@target_dir, @system, @store_manager = target_dir, system, store_manager
|
45
51
|
@system = @store_manager.restore( system() )
|
@@ -48,8 +54,10 @@ module HPrevalence
|
|
48
54
|
def execute_command( command )
|
49
55
|
raise 'Invalid command' unless command.respond_to?( :execute )
|
50
56
|
@lock.synchronize {
|
57
|
+
set_time_if_requested(command)
|
58
|
+
result = command.execute( @system )
|
51
59
|
@store_manager.store( command )
|
52
|
-
|
60
|
+
result
|
53
61
|
}
|
54
62
|
end
|
55
63
|
|
@@ -63,174 +71,12 @@ module HPrevalence
|
|
63
71
|
}
|
64
72
|
end
|
65
73
|
|
66
|
-
end
|
67
|
-
|
68
|
-
#
|
69
|
-
#
|
70
|
-
class TransparentEngine < SimpleEngine
|
71
|
-
@@engines = Hash.new()
|
72
|
-
@@class_lock = Mutex.new
|
73
|
-
|
74
|
-
attr_reader :engine_id
|
75
|
-
|
76
|
-
def initialize( target_dir, system )
|
77
|
-
@proxies_lock = Mutex.new
|
78
|
-
@engine_id = Guid.new()
|
79
|
-
|
80
|
-
TransparentEngine.register_engine( self )
|
81
|
-
|
82
|
-
@proxies = Hash.new
|
83
|
-
add_engine_id_method( system )
|
84
|
-
store_manager = TransparentStorageManager.new(self, target_dir)
|
85
|
-
within_engine {
|
86
|
-
@proxied_system = HPrevalence::Transparent::TransparentProxy.new( system, Guid.from_s('00000000-0000-0000-0000-000000000000') )
|
87
|
-
}
|
88
|
-
|
89
|
-
super( target_dir, system, store_manager )
|
90
|
-
end
|
91
|
-
|
92
|
-
def system
|
93
|
-
@proxied_system
|
94
|
-
end
|
95
|
-
|
96
|
-
def close
|
97
|
-
super
|
98
|
-
TransparentEngine.unregister_engine( self )
|
99
|
-
end
|
100
|
-
|
101
|
-
def take_snapshot
|
102
|
-
@lock.synchronize {
|
103
|
-
begin
|
104
|
-
Thread.current[:references] = Hash.new
|
105
|
-
within_engine {
|
106
|
-
@store_manager.take_snapshot @proxied_system
|
107
|
-
}
|
108
|
-
ensure
|
109
|
-
Thread.current[:references] = nil
|
110
|
-
end
|
111
|
-
}
|
112
|
-
end
|
113
|
-
|
114
|
-
def execute_command(command)
|
115
|
-
begin
|
116
|
-
Thread.current[:references] = Hash.new
|
117
|
-
super(command)
|
118
|
-
ensure
|
119
|
-
Thread.current[:references] = nil
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def register_proxy(proxy)
|
124
|
-
@proxies[ proxy.proxy_id.to_s ] = proxy
|
125
|
-
end
|
126
|
-
|
127
|
-
def proxy_by_id( id, related_symbol = nil, parent_proxy_id = nil )
|
128
|
-
p = @proxies[ id.to_s ]
|
129
|
-
return p unless p.nil?
|
130
|
-
if !related_symbol.nil? && !parent_proxy_id.nil?
|
131
|
-
return create_nested_proxy( parent_proxy_id, related_symbol )
|
132
|
-
end
|
133
|
-
nil
|
134
|
-
end
|
135
|
-
|
136
|
-
def create_nested_proxy( parent_proxy_id, related_symbol )
|
137
|
-
@proxies_lock.synchronize {
|
138
|
-
parent_proxy = proxy_by_id( parent_proxy_id )
|
139
|
-
target = parent_proxy.target
|
140
|
-
nested_target = target.send( related_symbol )
|
141
|
-
new_proxy = HPrevalence::Transparent::NestedTransparentProxy.new(
|
142
|
-
nested_target, related_symbol, parent_proxy_id )
|
143
|
-
target._set_proxy( related_symbol, new_proxy )
|
144
|
-
return new_proxy
|
145
|
-
}
|
146
|
-
end
|
147
|
-
|
148
|
-
def create_result_proxy( target )
|
149
|
-
@proxies_lock.synchronize {
|
150
|
-
# parent_proxy = proxy_by_id( parent_proxy_id )
|
151
|
-
# target = parent_proxy.target
|
152
|
-
# result = target.send( related_symbol, *args )
|
153
|
-
new_proxy = HPrevalence::Transparent::TransparentProxy.new( target )
|
154
|
-
return new_proxy
|
155
|
-
}
|
156
|
-
end
|
157
|
-
|
158
|
-
def within_engine()
|
159
|
-
begin
|
160
|
-
Thread.current[:engine] = self
|
161
|
-
yield
|
162
|
-
ensure
|
163
|
-
Thread.current[:engine] = nil
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def restore(proxy)
|
168
|
-
proxy.engine_id = @engine_id
|
169
|
-
p = proxy_by_id( proxy.proxy_id )
|
170
|
-
if (p.nil?)
|
171
|
-
register_proxy(proxy)
|
172
|
-
p = proxy
|
173
|
-
end
|
174
|
-
p
|
175
|
-
end
|
176
|
-
|
177
|
-
def self.create_nested_proxy( parent_proxy_id, symbol, engine_id )
|
178
|
-
within_engine( engine_id ) { |engine|
|
179
|
-
engine.create_nested_proxy( parent_proxy_id, symbol )
|
180
|
-
}
|
181
|
-
end
|
182
|
-
|
183
|
-
def self.create_result_proxy( target, engine_id )
|
184
|
-
within_engine( engine_id ) { |engine|
|
185
|
-
engine.create_result_proxy( target )
|
186
|
-
}
|
187
|
-
end
|
188
|
-
|
189
|
-
def self.within_engine( engine_id )
|
190
|
-
engine = @@engines[ engine_id ]
|
191
|
-
raise 'Engine not found' if engine.nil?
|
192
|
-
begin
|
193
|
-
# puts 'engine>'
|
194
|
-
Thread.current[:engine] = engine
|
195
|
-
yield(engine)
|
196
|
-
ensure
|
197
|
-
Thread.current[:engine] = nil
|
198
|
-
# puts 'engine<'
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
def self.current()
|
203
|
-
engine = Thread.current[:engine]
|
204
|
-
|
205
|
-
if block_given?
|
206
|
-
# puts 'engine.current'
|
207
|
-
raise 'Engine not found' if engine.nil?
|
208
|
-
yield( engine )
|
209
|
-
# puts 'end.current'
|
210
|
-
else
|
211
|
-
return engine
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
74
|
protected
|
216
75
|
|
217
|
-
def
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
end
|
222
|
-
|
223
|
-
def self.unregister_engine( engine )
|
224
|
-
@@class_lock.synchronize {
|
225
|
-
@@engines.delete(engine.engine_id)
|
226
|
-
}
|
227
|
-
end
|
228
|
-
|
229
|
-
def add_engine_id_method( system )
|
230
|
-
temp_id = @engine_id
|
231
|
-
system.instance_eval {
|
232
|
-
@engine_id = temp_id
|
233
|
-
}
|
76
|
+
def set_time_if_requested(command)
|
77
|
+
if command.respond_to?( :now= )
|
78
|
+
command.now = Time.now()
|
79
|
+
end
|
234
80
|
end
|
235
81
|
end
|
236
82
|
|
@@ -253,6 +99,7 @@ module HPrevalence
|
|
253
99
|
def initialize( engine, snapshot_interval )
|
254
100
|
@engine = engine
|
255
101
|
@snapshot_interval = snapshot_interval
|
102
|
+
start_snapshot_thread
|
256
103
|
end
|
257
104
|
|
258
105
|
def start_snapshot_thread
|
@@ -1,65 +1,47 @@
|
|
1
1
|
|
2
|
-
class
|
3
|
-
|
4
|
-
def initialize( io )
|
2
|
+
class CommandSerializer
|
3
|
+
def initialize( io, marshaler )
|
5
4
|
raise 'Invalid stream' if io.nil?
|
6
|
-
@io = io
|
5
|
+
@io, @marshaler = io, marshaler
|
7
6
|
@io.binmode
|
8
|
-
# register_finalize()
|
9
7
|
end
|
10
8
|
|
11
9
|
def <<(command)
|
12
10
|
raise 'Invalid command' if command.nil?
|
13
|
-
|
11
|
+
@marshaler.serialize_to_stream( command, @io )
|
14
12
|
@io.flush
|
15
13
|
@io.fsync
|
16
14
|
end
|
17
15
|
|
18
|
-
def self.restore_from_io( io, system )
|
19
|
-
|
16
|
+
def self.restore_from_io( io, system, marshaler )
|
17
|
+
# Theorically this should work and its more elegant than the current version
|
20
18
|
# Marshal.load( io ) { |command|
|
21
19
|
# command.execute( system )
|
22
20
|
# }
|
23
21
|
while( !io.eof? )
|
24
|
-
command =
|
22
|
+
command = marshaler.restore( io )
|
25
23
|
command.execute( system )
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
27
|
def close
|
30
28
|
@io.close
|
31
|
-
# unregister_finalize
|
32
29
|
end
|
33
|
-
#
|
34
|
-
# protected
|
35
|
-
#
|
36
|
-
# def register_finalize
|
37
|
-
# ObjectSpace.define_finalizer( self ) {
|
38
|
-
# |logger|
|
39
|
-
# logger.close
|
40
|
-
# }
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# def unregister_finalize
|
44
|
-
# ObjectSpace.undefine_finalizer( self )
|
45
|
-
# end
|
46
|
-
|
47
30
|
end
|
48
31
|
|
49
32
|
class CommandLogger
|
50
|
-
|
51
33
|
Logger_Extension = 'commandlog'
|
52
34
|
|
53
35
|
attr_reader :current_file_name
|
54
36
|
|
55
|
-
def initialize( iomanager )
|
56
|
-
@iomanager = iomanager
|
37
|
+
def initialize( iomanager, marshaler )
|
38
|
+
@iomanager, @marshaler = iomanager, marshaler
|
57
39
|
end
|
58
40
|
|
59
41
|
def create_command_store()
|
60
42
|
stream = @iomanager.create_new_stream( Logger_Extension )
|
61
43
|
@current_file_name = stream.full_name
|
62
|
-
|
44
|
+
CommandSerializer.new( stream, @marshaler )
|
63
45
|
end
|
64
46
|
|
65
47
|
def log_files
|
@@ -69,29 +51,24 @@ class CommandLogger
|
|
69
51
|
# removes all command_logs as a snapshot has been taken
|
70
52
|
def reset_commands()
|
71
53
|
streams = @iomanager.obtain_ordered_read_streams( Logger_Extension )
|
72
|
-
|
73
54
|
streams.each do |stream|
|
74
55
|
stream.close
|
75
56
|
File.delete stream.full_name
|
76
57
|
end
|
77
|
-
|
78
58
|
end
|
79
59
|
|
80
60
|
def restore( system )
|
81
61
|
streams = @iomanager.obtain_ordered_read_streams( Logger_Extension )
|
82
62
|
|
83
63
|
begin
|
84
|
-
|
85
64
|
streams.each do |stream|
|
86
|
-
|
65
|
+
CommandSerializer.restore_from_io( stream, system, @marshaler )
|
87
66
|
end
|
88
|
-
|
89
67
|
ensure
|
90
68
|
streams.each do |stream|
|
91
69
|
stream.close
|
92
70
|
end
|
93
71
|
end
|
94
|
-
|
95
72
|
end
|
96
73
|
|
97
74
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
require 'soap/marshal'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Probably the most inneficient
|
6
|
+
# marshaller implementation
|
7
|
+
#
|
8
|
+
class SoapMarshaller
|
9
|
+
|
10
|
+
def serialize(graph)
|
11
|
+
content = SOAP::Marshal.dump(graph)
|
12
|
+
Marshal.dump( content )
|
13
|
+
end
|
14
|
+
|
15
|
+
def serialize_to_stream(graph, stream)
|
16
|
+
content = SOAP::Marshal.dump(graph)
|
17
|
+
Marshal.dump( content, stream )
|
18
|
+
end
|
19
|
+
|
20
|
+
def restore(stream)
|
21
|
+
content = Marshal.load( stream )
|
22
|
+
SOAP::Marshal.load(content)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
class YamlMarshaller
|
5
|
+
|
6
|
+
def serialize(graph)
|
7
|
+
content = YAML.dump(graph)
|
8
|
+
Marshal.dump( content )
|
9
|
+
end
|
10
|
+
|
11
|
+
def serialize_to_stream(graph, stream)
|
12
|
+
content = YAML.dump(graph)
|
13
|
+
Marshal.dump( content, stream )
|
14
|
+
end
|
15
|
+
|
16
|
+
def restore(stream)
|
17
|
+
content = Marshal.load( stream )
|
18
|
+
YAML.load(content)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
data/lib/internal/serializer.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
|
2
2
|
class DefaultModelSerializer
|
3
|
-
|
4
3
|
Snapshot_Extension = 'snapshot'
|
5
4
|
|
6
|
-
def initialize( iomanager )
|
7
|
-
@iomanager = iomanager
|
5
|
+
def initialize( iomanager, marshaller )
|
6
|
+
@iomanager, @marshaller = iomanager, marshaller
|
8
7
|
end
|
9
8
|
|
10
9
|
def dump( object_model )
|
11
10
|
begin
|
12
11
|
stream = @iomanager.create_new_stream( Snapshot_Extension )
|
13
|
-
|
12
|
+
@marshaller.serialize_to_stream( object_model, stream )
|
14
13
|
ensure
|
15
14
|
stream.close
|
16
15
|
end
|
@@ -22,7 +21,7 @@ class DefaultModelSerializer
|
|
22
21
|
return nil if stream.nil?
|
23
22
|
|
24
23
|
begin
|
25
|
-
object_model =
|
24
|
+
object_model = @marshaller.restore( stream )
|
26
25
|
ensure
|
27
26
|
stream.close
|
28
27
|
end
|
@@ -32,52 +31,39 @@ class DefaultModelSerializer
|
|
32
31
|
|
33
32
|
end
|
34
33
|
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
34
|
+
#
|
35
|
+
# TODO: VersionIndependentSerializer is intended to handle
|
36
|
+
# small modifications in the object model, like new fields or
|
37
|
+
# even excluded fields, without breaking the existing snapshots
|
38
38
|
#
|
39
|
-
|
40
|
-
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# def dump( object_model )
|
44
|
-
#
|
45
|
-
# begin
|
46
|
-
# stream = @iomanager.create_new_stream( Snapshot_Extension )
|
47
|
-
# graph = ObjectGraph.build( object_model )
|
48
|
-
# write_object_tree( stream, graph )
|
49
|
-
# ensure
|
50
|
-
# stream.close
|
51
|
-
# end
|
52
|
-
#
|
53
|
-
# end
|
54
|
-
#
|
55
|
-
# def load()
|
56
|
-
#
|
57
|
-
# object_model = nil
|
58
|
-
#
|
59
|
-
# begin
|
60
|
-
# stream = @iomanager.obtain_latest_read_stream( Snapshot_Extension )
|
61
|
-
# graph = read_object_tree( stream )
|
62
|
-
# object_model = graph.root
|
63
|
-
# ensure
|
64
|
-
# stream.close
|
65
|
-
# end
|
66
|
-
#
|
67
|
-
# object_model
|
68
|
-
#
|
69
|
-
# end
|
70
|
-
#
|
71
|
-
# protected
|
72
|
-
#
|
73
|
-
# def write_object_tree( stream, object )
|
74
|
-
# Marshal.dump( object, stream )
|
75
|
-
# end
|
76
|
-
#
|
77
|
-
# def read_object_tree( stream )
|
78
|
-
# Marshal.load( stream )
|
79
|
-
# end
|
80
|
-
#
|
81
|
-
#end
|
82
|
-
|
39
|
+
class VersionIndependentSerializer
|
40
|
+
Snapshot_Extension = 'version-ind-snapshot'
|
83
41
|
|
42
|
+
def initialize( iomanager, marshaller )
|
43
|
+
@iomanager, @marshaller = iomanager, marshaller
|
44
|
+
end
|
45
|
+
|
46
|
+
def dump( object_model )
|
47
|
+
begin
|
48
|
+
stream = @iomanager.create_new_stream( Snapshot_Extension )
|
49
|
+
@marshaller.serialize_to_stream( object_model, stream )
|
50
|
+
ensure
|
51
|
+
stream.close
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def load()
|
56
|
+
object_model = nil
|
57
|
+
stream = @iomanager.obtain_latest_read_stream( Snapshot_Extension )
|
58
|
+
return nil if stream.nil?
|
59
|
+
|
60
|
+
begin
|
61
|
+
object_model = @marshaller.restore( stream )
|
62
|
+
ensure
|
63
|
+
stream.close
|
64
|
+
end
|
65
|
+
|
66
|
+
object_model
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|