roby 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +29 -0
- data/History.txt +4 -0
- data/License-fr.txt +519 -0
- data/License.txt +515 -0
- data/Manifest.txt +245 -0
- data/NOTES +4 -0
- data/README.txt +163 -0
- data/Rakefile +161 -0
- data/TODO.txt +146 -0
- data/app/README.txt +24 -0
- data/app/Rakefile +8 -0
- data/app/config/ROBOT.rb +5 -0
- data/app/config/app.yml +91 -0
- data/app/config/init.rb +7 -0
- data/app/config/roby.yml +3 -0
- data/app/controllers/.gitattributes +0 -0
- data/app/controllers/ROBOT.rb +2 -0
- data/app/data/.gitattributes +0 -0
- data/app/planners/ROBOT/main.rb +6 -0
- data/app/planners/main.rb +5 -0
- data/app/scripts/distributed +3 -0
- data/app/scripts/generate/bookmarks +3 -0
- data/app/scripts/replay +3 -0
- data/app/scripts/results +3 -0
- data/app/scripts/run +3 -0
- data/app/scripts/server +3 -0
- data/app/scripts/shell +3 -0
- data/app/scripts/test +3 -0
- data/app/tasks/.gitattributes +0 -0
- data/app/tasks/ROBOT/.gitattributes +0 -0
- data/bin/roby +210 -0
- data/bin/roby-log +168 -0
- data/bin/roby-shell +25 -0
- data/doc/images/event_generalization.png +0 -0
- data/doc/images/exception_propagation_1.png +0 -0
- data/doc/images/exception_propagation_2.png +0 -0
- data/doc/images/exception_propagation_3.png +0 -0
- data/doc/images/exception_propagation_4.png +0 -0
- data/doc/images/exception_propagation_5.png +0 -0
- data/doc/images/replay_handler_error.png +0 -0
- data/doc/images/replay_handler_error_0.png +0 -0
- data/doc/images/replay_handler_error_1.png +0 -0
- data/doc/images/roby_cycle_overview.png +0 -0
- data/doc/images/roby_replay_02.png +0 -0
- data/doc/images/roby_replay_03.png +0 -0
- data/doc/images/roby_replay_04.png +0 -0
- data/doc/images/roby_replay_event_representation.png +0 -0
- data/doc/images/roby_replay_first_state.png +0 -0
- data/doc/images/roby_replay_relations.png +0 -0
- data/doc/images/roby_replay_startup.png +0 -0
- data/doc/images/task_event_generalization.png +0 -0
- data/doc/papers.rdoc +11 -0
- data/doc/styles/allison.css +314 -0
- data/doc/styles/allison.js +316 -0
- data/doc/styles/allison.rb +276 -0
- data/doc/styles/jamis.rb +593 -0
- data/doc/tutorials/01-GettingStarted.rdoc +86 -0
- data/doc/tutorials/02-GoForward.rdoc +220 -0
- data/doc/tutorials/03-PlannedPath.rdoc +268 -0
- data/doc/tutorials/04-EventPropagation.rdoc +236 -0
- data/doc/tutorials/05-ErrorHandling.rdoc +319 -0
- data/doc/tutorials/06-Overview.rdoc +40 -0
- data/doc/videos.rdoc +69 -0
- data/ext/droby/dump.cc +175 -0
- data/ext/droby/extconf.rb +3 -0
- data/ext/graph/algorithm.cc +746 -0
- data/ext/graph/extconf.rb +7 -0
- data/ext/graph/graph.cc +529 -0
- data/ext/graph/graph.hh +183 -0
- data/ext/graph/iterator_sequence.hh +102 -0
- data/ext/graph/undirected_dfs.hh +226 -0
- data/ext/graph/undirected_graph.hh +421 -0
- data/lib/roby.rb +41 -0
- data/lib/roby/app.rb +870 -0
- data/lib/roby/app/rake.rb +56 -0
- data/lib/roby/app/run.rb +14 -0
- data/lib/roby/app/scripts/distributed.rb +13 -0
- data/lib/roby/app/scripts/generate/bookmarks.rb +162 -0
- data/lib/roby/app/scripts/replay.rb +31 -0
- data/lib/roby/app/scripts/results.rb +15 -0
- data/lib/roby/app/scripts/run.rb +26 -0
- data/lib/roby/app/scripts/server.rb +18 -0
- data/lib/roby/app/scripts/shell.rb +88 -0
- data/lib/roby/app/scripts/test.rb +40 -0
- data/lib/roby/basic_object.rb +151 -0
- data/lib/roby/config.rb +5 -0
- data/lib/roby/control.rb +747 -0
- data/lib/roby/decision_control.rb +17 -0
- data/lib/roby/distributed.rb +32 -0
- data/lib/roby/distributed/base.rb +440 -0
- data/lib/roby/distributed/communication.rb +871 -0
- data/lib/roby/distributed/connection_space.rb +592 -0
- data/lib/roby/distributed/distributed_object.rb +206 -0
- data/lib/roby/distributed/drb.rb +62 -0
- data/lib/roby/distributed/notifications.rb +539 -0
- data/lib/roby/distributed/peer.rb +550 -0
- data/lib/roby/distributed/protocol.rb +529 -0
- data/lib/roby/distributed/proxy.rb +343 -0
- data/lib/roby/distributed/subscription.rb +311 -0
- data/lib/roby/distributed/transaction.rb +498 -0
- data/lib/roby/event.rb +897 -0
- data/lib/roby/exceptions.rb +234 -0
- data/lib/roby/executives/simple.rb +30 -0
- data/lib/roby/graph.rb +166 -0
- data/lib/roby/interface.rb +390 -0
- data/lib/roby/log.rb +3 -0
- data/lib/roby/log/chronicle.rb +303 -0
- data/lib/roby/log/console.rb +72 -0
- data/lib/roby/log/data_stream.rb +197 -0
- data/lib/roby/log/dot.rb +279 -0
- data/lib/roby/log/event_stream.rb +151 -0
- data/lib/roby/log/file.rb +340 -0
- data/lib/roby/log/gui/basic_display.ui +83 -0
- data/lib/roby/log/gui/chronicle.rb +26 -0
- data/lib/roby/log/gui/chronicle_view.rb +40 -0
- data/lib/roby/log/gui/chronicle_view.ui +70 -0
- data/lib/roby/log/gui/data_displays.rb +172 -0
- data/lib/roby/log/gui/data_displays.ui +155 -0
- data/lib/roby/log/gui/notifications.rb +26 -0
- data/lib/roby/log/gui/relations.rb +248 -0
- data/lib/roby/log/gui/relations.ui +123 -0
- data/lib/roby/log/gui/relations_view.rb +185 -0
- data/lib/roby/log/gui/relations_view.ui +149 -0
- data/lib/roby/log/gui/replay.rb +327 -0
- data/lib/roby/log/gui/replay_controls.rb +200 -0
- data/lib/roby/log/gui/replay_controls.ui +259 -0
- data/lib/roby/log/gui/runtime.rb +130 -0
- data/lib/roby/log/hooks.rb +185 -0
- data/lib/roby/log/logger.rb +202 -0
- data/lib/roby/log/notifications.rb +244 -0
- data/lib/roby/log/plan_rebuilder.rb +470 -0
- data/lib/roby/log/relations.rb +1056 -0
- data/lib/roby/log/server.rb +550 -0
- data/lib/roby/log/sqlite.rb +47 -0
- data/lib/roby/log/timings.rb +164 -0
- data/lib/roby/plan-object.rb +247 -0
- data/lib/roby/plan.rb +762 -0
- data/lib/roby/planning.rb +13 -0
- data/lib/roby/planning/loops.rb +302 -0
- data/lib/roby/planning/model.rb +906 -0
- data/lib/roby/planning/task.rb +151 -0
- data/lib/roby/propagation.rb +562 -0
- data/lib/roby/query.rb +619 -0
- data/lib/roby/relations.rb +583 -0
- data/lib/roby/relations/conflicts.rb +70 -0
- data/lib/roby/relations/ensured.rb +20 -0
- data/lib/roby/relations/error_handling.rb +23 -0
- data/lib/roby/relations/events.rb +9 -0
- data/lib/roby/relations/executed_by.rb +193 -0
- data/lib/roby/relations/hierarchy.rb +239 -0
- data/lib/roby/relations/influence.rb +10 -0
- data/lib/roby/relations/planned_by.rb +63 -0
- data/lib/roby/robot.rb +7 -0
- data/lib/roby/standard_errors.rb +218 -0
- data/lib/roby/state.rb +5 -0
- data/lib/roby/state/events.rb +221 -0
- data/lib/roby/state/information.rb +55 -0
- data/lib/roby/state/pos.rb +110 -0
- data/lib/roby/state/shapes.rb +32 -0
- data/lib/roby/state/state.rb +353 -0
- data/lib/roby/support.rb +92 -0
- data/lib/roby/task-operations.rb +182 -0
- data/lib/roby/task.rb +1618 -0
- data/lib/roby/test/common.rb +399 -0
- data/lib/roby/test/distributed.rb +214 -0
- data/lib/roby/test/tasks/empty_task.rb +9 -0
- data/lib/roby/test/tasks/goto.rb +36 -0
- data/lib/roby/test/tasks/simple_task.rb +23 -0
- data/lib/roby/test/testcase.rb +519 -0
- data/lib/roby/test/tools.rb +160 -0
- data/lib/roby/thread_task.rb +87 -0
- data/lib/roby/transactions.rb +462 -0
- data/lib/roby/transactions/proxy.rb +292 -0
- data/lib/roby/transactions/updates.rb +139 -0
- data/plugins/fault_injection/History.txt +4 -0
- data/plugins/fault_injection/README.txt +37 -0
- data/plugins/fault_injection/Rakefile +18 -0
- data/plugins/fault_injection/TODO.txt +0 -0
- data/plugins/fault_injection/app.rb +52 -0
- data/plugins/fault_injection/fault_injection.rb +89 -0
- data/plugins/fault_injection/test/test_fault_injection.rb +84 -0
- data/plugins/subsystems/README.txt +40 -0
- data/plugins/subsystems/Rakefile +18 -0
- data/plugins/subsystems/app.rb +171 -0
- data/plugins/subsystems/test/app/README +24 -0
- data/plugins/subsystems/test/app/Rakefile +8 -0
- data/plugins/subsystems/test/app/config/app.yml +71 -0
- data/plugins/subsystems/test/app/config/init.rb +9 -0
- data/plugins/subsystems/test/app/config/roby.yml +3 -0
- data/plugins/subsystems/test/app/planners/main.rb +20 -0
- data/plugins/subsystems/test/app/scripts/distributed +3 -0
- data/plugins/subsystems/test/app/scripts/replay +3 -0
- data/plugins/subsystems/test/app/scripts/results +3 -0
- data/plugins/subsystems/test/app/scripts/run +3 -0
- data/plugins/subsystems/test/app/scripts/server +3 -0
- data/plugins/subsystems/test/app/scripts/shell +3 -0
- data/plugins/subsystems/test/app/scripts/test +3 -0
- data/plugins/subsystems/test/app/tasks/services.rb +15 -0
- data/plugins/subsystems/test/test_subsystems.rb +71 -0
- data/test/distributed/test_communication.rb +178 -0
- data/test/distributed/test_connection.rb +282 -0
- data/test/distributed/test_execution.rb +373 -0
- data/test/distributed/test_mixed_plan.rb +341 -0
- data/test/distributed/test_plan_notifications.rb +238 -0
- data/test/distributed/test_protocol.rb +516 -0
- data/test/distributed/test_query.rb +102 -0
- data/test/distributed/test_remote_plan.rb +491 -0
- data/test/distributed/test_transaction.rb +463 -0
- data/test/mockups/tasks.rb +27 -0
- data/test/planning/test_loops.rb +380 -0
- data/test/planning/test_model.rb +427 -0
- data/test/planning/test_task.rb +106 -0
- data/test/relations/test_conflicts.rb +42 -0
- data/test/relations/test_ensured.rb +38 -0
- data/test/relations/test_executed_by.rb +149 -0
- data/test/relations/test_hierarchy.rb +158 -0
- data/test/relations/test_planned_by.rb +54 -0
- data/test/suite_core.rb +24 -0
- data/test/suite_distributed.rb +9 -0
- data/test/suite_planning.rb +3 -0
- data/test/suite_relations.rb +8 -0
- data/test/test_bgl.rb +508 -0
- data/test/test_control.rb +399 -0
- data/test/test_event.rb +894 -0
- data/test/test_exceptions.rb +592 -0
- data/test/test_interface.rb +37 -0
- data/test/test_log.rb +114 -0
- data/test/test_log_server.rb +132 -0
- data/test/test_plan.rb +584 -0
- data/test/test_propagation.rb +210 -0
- data/test/test_query.rb +266 -0
- data/test/test_relations.rb +180 -0
- data/test/test_state.rb +414 -0
- data/test/test_support.rb +16 -0
- data/test/test_task.rb +938 -0
- data/test/test_testcase.rb +122 -0
- data/test/test_thread_task.rb +73 -0
- data/test/test_transactions.rb +569 -0
- data/test/test_transactions_proxy.rb +198 -0
- metadata +570 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
module Roby
|
2
|
+
class DecisionControl
|
3
|
+
def conflict(starting_task, running_tasks)
|
4
|
+
for t in running_tasks
|
5
|
+
starting_task.event(:start).postpone t.event(:stop)
|
6
|
+
return
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_reader :decision_control
|
13
|
+
end
|
14
|
+
|
15
|
+
@decision_control = DecisionControl.new
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'roby'
|
2
|
+
require 'roby/distributed/drb'
|
3
|
+
require 'roby/distributed/protocol'
|
4
|
+
|
5
|
+
require 'roby/distributed/proxy'
|
6
|
+
require 'roby/distributed/connection_space'
|
7
|
+
require 'roby/distributed/notifications'
|
8
|
+
require 'roby/distributed/peer'
|
9
|
+
require 'roby/distributed/transaction'
|
10
|
+
|
11
|
+
# == Communication protocol (and code namespace structure)
|
12
|
+
# == Getting remote objects
|
13
|
+
# There is actually two ways to get a remote object
|
14
|
+
# * the object has been explicitely subscribed to by calling Peer#subscribe
|
15
|
+
# * the object has been sent to us because it is linked to an object we own
|
16
|
+
# or an object we are subscribed to
|
17
|
+
#
|
18
|
+
# In the first case, the object must be referenced in the first place. It can
|
19
|
+
# have been sent to us as a query result (see Query), or because it has been
|
20
|
+
# involved in a distributed transaction. In the second case, it is either us
|
21
|
+
# which have added the relation, or the remote peer. If it is us, we should
|
22
|
+
# have subscribed to the object, added the relation, and then we may
|
23
|
+
# unsubscribe to the object.
|
24
|
+
#
|
25
|
+
# We forget about a remote object when Plan#garbage_collect removes it.
|
26
|
+
#
|
27
|
+
# == Subscription management
|
28
|
+
# The pDB gets updated about all objects it is subscribed to.
|
29
|
+
module Roby::Distributed
|
30
|
+
end
|
31
|
+
|
32
|
+
|
@@ -0,0 +1,440 @@
|
|
1
|
+
require 'drb'
|
2
|
+
|
3
|
+
# A thread-safe reference-counting class
|
4
|
+
class RefCounting
|
5
|
+
def initialize
|
6
|
+
@values = Hash.new(0)
|
7
|
+
@mutex = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# True if +obj+ is referenced
|
11
|
+
def ref?(obj); @mutex.synchronize { @values[obj] > 0 } end
|
12
|
+
# Dereference +obj+ by one
|
13
|
+
def deref(obj)
|
14
|
+
@mutex.synchronize do
|
15
|
+
if (@values[obj] -= 1) == 0
|
16
|
+
@values.delete(obj)
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
false
|
21
|
+
end
|
22
|
+
# Add +1 to the reference count of +obj+
|
23
|
+
def ref(obj)
|
24
|
+
@mutex.synchronize do
|
25
|
+
@values[obj] += 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# Returns the set of referenced objects
|
29
|
+
def referenced_objects
|
30
|
+
@mutex.synchronize do
|
31
|
+
@values.keys
|
32
|
+
end
|
33
|
+
end
|
34
|
+
# Remove +object+ from the set of referenced objects, regardless of its
|
35
|
+
# reference count
|
36
|
+
def delete(object)
|
37
|
+
@mutex.synchronize do
|
38
|
+
@values.delete(object)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Object
|
44
|
+
def initialize_copy(old) # :nodoc:
|
45
|
+
super
|
46
|
+
@__droby_remote_id__ = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# The Roby::Distributed::RemoteID for this object
|
50
|
+
def remote_id
|
51
|
+
@__droby_remote_id__ ||= Roby::Distributed::RemoteID.from_object(self)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class DRbObject
|
56
|
+
# We don't want this method to call the remote object.
|
57
|
+
def to_s
|
58
|
+
inspect
|
59
|
+
end
|
60
|
+
# Converts this DRbObject into Roby::Distributed::RemoteID
|
61
|
+
def remote_id
|
62
|
+
@__droby_remote_id__ ||= Roby::Distributed::RemoteID.new(__drburi, __drbref)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module Roby
|
67
|
+
module Distributed
|
68
|
+
DISCOVERY_RING_PORT = 48901
|
69
|
+
DEFAULT_DROBY_PORT = 48902
|
70
|
+
|
71
|
+
class InvalidRemoteOperation < RuntimeError; end
|
72
|
+
|
73
|
+
class InvalidRemoteTaskOperation < InvalidRemoteOperation
|
74
|
+
attr_reader :task
|
75
|
+
def initialize(task); @task = task end
|
76
|
+
end
|
77
|
+
|
78
|
+
extend Logger::Hierarchy
|
79
|
+
extend Logger::Forward
|
80
|
+
|
81
|
+
# RemoteID objects are used in dRoby to reference objects on other
|
82
|
+
# peers. It uses the same mechanisms that DRbObject but is not
|
83
|
+
# converted back into a local object automatically, and does not allow
|
84
|
+
# to call remote methods on a remote object.
|
85
|
+
class RemoteID
|
86
|
+
# The URI of the DRb server
|
87
|
+
attr_reader :uri
|
88
|
+
# The reference ID of the object on the DRb server
|
89
|
+
attr_reader :ref
|
90
|
+
|
91
|
+
# Creates a new RemoteID with the given URI and ID
|
92
|
+
def initialize(uri, ref)
|
93
|
+
@uri, @ref = uri, ref.to_int
|
94
|
+
@hash = [uri, ref].hash
|
95
|
+
end
|
96
|
+
|
97
|
+
def _dump(lvl) # :nodoc:
|
98
|
+
@__droby_marshalled__ ||= Marshal.dump([uri, ref])
|
99
|
+
end
|
100
|
+
def self._load(str) # :nodoc:
|
101
|
+
new(*Marshal.load(str))
|
102
|
+
end
|
103
|
+
|
104
|
+
def ==(other) # :nodoc:
|
105
|
+
other.kind_of?(RemoteID) && other.ref == ref && other.uri == uri
|
106
|
+
end
|
107
|
+
alias :eql? :==
|
108
|
+
attr_reader :hash
|
109
|
+
|
110
|
+
# True if this object references a local object
|
111
|
+
def local?; DRb.here?(uri) end
|
112
|
+
# If this ID references a local object, returns it. Otherwise, returns self.
|
113
|
+
def local_object
|
114
|
+
if DRb.here?(uri)
|
115
|
+
DRb.to_obj(ref)
|
116
|
+
else
|
117
|
+
self
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def to_s(peer = nil)
|
122
|
+
if peer
|
123
|
+
"0x#{Object.address_from_id(ref).to_s(16)}@#{peer.name}"
|
124
|
+
else
|
125
|
+
"0x#{Object.address_from_id(ref).to_s(16)}@#{uri}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
def inspect; to_s end
|
129
|
+
def pretty_print(pp); pp.text to_s end
|
130
|
+
|
131
|
+
def to_local(peer, create)
|
132
|
+
object = local_object
|
133
|
+
if object.kind_of?(RemoteID)
|
134
|
+
if local_proxy = peer.proxies[object]
|
135
|
+
return peer.proxy_setup(local_proxy)
|
136
|
+
elsif !create
|
137
|
+
return
|
138
|
+
elsif peer.removing_proxies.has_key?(object)
|
139
|
+
marshalled_object = peer.removing_proxies[object].last
|
140
|
+
Distributed.debug "reusing marshalled #{marshalled_object} for #{self} from #{peer}"
|
141
|
+
marshalled_object.remote_siblings.delete(Distributed.droby_dump)
|
142
|
+
marshalled_object.remote_siblings[peer.droby_dump] = self
|
143
|
+
|
144
|
+
if marshalled_object.respond_to?(:plan) && !marshalled_object.plan
|
145
|
+
# Take care of the "proxy is GCed while the peer
|
146
|
+
# sends us messages about it" case. In this case,
|
147
|
+
# the object has already been removed when it is
|
148
|
+
# marshalled (#plan == nil).
|
149
|
+
#
|
150
|
+
# This cannot happen in transactions: it only happens
|
151
|
+
# in plans where one side can remove an object while
|
152
|
+
# the other side is doing something on it
|
153
|
+
marshalled_object.instance_variable_set(:@plan, Roby.plan)
|
154
|
+
end
|
155
|
+
|
156
|
+
object = peer.local_object(marshalled_object)
|
157
|
+
|
158
|
+
if object.respond_to?(:plan) && !object.plan
|
159
|
+
raise "#{object} has no plan !"
|
160
|
+
end
|
161
|
+
|
162
|
+
return object
|
163
|
+
end
|
164
|
+
raise ArgumentError, "#{self} has no proxy"
|
165
|
+
else
|
166
|
+
object
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
private :remote_id
|
171
|
+
|
172
|
+
# Returns the RemoteID object for +obj+. This is actually
|
173
|
+
# equivalent to obj.remote_id
|
174
|
+
def self.from_object(obj)
|
175
|
+
Roby::Distributed::RemoteID.new(DRb.current_server.uri, DRb.to_id(obj) || 0)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Creates a DRbObject corresponding to the object referenced by this RemoteID
|
179
|
+
def to_drb_object
|
180
|
+
DRbObject.new_with(uri, (ref == 0 ? nil : ref))
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
@updated_objects = ValueSet.new
|
185
|
+
@allowed_remote_access = Array.new
|
186
|
+
@keep = RefCounting.new
|
187
|
+
@removed_objects = ValueSet.new
|
188
|
+
class << self
|
189
|
+
# The one and only ConnectionSpace object
|
190
|
+
attr_reader :state
|
191
|
+
|
192
|
+
# Sets the #state attribute for Roby::Distributed
|
193
|
+
def state=(new_state)
|
194
|
+
if log = logger
|
195
|
+
if new_state
|
196
|
+
logger.progname = new_state.name
|
197
|
+
else
|
198
|
+
logger.progname = "Roby"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
@state = new_state
|
202
|
+
end
|
203
|
+
|
204
|
+
# True if this plan manager owns +object+
|
205
|
+
def owns?(object); !state || state.owns?(object) end
|
206
|
+
|
207
|
+
# The set of objects we should temporarily keep because they are used
|
208
|
+
# in a callback mechanism (like a remote query or a trigger)
|
209
|
+
attr_reader :keep
|
210
|
+
|
211
|
+
# Compute the subset of +candidates+ that are to be considered as
|
212
|
+
# useful because of our peers and returns it.
|
213
|
+
#
|
214
|
+
# More specifically, an object will be included in the result if:
|
215
|
+
# * this plan manager is subscribed to it
|
216
|
+
# * the object is directly related to a self-owned object
|
217
|
+
# * if +include_subscriptions_relations+ is true, +object+ is
|
218
|
+
# directly related to a subscribed object.
|
219
|
+
#
|
220
|
+
# The method takes into account plan children in its computation:
|
221
|
+
# for instance, a task will be included in the result if one of
|
222
|
+
# its events meet the requirements described above.
|
223
|
+
#
|
224
|
+
# If +result+ is non-nil, the method adds the objects to +result+
|
225
|
+
# using #<< and returns it.
|
226
|
+
def remotely_useful_objects(candidates, include_subscriptions_relations, result = nil)
|
227
|
+
return ValueSet.new if candidates.empty?
|
228
|
+
|
229
|
+
result ||= Distributed.keep.referenced_objects.to_value_set
|
230
|
+
|
231
|
+
child_set = ValueSet.new
|
232
|
+
for obj in candidates
|
233
|
+
if result.include?(obj.root_object)
|
234
|
+
next
|
235
|
+
elsif obj.subscribed?
|
236
|
+
result << obj
|
237
|
+
next
|
238
|
+
end
|
239
|
+
|
240
|
+
not_found = obj.each_relation do |rel|
|
241
|
+
next unless rel.distribute? && rel.root_relation?
|
242
|
+
|
243
|
+
not_found = obj.each_parent_object(rel) do |parent|
|
244
|
+
parent = parent.root_object
|
245
|
+
if parent.distribute? &&
|
246
|
+
((include_subscriptions_relations && parent.subscribed?) || parent.self_owned?)
|
247
|
+
result << obj.root_object
|
248
|
+
break
|
249
|
+
end
|
250
|
+
end
|
251
|
+
break unless not_found
|
252
|
+
|
253
|
+
not_found = obj.each_child_object(rel) do |child|
|
254
|
+
child = child.root_object
|
255
|
+
if child.distribute? &&
|
256
|
+
((include_subscriptions_relations && child.subscribed?) || child.self_owned?)
|
257
|
+
result << obj.root_object
|
258
|
+
break
|
259
|
+
end
|
260
|
+
end
|
261
|
+
break unless not_found
|
262
|
+
end
|
263
|
+
|
264
|
+
if not_found && obj.respond_to?(:each_plan_child)
|
265
|
+
obj.each_plan_child { |plan_child| child_set << plan_child }
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
result.merge remotely_useful_objects(child_set, false, result)
|
270
|
+
end
|
271
|
+
|
272
|
+
# The list of objects that are being updated because of remote update
|
273
|
+
attr_reader :updated_objects
|
274
|
+
|
275
|
+
# True if we are updating +object+
|
276
|
+
def updating?(object)
|
277
|
+
updated_objects.include?(object)
|
278
|
+
end
|
279
|
+
|
280
|
+
# True if we are updating all objects in +objects+
|
281
|
+
def updating_all?(objects)
|
282
|
+
updated_objects.include_all?(objects.to_value_set)
|
283
|
+
end
|
284
|
+
|
285
|
+
# Call the block with the objects in +objects+ added to the
|
286
|
+
# updated_objects set
|
287
|
+
def update_all(objects)
|
288
|
+
old_updated_objects = @updated_objects
|
289
|
+
@updated_objects |= objects.to_value_set
|
290
|
+
yield
|
291
|
+
ensure
|
292
|
+
@updated_objects = old_updated_objects
|
293
|
+
end
|
294
|
+
|
295
|
+
# Call the block with the objects in +objects+ added to the
|
296
|
+
# updated_objects set
|
297
|
+
def update(object)
|
298
|
+
if object.respond_to?(:__getobj__) && !object.kind_of?(Roby::Transactions::Proxy)
|
299
|
+
object = object.__getobj__
|
300
|
+
end
|
301
|
+
|
302
|
+
included = unless updated_objects.include?(object)
|
303
|
+
@updated_objects << object
|
304
|
+
end
|
305
|
+
|
306
|
+
yield
|
307
|
+
ensure
|
308
|
+
@updated_objects.delete(object) if included
|
309
|
+
end
|
310
|
+
|
311
|
+
# Yields the relations of +object+ which are to be distributed
|
312
|
+
# among peers.
|
313
|
+
def each_object_relation(object)
|
314
|
+
object.each_relation do |rel|
|
315
|
+
yield(rel) if rel.distribute?
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# The list of known peers. See ConnectionSpace#peers
|
320
|
+
def peers
|
321
|
+
if state then state.peers
|
322
|
+
else {}
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
# The set of objects that have been removed locally, but for which
|
327
|
+
# there are still references on our peers
|
328
|
+
attr_reader :removed_objects
|
329
|
+
end
|
330
|
+
|
331
|
+
@cycles_rx = Queue.new
|
332
|
+
@pending_cycles = Array.new
|
333
|
+
@pending_remote_events = Array.new
|
334
|
+
|
335
|
+
class << self
|
336
|
+
# The queue of cycles read by ConnectionSpace#receive and not processed
|
337
|
+
attr_reader :cycles_rx
|
338
|
+
# The set of cycles that have been read from #pending_cycles but
|
339
|
+
# have not been processed yet because the peers have disabled_rx? set
|
340
|
+
#
|
341
|
+
# This variable must be accessed only in the control thread
|
342
|
+
attr_reader :pending_cycles
|
343
|
+
end
|
344
|
+
|
345
|
+
# Extract data received so far from our peers and replays it if
|
346
|
+
# possible. Data can be ignored if RX is disabled with this peer
|
347
|
+
# (through Peer#disable_rx), or delayed if there is event propagation
|
348
|
+
# involved. In that last case, the events will be fired at the
|
349
|
+
# beginning of the next execution cycle and the remaining messages at
|
350
|
+
# the end of that same cycle.
|
351
|
+
def self.process_pending
|
352
|
+
delayed_cycles = []
|
353
|
+
while !(pending_cycles.empty? && cycles_rx.empty?)
|
354
|
+
peer, calls = if pending_cycles.empty?
|
355
|
+
cycles_rx.pop
|
356
|
+
else pending_cycles.shift
|
357
|
+
end
|
358
|
+
|
359
|
+
if peer.disabled_rx?
|
360
|
+
delayed_cycles.push [peer, calls]
|
361
|
+
else
|
362
|
+
if remaining = process_cycle(peer, calls)
|
363
|
+
delayed_cycles.push [peer, remaining]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
ensure
|
369
|
+
@pending_cycles = delayed_cycles
|
370
|
+
end
|
371
|
+
|
372
|
+
# Process once cycle worth of data from the given peer.
|
373
|
+
def self.process_cycle(peer, calls)
|
374
|
+
from = Time.now
|
375
|
+
calls_size = calls.size
|
376
|
+
|
377
|
+
peer_server = peer.local_server
|
378
|
+
peer_server.processing = true
|
379
|
+
|
380
|
+
if !peer.connected?
|
381
|
+
return
|
382
|
+
end
|
383
|
+
|
384
|
+
while call_spec = calls.shift
|
385
|
+
return unless call_spec
|
386
|
+
|
387
|
+
is_callback, method, args, critical, message_id = *call_spec
|
388
|
+
Distributed.debug do
|
389
|
+
args_s = args.map { |obj| obj ? obj.to_s : 'nil' }
|
390
|
+
"processing #{is_callback ? 'callback' : 'method'} [#{message_id}]#{method}(#{args_s.join(", ")})"
|
391
|
+
end
|
392
|
+
|
393
|
+
result = catch(:ignore_this_call) do
|
394
|
+
peer_server.queued_completion = false
|
395
|
+
peer_server.current_message_id = message_id
|
396
|
+
peer_server.processing_callback = !!is_callback
|
397
|
+
|
398
|
+
result = begin
|
399
|
+
peer_server.send(method, *args)
|
400
|
+
rescue Exception => e
|
401
|
+
if critical
|
402
|
+
peer.fatal_error e, method, args
|
403
|
+
else
|
404
|
+
peer_server.completed!(e, true)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
if !peer.connected?
|
409
|
+
return
|
410
|
+
end
|
411
|
+
result
|
412
|
+
end
|
413
|
+
|
414
|
+
if method != :completed && method != :completion_group && !peer.disconnecting? && !peer.disconnected?
|
415
|
+
if peer_server.queued_completion?
|
416
|
+
Distributed.debug "done and already queued the completion message"
|
417
|
+
else
|
418
|
+
Distributed.debug { "done, returns #{result || 'nil'}" }
|
419
|
+
peer.queue_call false, :completed, [result, false, message_id]
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
if peer.disabled_rx?
|
424
|
+
return calls
|
425
|
+
end
|
426
|
+
|
427
|
+
end
|
428
|
+
|
429
|
+
Distributed.debug "successfully served #{calls_size} calls in #{Time.now - from} seconds"
|
430
|
+
nil
|
431
|
+
|
432
|
+
rescue Exception => e
|
433
|
+
Distributed.info "error in dRoby processing: #{e.full_message}"
|
434
|
+
peer.disconnect
|
435
|
+
|
436
|
+
ensure
|
437
|
+
peer_server.processing = false
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|