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.
- data/lib/deep-connect.rb +83 -0
- data/lib/deep-connect/accepter.rb +64 -0
- data/lib/deep-connect/class-spec-space.rb +652 -0
- data/lib/deep-connect/conf.rb +48 -0
- data/lib/deep-connect/cron.rb +91 -0
- data/lib/deep-connect/deep-fork.rb +70 -0
- data/lib/deep-connect/deep-mq.rb +62 -0
- data/lib/deep-connect/deep-space.rb +403 -0
- data/lib/deep-connect/evaluator.rb +149 -0
- data/lib/deep-connect/event.rb +551 -0
- data/lib/deep-connect/exceptions.rb +38 -0
- data/lib/deep-connect/future.rb +67 -0
- data/lib/deep-connect/organizer.rb +378 -0
- data/lib/deep-connect/port.rb +151 -0
- data/lib/deep-connect/reference.rb +422 -0
- data/lib/deep-connect/serialize.rb +127 -0
- data/lib/deep-connect/session.rb +348 -0
- data/lib/deep-connect/version.rb +8 -0
- metadata +86 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# serialize.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
# --
|
8
|
+
#
|
9
|
+
#
|
10
|
+
#
|
11
|
+
|
12
|
+
require "deep-connect/reference"
|
13
|
+
|
14
|
+
module DeepConnect
|
15
|
+
UNSERIALIZABLE_CLASSES = [
|
16
|
+
Binding,
|
17
|
+
UnboundMethod,
|
18
|
+
Method,
|
19
|
+
Proc,
|
20
|
+
Dir,
|
21
|
+
File,
|
22
|
+
IO,
|
23
|
+
ThreadGroup,
|
24
|
+
Thread,
|
25
|
+
Data,
|
26
|
+
# Class,
|
27
|
+
# Module,
|
28
|
+
]
|
29
|
+
if defined?(Continuation)
|
30
|
+
UNSERIALIZABLE_CLASSES.push Continuation
|
31
|
+
end
|
32
|
+
if defined?(StopIteration)
|
33
|
+
UNSERIALIZABLE_CLASSES.push StopIteration
|
34
|
+
end
|
35
|
+
if defined?(Enumerable::Enumerator)
|
36
|
+
UNSERIALIZABLE_CLASSES.push Enumerable::Enumerator
|
37
|
+
end
|
38
|
+
|
39
|
+
UNSERIALIZABLE_CLASS_SET = {}
|
40
|
+
UNSERIALIZABLE_CLASSES.each do|k|
|
41
|
+
UNSERIALIZABLE_CLASS_SET[k] = k
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Object
|
46
|
+
def self.deep_connect_materialize_val(deep_space, value)
|
47
|
+
obj = allocate
|
48
|
+
value.each do |v, o|
|
49
|
+
obj.instance_variable_set(v, DeepConnect::Reference.materialize(deep_space, *o))
|
50
|
+
end
|
51
|
+
obj
|
52
|
+
end
|
53
|
+
|
54
|
+
def deep_connect_serialize_val(deep_space)
|
55
|
+
if DeepConnect::UNSERIALIZABLE_CLASS_SET.include?(self.class)
|
56
|
+
DeepConnect.Raise CantSerializable, self.class.name
|
57
|
+
end
|
58
|
+
vnames = instance_variables
|
59
|
+
vnames.collect{|v|
|
60
|
+
[v,
|
61
|
+
DeepConnect::Reference.serialize(deep_space, instance_variable_get(v))]}
|
62
|
+
end
|
63
|
+
|
64
|
+
def deep_connect_dup
|
65
|
+
if DeepConnect::UNSERIALIZABLE_CLASS_SET.include?(self.class)
|
66
|
+
DeepConnect.Raise CantDup, self.class.name
|
67
|
+
end
|
68
|
+
self
|
69
|
+
end
|
70
|
+
alias dc_dup deep_connect_dup
|
71
|
+
DeepConnect.def_method_spec(self, :rets=>"VAL", :method=>:deep_connect_dup)
|
72
|
+
DeepConnect.def_method_spec(self, :rets=>"VAL", :method=>:dc_dup)
|
73
|
+
|
74
|
+
def deep_connect_deep_copy
|
75
|
+
if DeepConnect::UNSERIALIZABLE_CLASS_SET.include?(self.class)
|
76
|
+
DeepConnect.Raise CantDeepCopy, self.class.name
|
77
|
+
end
|
78
|
+
self
|
79
|
+
end
|
80
|
+
alias dc_deep_copy deep_connect_deep_copy
|
81
|
+
DeepConnect.def_method_spec(self, :rets=>"DVAL", :method=>:deep_connect_deep_copy)
|
82
|
+
DeepConnect.def_method_spec(self, :rets=>"DVAL", :method=>:dc_deep_copy)
|
83
|
+
end
|
84
|
+
|
85
|
+
class Array
|
86
|
+
def self.deep_connect_materialize_val(deep_space, value)
|
87
|
+
ary = new
|
88
|
+
value.each{|e| ary.push DeepConnect::Reference.materialize(deep_space, *e)}
|
89
|
+
ary
|
90
|
+
end
|
91
|
+
|
92
|
+
def deep_connect_serialize_val(deep_space)
|
93
|
+
collect{|e| DeepConnect::Reference.serialize(deep_space, e)}
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
class Hash
|
99
|
+
def self.deep_connect_materialize_val(deep_space, value)
|
100
|
+
hash = new
|
101
|
+
value.each do |k, v|
|
102
|
+
key = DeepConnect::Reference.materialize(deep_space, *k)
|
103
|
+
value = DeepConnect::Reference.materialize(deep_space, *v)
|
104
|
+
hash[key] = value
|
105
|
+
end
|
106
|
+
hash
|
107
|
+
end
|
108
|
+
|
109
|
+
def deep_connect_serialize_val(deep_space)
|
110
|
+
collect{|k, v|
|
111
|
+
[DeepConnect::Reference.serialize(deep_space, k),
|
112
|
+
DeepConnect::Reference.serialize(deep_space, v)]}
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
class Struct
|
118
|
+
def self.deep_connect_materialize_val(deep_space, value)
|
119
|
+
new(*value.collect{|e| DeepConnect::Reference.materialize(deep_space, *e)})
|
120
|
+
end
|
121
|
+
|
122
|
+
def deep_connect_serialize_val(deep_space)
|
123
|
+
to_a.collect{|e| DeepConnect::Reference.serialize(deep_space, e)}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
@@ -0,0 +1,348 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# session.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
# --
|
8
|
+
#
|
9
|
+
#
|
10
|
+
#
|
11
|
+
|
12
|
+
require "thread"
|
13
|
+
#require "mutex_m"
|
14
|
+
require "weakref"
|
15
|
+
|
16
|
+
require "ipaddr"
|
17
|
+
|
18
|
+
require "deep-connect/exceptions"
|
19
|
+
|
20
|
+
module DeepConnect
|
21
|
+
class Session
|
22
|
+
|
23
|
+
def initialize(deep_space, port, local_id = nil)
|
24
|
+
@status = :INITIALIZE
|
25
|
+
|
26
|
+
@organizer = deep_space.organizer
|
27
|
+
@deep_space = deep_space
|
28
|
+
@port = port
|
29
|
+
|
30
|
+
@export_queue = Queue.new
|
31
|
+
|
32
|
+
@waiting = Hash.new
|
33
|
+
@waiting_mutex = Mutex.new
|
34
|
+
@next_request_event_id = 0
|
35
|
+
@next_request_event_id_mutex = Mutex.new
|
36
|
+
|
37
|
+
@last_keep_alive = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :organizer
|
41
|
+
attr_reader :deep_space
|
42
|
+
|
43
|
+
def peer_uuid
|
44
|
+
@deep_space.peer_uuid
|
45
|
+
end
|
46
|
+
alias peer_id peer_uuid
|
47
|
+
|
48
|
+
def start
|
49
|
+
@last_keep_alive = @organizer.tick
|
50
|
+
|
51
|
+
@status = :SERVICING
|
52
|
+
send_class_specs
|
53
|
+
|
54
|
+
@import_thread = Thread.start {
|
55
|
+
loop do
|
56
|
+
begin
|
57
|
+
ev = @port.import
|
58
|
+
@last_keep_alive = @organizer.tick
|
59
|
+
rescue EOFError, DC::DisconnectClient
|
60
|
+
# EOFError: クライアントが閉じていた場合
|
61
|
+
# DisconnectClient: 通信中にクライアント接続が切れた
|
62
|
+
Thread.start do
|
63
|
+
@organizer.disconnect_deep_space(@deep_space, :SESSION_CLOSED)
|
64
|
+
end
|
65
|
+
Thread.stop
|
66
|
+
rescue DC::ProtocolError
|
67
|
+
# 何らかの障害のためにプロトコルが正常じゃなくなった
|
68
|
+
end
|
69
|
+
if @status == :SERVICING
|
70
|
+
receive(ev)
|
71
|
+
else
|
72
|
+
puts "INFO: service is stoped, imported event abandoned(#{ev.inspect})"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
}
|
76
|
+
|
77
|
+
@export_thread = Thread.start {
|
78
|
+
loop do
|
79
|
+
ev = @export_queue.pop
|
80
|
+
if @status == :SERVICING
|
81
|
+
begin
|
82
|
+
# export中にexportが発生するとデッドロックになる
|
83
|
+
# threadが欲しいか?
|
84
|
+
# Thread.start do
|
85
|
+
@port.export(ev)
|
86
|
+
# end
|
87
|
+
rescue Errno::EPIPE, DC::DisconnectClient
|
88
|
+
# EPIPE: クライアントが終了している
|
89
|
+
# DisconnectClient: 通信中にクライアント接続が切れた
|
90
|
+
Thread.start do
|
91
|
+
@organizer.disconnect_deep_space(@deep_space, :SESSION_CLOSED)
|
92
|
+
end
|
93
|
+
Thread.stop
|
94
|
+
end
|
95
|
+
else
|
96
|
+
puts "INFO: service is stoped, export event abandoned(#{ev.inspect})"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
}
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
def stop_service(*opts)
|
104
|
+
unless Conf.DISABLE_INFO
|
105
|
+
puts "INFO: STOP_SERVICE: Session: #{self.peer_uuid} #{opts.join(' ')} "
|
106
|
+
end
|
107
|
+
org_status = @status
|
108
|
+
@status = :SERVICE_STOP
|
109
|
+
|
110
|
+
if !opts.include?(:SESSION_CLOSED)
|
111
|
+
@port.shutdown_reading
|
112
|
+
end
|
113
|
+
|
114
|
+
if org_status == :SERVICING
|
115
|
+
@import_thread.exit
|
116
|
+
@export_thread.exit
|
117
|
+
|
118
|
+
@waiting_mutex.synchronize do
|
119
|
+
waiting_events = @waiting.sort{|s1, s2| s1[0] <=> s2[0]}
|
120
|
+
for seq, ev in waiting_events
|
121
|
+
begin
|
122
|
+
p ev
|
123
|
+
DC.Raise SessionServiceStopped
|
124
|
+
rescue
|
125
|
+
ev.result = ev.reply(nil, $!)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
@waiting.clear
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def stop(*opts)
|
135
|
+
begin
|
136
|
+
@port.close
|
137
|
+
rescue IOError
|
138
|
+
puts "WARN: #{$!}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# peerからの受取り
|
143
|
+
def receive(ev)
|
144
|
+
case ev
|
145
|
+
when Event::MQRequest
|
146
|
+
# Thread.start{ev.receiver.enq(self, ev)}
|
147
|
+
ev.receiver.enq(self, ev)
|
148
|
+
when Event::IteratorCallBackRequest
|
149
|
+
Thread.start{@organizer.evaluator.evaluate_block_yield(self, ev)}
|
150
|
+
when Event::IteratorRequest
|
151
|
+
Thread.start{@organizer.evaluator.evaluate_iterator_request(self, ev)}
|
152
|
+
when Event::Request
|
153
|
+
Thread.start{@organizer.evaluator.evaluate_request(self, ev)}
|
154
|
+
else
|
155
|
+
req = nil
|
156
|
+
@waiting_mutex.synchronize do
|
157
|
+
req = @waiting.delete(ev.seq)
|
158
|
+
end
|
159
|
+
unless req
|
160
|
+
DC.InternalError "対応する request eventがありません(#{ev.inspect})"
|
161
|
+
end
|
162
|
+
req.result = ev
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# イベントの受け取り
|
167
|
+
def accept(ev)
|
168
|
+
@export_queue.push ev
|
169
|
+
end
|
170
|
+
|
171
|
+
# イベントの生成/送信
|
172
|
+
def send_to(ref, method, args=[], &block)
|
173
|
+
unless @status == :SERVICING
|
174
|
+
DC.Raise SessionServiceStopped
|
175
|
+
end
|
176
|
+
if iterator?
|
177
|
+
ev = Event::IteratorRequest.request(self, ref, method, args, block)
|
178
|
+
else
|
179
|
+
ev = Event::Request.request(self, ref, method, args)
|
180
|
+
end
|
181
|
+
@waiting_mutex.synchronize do
|
182
|
+
@waiting[ev.seq] = ev
|
183
|
+
end
|
184
|
+
@export_queue.push ev
|
185
|
+
ev.result
|
186
|
+
end
|
187
|
+
|
188
|
+
def block_yield(event, args)
|
189
|
+
ev = Event::IteratorCallBackRequest.call_back_event(event, args)
|
190
|
+
@waiting_mutex.synchronize do
|
191
|
+
@waiting[ev.seq] = ev
|
192
|
+
end
|
193
|
+
@export_queue.push ev
|
194
|
+
ev
|
195
|
+
end
|
196
|
+
|
197
|
+
def asynchronus_send_to(ref, method, args=[], callback=nil)
|
198
|
+
unless @status == :SERVICING
|
199
|
+
DC.Raise SessionServiceStopped
|
200
|
+
end
|
201
|
+
ev = Event::AsyncronusRequest.request(self, ref, method, args, callback)
|
202
|
+
@waiting_mutex.synchronize do
|
203
|
+
@waiting[ev.seq] = ev
|
204
|
+
end
|
205
|
+
@export_queue.push ev
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
alias asyncronus_send_to asynchronus_send_to
|
209
|
+
|
210
|
+
def mq_send_to(ref, method, args=[], callback=nil)
|
211
|
+
unless @status == :SERVICING
|
212
|
+
DC.Raise SessionServiceStopped
|
213
|
+
end
|
214
|
+
ev = Event::MQRequest.request(self, ref, method, args, callback)
|
215
|
+
@waiting_mutex.synchronize do
|
216
|
+
@waiting[ev.seq] = ev
|
217
|
+
end
|
218
|
+
@export_queue.push ev
|
219
|
+
ev.result
|
220
|
+
end
|
221
|
+
|
222
|
+
# イベントID取得
|
223
|
+
def next_request_event_id
|
224
|
+
@next_request_event_id_mutex.synchronize do
|
225
|
+
@next_request_event_id += 1
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def send_peer_session(req, *args)
|
230
|
+
ev = Event::SessionRequest.request(self, (req.id2name+"_impl").intern, args)
|
231
|
+
@waiting_mutex.synchronize do
|
232
|
+
@waiting[ev.seq] = ev
|
233
|
+
end
|
234
|
+
@export_queue.push ev
|
235
|
+
ev.result
|
236
|
+
end
|
237
|
+
|
238
|
+
def send_peer_session_no_recv(req, *args)
|
239
|
+
ev = Event::SessionRequestNoReply.request(self, (req.id2name+"_impl").intern, args)
|
240
|
+
@export_queue.push ev
|
241
|
+
end
|
242
|
+
|
243
|
+
def send_disconnect
|
244
|
+
return unless @status == :SERVICING
|
245
|
+
|
246
|
+
ev = Event::SessionRequestNoReply.request(self, :recv_disconnect)
|
247
|
+
@port.export(ev)
|
248
|
+
end
|
249
|
+
|
250
|
+
def recv_disconnect
|
251
|
+
@organizer.disconnect_deep_space(@deep_space, :REQUEST_FROM_PEER)
|
252
|
+
end
|
253
|
+
Organizer.def_interface(self, :recv_disconnect)
|
254
|
+
|
255
|
+
|
256
|
+
def get_service(name, waitp = false)
|
257
|
+
if (sv = send_peer_session(:get_service, name, waitp)) == :DEEPCONNECT_NO_SUCH_SERVICE
|
258
|
+
DC.Raise NoServiceError, name
|
259
|
+
end
|
260
|
+
sv
|
261
|
+
end
|
262
|
+
|
263
|
+
def get_service_impl(name, waitp = false)
|
264
|
+
@organizer.service(name, waitp)
|
265
|
+
end
|
266
|
+
Organizer.def_interface(self, :get_service_impl)
|
267
|
+
|
268
|
+
def import_mq(name, waitp = false)
|
269
|
+
unless sv = send_peer_session(:import_mq, name, waitp)
|
270
|
+
DC.Raise NoServiceError, name
|
271
|
+
end
|
272
|
+
sv
|
273
|
+
end
|
274
|
+
|
275
|
+
def import_mq_impl(name, waitp = false)
|
276
|
+
@organizer.get_mq(name, waitp)
|
277
|
+
end
|
278
|
+
Organizer.def_interface(self, :import_mq_impl)
|
279
|
+
|
280
|
+
|
281
|
+
def register_root_to_peer(id)
|
282
|
+
# 同期を取るためにno_recvはNG
|
283
|
+
send_peer_session(:register_root, id)
|
284
|
+
end
|
285
|
+
|
286
|
+
def register_root_impl(id)
|
287
|
+
@deep_space.register_root_from_other_session(id)
|
288
|
+
end
|
289
|
+
Organizer.def_interface(self, :register_root_impl)
|
290
|
+
|
291
|
+
def deregister_root_to_peer(ids)
|
292
|
+
idsdump = Marshal.dump(ids)
|
293
|
+
send_peer_session_no_recv(:deregister_root, idsdump)
|
294
|
+
end
|
295
|
+
|
296
|
+
def deregister_root_impl(idsdump)
|
297
|
+
ids = Marshal.load(idsdump)
|
298
|
+
@deep_space.delete_roots(ids)
|
299
|
+
nil
|
300
|
+
end
|
301
|
+
Organizer.def_interface(self, :deregister_root_impl)
|
302
|
+
|
303
|
+
def send_class_specs
|
304
|
+
specs_dump = Marshal.dump(Organizer::class_specs)
|
305
|
+
send_peer_session_no_recv(:recv_class_specs, specs_dump)
|
306
|
+
end
|
307
|
+
|
308
|
+
def recv_class_specs_impl(specs_dump)
|
309
|
+
specs = Marshal.load(specs_dump)
|
310
|
+
@deep_space.class_specs = specs
|
311
|
+
#p specs
|
312
|
+
end
|
313
|
+
Organizer.def_interface(self, :recv_class_specs_impl)
|
314
|
+
|
315
|
+
|
316
|
+
# def send_class_specs(cspecs)
|
317
|
+
# specs_dump = Marshal.dump(cspecs)
|
318
|
+
# ret = send_peer_session(:send_class_specs_impl, cspecs)
|
319
|
+
# end
|
320
|
+
|
321
|
+
# def send_class_specs_impl(spec_dump)
|
322
|
+
# specs = Marshal.load(spec_dump)
|
323
|
+
# @object_space.recv_class_specs(specs)
|
324
|
+
# end
|
325
|
+
|
326
|
+
def keep_alive
|
327
|
+
now = @organizer.tick
|
328
|
+
if now > @last_keep_alive + Conf.KEEP_ALIVE_INTERVAL*10
|
329
|
+
puts "KEEP ALIVE: session #{self} is dead." if Conf.DISPLAY_KEEP_ALIVE
|
330
|
+
false
|
331
|
+
else
|
332
|
+
if Conf.DISPLAY_KEEP_ALIVE
|
333
|
+
puts "KEEP ALIVE: session #{self} is alive(INT: #{now - @last_keep_alive})."
|
334
|
+
puts "KEEP ALIVE: send #{self} to keep alive."
|
335
|
+
end
|
336
|
+
send_peer_session_no_recv(:recv_keep_alive)
|
337
|
+
true
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def recv_keep_alive_impl
|
342
|
+
puts "RECV_KEEP_ALIVE" if Conf.DISPLAY_KEEP_ALIVE
|
343
|
+
@last_keep_alive = @organizer.tick
|
344
|
+
end
|
345
|
+
Organizer.def_interface(self, :recv_keep_alive_impl)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|