roby 0.7
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/.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
|