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.
Files changed (240) hide show
  1. data/.gitignore +29 -0
  2. data/History.txt +4 -0
  3. data/License-fr.txt +519 -0
  4. data/License.txt +515 -0
  5. data/Manifest.txt +245 -0
  6. data/NOTES +4 -0
  7. data/README.txt +163 -0
  8. data/Rakefile +161 -0
  9. data/TODO.txt +146 -0
  10. data/app/README.txt +24 -0
  11. data/app/Rakefile +8 -0
  12. data/app/config/ROBOT.rb +5 -0
  13. data/app/config/app.yml +91 -0
  14. data/app/config/init.rb +7 -0
  15. data/app/config/roby.yml +3 -0
  16. data/app/controllers/.gitattributes +0 -0
  17. data/app/controllers/ROBOT.rb +2 -0
  18. data/app/data/.gitattributes +0 -0
  19. data/app/planners/ROBOT/main.rb +6 -0
  20. data/app/planners/main.rb +5 -0
  21. data/app/scripts/distributed +3 -0
  22. data/app/scripts/generate/bookmarks +3 -0
  23. data/app/scripts/replay +3 -0
  24. data/app/scripts/results +3 -0
  25. data/app/scripts/run +3 -0
  26. data/app/scripts/server +3 -0
  27. data/app/scripts/shell +3 -0
  28. data/app/scripts/test +3 -0
  29. data/app/tasks/.gitattributes +0 -0
  30. data/app/tasks/ROBOT/.gitattributes +0 -0
  31. data/bin/roby +210 -0
  32. data/bin/roby-log +168 -0
  33. data/bin/roby-shell +25 -0
  34. data/doc/images/event_generalization.png +0 -0
  35. data/doc/images/exception_propagation_1.png +0 -0
  36. data/doc/images/exception_propagation_2.png +0 -0
  37. data/doc/images/exception_propagation_3.png +0 -0
  38. data/doc/images/exception_propagation_4.png +0 -0
  39. data/doc/images/exception_propagation_5.png +0 -0
  40. data/doc/images/replay_handler_error.png +0 -0
  41. data/doc/images/replay_handler_error_0.png +0 -0
  42. data/doc/images/replay_handler_error_1.png +0 -0
  43. data/doc/images/roby_cycle_overview.png +0 -0
  44. data/doc/images/roby_replay_02.png +0 -0
  45. data/doc/images/roby_replay_03.png +0 -0
  46. data/doc/images/roby_replay_04.png +0 -0
  47. data/doc/images/roby_replay_event_representation.png +0 -0
  48. data/doc/images/roby_replay_first_state.png +0 -0
  49. data/doc/images/roby_replay_relations.png +0 -0
  50. data/doc/images/roby_replay_startup.png +0 -0
  51. data/doc/images/task_event_generalization.png +0 -0
  52. data/doc/papers.rdoc +11 -0
  53. data/doc/styles/allison.css +314 -0
  54. data/doc/styles/allison.js +316 -0
  55. data/doc/styles/allison.rb +276 -0
  56. data/doc/styles/jamis.rb +593 -0
  57. data/doc/tutorials/01-GettingStarted.rdoc +86 -0
  58. data/doc/tutorials/02-GoForward.rdoc +220 -0
  59. data/doc/tutorials/03-PlannedPath.rdoc +268 -0
  60. data/doc/tutorials/04-EventPropagation.rdoc +236 -0
  61. data/doc/tutorials/05-ErrorHandling.rdoc +319 -0
  62. data/doc/tutorials/06-Overview.rdoc +40 -0
  63. data/doc/videos.rdoc +69 -0
  64. data/ext/droby/dump.cc +175 -0
  65. data/ext/droby/extconf.rb +3 -0
  66. data/ext/graph/algorithm.cc +746 -0
  67. data/ext/graph/extconf.rb +7 -0
  68. data/ext/graph/graph.cc +529 -0
  69. data/ext/graph/graph.hh +183 -0
  70. data/ext/graph/iterator_sequence.hh +102 -0
  71. data/ext/graph/undirected_dfs.hh +226 -0
  72. data/ext/graph/undirected_graph.hh +421 -0
  73. data/lib/roby.rb +41 -0
  74. data/lib/roby/app.rb +870 -0
  75. data/lib/roby/app/rake.rb +56 -0
  76. data/lib/roby/app/run.rb +14 -0
  77. data/lib/roby/app/scripts/distributed.rb +13 -0
  78. data/lib/roby/app/scripts/generate/bookmarks.rb +162 -0
  79. data/lib/roby/app/scripts/replay.rb +31 -0
  80. data/lib/roby/app/scripts/results.rb +15 -0
  81. data/lib/roby/app/scripts/run.rb +26 -0
  82. data/lib/roby/app/scripts/server.rb +18 -0
  83. data/lib/roby/app/scripts/shell.rb +88 -0
  84. data/lib/roby/app/scripts/test.rb +40 -0
  85. data/lib/roby/basic_object.rb +151 -0
  86. data/lib/roby/config.rb +5 -0
  87. data/lib/roby/control.rb +747 -0
  88. data/lib/roby/decision_control.rb +17 -0
  89. data/lib/roby/distributed.rb +32 -0
  90. data/lib/roby/distributed/base.rb +440 -0
  91. data/lib/roby/distributed/communication.rb +871 -0
  92. data/lib/roby/distributed/connection_space.rb +592 -0
  93. data/lib/roby/distributed/distributed_object.rb +206 -0
  94. data/lib/roby/distributed/drb.rb +62 -0
  95. data/lib/roby/distributed/notifications.rb +539 -0
  96. data/lib/roby/distributed/peer.rb +550 -0
  97. data/lib/roby/distributed/protocol.rb +529 -0
  98. data/lib/roby/distributed/proxy.rb +343 -0
  99. data/lib/roby/distributed/subscription.rb +311 -0
  100. data/lib/roby/distributed/transaction.rb +498 -0
  101. data/lib/roby/event.rb +897 -0
  102. data/lib/roby/exceptions.rb +234 -0
  103. data/lib/roby/executives/simple.rb +30 -0
  104. data/lib/roby/graph.rb +166 -0
  105. data/lib/roby/interface.rb +390 -0
  106. data/lib/roby/log.rb +3 -0
  107. data/lib/roby/log/chronicle.rb +303 -0
  108. data/lib/roby/log/console.rb +72 -0
  109. data/lib/roby/log/data_stream.rb +197 -0
  110. data/lib/roby/log/dot.rb +279 -0
  111. data/lib/roby/log/event_stream.rb +151 -0
  112. data/lib/roby/log/file.rb +340 -0
  113. data/lib/roby/log/gui/basic_display.ui +83 -0
  114. data/lib/roby/log/gui/chronicle.rb +26 -0
  115. data/lib/roby/log/gui/chronicle_view.rb +40 -0
  116. data/lib/roby/log/gui/chronicle_view.ui +70 -0
  117. data/lib/roby/log/gui/data_displays.rb +172 -0
  118. data/lib/roby/log/gui/data_displays.ui +155 -0
  119. data/lib/roby/log/gui/notifications.rb +26 -0
  120. data/lib/roby/log/gui/relations.rb +248 -0
  121. data/lib/roby/log/gui/relations.ui +123 -0
  122. data/lib/roby/log/gui/relations_view.rb +185 -0
  123. data/lib/roby/log/gui/relations_view.ui +149 -0
  124. data/lib/roby/log/gui/replay.rb +327 -0
  125. data/lib/roby/log/gui/replay_controls.rb +200 -0
  126. data/lib/roby/log/gui/replay_controls.ui +259 -0
  127. data/lib/roby/log/gui/runtime.rb +130 -0
  128. data/lib/roby/log/hooks.rb +185 -0
  129. data/lib/roby/log/logger.rb +202 -0
  130. data/lib/roby/log/notifications.rb +244 -0
  131. data/lib/roby/log/plan_rebuilder.rb +470 -0
  132. data/lib/roby/log/relations.rb +1056 -0
  133. data/lib/roby/log/server.rb +550 -0
  134. data/lib/roby/log/sqlite.rb +47 -0
  135. data/lib/roby/log/timings.rb +164 -0
  136. data/lib/roby/plan-object.rb +247 -0
  137. data/lib/roby/plan.rb +762 -0
  138. data/lib/roby/planning.rb +13 -0
  139. data/lib/roby/planning/loops.rb +302 -0
  140. data/lib/roby/planning/model.rb +906 -0
  141. data/lib/roby/planning/task.rb +151 -0
  142. data/lib/roby/propagation.rb +562 -0
  143. data/lib/roby/query.rb +619 -0
  144. data/lib/roby/relations.rb +583 -0
  145. data/lib/roby/relations/conflicts.rb +70 -0
  146. data/lib/roby/relations/ensured.rb +20 -0
  147. data/lib/roby/relations/error_handling.rb +23 -0
  148. data/lib/roby/relations/events.rb +9 -0
  149. data/lib/roby/relations/executed_by.rb +193 -0
  150. data/lib/roby/relations/hierarchy.rb +239 -0
  151. data/lib/roby/relations/influence.rb +10 -0
  152. data/lib/roby/relations/planned_by.rb +63 -0
  153. data/lib/roby/robot.rb +7 -0
  154. data/lib/roby/standard_errors.rb +218 -0
  155. data/lib/roby/state.rb +5 -0
  156. data/lib/roby/state/events.rb +221 -0
  157. data/lib/roby/state/information.rb +55 -0
  158. data/lib/roby/state/pos.rb +110 -0
  159. data/lib/roby/state/shapes.rb +32 -0
  160. data/lib/roby/state/state.rb +353 -0
  161. data/lib/roby/support.rb +92 -0
  162. data/lib/roby/task-operations.rb +182 -0
  163. data/lib/roby/task.rb +1618 -0
  164. data/lib/roby/test/common.rb +399 -0
  165. data/lib/roby/test/distributed.rb +214 -0
  166. data/lib/roby/test/tasks/empty_task.rb +9 -0
  167. data/lib/roby/test/tasks/goto.rb +36 -0
  168. data/lib/roby/test/tasks/simple_task.rb +23 -0
  169. data/lib/roby/test/testcase.rb +519 -0
  170. data/lib/roby/test/tools.rb +160 -0
  171. data/lib/roby/thread_task.rb +87 -0
  172. data/lib/roby/transactions.rb +462 -0
  173. data/lib/roby/transactions/proxy.rb +292 -0
  174. data/lib/roby/transactions/updates.rb +139 -0
  175. data/plugins/fault_injection/History.txt +4 -0
  176. data/plugins/fault_injection/README.txt +37 -0
  177. data/plugins/fault_injection/Rakefile +18 -0
  178. data/plugins/fault_injection/TODO.txt +0 -0
  179. data/plugins/fault_injection/app.rb +52 -0
  180. data/plugins/fault_injection/fault_injection.rb +89 -0
  181. data/plugins/fault_injection/test/test_fault_injection.rb +84 -0
  182. data/plugins/subsystems/README.txt +40 -0
  183. data/plugins/subsystems/Rakefile +18 -0
  184. data/plugins/subsystems/app.rb +171 -0
  185. data/plugins/subsystems/test/app/README +24 -0
  186. data/plugins/subsystems/test/app/Rakefile +8 -0
  187. data/plugins/subsystems/test/app/config/app.yml +71 -0
  188. data/plugins/subsystems/test/app/config/init.rb +9 -0
  189. data/plugins/subsystems/test/app/config/roby.yml +3 -0
  190. data/plugins/subsystems/test/app/planners/main.rb +20 -0
  191. data/plugins/subsystems/test/app/scripts/distributed +3 -0
  192. data/plugins/subsystems/test/app/scripts/replay +3 -0
  193. data/plugins/subsystems/test/app/scripts/results +3 -0
  194. data/plugins/subsystems/test/app/scripts/run +3 -0
  195. data/plugins/subsystems/test/app/scripts/server +3 -0
  196. data/plugins/subsystems/test/app/scripts/shell +3 -0
  197. data/plugins/subsystems/test/app/scripts/test +3 -0
  198. data/plugins/subsystems/test/app/tasks/services.rb +15 -0
  199. data/plugins/subsystems/test/test_subsystems.rb +71 -0
  200. data/test/distributed/test_communication.rb +178 -0
  201. data/test/distributed/test_connection.rb +282 -0
  202. data/test/distributed/test_execution.rb +373 -0
  203. data/test/distributed/test_mixed_plan.rb +341 -0
  204. data/test/distributed/test_plan_notifications.rb +238 -0
  205. data/test/distributed/test_protocol.rb +516 -0
  206. data/test/distributed/test_query.rb +102 -0
  207. data/test/distributed/test_remote_plan.rb +491 -0
  208. data/test/distributed/test_transaction.rb +463 -0
  209. data/test/mockups/tasks.rb +27 -0
  210. data/test/planning/test_loops.rb +380 -0
  211. data/test/planning/test_model.rb +427 -0
  212. data/test/planning/test_task.rb +106 -0
  213. data/test/relations/test_conflicts.rb +42 -0
  214. data/test/relations/test_ensured.rb +38 -0
  215. data/test/relations/test_executed_by.rb +149 -0
  216. data/test/relations/test_hierarchy.rb +158 -0
  217. data/test/relations/test_planned_by.rb +54 -0
  218. data/test/suite_core.rb +24 -0
  219. data/test/suite_distributed.rb +9 -0
  220. data/test/suite_planning.rb +3 -0
  221. data/test/suite_relations.rb +8 -0
  222. data/test/test_bgl.rb +508 -0
  223. data/test/test_control.rb +399 -0
  224. data/test/test_event.rb +894 -0
  225. data/test/test_exceptions.rb +592 -0
  226. data/test/test_interface.rb +37 -0
  227. data/test/test_log.rb +114 -0
  228. data/test/test_log_server.rb +132 -0
  229. data/test/test_plan.rb +584 -0
  230. data/test/test_propagation.rb +210 -0
  231. data/test/test_query.rb +266 -0
  232. data/test/test_relations.rb +180 -0
  233. data/test/test_state.rb +414 -0
  234. data/test/test_support.rb +16 -0
  235. data/test/test_task.rb +938 -0
  236. data/test/test_testcase.rb +122 -0
  237. data/test/test_thread_task.rb +73 -0
  238. data/test/test_transactions.rb +569 -0
  239. data/test/test_transactions_proxy.rb +198 -0
  240. metadata +570 -0
