DeepConnect 0.4.06

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.
@@ -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
+