DeepConnect 0.4.06

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # conf.rb -
4
+ # Copyright (C) 1996-2010 Keiju ISHITSUKA
5
+ # (Penta Advanced Labrabries, Co.,Ltd)
6
+ #
7
+
8
+ module DeepConnect
9
+ class Config
10
+ def initialize
11
+
12
+ # enable distributed garbage collection.
13
+ @ENABLE_GC = false
14
+
15
+ @KEEP_ALIVE_INTERVAL = 60
16
+ @MON_INTERVAL = 10
17
+
18
+ # debugging attributes.
19
+ @DISABLE_INFO = false
20
+
21
+ @DISPLAY_MESSAGE_TRACE = false
22
+ @MESSAGE_DISPLAY = false
23
+ @DEBUG = false
24
+ @DISPLAY_METHOD_SPEC = false
25
+ @DISPLAY_MONITOR_MESSAGE = false
26
+ @DISPLAY_KEEP_ALIVE = false
27
+
28
+ @DEBUG_REFERENCE = false
29
+ @DISPLAY_GC = false
30
+ end
31
+
32
+ attr_accessor :ENABLE_GC
33
+ attr_accessor :KEEP_ALIVE_INTERVAL
34
+ attr_accessor :MON_INTERVAL
35
+
36
+ attr_accessor :DISPLAY_MESSAGE_TRACE
37
+ attr_accessor :MESSAGE_DISPLAY
38
+ attr_accessor :DEBUG
39
+ attr_accessor :DISPLAY_METHOD_SPEC
40
+ attr_accessor :DISPLAY_MONITOR_MESSAGE
41
+ attr_accessor :DISPLAY_KEEP_ALIVE
42
+
43
+ attr_accessor :DEBUG_REFERENCE
44
+ attr_accessor :DISPLAY_GC
45
+
46
+ attr_accessor :DISABLE_INFO
47
+ end
48
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # cron.rb -
4
+ # Copyright (C) 1996-2010 Keiju ISHITSUKA
5
+ # (Penta Advanced Labrabries, Co.,Ltd)
6
+ #
7
+
8
+ @RCS_ID='-$Id: $-'
9
+
10
+ module DeepConnect
11
+
12
+ class Cron
13
+
14
+ TAB = [
15
+ [10, proc{|org, cron, t| cron.mon_10sec}],
16
+ [60, proc{|org, cron, t| cron.mon_min}],
17
+ [3060, proc{|org, cron, t| cron.mon_hour}],
18
+ [Conf.KEEP_ALIVE_INTERVAL, proc{|org, cron, t| org.keep_alive}],
19
+ ]
20
+
21
+ def initialize(organizer)
22
+ @organizer = organizer
23
+
24
+ @timer = 0
25
+ @last_exec_times = {}
26
+
27
+ @mon_mutex = Mutex.new
28
+
29
+ @prev_message10s = nil
30
+ end
31
+
32
+ attr_reader :timer
33
+ alias tick timer
34
+
35
+ def start
36
+ Thread.start do
37
+ loop do
38
+ sleep Conf.MON_INTERVAL
39
+ @timer += Conf.MON_INTERVAL
40
+
41
+ Thread.start do
42
+ @mon_mutex.synchronize do
43
+ for tab in TAB
44
+ last_time = @last_exec_times[tab]
45
+ last_time = 0 unless last_time
46
+ if @timer >= last_time + tab[0]
47
+ @last_exec_times[tab] = @timer
48
+ tab[1].call @organizer, self, @timer
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ def mon_10sec
58
+ return if @organizer.deep_spaces.size == 0
59
+
60
+ if Conf.DISPLAY_MONITOR_MESSAGE
61
+ str = ""
62
+ str.concat "Connect DeepSpaces: BEGIN\n"
63
+ for peer_id, ds in @organizer.deep_spaces.dup
64
+ str.concat "#{peer_id.inspect} => \n"
65
+ str.concat "\t#{ds}\n"
66
+ end
67
+ str.concat "Connect DeepSpaces: END\n"
68
+
69
+ if @prev_message10s != str
70
+ @prev_message10s = str
71
+ puts "MON 10SEC: #{@timer}\n", str
72
+ end
73
+ end
74
+ end
75
+
76
+ def mon_min
77
+ if Conf.DISPLAY_MONITOR_MESSAGE
78
+ puts "MON MIN: #{@timer}"
79
+ end
80
+ end
81
+
82
+ def mon_hour
83
+ if Conf.DISPLAY_MONITOR_MESSAGE
84
+ puts "MON HOUR: #{@timer}"
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+
@@ -0,0 +1,70 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # deep-fork.rb -
4
+ # Copyright (C) 1996-2010 Keiju ISHITSUKA
5
+ # (Penta Advanced Labrabries, Co.,Ltd)
6
+ #
7
+
8
+ @RCS_ID='-$Id: $-'
9
+
10
+
11
+ require "thread"
12
+
13
+ module DeepConnect
14
+
15
+ class DeepFork
16
+
17
+ def initialize(dc1, service = 0, except_closing_io = [STDIN, STDOUT, STDERR], &block)
18
+ @dc1 = dc1
19
+
20
+ @peer_pid = nil
21
+ @peer_deep_space = nil
22
+ @peer_deep_space_mx = Mutex.new
23
+ @peer_deep_space_cv = ConditionVariable.new
24
+
25
+ exp = "DeepFork_#{format("%0xd", self.object_id)}"
26
+ @dc1.export(exp, self)
27
+
28
+ @peer_pid = Process.fork {
29
+ ionos = except_closing_io.collect{|io| io.fileno}
30
+
31
+ ObjectSpace.each_object(IO) do |io|
32
+ begin
33
+ unless ionos.include?(io.fileno)
34
+ io.close
35
+ end
36
+ rescue
37
+ end
38
+ end
39
+ dc2 = DeepConnect.start(service)
40
+ ds2 = dc2.open_deepspace("localhost", @dc1.local_id)
41
+ df1 = ds2.import(exp)
42
+ df1.connect(self, $$)
43
+ block.call(dc2, ds2)
44
+ }
45
+
46
+ @peer_deep_space_mx.synchronize do
47
+ until @peer_deep_space
48
+ @peer_deep_space_cv.wait(@peer_deep_space_mx)
49
+ end
50
+ end
51
+ self
52
+ end
53
+
54
+ attr_reader :peer_deep_space
55
+ attr_reader :peer_pid
56
+
57
+ def connect(df2, peer_pid)
58
+ @peer_deep_space_mx.synchronize do
59
+ if @peer_pid == peer_pid
60
+ @peer_deep_space = df2.deep_space
61
+ @peer_deep_space_cv.signal
62
+ end
63
+ end
64
+ end
65
+
66
+ class <<self
67
+ alias fork new
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # deep-mq.rb -
4
+ # Copyright (C) 1996-2010 Keiju ISHITSUKA
5
+ # (Penta Advanced Labrabries, Co.,Ltd)
6
+ #
7
+
8
+ @RCS_ID='-$Id: $-'
9
+
10
+
11
+ require "thread"
12
+
13
+ module DeepConnect
14
+ module DeepMQ
15
+ class SV
16
+ def initialize(org)
17
+ @organizer = org
18
+ @event_q = Queue.new
19
+ start
20
+ end
21
+
22
+ def enq(session, ev)
23
+ begin
24
+ @event_q.push [session, ev]
25
+ session.accept ev.reply(nil)
26
+ rescue SystemExit
27
+ raise
28
+ rescue Exception
29
+ session.accept event.reply(ret, $!)
30
+ end
31
+ end
32
+
33
+ def start
34
+ Thread.start do
35
+ loop do
36
+ evaluate_request(*@event_q.pop)
37
+ end
38
+ end
39
+ end
40
+
41
+ def evaluate_request(session, ev)
42
+ receiver = ev.args.first
43
+ method = ev.args[1]
44
+ args = ev.args[2..-1]
45
+ callback = ev.callback
46
+ ev0 = Event::Request.request(session, receiver, method, args)
47
+ @organizer.evaluator.evaluate_mq_request(session, ev0, callback)
48
+ end
49
+ end
50
+
51
+ class CL
52
+ def initialize(sv)
53
+ @sv = sv
54
+ end
55
+
56
+ def push(ref, method, *arg, &callback)
57
+ @sv.deep_space.session.mq_send_to(@sv, :push, [ref, method, *arg], callback)
58
+ end
59
+ # Organizer::def_method_spec(SV, "push(DEFAULT, DEFAULT, VAL)")
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,403 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # deep-space.rb -
4
+ # Copyright (C) 1996-2010 Keiju ISHITSUKA
5
+ # (Penta Advanced Labrabries, Co.,Ltd)
6
+ #
7
+
8
+ require "thread"
9
+ require "forwardable"
10
+
11
+ require "ipaddr"
12
+
13
+ require "deep-connect/session"
14
+ require "deep-connect/class-spec-space"
15
+
16
+ module DeepConnect
17
+ class DeepSpace
18
+ extend Forwardable
19
+
20
+ def initialize(org, port, local_id = nil)
21
+ @status = :INITIALIZE
22
+
23
+ @organizer = org
24
+ @session = Session.new(self, port, local_id)
25
+
26
+ unless local_id
27
+ local_id = port.peeraddr[1]
28
+ end
29
+
30
+ addr = port.peeraddr[3]
31
+ ipaddr = IPAddr.new(addr)
32
+ # ipaddr = ipaddr.ipv4_mapped if ipaddr.ipv4?
33
+ ipaddr = ipaddr.native
34
+
35
+ @peer_uuid = [ipaddr.to_s, local_id]
36
+
37
+ init_class_spec_feature
38
+ init_export_feature
39
+ init_import_feature
40
+ end
41
+
42
+ attr_reader :status
43
+ attr_reader :organizer
44
+ attr_reader :session
45
+ attr_reader :peer_uuid
46
+ alias peer_id peer_uuid
47
+
48
+ def close
49
+ @organizer.close_deepspace(self)
50
+ end
51
+
52
+ def connect
53
+ @session.start
54
+
55
+ @deregister_reference_thread = start_deregister_reference
56
+
57
+ @status = :SERVICING
58
+ end
59
+
60
+ def disconnect(*opts)
61
+ org_status = @status
62
+ @status = :SERVICE_STOP
63
+
64
+ @session.stop_service(*opts)
65
+ if !opts.include?(:SESSION_CLOSED) && !opts.include?(:REQUEST_FROM_PEER)
66
+ @session.send_disconnect
67
+ end
68
+ @session.stop
69
+
70
+ @deregister_reference_thread.exit if org_status == :SERVICING
71
+ @import_reference = nil
72
+ @export_roots = nil
73
+ end
74
+
75
+ def import(name, waitp = false)
76
+ @session.get_service(name, waitp)
77
+ end
78
+ alias get_service import
79
+
80
+ def import_mq(name, waitp = false)
81
+ sv = @session.import_mq(name, waitp)
82
+ DeepMQ::CL.new(sv)
83
+ end
84
+ alias get_mq import_mq
85
+
86
+ #
87
+ # class spec feature
88
+ #
89
+ def init_class_spec_feature
90
+ # class spec
91
+ @class_spec_space = ClassSpecSpace.new(:remote)
92
+ end
93
+
94
+ def_delegator :@class_spec_space, :class_specs=
95
+ def_delegator :@class_spec_space, :method_spec
96
+ def_delegator :@class_spec_space, :class_spec_id_of
97
+ alias csid_of class_spec_id_of
98
+
99
+ def my_method_spec(obj, method)
100
+ Organizer::method_spec(obj, method)
101
+ end
102
+
103
+ def my_csid_of(obj)
104
+ Organizer::class_spec_id_of(obj)
105
+ end
106
+
107
+ def recv_class_spec(cspecs)
108
+ cspecs.each{|cspec| add_class_spec(cspec)}
109
+ make_class_spec_cache(cspecs.first)
110
+ end
111
+
112
+ def make_class_spec_cache(cspec)
113
+ cache = ClassSpec.new
114
+ end
115
+
116
+ #
117
+ # export root 関連メソッド
118
+ #
119
+ def init_export_feature
120
+ # exportしているオブジェクト
121
+ @export_roots_mutex = Mutex.new
122
+ @export_roots = {}
123
+ end
124
+
125
+ def release_object(obj)
126
+ @export_roots_mutex.synchronize do
127
+ @export_roots.delete(obj.object_id)
128
+ end
129
+ end
130
+
131
+ def set_root(root)
132
+ #if root.kind_of?(Proc)
133
+ # puts "SET_ROOT: #{root}\n #{caller(0)}"
134
+ #end
135
+ @export_roots_mutex.synchronize do
136
+ if pair = @export_roots[root.object_id]
137
+ pair[1] += 1
138
+ else
139
+ @export_roots[root.object_id] = [root, 1]
140
+ end
141
+ root.object_id
142
+ end
143
+ end
144
+ alias set_export_root set_root
145
+
146
+ def root(id)
147
+ @export_roots_mutex.synchronize do
148
+ pair = @export_roots.fetch(id){return IllegalObject.new(id)}
149
+ pair.first
150
+ #@export_roots.fetch(id){:__DEEPCONNECT_NO_VALUE__}
151
+ end
152
+ end
153
+ alias export_root root
154
+
155
+ def register_root_from_other_session(id)
156
+ obj = @organizer.id2obj(id)
157
+ @export_roots_mutex.synchronize do
158
+ if pair = @export_roots[id]
159
+ pair[1] += 1
160
+ else
161
+ @export_roots[id] = [obj, 1]
162
+ end
163
+ end
164
+ obj
165
+ end
166
+
167
+ def delete_roots(pairs)
168
+ @export_roots_mutex.synchronize do
169
+ pairs.each_slice(2) do |id, refcount|
170
+ if pair = @export_roots[id]
171
+ # puts "#{$$}: GC: #{id} #{refcount} #{pair.first.class} #{pair.last}"
172
+
173
+ if (pair[1] -= refcount) == 0
174
+ obj = @export_roots.delete(id)
175
+ if Conf.DISPLAY_GC
176
+ puts "#{$$}: GC: delete root: #{id} #{obj.first.to_s}"
177
+ end
178
+ else
179
+ if Conf.DISPLAY_GC
180
+ puts "#{$$}: GC: derefcount root: #{id} #{pair.first.to_s} #{pair[1]}"
181
+ if pair.first.kind_of?(Exception)
182
+ p pair.first
183
+ p pair.first.backtrace
184
+ end
185
+ end
186
+ end
187
+ else
188
+ if Conf.DISPLAY_GC
189
+ puts "#{$$}: GC: warn already deleted root: #{id.inspect}"
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ #
197
+ # import 関連メソッド
198
+ #
199
+ def init_import_feature
200
+ # importしているオブジェクト
201
+ # peer_id => ref_id
202
+ @import_reference = {}
203
+ @rev_import_reference = {}
204
+
205
+ @import_reference_mutex = Mutex.new
206
+ @import_reference_cv = ConditionVariable.new
207
+ @deregister_reference_queue = []
208
+
209
+ @deregister_thread = nil
210
+ end
211
+
212
+ def import_reference(peer_id)
213
+ return import_reference_for_disable_gc(peer_id) unless Conf.ENABLE_GC
214
+
215
+ status = GC.disable
216
+ begin
217
+ @import_reference_mutex.synchronize do
218
+ if pair = @import_reference[peer_id]
219
+ begin
220
+ ObjectSpace._id2ref(pair.first)
221
+ rescue
222
+ ref_id = @import_reference.delete(peer_id)
223
+ @rev_import_reference.delete(ref_id)
224
+ @deregister_reference_queue.concat [peer_id, 1]
225
+ return nil
226
+ end
227
+ else
228
+ nil
229
+ end
230
+ end
231
+ ensure
232
+ GC.enable unless status
233
+ end
234
+ end
235
+
236
+ def import_reference_for_disable_gc(peer_id)
237
+ @import_reference_mutex.synchronize do
238
+ if pair = @import_reference[peer_id]
239
+ pair.first
240
+ else
241
+ nil
242
+ end
243
+ end
244
+ end
245
+
246
+ def register_import_reference(ref)
247
+ return register_import_reference_for_disable_gc(ref) unless Conf.ENABLE_GC
248
+
249
+ status = GC.disable
250
+ begin
251
+ @import_reference_mutex.synchronize do
252
+ if pair = @import_reference[ref.peer_id]
253
+ pair[1] += 1
254
+ else
255
+ @import_reference[ref.peer_id] = [ref.object_id, 1]
256
+ @rev_import_reference[ref.object_id] = ref.peer_id
257
+ end
258
+ end
259
+ ObjectSpace.define_finalizer(ref, deregister_import_reference_proc)
260
+ ensure
261
+ GC.enable unless status
262
+ end
263
+ end
264
+
265
+ def register_import_reference_for_disable_gc(ref)
266
+ @import_reference_mutex.synchronize do
267
+ if pair = @import_reference[ref.peer_id]
268
+ pair[1] += 1
269
+ else
270
+ @import_reference[ref.peer_id] = [ref, 1]
271
+ end
272
+ end
273
+ end
274
+
275
+ def deregister_import_reference(ref)
276
+ return deregister_import_reference_for_disable_gc(ref) unless Conf.ENABLE_GC
277
+ status = GC.disable
278
+ begin
279
+ @import_reference_mutex.synchronize do
280
+ pair = @import_reference.delete(ref.peer_id)
281
+ @rev_import_reference.delete(pair.first)
282
+ @deregister_reference_queue.concat [ref.peer_id, pair.last]
283
+ end
284
+ ensure
285
+ GC.enable unless status
286
+ @deregister_thread.wakeup
287
+ end
288
+ end
289
+
290
+ def deregister_import_reference_for_disable_gc(ref)
291
+ status = GC.disable
292
+ begin
293
+ @import_reference_mutex.synchronize do
294
+ pair = @import_reference.delete(ref.peer_id)
295
+ @deregister_reference_queue.concat [ref.peer_id, pair.last]
296
+ end
297
+ ensure
298
+ GC.enable unless status
299
+ @deregister_thread.wakeup
300
+ end
301
+ end
302
+
303
+ def deregister_import_reference_proc
304
+ proc do |ref_id|
305
+ if @status == :SERVICING
306
+ puts "#{$$}: GC: gced id: #{ref_id}" if Conf.DISPLAY_GC
307
+ peer_id = @rev_import_reference.delete(ref_id)
308
+ pair = @import_reference.delete(peer_id)
309
+ @deregister_reference_queue.concat [peer_id, pair.last]
310
+ @deregister_thread.wakeup
311
+ end
312
+ end
313
+ end
314
+
315
+ def start_deregister_reference_org
316
+ @deregister_thread = Thread.start {
317
+ ids = []
318
+ while ids.push @deregister_reference_queue.pop
319
+ begin
320
+ while ids.push @deregister_reference_queue.pop(true); end
321
+ rescue ThreadError
322
+ deregister_roots_to_peer(ids) if @status == :SERVICING
323
+ end
324
+ end
325
+ }
326
+ end
327
+
328
+ def start_deregister_reference
329
+ @deregister_thread = Thread.start {
330
+ ids = []
331
+ loop do
332
+ Thread.stop
333
+ Thread.exit unless @status == :SERVICING
334
+
335
+ ids = []
336
+ @import_reference_mutex.synchronize do
337
+ status = GC.disable
338
+ begin
339
+ ids = @deregister_reference_queue.dup
340
+ @deregister_reference_queue.clear
341
+ ensure
342
+ GC.enable unless status
343
+ end
344
+ end
345
+ unless ids.empty?
346
+ deregister_roots_to_peer(ids)
347
+ end
348
+ sleep 1
349
+ end
350
+ }
351
+ end
352
+
353
+ def register_root_to_peer(id)
354
+ unless import_reference(id)
355
+ @session.register_root_to_peer(id)
356
+ end
357
+ end
358
+
359
+ def deregister_roots_to_peer(ids)
360
+ puts "#{$$}: GC: send deregister id: #{ids.join(' ')}" if Conf.DISPLAY_GC
361
+ @session.deregister_root_to_peer(ids)
362
+ end
363
+
364
+ end
365
+
366
+ class DeepSpaceNoConnection
367
+ def initialize(peer_id)
368
+ @peer_id = peer_id
369
+ end
370
+
371
+ attr_reader :peer_id
372
+ alias peer_uuid peer_id
373
+
374
+ def session
375
+ DC::Raise ConnectionRefused, @peer_id
376
+ end
377
+ def register_import_reference(r)
378
+ nil
379
+ end
380
+
381
+ def import_reference(r)
382
+ nil
383
+ end
384
+
385
+ def register_root_to_peer(object_id)
386
+ # do nothing
387
+ end
388
+
389
+ end
390
+
391
+ class IllegalObject
392
+ def initialize(id)
393
+ @id = id
394
+ end
395
+
396
+ def send(*opts)
397
+ DC.Raise IllegalReference, @id, opts.first
398
+ end
399
+ alias __send__ send
400
+ alias __public_send__ send
401
+ end
402
+ end
403
+