hprevalence 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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( target_dir, &system_init )
16
- ensure_dir( target_dir )
17
- system = system_init.call
18
- SimpleEngine.new( target_dir, system )
19
- end
20
-
21
- def self.build_transparent( target_dir, &system_init )
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
- TransparentEngine.new( target_dir, system )
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( target_dir, system, store_manager = StorageManager.new(target_dir) )
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
- return command.execute( @system )
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 self.register_engine( engine )
218
- @@class_lock.synchronize {
219
- @@engines[engine.engine_id] = engine
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 BinaryCommandSerializer
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
- Marshal.dump( command, @io )
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
- # Theorically this should work and its more elegant than the current version
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 = Marshal.load( io )
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
- BinaryCommandSerializer.new( stream )
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
- BinaryCommandSerializer.restore_from_io( stream, system )
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,17 @@
1
+
2
+ class DefaultMarshaller
3
+
4
+ def serialize(graph)
5
+ Marshal.dump(graph)
6
+ end
7
+
8
+ def serialize_to_stream(graph, stream)
9
+ Marshal.dump(graph, stream)
10
+ end
11
+
12
+ def restore(stream)
13
+ Marshal.restore(stream)
14
+ end
15
+
16
+ end
17
+
@@ -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
+
@@ -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
- Marshal.dump( object_model, stream )
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 = Marshal.load( stream )
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
- #class SmartModelSerializer
36
- #
37
- # Snapshot_Extension = 'ssnapshot'
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
- # def initialize( iomanager )
40
- # @iomanager = iomanager
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