@@ -0,0 +1,244 @@
1
+ require 'roby/log/data_stream'
2
+
3
+ class Roby::Task::DRoby
4
+ attr_accessor :mission
5
+ end
6
+
7
+ module Roby
8
+ module Log
9
+ class Notifications < Roby::Log::DataDecoder
10
+ GENERATOR_CALL_LIMIT = 0.1
11
+
12
+ attr_reader :tasks
13
+
14
+ attr_reader :histories
15
+ def initialize(name)
16
+ @tasks = Hash.new
17
+ @histories = Hash.new { |h, k| h[k] = Array.new }
18
+ super(name)
19
+ end
20
+
21
+ def added_task(task)
22
+ task.remote_siblings.each_value do |id|
23
+ tasks[id] = task
24
+ end
25
+ end
26
+ def removed_task(remote_id)
27
+ task = tasks.delete(remote_id)
28
+ task.remote_siblings.each_value do |id|
29
+ tasks.delete(id)
30
+ end
31
+ end
32
+
33
+ def clear
34
+ super
35
+
36
+ @tasks.clear
37
+ @histories.clear
38
+ end
39
+
40
+
41
+ def process(data)
42
+ data.each_slice(4) do |m, sec, usec, args|
43
+ time = Time.at(sec, usec)
44
+ case m.to_s
45
+ when /inserted/
46
+ task = tasks[args[1]]
47
+ task.mission = true
48
+ event :added_mission, args[0], task
49
+
50
+ when /discarded/
51
+ task = tasks[args[1]]
52
+ task.mission = false
53
+ event :discarded_mission, args[0], task
54
+
55
+ when /discovered_tasks/
56
+ args[1].each { |t| added_task(t) }
57
+
58
+ when /finalized_task/
59
+ id = args[1]
60
+ task = tasks[id]
61
+ if histories[id].empty?
62
+ event :finalized_pending, time, task
63
+ end
64
+ histories.delete(task)
65
+ removed_task(args[1])
66
+
67
+ when /generator_calling/
68
+ @current_call = [time, args[0]]
69
+
70
+ when /generator_called/
71
+ if @current_call[1] == args[0]
72
+ duration = time - @current_call[0]
73
+ if duration > GENERATOR_CALL_LIMIT
74
+ event :overly_long_call, time, duration, tasks[args[0].task], args[0].symbol, args[1]
75
+ end
76
+ end
77
+
78
+ when /exception/
79
+ error, involved_tasks = *args
80
+ involved_tasks = involved_tasks.map { |id| tasks[id] }
81
+ event m, time, error, involved_tasks
82
+ when /generator_fired/
83
+ generator = args[0]
84
+ if generator.respond_to?(:task)
85
+ histories[generator.task] << args
86
+ if generator.symbol == :failed
87
+ event :failed_task, time, tasks[generator.task], histories[generator.task]
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def event(name, *args)
95
+ displays.each do |display|
96
+ if display.respond_to?(name)
97
+ display.send(name, *args)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ class NotificationsDisplay < Qt::TextBrowser
104
+ include DataDisplay
105
+ decoder Notifications
106
+
107
+ attr_reader :document
108
+ attr_reader :text
109
+
110
+ STYLESHEET = <<-EOS
111
+ h1 { font-size: large; }
112
+ h1 { margin-bottom: 3px; }
113
+ h2 { font-size: medium; }
114
+ .time {
115
+ margin-right: 10px;
116
+ }
117
+
118
+ div.info {
119
+ color: black;
120
+ margin-top: 20px;
121
+ border-top: thin solid black;
122
+ }
123
+ div.info h1 { margin-top: 0; background-color: #5FB86A; }
124
+ div.warn {
125
+ color: black;
126
+ margin-top: 20px;
127
+ border-top: thin solid black;
128
+ }
129
+ div.warn h1 { margin-top: 0; background-color: #B8AC5F; }
130
+ div.error {
131
+ color: black;
132
+ margin-top: 20px;
133
+ border-top: thin solid black;
134
+ }
135
+ div.error h1 { margin-top: 0; background-color: #B8937D; }
136
+ EOS
137
+
138
+ def initialize
139
+ super()
140
+
141
+ resize(500, 600)
142
+ @main = self
143
+ @document = Qt::TextDocument.new
144
+
145
+ self.document = document
146
+ document.setDefaultStyleSheet(STYLESHEET)
147
+ end
148
+
149
+
150
+ def render_event(kind, time, title)
151
+ @text = ""
152
+ text << "\n<div class=#{kind}>\n <h1><span class=\"time\">#{time.to_hms}</span> #{title}</h1>\n "
153
+ yield
154
+
155
+ ensure
156
+ text << "\n</div>"
157
+ insertHtml(text)
158
+ verticalScrollBar.value = verticalScrollBar.maximum
159
+ end
160
+
161
+ def render_task(task)
162
+ remote_siblings = "{ " << task.remote_siblings.map { |peer, id| id.to_s(peer) }.join(", ") << " }"
163
+ text << "<div class=\"task\">
164
+ #{task.model.ancestors.first.first}#{remote_siblings}\n "
165
+
166
+ unless task.arguments.empty?
167
+ text << "<ul class=\"task-arguments\">\n "
168
+ task.arguments.each do |key, value|
169
+ text << " <li>#{key}: #{value}<li>\n"
170
+ end
171
+ text << " </ul>\n"
172
+ end
173
+ text << "</div>"
174
+ end
175
+
176
+ def render_history(history)
177
+ text << "<ul class=\"history\">\n"
178
+ history.each do |generator, id, time, context|
179
+ text << "<li>#{time.to_hms} #{generator.symbol} [#{context}]</li>"
180
+ end
181
+ text << "</ul>"
182
+ end
183
+
184
+ def clear
185
+ document.clear
186
+ end
187
+
188
+ def finalized_pending(time, task)
189
+ render_event("warn", time, "Finalized pending task") do
190
+ render_task(task)
191
+ end
192
+ end
193
+ def added_mission(time, task)
194
+ render_event("info", time, "New mission") do
195
+ render_task(task)
196
+ end
197
+ end
198
+ def removed_mission(time, task)
199
+ render_event("info", time, "Removed mission") do
200
+ render_task(task)
201
+ end
202
+ end
203
+ def render_error(error, tasks)
204
+ error = Qt.escape(error.to_s)
205
+ error = error.split("\n").map do |line|
206
+ line.gsub(/^\s+/) { "&nbsp;" * $&.size }
207
+ end.join("<br>")
208
+
209
+ text << error
210
+ text << "<h2>Involved tasks</h2>"
211
+ text << "<ul>"
212
+ tasks.each do |t|
213
+ text << "<li>"
214
+ render_task(t)
215
+ text << "</li>"
216
+ end
217
+ end
218
+
219
+ def fatal_exception(time, error, tasks)
220
+ render_event("error", time, "Fatal exception") do
221
+ render_error(error, tasks)
222
+ end
223
+ end
224
+ def handled_exception(time, error, tasks)
225
+ render_event("warn", time, "Handled exception") do
226
+ render_error(error, tasks)
227
+ end
228
+ end
229
+ def failed_task(time, task, history)
230
+ render_event("warn", time, "Failed task") do
231
+ render_task(task)
232
+ render_history(history)
233
+ end
234
+ end
235
+ def overly_long_call(time, duration, task, event_name, context)
236
+ render_event("warn", time, "Overly long call: ") do
237
+ text << "Call of #{event_name}(#{context}) lasted #{Integer(duration * 1000)}ms in<br>"
238
+ render_task(task)
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end
244
+
@@ -0,0 +1,470 @@
1
+ require 'roby/distributed/protocol'
2
+ require 'roby/log/data_stream'
3
+ require 'stringio'
4
+
5
+ module Roby
6
+ class ObjectIDManager
7
+ attr_reader :siblings
8
+ attr_reader :objects
9
+ def initialize
10
+ @siblings = Hash.new
11
+ @objects = Hash.new
12
+ @inserted_at = Hash.new
13
+ end
14
+
15
+ def clear
16
+ siblings.clear
17
+ objects.clear
18
+ end
19
+
20
+ def local_object(object, allow_new = true)
21
+ return unless object
22
+
23
+ current_siblings = Set.new
24
+ ids = Set.new
25
+ if object.kind_of?(Distributed::RemoteID)
26
+ ids << object
27
+ if sibling = siblings[object]
28
+ current_siblings << sibling
29
+ end
30
+ else
31
+ for _, id in object.remote_siblings
32
+ ids << id
33
+ if sibling = siblings[id]
34
+ current_siblings << sibling
35
+ end
36
+ end
37
+ end
38
+
39
+ if current_siblings.size > 1
40
+ raise "more than one object matching"
41
+ elsif current_siblings.empty?
42
+ if object.kind_of?(Distributed::RemoteID)
43
+ raise "no object for this ID"
44
+ elsif !allow_new
45
+ raise "new object ot type #{object.class} is not allowed here"
46
+ end
47
+ else
48
+ obj = current_siblings.find { true }
49
+ if object.kind_of?(Distributed::RemoteID)
50
+ object = obj
51
+ end
52
+
53
+ if obj.class != object.class
54
+ # Special case: +obj+ is a PlanObject and it is in no plan.
55
+ #
56
+ # In this case, we just replace it silently. It handles the
57
+ # corner case of having a task hanging around because it is
58
+ # linked to others, but has not been included in a plan.
59
+ #
60
+ # Note that this is a hack and should be fixed
61
+ if obj.respond_to?(:plan) && !obj.plan
62
+ for id in objects.delete(obj)
63
+ siblings.delete(id)
64
+ end
65
+ else
66
+ raise "class mismatch #{obj.class} != #{object.class}. Old object is #{obj}"
67
+ end
68
+ elsif block_given?
69
+ ids.merge objects.delete(obj)
70
+ object = yield(obj)
71
+ else
72
+ object = obj
73
+ end
74
+ end
75
+
76
+ objects[object] ||= Set.new
77
+ objects[object].merge ids
78
+ for i in ids
79
+ siblings[i] = object
80
+ end
81
+
82
+ object
83
+ end
84
+
85
+ def add_id(object, id)
86
+ if siblings[id]
87
+ raise "there is already an object for this ID"
88
+ elsif !id.kind_of(Distributed::RemoteID)
89
+ raise "#{id} is not a valid RemoteID"
90
+ end
91
+
92
+ siblings[id] = object
93
+ objects[object] << id
94
+ end
95
+
96
+ def remove_id(id)
97
+ if !(object = siblings.delete(id))
98
+ raise "#{id} does not reference anything"
99
+ end
100
+ objects[object].delete(id)
101
+ end
102
+
103
+ def remove(object)
104
+ object = local_object(object)
105
+
106
+ ids = objects.delete(object)
107
+ for i in ids
108
+ siblings.delete(i)
109
+ end
110
+ end
111
+ end
112
+
113
+ class PlanObject::DRoby
114
+ include DirectedRelationSupport
115
+ attr_writer :plan
116
+
117
+ def update_from(new)
118
+ super if defined? super
119
+ end
120
+ end
121
+ class TaskEventGenerator::DRoby
122
+ include DirectedRelationSupport
123
+ attr_writer :plan
124
+ attr_writer :task
125
+
126
+ def update_from(new)
127
+ super if defined? super
128
+ end
129
+ end
130
+ class Task::DRoby
131
+ attr_writer :plan
132
+ attribute(:events) { Hash.new }
133
+
134
+ def update_from(new)
135
+ super if defined? super
136
+ self.flags.merge! new.flags
137
+ self.plan = new.plan
138
+ end
139
+ end
140
+
141
+ class Transaction::Proxy::DRoby
142
+ include DirectedRelationSupport
143
+ attr_writer :transaction
144
+ attr_accessor :plan
145
+
146
+ def events; Hash.new end
147
+ def update_from(new)
148
+ super if defined? super
149
+ end
150
+ end
151
+
152
+ module LoggedPlan
153
+ attribute(:missions) { ValueSet.new }
154
+ attribute(:known_tasks) { ValueSet.new }
155
+ attribute(:free_events) { ValueSet.new }
156
+ attribute(:transactions) { ValueSet.new }
157
+ attribute(:finalized_tasks) { ValueSet.new }
158
+ attribute(:finalized_events) { ValueSet.new }
159
+ attribute(:proxies) { ValueSet.new }
160
+ attr_accessor :parent_plan
161
+
162
+ def root_plan?; !parent_plan end
163
+ def update_from(new); end
164
+ def clear
165
+ transactions.dup.each do |trsc|
166
+ trsc.clear
167
+ removed_transaction(trsc)
168
+ end
169
+ known_tasks.dup.each { |t| finalized_task(t) }
170
+ free_events.dup.each { |e| finalized_event(e) }
171
+ clear_finalized(finalized_tasks, finalized_events)
172
+ end
173
+
174
+ def finalized_task(task)
175
+ missions.delete(task)
176
+ known_tasks.delete(task)
177
+ proxies.delete(task)
178
+ finalized_tasks << task
179
+ end
180
+ def finalized_event(event)
181
+ free_events.delete(event)
182
+ proxies.delete(event)
183
+ finalized_events << event unless event.respond_to?(:task)
184
+ end
185
+ def clear_finalized(tasks, events)
186
+ tasks.each { |task| task.clear_vertex }
187
+ @finalized_tasks = finalized_tasks - tasks
188
+ events.each { |event| event.clear_vertex }
189
+ @finalized_events = finalized_events - events
190
+ end
191
+ def removed_transaction(trsc)
192
+ transactions.delete(trsc)
193
+ end
194
+ end
195
+
196
+ class Plan::DRoby
197
+ include LoggedPlan
198
+ end
199
+
200
+ class Distributed::Transaction::DRoby
201
+ include LoggedPlan
202
+ attr_writer :plan
203
+ end
204
+
205
+ module Log
206
+ # This class rebuilds a plan-like structure from events saved by a
207
+ # FileLogger object This is compatible with the EventStream data source
208
+ class PlanRebuilder < DataDecoder
209
+ attr_reader :plans
210
+ attr_reader :tasks
211
+ attr_reader :events
212
+ attr_reader :last_finalized
213
+ attr_reader :manager
214
+
215
+ attr_reader :start_time
216
+ attr_reader :time
217
+ def initialize(name)
218
+ @plans = ValueSet.new
219
+ @tasks = ValueSet.new
220
+ @events = ValueSet.new
221
+ @manager = ObjectIDManager.new
222
+ @last_finalized = Hash.new
223
+ super(name)
224
+ end
225
+
226
+ def clear
227
+ manager.clear
228
+ super
229
+
230
+ plans.dup.each { |p, _| p.clear if p.root_plan? }
231
+ plans.clear
232
+ tasks.clear
233
+ events.clear
234
+ @start_time = nil
235
+ @time = nil
236
+ end
237
+
238
+ def rewind
239
+ clear
240
+ end
241
+
242
+ def process(data)
243
+ @time = data.last[0][:start]
244
+ @start_time ||= @time
245
+
246
+ data.each_slice(4) do |m, sec, usec, args|
247
+ time = Time.at(sec, usec)
248
+ reason = catch :ignored do
249
+ begin
250
+ if respond_to?(m)
251
+ send(m, time, *args)
252
+ end
253
+ displays.each { |d| d.send(m, time, *args) if d.respond_to?(m) }
254
+ rescue Exception => e
255
+ display_args = args.map do |obj|
256
+ case obj
257
+ when NilClass: 'nil'
258
+ when Time: obj.to_hms
259
+ when DRbObject: obj.inspect
260
+ else (obj.to_s rescue "failed_to_s")
261
+ end
262
+ end
263
+
264
+ raise e, "#{e.message} while serving #{m}(#{display_args.join(", ")})", e.backtrace
265
+ end
266
+ nil
267
+ end
268
+ if reason
269
+ Roby.warn "Ignored #{m}(#{args.join(", ")}): #{reason}"
270
+ end
271
+ end
272
+ end
273
+
274
+ def local_object(object)
275
+ return nil unless object
276
+
277
+ object = manager.local_object(object)
278
+ plan = if block_given?
279
+ yield
280
+ elsif object.respond_to?(:transaction)
281
+ local_plan(object.transaction, false)
282
+ elsif object.respond_to?(:plan)
283
+ local_plan(object.plan, false)
284
+ end
285
+
286
+ if plan
287
+ object.plan = plan
288
+ if object.respond_to?(:transaction)
289
+ object.transaction = plan
290
+ plan.proxies << object
291
+ end
292
+ end
293
+
294
+ object
295
+ end
296
+
297
+ def clear_integrated
298
+ last_finalized.clear
299
+ plans.each do |plan|
300
+ plan.clear_finalized(plan.finalized_tasks.dup, plan.finalized_events.dup)
301
+ end
302
+
303
+ super
304
+ end
305
+
306
+ def display
307
+ plans.each do |plan|
308
+ if finalized = last_finalized[plan]
309
+ plan.clear_finalized(*finalized)
310
+ end
311
+ end
312
+
313
+ super
314
+
315
+ # Save a per-plan set of finalized tasks, to be removed the
316
+ # next time #display is called
317
+ @last_finalized = Hash.new
318
+ plans.each do |plan|
319
+ last_finalized[plan] = [plan.finalized_tasks.dup, plan.finalized_events.dup]
320
+ end
321
+ end
322
+
323
+ def local_plan(plan, allow_new = false)
324
+ plan = manager.local_object(plan, plans.empty? || allow_new)
325
+ plans << plan if plan
326
+ plan
327
+ end
328
+ def local_task(task, &block)
329
+ local_object(task, &block)
330
+ end
331
+ def local_event(event, &block)
332
+ if event.respond_to?(:task)
333
+ task = local_task(event.task, &block)
334
+ if task.events[event.symbol]
335
+ task.events[event.symbol]
336
+ else
337
+ event.task = task
338
+ event.plan = task.plan
339
+ task.events[event.symbol] = event
340
+ end
341
+ else
342
+ local_object(event, &block)
343
+ end
344
+ end
345
+
346
+ def inserted_tasks(time, plan, task)
347
+ plan = local_plan(plan)
348
+ plan.missions << task
349
+ end
350
+ def discarded_tasks(time, plan, task)
351
+ plan = local_plan(plan)
352
+ plan.missions.delete(task)
353
+ end
354
+ def replaced_tasks(time, plan, from, to)
355
+ end
356
+ def discovered_events(time, plan, events)
357
+ plan = local_plan(plan)
358
+ events.each do |ev|
359
+ ev = local_event(ev) { plan }
360
+ plan.free_events << ev
361
+ end
362
+ end
363
+ def discovered_tasks(time, plan, tasks)
364
+ plan = local_plan(plan)
365
+ tasks.each do |t|
366
+ t = local_task(t) { plan }
367
+ plan.known_tasks << t
368
+ end
369
+ end
370
+ def garbage_task(time, plan, task)
371
+ end
372
+ def finalized_event(time, plan, event)
373
+ event = local_event(event)
374
+ plan = local_plan(plan)
375
+ unless event.respond_to?(:task)
376
+ plan.finalized_event(event)
377
+ manager.remove(event)
378
+ end
379
+ end
380
+ def finalized_task(time, plan, task)
381
+ task = local_task(task)
382
+ plan = local_plan(plan)
383
+ plan.finalized_task(task)
384
+ manager.remove(task)
385
+ end
386
+ def added_transaction(time, plan, trsc)
387
+ plan = local_plan(plan)
388
+ trsc = local_plan(trsc, true)
389
+ plan.transactions << trsc
390
+ trsc.parent_plan = plan
391
+ end
392
+ def removed_transaction(time, plan, trsc)
393
+ plan = local_plan(plan)
394
+ trsc = local_plan(trsc)
395
+
396
+ (trsc.known_tasks - plan.known_tasks).each do |obj|
397
+ trsc.finalized_task(obj)
398
+ manager.remove(obj)
399
+ end
400
+ (trsc.free_events - plan.free_events).each do |obj|
401
+ trsc.finalized_event(obj)
402
+ manager.remove(obj)
403
+ end
404
+ trsc.proxies.each do |p|
405
+ manager.remove(p)
406
+ end
407
+
408
+ trsc.clear_finalized(trsc.finalized_tasks, trsc.finalized_events)
409
+ plans.delete(trsc)
410
+ manager.remove(trsc)
411
+ plan.transactions.delete(trsc)
412
+ end
413
+
414
+ GENERATOR_TO_STATE = { :start => :started,
415
+ :success => :success,
416
+ :stop => :finished }
417
+
418
+ def generator_fired(time, generator, id, ev_time, context)
419
+ generator = local_event(generator)
420
+ generator.instance_variable_set("@happened", true)
421
+ if generator.respond_to?(:task) && (state = GENERATOR_TO_STATE[generator.symbol])
422
+ generator.task.flags[state] = true
423
+ end
424
+ end
425
+
426
+ def added_task_child(time, parent, rel, child, info)
427
+ parent = local_task(parent)
428
+ child = local_task(child)
429
+ if !parent then throw :ignored, "unknown parent"
430
+ elsif !child then throw :ignored, "unknown child"
431
+ end
432
+
433
+ rel = rel.first if rel.kind_of?(Array)
434
+ rel = rel.proxy(nil)
435
+ parent.add_child_object(child, rel, info)
436
+ end
437
+ def removed_task_child(time, parent, rel, child)
438
+ parent = local_task(parent)
439
+ child = local_task(child)
440
+ rel = rel.first if rel.kind_of?(Array)
441
+ rel = rel.proxy(nil)
442
+ parent.remove_child_object(child, rel)
443
+ end
444
+ def added_event_child(time, parent, rel, child, info)
445
+ parent = local_event(parent)
446
+ child = local_event(child)
447
+ rel = rel.first if rel.kind_of?(Array)
448
+ rel = rel.proxy(nil)
449
+ parent.add_child_object(child, rel, info)
450
+ end
451
+ def removed_event_child(time, parent, rel, child)
452
+ parent = local_event(parent)
453
+ child = local_event(child)
454
+ rel = rel.first if rel.kind_of?(Array)
455
+ rel = rel.proxy(nil)
456
+ parent.remove_child_object(child, rel)
457
+ end
458
+ def added_owner(time, object, peer)
459
+ object = local_object(object)
460
+ object.owners << peer
461
+ end
462
+ def removed_owner(time, object, peer)
463
+ object = local_object(object)
464
+ object.owners.delete(peer)
465
+ end
466
+ end
467
+
468
+ end
469
+ end
470
+